| /* mp4tags -- tool to set iTunes-compatible metadata tags |
| * |
| * 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. |
| * |
| * Contributed to MPEG4IP |
| * by Christopher League <league@contrapunctus.net> |
| */ |
| |
| #include "util/impl.h" |
| |
| using namespace mp4v2::util; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| /* One-letter options -- if you want to rearrange these, change them |
| here, immediately below in OPT_STRING, and in the help text. */ |
| #define OPT_HELP 0x01ff |
| #define OPT_VERSION 0x02ff |
| #define OPT_REMOVE 'r' |
| #define OPT_ALBUM 'A' |
| #define OPT_ARTIST 'a' |
| #define OPT_TEMPO 'b' |
| #define OPT_COMMENT 'c' |
| #define OPT_COPYRIGHT 'C' |
| #define OPT_DISK 'd' |
| #define OPT_DISKS 'D' |
| #define OPT_ENCODEDBY 'e' |
| #define OPT_TOOL 'E' |
| #define OPT_GENRE 'g' |
| #define OPT_GROUPING 'G' |
| #define OPT_HD 'H' |
| #define OPT_MEDIA_TYPE 'i' |
| #define OPT_CONTENTID 'I' |
| #define OPT_LONGDESC 'l' |
| #define OPT_GENREID 'j' |
| #define OPT_LYRICS 'L' |
| #define OPT_DESCRIPTION 'm' |
| #define OPT_TVEPISODE 'M' |
| #define OPT_TVSEASON 'n' |
| #define OPT_TVNETWORK 'N' |
| #define OPT_TVEPISODEID 'o' |
| #define OPT_CATEGORY 'O' |
| #define OPT_PLAYLISTID 'p' |
| #define OPT_PICTURE 'P' |
| #define OPT_PODCAST 'B' |
| #define OPT_ALBUM_ARTIST 'R' |
| #define OPT_NAME 's' |
| #define OPT_TVSHOW 'S' |
| #define OPT_TRACK 't' |
| #define OPT_TRACKS 'T' |
| #define OPT_XID 'x' |
| #define OPT_RATING 'X' |
| #define OPT_COMPOSER 'w' |
| #define OPT_RELEASEDATE 'y' |
| #define OPT_ARTISTID 'z' |
| #define OPT_COMPOSERID 'Z' |
| |
| #define OPT_STRING "r:A:a:b:c:C:d:D:e:E:g:G:H:i:I:j:l:L:m:M:n:N:o:O:p:P:B:R:s:S:t:T:x:X:w:y:z:Z:" |
| |
| #define ELEMENT_OF(x,i) x[int(i)] |
| |
| static const char* const help_text = |
| "OPTION... FILE...\n" |
| "Adds or modifies iTunes-compatible tags on MP4 files.\n" |
| "\n" |
| " -help Display this help text and exit\n" |
| " -version Display version information and exit\n" |
| " -A, -album STR Set the album title\n" |
| " -a, -artist STR Set the artist information\n" |
| " -b, -tempo NUM Set the tempo (beats per minute)\n" |
| " -c, -comment STR Set a general comment\n" |
| " -C, -copyright STR Set the copyright information\n" |
| " -d, -disk NUM Set the disk number\n" |
| " -D, -disks NUM Set the number of disks\n" |
| " -e, -encodedby STR Set the name of the person or company who encoded the file\n" |
| " -E, -tool STR Set the software used for encoding\n" |
| " -g, -genre STR Set the genre name\n" |
| " -G, -grouping STR Set the grouping name\n" |
| " -H, -hdvideo NUM Set the HD flag (1\\0)\n" |
| " -i, -type STR Set the Media Type(tvshow, movie, music, ...)\n" |
| " -I, -contentid NUM Set the content ID\n" |
| " -j, -genreid NUM Set the genre ID\n" |
| " -l, -longdesc STR Set the long description\n" |
| " -L, -lyrics NUM Set the lyrics\n" |
| " -m, -description STR Set the short description\n" |
| " -M, -episode NUM Set the episode number\n" |
| " -n, -season NUM Set the season number\n" |
| " -N, -network STR Set the TV network\n" |
| " -o, -episodeid STR Set the TV episode ID\n" |
| " -O, -category STR Set the category\n" |
| " -p, -playlistid NUM Set the playlist ID\n" |
| " -P, -picture PTH Set the picture as a .png\n" |
| " -B, -podcast NUM Set the podcast flag.\n" |
| " -R, -albumartist STR Set the album artist\n" |
| " -s, -song STR Set the song title\n" |
| " -S -show STR Set the TV show\n" |
| " -t, -track NUM Set the track number\n" |
| " -T, -tracks NUM Set the number of tracks\n" |
| " -x, -xid STR Set the globally-unique xid (vendor:scheme:id)\n" |
| " -X, -rating STR Set the Rating(none, clean, explicit)\n" |
| " -w, -writer STR Set the composer information\n" |
| " -y, -year NUM Set the release date\n" |
| " -z, -artistid NUM Set the artist ID\n" |
| " -Z, -composerid NUM Set the composer ID\n" |
| " -r, -remove STR Remove tags by code (e.g. \"-r cs\"\n" |
| " removes the comment and song tags)"; |
| |
| extern "C" int |
| main( int argc, char** argv ) |
| { |
| const prog::Option long_options[] = { |
| { "help", prog::Option::NO_ARG, 0, OPT_HELP }, |
| { "version", prog::Option::NO_ARG, 0, OPT_VERSION }, |
| { "album", prog::Option::REQUIRED_ARG, 0, OPT_ALBUM }, |
| { "artist", prog::Option::REQUIRED_ARG, 0, OPT_ARTIST }, |
| { "comment", prog::Option::REQUIRED_ARG, 0, OPT_COMMENT }, |
| { "copyright", prog::Option::REQUIRED_ARG, 0, OPT_COPYRIGHT }, |
| { "disk", prog::Option::REQUIRED_ARG, 0, OPT_DISK }, |
| { "disks", prog::Option::REQUIRED_ARG, 0, OPT_DISKS }, |
| { "encodedby", prog::Option::REQUIRED_ARG, 0, OPT_ENCODEDBY }, |
| { "tool", prog::Option::REQUIRED_ARG, 0, OPT_TOOL }, |
| { "genre", prog::Option::REQUIRED_ARG, 0, OPT_GENRE }, |
| { "grouping", prog::Option::REQUIRED_ARG, 0, OPT_GROUPING }, |
| { "hdvideo", prog::Option::REQUIRED_ARG, 0, OPT_HD }, |
| { "type", prog::Option::REQUIRED_ARG, 0, OPT_MEDIA_TYPE }, |
| { "contentid", prog::Option::REQUIRED_ARG, 0, OPT_CONTENTID }, |
| { "longdesc", prog::Option::REQUIRED_ARG, 0, OPT_LONGDESC }, |
| { "genreid", prog::Option::REQUIRED_ARG, 0, OPT_GENREID }, |
| { "lyrics", prog::Option::REQUIRED_ARG, 0, OPT_LYRICS }, |
| { "description", prog::Option::REQUIRED_ARG, 0, OPT_DESCRIPTION }, |
| { "episode", prog::Option::REQUIRED_ARG, 0, OPT_TVEPISODE }, |
| { "season", prog::Option::REQUIRED_ARG, 0, OPT_TVSEASON }, |
| { "network", prog::Option::REQUIRED_ARG, 0, OPT_TVNETWORK }, |
| { "episodeid", prog::Option::REQUIRED_ARG, 0, OPT_TVEPISODEID }, |
| { "playlistid", prog::Option::REQUIRED_ARG, 0, OPT_PLAYLISTID }, |
| { "picture", prog::Option::REQUIRED_ARG, 0, OPT_PICTURE }, |
| { "podcast", prog::Option::REQUIRED_ARG, 0, OPT_PODCAST }, |
| { "song", prog::Option::REQUIRED_ARG, 0, OPT_NAME }, |
| { "show", prog::Option::REQUIRED_ARG, 0, OPT_TVSHOW }, |
| { "tempo", prog::Option::REQUIRED_ARG, 0, OPT_TEMPO }, |
| { "track", prog::Option::REQUIRED_ARG, 0, OPT_TRACK }, |
| { "tracks", prog::Option::REQUIRED_ARG, 0, OPT_TRACKS }, |
| { "xid", prog::Option::REQUIRED_ARG, 0, OPT_XID }, |
| { "writer", prog::Option::REQUIRED_ARG, 0, OPT_COMPOSER }, |
| { "year", prog::Option::REQUIRED_ARG, 0, OPT_RELEASEDATE }, |
| { "artistid", prog::Option::REQUIRED_ARG, 0, OPT_ARTISTID }, |
| { "composerid", prog::Option::REQUIRED_ARG, 0, OPT_COMPOSERID }, |
| { "remove", prog::Option::REQUIRED_ARG, 0, OPT_REMOVE }, |
| { "albumartist", prog::Option::REQUIRED_ARG, 0, OPT_ALBUM_ARTIST }, |
| { "category", prog::Option::REQUIRED_ARG, 0, OPT_CATEGORY }, |
| { "rating", prog::Option::REQUIRED_ARG, 0, OPT_RATING }, |
| { NULL, prog::Option::NO_ARG, 0, 0 } |
| }; |
| |
| /* Sparse arrays of tag data: some space is wasted, but it's more |
| convenient to say tags[OPT_SONG] than to enumerate all the |
| metadata types (again) as a struct. */ |
| const char *tags[UCHAR_MAX]; |
| uint64_t nums[UCHAR_MAX]; |
| |
| memset( tags, 0, sizeof( tags ) ); |
| memset( nums, 0, sizeof( nums ) ); |
| |
| /* Any modifications requested? */ |
| int mods = 0; |
| |
| /* Option-processing loop. */ |
| int c = prog::getOptionSingle( argc, argv, OPT_STRING, long_options, NULL ); |
| while ( c != -1 ) { |
| int r = 2; |
| switch ( c ) { |
| /* getopt() returns '?' if there was an error. It already |
| printed the error message, so just return. */ |
| case '?': |
| return 1; |
| |
| /* Help and version requests handled here. */ |
| case OPT_HELP: |
| fprintf( stderr, "usage %s %s\n", argv[0], help_text ); |
| return 0; |
| case OPT_VERSION: |
| fprintf( stderr, "%s - %s\n", argv[0], MP4V2_PROJECT_name_formal ); |
| return 0; |
| |
| /* Integer arguments: convert them using sscanf(). */ |
| case OPT_TEMPO: |
| case OPT_DISK: |
| case OPT_DISKS: |
| case OPT_HD: |
| case OPT_CONTENTID: |
| case OPT_GENREID: |
| case OPT_TVEPISODE: |
| case OPT_TVSEASON: |
| case OPT_PLAYLISTID: |
| case OPT_TRACK: |
| case OPT_TRACKS: |
| case OPT_ARTISTID: |
| case OPT_COMPOSERID: |
| case OPT_PODCAST: |
| if ( c == OPT_PLAYLISTID ) { |
| r = sscanf( prog::optarg, "%llu", &nums[c] ); |
| } else { |
| unsigned int n; |
| r = sscanf( prog::optarg, "%u", &n ); |
| if ( r >= 1 ) |
| { |
| nums[c] = static_cast<uint64_t>( n ); |
| } |
| } |
| if ( r < 1 ) { |
| fprintf( stderr, "%s: option requires integer argument -- %c\n", |
| argv[0], c ); |
| return 2; |
| } |
| /* Break not, lest ye be broken. :) */ |
| /* All arguments: all valid options end up here, and we just |
| stuff the string pointer into the tags[] array. */ |
| default: |
| tags[c] = prog::optarg; |
| mods++; |
| } /* end switch */ |
| |
| c = prog::getOptionSingle( argc, argv, OPT_STRING, long_options, NULL ); |
| } /* end while */ |
| |
| /* Check that we have at least one non-option argument */ |
| if ( ( argc - prog::optind ) < 1 ) { |
| fprintf( stderr, |
| "%s: You must specify at least one MP4 file.\n", |
| argv[0] ); |
| fprintf( stderr, "usage %s %s\n", argv[0], help_text ); |
| return 3; |
| } |
| |
| /* Check that we have at least one requested modification. Probably |
| it's useful instead to print the metadata if no modifications are |
| requested? */ |
| if ( !mods ) { |
| fprintf( stderr, |
| "%s: You must specify at least one tag modification.\n", |
| argv[0] ); |
| fprintf( stderr, "usage %s %s\n", argv[0], help_text ); |
| return 4; |
| } |
| |
| /* Loop through the non-option arguments, and modify the tags as |
| requested. */ |
| while ( prog::optind < argc ) { |
| char *mp4 = argv[prog::optind++]; |
| |
| MP4FileHandle h = MP4Modify( mp4 ); |
| if ( h == MP4_INVALID_FILE_HANDLE ) { |
| fprintf( stderr, "Could not open '%s'... aborting\n", mp4 ); |
| return 5; |
| } |
| /* Read out the existing metadata */ |
| const MP4Tags* mdata = MP4TagsAlloc(); |
| MP4TagsFetch( mdata, h ); |
| |
| /* Remove any tags */ |
| if ( ELEMENT_OF(tags,OPT_REMOVE) ) { |
| for ( const char *p = ELEMENT_OF(tags,OPT_REMOVE); *p; p++ ) { |
| switch ( *p ) { |
| case OPT_ALBUM: |
| MP4TagsSetAlbum( mdata, NULL ); |
| break; |
| case OPT_ARTIST: |
| MP4TagsSetArtist( mdata, NULL ); |
| break; |
| case OPT_TEMPO: |
| MP4TagsSetTempo( mdata, NULL ); |
| break; |
| case OPT_COMMENT: |
| MP4TagsSetComments( mdata, NULL ); |
| break; |
| case OPT_COPYRIGHT: |
| MP4TagsSetCopyright( mdata, NULL ); |
| break; |
| case OPT_DISK: |
| MP4TagsSetDisk( mdata, NULL ); |
| break; |
| case OPT_DISKS: |
| MP4TagsSetDisk( mdata, NULL ); |
| break; |
| case OPT_ENCODEDBY: |
| MP4TagsSetEncodedBy( mdata, NULL ); |
| break; |
| case OPT_TOOL: |
| MP4TagsSetEncodingTool( mdata, NULL ); |
| break; |
| case OPT_GENRE: |
| MP4TagsSetGenre( mdata, NULL ); |
| break; |
| case OPT_GROUPING: |
| MP4TagsSetGrouping( mdata, NULL ); |
| break; |
| case OPT_HD: |
| MP4TagsSetHDVideo( mdata, NULL ); |
| break; |
| case OPT_MEDIA_TYPE: |
| MP4TagsSetMediaType( mdata, NULL ); |
| break; |
| case OPT_CONTENTID: |
| MP4TagsSetContentID( mdata, NULL ); |
| break; |
| case OPT_LONGDESC: |
| MP4TagsSetLongDescription( mdata, NULL ); |
| break; |
| case OPT_GENREID: |
| MP4TagsSetGenreID( mdata, NULL ); |
| break; |
| case OPT_LYRICS: |
| MP4TagsSetLyrics( mdata, NULL ); |
| break; |
| case OPT_DESCRIPTION: |
| MP4TagsSetDescription( mdata, NULL ); |
| break; |
| case OPT_TVEPISODE: |
| MP4TagsSetTVEpisode( mdata, NULL ); |
| break; |
| case OPT_TVSEASON: |
| MP4TagsSetTVSeason( mdata, NULL ); |
| break; |
| case OPT_TVNETWORK: |
| MP4TagsSetTVNetwork( mdata, NULL ); |
| break; |
| case OPT_TVEPISODEID: |
| MP4TagsSetTVEpisodeID( mdata, NULL ); |
| break; |
| case OPT_PLAYLISTID: |
| MP4TagsSetPlaylistID( mdata, NULL ); |
| break; |
| case OPT_PICTURE: |
| if( mdata->artworkCount ) |
| MP4TagsRemoveArtwork( mdata, 0 ); |
| break; |
| case OPT_ALBUM_ARTIST: |
| MP4TagsSetAlbumArtist( mdata, NULL ); |
| break ; |
| case OPT_NAME: |
| MP4TagsSetName( mdata, NULL ); |
| break; |
| case OPT_TVSHOW: |
| MP4TagsSetTVShow( mdata, NULL ); |
| break; |
| case OPT_TRACK: |
| MP4TagsSetTrack( mdata, NULL ); |
| break; |
| case OPT_TRACKS: |
| MP4TagsSetTrack( mdata, NULL ); |
| break; |
| case OPT_XID: |
| MP4TagsSetXID( mdata, NULL ); |
| break; |
| case OPT_COMPOSER: |
| MP4TagsSetComposer( mdata, NULL ); |
| break; |
| case OPT_RELEASEDATE: |
| MP4TagsSetReleaseDate( mdata, NULL ); |
| break; |
| case OPT_ARTISTID: |
| MP4TagsSetArtistID( mdata, NULL ); |
| break; |
| case OPT_COMPOSERID: |
| MP4TagsSetComposerID( mdata, NULL ); |
| break; |
| case OPT_PODCAST: |
| MP4TagsSetPodcast(mdata, NULL); |
| break; |
| case OPT_CATEGORY: |
| MP4TagsSetCategory(mdata, NULL); |
| break; |
| case OPT_RATING: |
| MP4TagsSetContentRating(mdata, NULL); |
| break; |
| } |
| } |
| } |
| |
| /* Track/disk numbers need to be set all at once, but we'd like to |
| allow users to just specify -T 12 to indicate that all existing |
| track numbers are out of 12. This means we need to look up the |
| current info if it is not being set. */ |
| |
| if ( ELEMENT_OF(tags,OPT_TRACK) || ELEMENT_OF(tags,OPT_TRACKS) ) { |
| MP4TagTrack tt; |
| tt.index = 0; |
| tt.total = 0; |
| |
| if( mdata->track ) { |
| tt.index = mdata->track->index; |
| tt.total = mdata->track->total; |
| } |
| |
| if( ELEMENT_OF(tags,OPT_TRACK) ) |
| tt.index = static_cast<uint16_t>( ELEMENT_OF(nums,OPT_TRACK) ); |
| if( ELEMENT_OF(tags,OPT_TRACKS) ) |
| tt.total = static_cast<uint16_t>( ELEMENT_OF(nums,OPT_TRACKS) ); |
| |
| MP4TagsSetTrack( mdata, &tt ); |
| } |
| |
| if ( ELEMENT_OF(tags,OPT_DISK) || ELEMENT_OF(tags,OPT_DISKS) ) { |
| MP4TagDisk td; |
| td.index = 0; |
| td.total = 0; |
| |
| if( mdata->disk ) { |
| td.index = mdata->disk->index; |
| td.total = mdata->disk->total; |
| } |
| |
| if( ELEMENT_OF(tags,OPT_DISK) ) |
| td.index = static_cast<uint16_t>( ELEMENT_OF(nums,OPT_DISK) ); |
| if( ELEMENT_OF(tags,OPT_DISKS) ) |
| td.total = static_cast<uint16_t>( ELEMENT_OF(nums,OPT_DISKS) ); |
| |
| MP4TagsSetDisk( mdata, &td ); |
| } |
| |
| /* Set the other relevant attributes */ |
| for ( int i = 0; i < UCHAR_MAX; i++ ) { |
| if ( tags[i] ) { |
| switch ( i ) { |
| case OPT_ALBUM: |
| MP4TagsSetAlbum( mdata, tags[i] ); |
| break; |
| case OPT_ARTIST: |
| MP4TagsSetArtist( mdata, tags[i] ); |
| break; |
| case OPT_TEMPO: |
| { |
| uint16_t value = static_cast<uint16_t>( nums[i] ); |
| MP4TagsSetTempo( mdata, &value ); |
| break; |
| } |
| case OPT_COMMENT: |
| MP4TagsSetComments( mdata, tags[i] ); |
| break; |
| case OPT_COPYRIGHT: |
| MP4TagsSetCopyright( mdata, tags[i] ); |
| break; |
| case OPT_ENCODEDBY: |
| MP4TagsSetEncodedBy( mdata, tags[i] ); |
| break; |
| case OPT_TOOL: |
| MP4TagsSetEncodingTool( mdata, tags[i] ); |
| break; |
| case OPT_GENRE: |
| MP4TagsSetGenre( mdata, tags[i] ); |
| break; |
| case OPT_GROUPING: |
| MP4TagsSetGrouping( mdata, tags[i] ); |
| break; |
| case OPT_HD: |
| { |
| uint8_t value = static_cast<uint8_t>( nums[i] ); |
| MP4TagsSetHDVideo( mdata, &value ); |
| break; |
| } |
| case OPT_MEDIA_TYPE: |
| { |
| uint8_t st = static_cast<uint8_t>( itmf::enumStikType.toType( tags[i] ) ) ; |
| MP4TagsSetMediaType( mdata, &st ); |
| break; |
| } |
| case OPT_CONTENTID: |
| { |
| uint32_t value = static_cast<uint32_t>( nums[i] ); |
| MP4TagsSetContentID( mdata, &value ); |
| break; |
| } |
| case OPT_LONGDESC: |
| MP4TagsSetLongDescription( mdata, tags[i] ); |
| break; |
| case OPT_GENREID: |
| { |
| uint32_t value = static_cast<uint32_t>( nums[i] ); |
| MP4TagsSetGenreID( mdata, &value ); |
| break; |
| } |
| case OPT_LYRICS: |
| MP4TagsSetLyrics( mdata, tags[i] ); |
| break; |
| case OPT_DESCRIPTION: |
| MP4TagsSetDescription( mdata, tags[i] ); |
| break; |
| case OPT_TVEPISODE: |
| { |
| uint32_t value = static_cast<uint32_t>( nums[i] ); |
| MP4TagsSetTVEpisode( mdata, &value ); |
| break; |
| } |
| case OPT_TVSEASON: |
| { |
| uint32_t value = static_cast<uint32_t>( nums[i] ); |
| MP4TagsSetTVSeason( mdata, &value ); |
| break; |
| } |
| case OPT_TVNETWORK: |
| MP4TagsSetTVNetwork( mdata, tags[i] ); |
| break; |
| case OPT_TVEPISODEID: |
| MP4TagsSetTVEpisodeID( mdata, tags[i] ); |
| break; |
| case OPT_PLAYLISTID: |
| { |
| uint64_t value = static_cast<uint64_t>( nums[i] ); |
| MP4TagsSetPlaylistID( mdata, &value ); |
| break; |
| } |
| case OPT_PICTURE: |
| { |
| File in( tags[i], File::MODE_READ ); |
| if( !in.open() ) { |
| MP4TagArtwork art; |
| art.size = (uint32_t)in.size; |
| art.data = malloc( art.size ); |
| art.type = MP4_ART_UNDEFINED; |
| |
| File::Size nin; |
| if( !in.read( art.data, art.size, nin ) && nin == art.size ) { |
| if( mdata->artworkCount ) |
| MP4TagsRemoveArtwork( mdata, 0 ); |
| MP4TagsAddArtwork( mdata, &art ); |
| } |
| |
| free( art.data ); |
| in.close(); |
| } |
| else { |
| fprintf( stderr, "Art file %s not found\n", tags[i] ); |
| } |
| break; |
| } |
| case OPT_ALBUM_ARTIST: |
| MP4TagsSetAlbumArtist( mdata, tags[i] ); |
| break; |
| case OPT_NAME: |
| MP4TagsSetName( mdata, tags[i] ); |
| break; |
| case OPT_TVSHOW: |
| MP4TagsSetTVShow( mdata, tags[i] ); |
| break; |
| case OPT_XID: |
| MP4TagsSetXID( mdata, tags[i] ); |
| break; |
| case OPT_COMPOSER: |
| MP4TagsSetComposer( mdata, tags[i] ); |
| break; |
| case OPT_RELEASEDATE: |
| MP4TagsSetReleaseDate( mdata, tags[i] ); |
| break; |
| case OPT_ARTISTID: |
| { |
| uint32_t value = static_cast<uint32_t>( nums[i] ); |
| MP4TagsSetArtistID( mdata, &value ); |
| break; |
| } |
| case OPT_COMPOSERID: |
| { |
| uint32_t value = static_cast<uint32_t>( nums[i] ); |
| MP4TagsSetComposerID( mdata, &value ); |
| break; |
| } |
| case OPT_PODCAST: |
| { |
| uint8_t value = static_cast<uint8_t>( nums[i] ); |
| MP4TagsSetPodcast(mdata, &value); |
| break; |
| } |
| case OPT_CATEGORY: |
| { |
| MP4TagsSetCategory(mdata, tags[i]); |
| break; |
| } |
| case OPT_RATING: |
| { |
| uint8_t rating = static_cast<uint8_t>( itmf::enumContentRating.toType( tags[i] ) ) ; |
| MP4TagsSetContentRating(mdata, &rating); |
| break; |
| } |
| } |
| } |
| } |
| /* Write out all tag modifications, free and close */ |
| MP4TagsStore( mdata, h ); |
| MP4TagsFree( mdata ); |
| MP4Close( h ); |
| } /* end while optind < argc */ |
| return 0; |
| } |