| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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, 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 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 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 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 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 string& code, 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 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 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 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 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 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 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 string& code, const 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 string Tags::CODE_NAME = "\xa9" "nam"; |
| const string Tags::CODE_ARTIST = "\xa9" "ART"; |
| const string Tags::CODE_ALBUMARTIST = "aART"; |
| const string Tags::CODE_ALBUM = "\xa9" "alb"; |
| const string Tags::CODE_GROUPING = "\xa9" "grp"; |
| const string Tags::CODE_COMPOSER = "\xa9" "wrt"; |
| const string Tags::CODE_COMMENTS = "\xa9" "cmt"; |
| const string Tags::CODE_GENRE = "\xa9" "gen"; |
| const string Tags::CODE_GENRETYPE = "gnre"; |
| const string Tags::CODE_RELEASEDATE = "\xa9" "day"; |
| const string Tags::CODE_TRACK = "trkn"; |
| const string Tags::CODE_DISK = "disk"; |
| const string Tags::CODE_TEMPO = "tmpo"; |
| const string Tags::CODE_COMPILATION = "cpil"; |
| |
| const string Tags::CODE_TVSHOW = "tvsh"; |
| const string Tags::CODE_TVNETWORK = "tvnn"; |
| const string Tags::CODE_TVEPISODEID = "tven"; |
| const string Tags::CODE_TVSEASON = "tvsn"; |
| const string Tags::CODE_TVEPISODE = "tves"; |
| |
| const string Tags::CODE_DESCRIPTION = "desc"; |
| const string Tags::CODE_LONGDESCRIPTION = "ldes"; |
| const string Tags::CODE_LYRICS = "\xa9" "lyr"; |
| |
| const string Tags::CODE_SORTNAME = "sonm"; |
| const string Tags::CODE_SORTARTIST = "soar"; |
| const string Tags::CODE_SORTALBUMARTIST = "soaa"; |
| const string Tags::CODE_SORTALBUM = "soal"; |
| const string Tags::CODE_SORTCOMPOSER = "soco"; |
| const string Tags::CODE_SORTTVSHOW = "sosn"; |
| |
| const string Tags::CODE_COPYRIGHT = "cprt"; |
| const string Tags::CODE_ENCODINGTOOL = "\xa9" "too"; |
| const string Tags::CODE_ENCODEDBY = "\xa9" "enc"; |
| const string Tags::CODE_PURCHASEDATE = "purd"; |
| |
| const string Tags::CODE_PODCAST = "pcst"; |
| const string Tags::CODE_KEYWORDS = "keyw"; |
| const string Tags::CODE_CATEGORY = "catg"; |
| |
| const string Tags::CODE_HDVIDEO = "hdvd"; |
| const string Tags::CODE_MEDIATYPE = "stik"; |
| const string Tags::CODE_CONTENTRATING = "rtng"; |
| const string Tags::CODE_GAPLESS = "pgap"; |
| |
| const string Tags::CODE_ITUNESACCOUNT = "apID"; |
| const string Tags::CODE_ITUNESACCOUNTTYPE = "akID"; |
| const string Tags::CODE_ITUNESCOUNTRY = "sfID"; |
| const string Tags::CODE_CONTENTID = "cnID"; |
| const string Tags::CODE_ARTISTID = "atID"; |
| const string Tags::CODE_PLAYLISTID = "plID"; |
| const string Tags::CODE_GENREID = "geID"; |
| const string Tags::CODE_COMPOSERID = "cmID"; |
| const string Tags::CODE_XID = "xid "; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| }}} // namespace mp4v2::impl::itmf |