blob: 012536249114d8398f55e675768c1057d8310a1f [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
//
// 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