| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // The contents of this file are subject to the Mozilla Public License |
| // Version 1.1 (the "License"); you may not use this file except in |
| // compliance with the License. You may obtain a copy of the License at |
| // http://www.mozilla.org/MPL/ |
| // |
| // Software distributed under the License is distributed on an "AS IS" |
| // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
| // License for the specific language governing rights and limitations |
| // under the License. |
| // |
| // The Original Code is MP4v2. |
| // |
| // The Initial Developer of the Original Code is Kona Blend. |
| // Portions created by Kona Blend are Copyright (C) 2008. |
| // All Rights Reserved. |
| // |
| // Contributors: |
| // Kona Blend, kona8lend@@gmail.com |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "impl.h" |
| |
| namespace mp4v2 { namespace impl { namespace itmf { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| CoverArtBox::Item::Item() |
| : type ( BT_UNDEFINED ) |
| , buffer ( NULL ) |
| , size ( 0 ) |
| , autofree ( false ) |
| { |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| CoverArtBox::Item::Item( const Item& rhs ) |
| : type ( BT_UNDEFINED ) |
| , buffer ( NULL ) |
| , size ( 0 ) |
| , autofree ( false ) |
| { |
| operator=( rhs ); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| CoverArtBox::Item::~Item() |
| { |
| reset(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| CoverArtBox::Item& |
| CoverArtBox::Item::operator=( const Item& rhs ) |
| { |
| type = rhs.type; |
| size = rhs.size; |
| autofree = rhs.autofree; |
| |
| if( rhs.autofree ) { |
| buffer = (uint8_t*)MP4Malloc(rhs.size); |
| memcpy( buffer, rhs.buffer, rhs.size ); |
| } |
| else { |
| buffer = rhs.buffer; |
| } |
| |
| return *this; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| void |
| CoverArtBox::Item::reset() |
| { |
| if( autofree && buffer ) |
| MP4Free( buffer ); |
| |
| type = BT_UNDEFINED; |
| buffer = NULL; |
| size = 0; |
| autofree = false; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| bool |
| CoverArtBox::add( MP4FileHandle hFile, const Item& item ) |
| { |
| MP4File& file = *((MP4File*)hFile); |
| |
| const char* const covr_name = "moov.udta.meta.ilst.covr"; |
| MP4Atom* covr = file.FindAtom( covr_name ); |
| if( !covr ) { |
| file.AddDescendantAtoms( "moov", "udta.meta.ilst.covr" ); |
| |
| covr = file.FindAtom( covr_name ); |
| if( !covr ) |
| return true; |
| } |
| |
| // use empty data atom if one exists |
| MP4Atom* data = NULL; |
| uint32_t index = 0; |
| const uint32_t atomc = covr->GetNumberOfChildAtoms(); |
| for( uint32_t i = 0; i < atomc; i++ ) { |
| MP4Atom* atom = covr->GetChildAtom( i ); |
| |
| MP4BytesProperty* metadata = NULL; |
| if( !atom->FindProperty( "data.metadata", (MP4Property**)&metadata )) |
| continue; |
| |
| if( metadata->GetCount() ) |
| continue; |
| |
| data = atom; |
| index = i; |
| break; |
| } |
| |
| // no empty atom found, create one. |
| if( !data ) { |
| data = MP4Atom::CreateAtom( file, covr, "data" ); |
| covr->AddChildAtom( data ); |
| data->Generate(); |
| index = covr->GetNumberOfChildAtoms() - 1; |
| } |
| |
| return set( hFile, item, index ); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| bool |
| CoverArtBox::get( MP4FileHandle hFile, Item& item, uint32_t index ) |
| { |
| item.reset(); |
| MP4File& file = *((MP4File*)hFile); |
| |
| MP4Atom* covr = file.FindAtom( "moov.udta.meta.ilst.covr" ); |
| if( !covr ) |
| return true; |
| |
| if( !(index < covr->GetNumberOfChildAtoms()) ) |
| return true; |
| |
| MP4DataAtom* data = static_cast<MP4DataAtom*>( covr->GetChildAtom( index )); |
| if( !data ) |
| return true; |
| |
| MP4BytesProperty* metadata = NULL; |
| if ( !data->FindProperty( "data.metadata", (MP4Property**)&metadata )) |
| return true; |
| |
| metadata->GetValue( &item.buffer, &item.size ); |
| item.autofree = true; |
| item.type = data->typeCode.GetValue(); |
| |
| return false; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| bool |
| CoverArtBox::list( MP4FileHandle hFile, ItemList& out ) |
| { |
| out.clear(); |
| MP4File& file = *((MP4File*)hFile); |
| MP4ItmfItemList* itemList = genericGetItemsByCode( file, "covr" ); // alloc |
| |
| if( itemList->size ) { |
| MP4ItmfDataList& dataList = itemList->elements[0].dataList; |
| out.resize( dataList.size ); |
| for( uint32_t i = 0; i < dataList.size; i++ ) |
| get( hFile, out[i], i ); |
| } |
| |
| genericItemListFree( itemList ); // free |
| return false; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| bool |
| CoverArtBox::remove( MP4FileHandle hFile, uint32_t index ) |
| { |
| MP4File& file = *((MP4File*)hFile); |
| |
| MP4Atom* covr = file.FindAtom( "moov.udta.meta.ilst.covr" ); |
| if( !covr ) |
| return true; |
| |
| // wildcard mode: delete covr and all images |
| if( index == numeric_limits<uint32_t>::max() ) { |
| covr->GetParentAtom()->DeleteChildAtom( covr ); |
| delete covr; |
| return false; |
| } |
| |
| if( !(index < covr->GetNumberOfChildAtoms()) ) |
| return true; |
| |
| MP4Atom* data = covr->GetChildAtom( index ); |
| if( !data ) |
| return true; |
| |
| // delete single image |
| covr->DeleteChildAtom( data ); |
| delete data; |
| |
| // delete empty covr |
| if( covr->GetNumberOfChildAtoms() == 0 ) { |
| covr->GetParentAtom()->DeleteChildAtom( covr ); |
| delete covr; |
| } |
| |
| return false; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| bool |
| CoverArtBox::set( MP4FileHandle hFile, const Item& item, uint32_t index ) |
| { |
| MP4File& file = *((MP4File*)hFile); |
| |
| MP4Atom* covr = file.FindAtom( "moov.udta.meta.ilst.covr" ); |
| if( !covr ) |
| return true; |
| |
| if( !(index < covr->GetNumberOfChildAtoms()) ) |
| return true; |
| |
| MP4DataAtom* data = static_cast<MP4DataAtom*>( covr->GetChildAtom( index )); |
| if( !data ) |
| return true; |
| |
| MP4BytesProperty* metadata = NULL; |
| if ( !data->FindProperty( "data.metadata", (MP4Property**)&metadata )) |
| return true; |
| |
| // autodetect type if BT_UNDEFINED |
| const BasicType final_type = (item.type == BT_UNDEFINED) |
| ? computeBasicType( item.buffer, item.size ) |
| : item.type; |
| |
| // set type; note: not really flags due to b0rked atom structure |
| data->typeCode.SetValue( final_type ); |
| metadata->SetValue( item.buffer, item.size ); |
| |
| return false; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| }}} // namespace mp4v2::impl::itmf |