blob: f4d055ff5f2569d36687dbb57bb7124c852a5fe3 [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.
// Portions created by David Byron are Copyright (C) 2011.
// All Rights Reserved.
//
// Contributors:
// Kona Blend, kona8lend@@gmail.com
// Rouven Wessling, mp4v2@rouvenwessling.de
// David Byron, dbyron@dbyron.com
//
///////////////////////////////////////////////////////////////////////////////
#include "impl.h"
namespace mp4v2 { namespace impl { namespace itmf {
///////////////////////////////////////////////////////////////////////////////
Tags::Tags()
: hasMetadata(false)
{
}
///////////////////////////////////////////////////////////////////////////////
Tags::~Tags()
{
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_addArtwork( MP4Tags*& tags, MP4TagArtwork& c_artwork )
{
artwork.resize( artwork.size() + 1 );
c_setArtwork( tags, (uint32_t)artwork.size() - 1, c_artwork );
updateArtworkShadow( tags );
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_alloc( MP4Tags*& tags )
{
tags = new MP4Tags();
memset( tags, 0, sizeof(MP4Tags) ); // safe: pure C-struct
tags->__handle = this;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_fetch( MP4Tags*& tags, MP4FileHandle hFile )
{
MP4Tags& c = *tags;
MP4File& file = *static_cast<MP4File*>(hFile);
MP4ItmfItemList* itemList = genericGetItems( file ); // alloc
hasMetadata = (itemList->size > 0);
/* create code -> item map.
* map will only be used for items which do not repeat; we do not care if
* cover-art is inserted multiple times.
*/
CodeItemMap cim;
for( uint32_t i = 0; i < itemList->size; i++ ) {
MP4ItmfItem& item = itemList->elements[i];
cim.insert( CodeItemMap::value_type( item.code, &item ));
}
fetchString( cim, CODE_NAME, name, c.name );
fetchString( cim, CODE_ARTIST, artist, c.artist );
fetchString( cim, CODE_ALBUMARTIST, albumArtist, c.albumArtist );
fetchString( cim, CODE_ALBUM, album, c.album );
fetchString( cim, CODE_GROUPING, grouping, c.grouping );
fetchString( cim, CODE_COMPOSER, composer, c.composer );
fetchString( cim, CODE_COMMENTS, comments, c.comments );
fetchString( cim, CODE_GENRE, genre, c.genre );
fetchGenre( cim, genreType, c.genreType );
fetchString( cim, CODE_RELEASEDATE, releaseDate, c.releaseDate );
fetchTrack( cim, track, c.track );
fetchDisk( cim, disk, c.disk );
fetchInteger( cim, CODE_TEMPO, tempo, c.tempo );
fetchInteger( cim, CODE_COMPILATION, compilation, c.compilation );
fetchString( cim, CODE_TVSHOW, tvShow, c.tvShow );
fetchString( cim, CODE_TVNETWORK, tvNetwork, c.tvNetwork );
fetchString( cim, CODE_TVEPISODEID, tvEpisodeID, c.tvEpisodeID );
fetchInteger( cim, CODE_TVSEASON, tvSeason, c.tvSeason );
fetchInteger( cim, CODE_TVEPISODE, tvEpisode, c.tvEpisode );
fetchString( cim, CODE_SORTNAME, sortName, c.sortName );
fetchString( cim, CODE_SORTARTIST, sortArtist, c.sortArtist );
fetchString( cim, CODE_SORTALBUMARTIST, sortAlbumArtist, c.sortAlbumArtist );
fetchString( cim, CODE_SORTALBUM, sortAlbum, c.sortAlbum );
fetchString( cim, CODE_SORTCOMPOSER, sortComposer, c.sortComposer );
fetchString( cim, CODE_SORTTVSHOW, sortTVShow, c.sortTVShow );
fetchString( cim, CODE_DESCRIPTION, description, c.description );
fetchString( cim, CODE_LONGDESCRIPTION, longDescription, c.longDescription );
fetchString( cim, CODE_LYRICS, lyrics, c.lyrics );
fetchString( cim, CODE_COPYRIGHT, copyright, c.copyright );
fetchString( cim, CODE_ENCODINGTOOL, encodingTool, c.encodingTool );
fetchString( cim, CODE_ENCODEDBY, encodedBy, c.encodedBy );
fetchString( cim, CODE_PURCHASEDATE, purchaseDate, c.purchaseDate );
fetchInteger( cim, CODE_PODCAST, podcast, c.podcast );
fetchString( cim, CODE_KEYWORDS, keywords, c.keywords );
fetchString( cim, CODE_CATEGORY, category, c.category );
fetchInteger( cim, CODE_HDVIDEO, hdVideo, c.hdVideo );
fetchInteger( cim, CODE_MEDIATYPE, mediaType, c.mediaType );
fetchInteger( cim, CODE_CONTENTRATING, contentRating, c.contentRating );
fetchInteger( cim, CODE_GAPLESS, gapless, c.gapless );
fetchString( cim, CODE_ITUNESACCOUNT, iTunesAccount, c.iTunesAccount );
fetchInteger( cim, CODE_ITUNESACCOUNTTYPE, iTunesAccountType, c.iTunesAccountType );
fetchInteger( cim, CODE_ITUNESCOUNTRY, iTunesCountry, c.iTunesCountry );
fetchInteger( cim, CODE_CONTENTID, contentID, c.contentID );
fetchInteger( cim, CODE_ARTISTID, artistID, c.artistID );
fetchInteger( cim, CODE_PLAYLISTID, playlistID, c.playlistID );
fetchInteger( cim, CODE_GENREID, genreID, c.genreID );
fetchInteger( cim, CODE_COMPOSERID, composerID, c.composerID );
fetchString( cim, CODE_XID, xid, c.xid );
genericItemListFree( itemList ); // free
// fetch full list and overwrite our copy, otherwise clear
{
CoverArtBox::ItemList items;
if( CoverArtBox::list( hFile, items ))
artwork.clear();
else
artwork = items;
updateArtworkShadow( tags );
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_free( MP4Tags*& tags )
{
MP4Tags* c = const_cast<MP4Tags*>(tags);
delete[] c->artwork;
delete c;
tags = NULL;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_removeArtwork( MP4Tags*& tags, uint32_t index )
{
if( !(index < artwork.size()) )
return;
artwork.erase( artwork.begin() + index );
updateArtworkShadow( tags );
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_setArtwork( MP4Tags*& tags, uint32_t index, MP4TagArtwork& c_artwork )
{
if( !(index < artwork.size()) )
return;
CoverArtBox::Item& item = artwork[index];
switch( c_artwork.type ) {
case MP4_ART_BMP:
item.type = BT_BMP;
break;
case MP4_ART_GIF:
item.type = BT_GIF;
break;
case MP4_ART_JPEG:
item.type = BT_JPEG;
break;
case MP4_ART_PNG:
item.type = BT_PNG;
break;
case MP4_ART_UNDEFINED:
default:
item.type = computeBasicType( c_artwork.data, c_artwork.size );
break;
}
item.buffer = (uint8_t*)malloc( c_artwork.size );
item.size = c_artwork.size;
item.autofree = true;
memcpy( item.buffer, c_artwork.data, c_artwork.size );
updateArtworkShadow( tags );
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_setInteger( const uint8_t* value, uint8_t& cpp, const uint8_t*& c )
{
if( !value ) {
cpp = 0;
c = NULL;
}
else {
cpp = *value;
c = &cpp;
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_setInteger( const uint16_t* value, uint16_t& cpp, const uint16_t*& c )
{
if( !value ) {
cpp = 0;
c = NULL;
}
else {
cpp = *value;
c = &cpp;
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_setInteger( const uint32_t* value, uint32_t& cpp, const uint32_t*& c )
{
if( !value ) {
cpp = 0;
c = NULL;
}
else {
cpp = *value;
c = &cpp;
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_setInteger( const uint64_t* value, uint64_t& cpp, const uint64_t*& c )
{
if( !value ) {
cpp = 0;
c = NULL;
}
else {
cpp = *value;
c = &cpp;
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_setString( const char* value, std::string& cpp, const char*& c )
{
if( !value ) {
cpp.clear();
c = NULL;
}
else {
cpp = value;
c = cpp.c_str();
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_setTrack( const MP4TagTrack* value, MP4TagTrack& cpp, const MP4TagTrack*& c )
{
if( !value ) {
cpp.index = 0;
cpp.total = 0;
c = NULL;
}
else {
cpp.index = value->index;
cpp.total = value->total;
c = &cpp;
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_setDisk( const MP4TagDisk* value, MP4TagDisk& cpp, const MP4TagDisk*& c )
{
if( !value ) {
cpp.index = 0;
cpp.total = 0;
c = NULL;
}
else {
cpp.index = value->index;
cpp.total = value->total;
c = &cpp;
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::c_store( MP4Tags*& tags, MP4FileHandle hFile )
{
MP4Tags& c = *tags;
MP4File& file = *static_cast<MP4File*>(hFile);
storeString( file, CODE_NAME, name, c.name );
storeString( file, CODE_ARTIST, artist, c.artist );
storeString( file, CODE_ALBUMARTIST, albumArtist, c.albumArtist );
storeString( file, CODE_ALBUM, album, c.album );
storeString( file, CODE_GROUPING, grouping, c.grouping );
storeString( file, CODE_COMPOSER, composer, c.composer );
storeString( file, CODE_COMMENTS, comments, c.comments );
storeString( file, CODE_GENRE, genre, c.genre );
storeGenre( file, genreType, c.genreType );
storeString( file, CODE_RELEASEDATE, releaseDate, c.releaseDate );
storeTrack( file, track, c.track );
storeDisk( file, disk, c.disk );
storeInteger( file, CODE_TEMPO, tempo, c.tempo );
storeInteger( file, CODE_COMPILATION, compilation, c.compilation );
storeString( file, CODE_TVSHOW, tvShow, c.tvShow );
storeString( file, CODE_TVNETWORK, tvNetwork, c.tvNetwork );
storeString( file, CODE_TVEPISODEID, tvEpisodeID, c.tvEpisodeID );
storeInteger( file, CODE_TVSEASON, tvSeason, c.tvSeason );
storeInteger( file, CODE_TVEPISODE, tvEpisode, c.tvEpisode );
storeString( file, CODE_SORTNAME, sortName, c.sortName );
storeString( file, CODE_SORTARTIST, sortArtist, c.sortArtist );
storeString( file, CODE_SORTALBUMARTIST, sortAlbumArtist, c.sortAlbumArtist );
storeString( file, CODE_SORTALBUM, sortAlbum, c.sortAlbum );
storeString( file, CODE_SORTCOMPOSER, sortComposer, c.sortComposer );
storeString( file, CODE_SORTTVSHOW, sortTVShow, c.sortTVShow );
storeString( file, CODE_DESCRIPTION, description, c.description );
storeString( file, CODE_LONGDESCRIPTION, longDescription, c.longDescription );
storeString( file, CODE_LYRICS, lyrics, c.lyrics );
storeString( file, CODE_COPYRIGHT, copyright, c.copyright );
storeString( file, CODE_ENCODINGTOOL, encodingTool, c.encodingTool );
storeString( file, CODE_ENCODEDBY, encodedBy, c.encodedBy );
storeString( file, CODE_PURCHASEDATE, purchaseDate, c.purchaseDate );
storeInteger( file, CODE_PODCAST, podcast, c.podcast );
storeString( file, CODE_KEYWORDS, keywords, c.keywords );
storeString( file, CODE_CATEGORY, category, c.category );
storeInteger( file, CODE_HDVIDEO, hdVideo, c.hdVideo );
storeInteger( file, CODE_MEDIATYPE, mediaType, c.mediaType );
storeInteger( file, CODE_CONTENTRATING, contentRating, c.contentRating );
storeInteger( file, CODE_GAPLESS, gapless, c.gapless );
storeString( file, CODE_ITUNESACCOUNT, iTunesAccount, c.iTunesAccount );
storeInteger( file, CODE_ITUNESACCOUNTTYPE, iTunesAccountType, c.iTunesAccountType );
storeInteger( file, CODE_ITUNESCOUNTRY, iTunesCountry, c.iTunesCountry );
storeInteger( file, CODE_CONTENTID, contentID, c.contentID );
storeInteger( file, CODE_ARTISTID, artistID, c.artistID );
storeInteger( file, CODE_PLAYLISTID, playlistID, c.playlistID );
storeInteger( file, CODE_GENREID, genreID, c.genreID );
storeInteger( file, CODE_COMPOSERID, composerID, c.composerID );
storeString( file, CODE_XID, xid, c.xid );
// destroy all cover-art then add each
{
CoverArtBox::remove( hFile );
const CoverArtBox::ItemList::size_type max = artwork.size();
for( CoverArtBox::ItemList::size_type i = 0; i < max; i++ )
CoverArtBox::add( hFile, artwork[i] );
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::fetchGenre( const CodeItemMap& cim, uint16_t& cpp, const uint16_t*& c )
{
cpp = 0;
c = NULL;
CodeItemMap::const_iterator f = cim.find( CODE_GENRETYPE );
if( f == cim.end() || 0 == f->second->dataList.size )
return;
MP4ItmfData& data = f->second->dataList.elements[0];
if( NULL == data.value )
return;
cpp = (uint16_t(data.value[0]) << 8)
| (uint16_t(data.value[1]) );
c = &cpp;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::fetchDisk( const CodeItemMap& cim, MP4TagDisk& cpp, const MP4TagDisk*& c )
{
cpp.index = 0;
cpp.total = 0;
c = NULL;
CodeItemMap::const_iterator f = cim.find( CODE_DISK );
if( f == cim.end() || 0 == f->second->dataList.size )
return;
MP4ItmfData& data = f->second->dataList.elements[0];
if( NULL == data.value )
return;
cpp.index = (uint16_t(data.value[2]) << 8)
| (uint16_t(data.value[3]) );
cpp.total = (uint16_t(data.value[4]) << 8)
| (uint16_t(data.value[5]) );
c = &cpp;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::fetchTrack( const CodeItemMap& cim, MP4TagTrack& cpp, const MP4TagTrack*& c )
{
cpp.index = 0;
cpp.total = 0;
c = NULL;
CodeItemMap::const_iterator f = cim.find( CODE_TRACK );
if( f == cim.end() || 0 == f->second->dataList.size )
return;
MP4ItmfData& data = f->second->dataList.elements[0];
if( NULL == data.value )
return;
cpp.index = (uint16_t(data.value[2]) << 8)
| (uint16_t(data.value[3]) );
cpp.total = (uint16_t(data.value[4]) << 8)
| (uint16_t(data.value[5]) );
c = &cpp;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::fetchInteger( const CodeItemMap& cim, const std::string& code, uint8_t& cpp, const uint8_t*& c )
{
cpp = 0;
c = NULL;
CodeItemMap::const_iterator f = cim.find( code );
if( f == cim.end() || 0 == f->second->dataList.size )
return;
MP4ItmfData& data = f->second->dataList.elements[0];
if( NULL == data.value )
return;
cpp = data.value[0];
c = &cpp;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::fetchInteger( const CodeItemMap& cim, const std::string& code, uint16_t& cpp, const uint16_t*& c )
{
cpp = 0;
c = NULL;
CodeItemMap::const_iterator f = cim.find( code );
if( f == cim.end() || 0 == f->second->dataList.size )
return;
MP4ItmfData& data = f->second->dataList.elements[0];
if( NULL == data.value )
return;
cpp = (uint16_t(data.value[0]) << 8)
| (uint16_t(data.value[1]) );
c = &cpp;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::fetchInteger( const CodeItemMap& cim, const std::string& code, uint32_t& cpp, const uint32_t*& c )
{
cpp = 0;
c = NULL;
CodeItemMap::const_iterator f = cim.find( code );
if( f == cim.end() || 0 == f->second->dataList.size )
return;
MP4ItmfData& data = f->second->dataList.elements[0];
if( NULL == data.value )
return;
cpp = (uint32_t(data.value[0]) << 24)
| (uint32_t(data.value[1]) << 16)
| (uint32_t(data.value[2]) << 8)
| (uint32_t(data.value[3]) );
c = &cpp;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::fetchInteger( const CodeItemMap& cim, const std::string& code, uint64_t& cpp, const uint64_t*& c )
{
cpp = 0;
c = NULL;
CodeItemMap::const_iterator f = cim.find( code );
if( f == cim.end() || 0 == f->second->dataList.size )
return;
MP4ItmfData& data = f->second->dataList.elements[0];
if( NULL == data.value )
return;
cpp = (uint64_t(data.value[0]) << 56)
| (uint64_t(data.value[1]) << 48)
| (uint64_t(data.value[2]) << 40)
| (uint64_t(data.value[3]) << 32)
| (uint64_t(data.value[4]) << 24)
| (uint64_t(data.value[5]) << 16)
| (uint64_t(data.value[6]) << 8)
| (uint64_t(data.value[7]) );
c = &cpp;
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::fetchString( const CodeItemMap& cim, const std::string& code, std::string& cpp, const char*& c )
{
cpp.clear();
c = NULL;
CodeItemMap::const_iterator f = cim.find( code );
if( f == cim.end() || 0 == f->second->dataList.size )
return;
MP4ItmfData& data = f->second->dataList.elements[0];
if( NULL == data.value )
return;
cpp.append( reinterpret_cast<char*>( data.value ), data.valueSize );
c = cpp.c_str();
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::remove( MP4File& file, const std::string& code )
{
MP4ItmfItemList* itemList = genericGetItemsByCode( file, code ); // alloc
if( itemList->size )
genericRemoveItem( file, &itemList->elements[0] );
genericItemListFree( itemList ); // free
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::store( MP4File& file, const std::string& code, MP4ItmfBasicType basicType, const void* buffer, uint32_t size )
{
// remove existing item
remove( file, code );
// add item
MP4ItmfItem& item = *genericItemAlloc( code, 1 ); // alloc
MP4ItmfData& data = item.dataList.elements[0];
data.typeCode = basicType;
data.valueSize = size;
data.value = (uint8_t*)malloc( data.valueSize );
memcpy( data.value, buffer, data.valueSize );
genericAddItem( file, &item );
genericItemFree( &item ); // free
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::storeGenre( MP4File& file, uint16_t cpp, const uint16_t* c )
{
if( c ) {
uint8_t buf[2];
buf[0] = uint8_t((cpp & 0xff00) >> 8);
buf[1] = uint8_t((cpp & 0x00ff) );
// it's not clear if you must use implicit in these situations and iirc iTunes and other software are not consistent in this regard.
// many other tags must be integer type yet no issues there. Silly that iTunes insists it must be implict, which is then hardcoded
// to interpret as genres anyways.
store( file, CODE_GENRETYPE, MP4_ITMF_BT_IMPLICIT, buf, sizeof(buf) );
}
else {
remove( file, CODE_GENRETYPE );
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::storeDisk( MP4File& file, const MP4TagDisk& cpp, const MP4TagDisk* c )
{
if( c ) {
uint8_t buf[6];
memset( buf, 0, sizeof(buf) );
buf[2] = uint8_t((cpp.index & 0xff00) >> 8);
buf[3] = uint8_t((cpp.index & 0x00ff) );
buf[4] = uint8_t((cpp.total & 0xff00) >> 8);
buf[5] = uint8_t((cpp.total & 0x00ff) );
store( file, CODE_DISK, MP4_ITMF_BT_IMPLICIT, buf, sizeof(buf) );
}
else {
remove( file, CODE_DISK );
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::storeTrack( MP4File& file, const MP4TagTrack& cpp, const MP4TagTrack* c )
{
if( c ) {
uint8_t buf[8]; // iTMF spec says 7 but iTunes media is 8
memset( buf, 0, sizeof(buf) );
buf[2] = uint8_t((cpp.index & 0xff00) >> 8);
buf[3] = uint8_t((cpp.index & 0x00ff) );
buf[4] = uint8_t((cpp.total & 0xff00) >> 8);
buf[5] = uint8_t((cpp.total & 0x00ff) );
store( file, CODE_TRACK, MP4_ITMF_BT_IMPLICIT, buf, sizeof(buf) );
}
else {
remove( file, CODE_TRACK );
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::storeInteger( MP4File& file, const std::string& code, uint8_t cpp, const uint8_t* c )
{
if( c )
store( file, code, MP4_ITMF_BT_INTEGER, &cpp, sizeof(cpp) );
else
remove( file, code );
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::storeInteger( MP4File& file, const std::string& code, uint16_t cpp, const uint16_t* c )
{
if( c ) {
uint8_t buf[2];
buf[0] = uint8_t((cpp & 0xff00) >> 8);
buf[1] = uint8_t((cpp & 0x00ff) );
store( file, code, MP4_ITMF_BT_INTEGER, buf, sizeof(buf) );
}
else {
remove( file, code );
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::storeInteger( MP4File& file, const std::string& code, uint32_t cpp, const uint32_t* c )
{
if( c ) {
uint8_t buf[4];
buf[0] = uint8_t((cpp & 0xff000000) >> 24 );
buf[1] = uint8_t((cpp & 0x00ff0000) >> 16 );
buf[2] = uint8_t((cpp & 0x0000ff00) >> 8 );
buf[3] = uint8_t((cpp & 0x000000ff) );
store( file, code, MP4_ITMF_BT_INTEGER, buf, sizeof(buf) );
}
else {
remove( file, code );
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::storeInteger( MP4File& file, const std::string& code, uint64_t cpp, const uint64_t* c )
{
if( c ) {
uint8_t buf[8];
buf[0] = uint8_t((cpp & 0xff00000000000000LL) >> 56 );
buf[1] = uint8_t((cpp & 0x00ff000000000000LL) >> 48 );
buf[2] = uint8_t((cpp & 0x0000ff0000000000LL) >> 40 );
buf[3] = uint8_t((cpp & 0x000000ff00000000LL) >> 32 );
buf[4] = uint8_t((cpp & 0x00000000ff000000LL) >> 24 );
buf[5] = uint8_t((cpp & 0x0000000000ff0000LL) >> 16 );
buf[6] = uint8_t((cpp & 0x000000000000ff00LL) >> 8 );
buf[7] = uint8_t((cpp & 0x00000000000000ffLL) );
store( file, code, MP4_ITMF_BT_INTEGER, buf, sizeof(buf) );
}
else {
remove( file, code );
}
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::storeString( MP4File& file, const std::string& code, const std::string& cpp, const char* c )
{
if( c )
store( file, code, MP4_ITMF_BT_UTF8, cpp.c_str(), (uint32_t)cpp.size() );
else
remove( file, code );
}
///////////////////////////////////////////////////////////////////////////////
void
Tags::updateArtworkShadow( MP4Tags*& tags )
{
if( tags->artwork ) {
delete[] tags->artwork;
tags->artwork = NULL;
tags->artworkCount = 0;
}
if( artwork.empty() )
return;
MP4TagArtwork* const cartwork = new MP4TagArtwork[ artwork.size() ];
uint32_t max = (uint32_t)artwork.size();
for( uint32_t i = 0; i < max; i++ ) {
MP4TagArtwork& a = cartwork[i];
CoverArtBox::Item& item = artwork[i];
a.data = item.buffer;
a.size = item.size;
switch( item.type ) {
case BT_BMP:
a.type = MP4_ART_BMP;
break;
case BT_GIF:
a.type = MP4_ART_GIF;
break;
case BT_JPEG:
a.type = MP4_ART_JPEG;
break;
case BT_PNG:
a.type = MP4_ART_PNG;
break;
default:
a.type = MP4_ART_UNDEFINED;
break;
}
}
tags->artwork = cartwork;
tags->artworkCount = max;
}
///////////////////////////////////////////////////////////////////////////////
const std::string Tags::CODE_NAME = "\xa9" "nam";
const std::string Tags::CODE_ARTIST = "\xa9" "ART";
const std::string Tags::CODE_ALBUMARTIST = "aART";
const std::string Tags::CODE_ALBUM = "\xa9" "alb";
const std::string Tags::CODE_GROUPING = "\xa9" "grp";
const std::string Tags::CODE_COMPOSER = "\xa9" "wrt";
const std::string Tags::CODE_COMMENTS = "\xa9" "cmt";
const std::string Tags::CODE_GENRE = "\xa9" "gen";
const std::string Tags::CODE_GENRETYPE = "gnre";
const std::string Tags::CODE_RELEASEDATE = "\xa9" "day";
const std::string Tags::CODE_TRACK = "trkn";
const std::string Tags::CODE_DISK = "disk";
const std::string Tags::CODE_TEMPO = "tmpo";
const std::string Tags::CODE_COMPILATION = "cpil";
const std::string Tags::CODE_TVSHOW = "tvsh";
const std::string Tags::CODE_TVNETWORK = "tvnn";
const std::string Tags::CODE_TVEPISODEID = "tven";
const std::string Tags::CODE_TVSEASON = "tvsn";
const std::string Tags::CODE_TVEPISODE = "tves";
const std::string Tags::CODE_DESCRIPTION = "desc";
const std::string Tags::CODE_LONGDESCRIPTION = "ldes";
const std::string Tags::CODE_LYRICS = "\xa9" "lyr";
const std::string Tags::CODE_SORTNAME = "sonm";
const std::string Tags::CODE_SORTARTIST = "soar";
const std::string Tags::CODE_SORTALBUMARTIST = "soaa";
const std::string Tags::CODE_SORTALBUM = "soal";
const std::string Tags::CODE_SORTCOMPOSER = "soco";
const std::string Tags::CODE_SORTTVSHOW = "sosn";
const std::string Tags::CODE_COPYRIGHT = "cprt";
const std::string Tags::CODE_ENCODINGTOOL = "\xa9" "too";
const std::string Tags::CODE_ENCODEDBY = "\xa9" "enc";
const std::string Tags::CODE_PURCHASEDATE = "purd";
const std::string Tags::CODE_PODCAST = "pcst";
const std::string Tags::CODE_KEYWORDS = "keyw";
const std::string Tags::CODE_CATEGORY = "catg";
const std::string Tags::CODE_HDVIDEO = "hdvd";
const std::string Tags::CODE_MEDIATYPE = "stik";
const std::string Tags::CODE_CONTENTRATING = "rtng";
const std::string Tags::CODE_GAPLESS = "pgap";
const std::string Tags::CODE_ITUNESACCOUNT = "apID";
const std::string Tags::CODE_ITUNESACCOUNTTYPE = "akID";
const std::string Tags::CODE_ITUNESCOUNTRY = "sfID";
const std::string Tags::CODE_CONTENTID = "cnID";
const std::string Tags::CODE_ARTISTID = "atID";
const std::string Tags::CODE_PLAYLISTID = "plID";
const std::string Tags::CODE_GENREID = "geID";
const std::string Tags::CODE_COMPOSERID = "cmID";
const std::string Tags::CODE_XID = "xid ";
///////////////////////////////////////////////////////////////////////////////
}}} // namespace mp4v2::impl::itmf