/////////////////////////////////////////////////////////////////////////////// // // 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) 2010. // All Rights Reserved. // // Contributors: // Kona Blend, kona8lend@@gmail.com // David Byron, dbyron@dbyron.com // /////////////////////////////////////////////////////////////////////////////// #include "util/impl.h" namespace mp4v2 { namespace util { /////////////////////////////////////////////////////////////////////////////// class TrackUtility : public Utility { private: enum TrackLongAction { LC_TRACK_WILDCARD = _LC_MAX, LC_TRACK_ID, LC_TRACK_INDEX, LC_SAMPLE_WILDCARD, LC_SAMPLE_ID, LC_SAMPLE_INDEX, LC_LIST, LC_ENABLED, LC_INMOVIE, LC_INPREVIEW, LC_LAYER, LC_ALTGROUP, LC_VOLUME, LC_WIDTH, LC_HEIGHT, LC_LANGUAGE, LC_HDLRNAME, LC_UDTANAME, LC_UDTANAME_R, LC_COLR_PARMS, LC_COLR_PARM_HD, LC_COLR_PARM_SD, LC_COLR_LIST, LC_COLR_ADD, LC_COLR_SET, LC_COLR_REMOVE, LC_PASP_PARMS, LC_PASP_LIST, LC_PASP_ADD, LC_PASP_SET, LC_PASP_REMOVE, }; public: TrackUtility( int, char** ); protected: // delegates implementation bool utility_option( int, bool& ); bool utility_job( JobContext& ); private: bool actionList( JobContext& ); bool actionListSingle( JobContext&, uint16_t ); bool actionColorParameterList ( JobContext& ); bool actionColorParameterAdd ( JobContext& ); bool actionColorParameterSet ( JobContext& ); bool actionColorParameterRemove ( JobContext& ); bool actionPictureAspectRatioList ( JobContext& ); bool actionPictureAspectRatioAdd ( JobContext& ); bool actionPictureAspectRatioSet ( JobContext& ); bool actionPictureAspectRatioRemove ( JobContext& ); bool actionTrackModifierSet ( JobContext& ); bool actionTrackModifierRemove ( JobContext& ); private: enum TrackMode { TM_UNDEFINED, TM_INDEX, TM_ID, TM_WILDCARD, }; enum SampleMode { SM_UNDEFINED, SM_INDEX, SM_ID, SM_WILDCARD, }; Group _actionGroup; Group _parmGroup; bool (TrackUtility::*_action)( JobContext& ); TrackMode _trackMode; uint16_t _trackIndex; uint32_t _trackId; SampleMode _sampleMode; uint16_t _sampleIndex; uint32_t _sampleId; qtff::ColorParameterBox::Item _colorParameterItem; qtff::PictureAspectRatioBox::Item _pictureAspectRatioItem; void (TrackModifier::*_actionTrackModifierSet_function)( const string& ); string _actionTrackModifierSet_name; string _actionTrackModifierSet_value; void (TrackModifier::*_actionTrackModifierRemove_function)(); string _actionTrackModifierRemove_name; }; /////////////////////////////////////////////////////////////////////////////// string toStringTrackType( string ); /////////////////////////////////////////////////////////////////////////////// TrackUtility::TrackUtility( int argc, char** argv ) : Utility ( "mp4track", argc, argv ) , _actionGroup ( "ACTIONS" ) , _parmGroup ( "PARAMETERS" ) , _action ( NULL ) , _trackMode ( TM_UNDEFINED ) , _trackIndex ( 0 ) , _trackId ( MP4_INVALID_TRACK_ID ) , _sampleMode ( SM_UNDEFINED ) , _sampleIndex ( 0 ) , _sampleId ( MP4_INVALID_SAMPLE_ID ) { // add standard options which make sense for this utility _group.add( STD_OPTIMIZE ); _group.add( STD_DRYRUN ); _group.add( STD_KEEPGOING ); _group.add( STD_OVERWRITE ); _group.add( STD_FORCE ); _group.add( STD_QUIET ); _group.add( STD_DEBUG ); _group.add( STD_VERBOSE ); _group.add( STD_HELP ); _group.add( STD_VERSION ); _group.add( STD_VERSIONX ); _parmGroup.add( "track-any", false, LC_TRACK_WILDCARD, "act on any/all tracks" ); _parmGroup.add( "track-index", true, LC_TRACK_INDEX, "act on track index IDX", "IDX" ); _parmGroup.add( "track-id", true, LC_TRACK_ID, "act on track id ID", "ID" ); /* _parmGroup.add( "sample-any", false, LC_SAMPLE_WILDCARD, "act on any sample (default)" ); _parmGroup.add( "sample-index", true, LC_SAMPLE_INDEX, "act on sample index IDX" ); _parmGroup.add( "sample-id", true, LC_SAMPLE_ID, "act on sample id ID" ); */ _parmGroup.add( "colr-parms", true, LC_COLR_PARMS, "where CSV is IDX1,IDX2,IDX3", "CSV" ); _parmGroup.add( "colr-parm-hd", false, LC_COLR_PARM_HD, "equivalent to --colr-parms=1,1,1" ); _parmGroup.add( "colr-parm-sd", false, LC_COLR_PARM_SD, "equivalent to --colr-parms=6,1,6" ); _parmGroup.add( "pasp-parms", true, LC_PASP_PARMS, "where CSV is hSPACING,vSPACING", "CSV" ); _groups.push_back( &_parmGroup ); _actionGroup.add( "list", false, LC_LIST, "list all tracks in mp4" ); _actionGroup.add( "enabled", true, LC_ENABLED, "set trak.tkhd.flags (enabled bit)", "BOOL" ); _actionGroup.add( "inmovie", true, LC_INMOVIE, "set trak.tkhd.flags (inMovie bit)", "BOOL" ); _actionGroup.add( "inpreview", true, LC_INPREVIEW, "set trak.tkhd.flags (inPreview bit)", "BOOL" ); _actionGroup.add( "layer", true, LC_LAYER, "set trak.tkhd.layer", "NUM" ); _actionGroup.add( "altgroup", true, LC_ALTGROUP, "set trak.tkhd.alternate_group", "NUM" ); _actionGroup.add( "volume", true, LC_VOLUME, "set trak.tkhd.volume", "FLOAT" ); _actionGroup.add( "width", true, LC_WIDTH, "set trak.tkhd.width", "FLOAT" ); _actionGroup.add( "height", true, LC_HEIGHT, "set trak.tkhd.height", "FLOAT" ); _actionGroup.add( "language", true, LC_LANGUAGE, "set trak.mdia.mdhd.language", "CODE" ); _actionGroup.add( "hdlrname", true, LC_HDLRNAME, "set trak.mdia.hdlr.name", "STR" ); _actionGroup.add( "udtaname", true, LC_UDTANAME, "set trak.udta.name.value", "STR" ); _actionGroup.add( "udtaname-remove", false, LC_UDTANAME_R, "remove trak.udta.name atom" ); _actionGroup.add( "colr-list", false, LC_COLR_LIST, "list all colr-boxes in mp4" ); _actionGroup.add( "colr-add", false, LC_COLR_ADD, "add colr-box to a video track" ); _actionGroup.add( "colr-set", false, LC_COLR_SET, "set colr-box parms" ); _actionGroup.add( "colr-remove", false, LC_COLR_REMOVE, "remove colr-box from track" ); _actionGroup.add( "pasp-list", false, LC_PASP_LIST, "list all pasp-boxes in mp4" ); _actionGroup.add( "pasp-add", false, LC_PASP_ADD, "add pasp-box to a video track" ); _actionGroup.add( "pasp-set", false, LC_PASP_SET, "set pasp-box parms" ); _actionGroup.add( "pasp-remove", false, LC_PASP_REMOVE, "remove pasp-box from track" ); _groups.push_back( &_actionGroup ); _usage = "[OPTION]... [PARAMETERS]... ACTION file..."; _description = // 79-cols, inclusive, max desired width // |----------------------------------------------------------------------------| "\nFor each mp4 file specified, perform the specified ACTION. An action must be" "\nspecified. Some options are not applicable to some actions."; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionColorParameterAdd( JobContext& job ) { ostringstream oss; oss << "adding colr-box(" << _colorParameterItem.convertToCSV() << ") -> " << job.file; switch( _trackMode ) { case TM_INDEX: oss << " (track index=" << _trackIndex << ')'; break; case TM_ID: oss << " (track id=" << _trackId << ')'; break; default: case TM_WILDCARD: return herrf( "track not specified\n" ); } verbose1f( "%s\n", oss.str().c_str() ); if( dryrunAbort() ) return SUCCESS; job.fileHandle = MP4Modify( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for write: %s\n", job.file.c_str() ); switch( _trackMode ) { default: case TM_INDEX: if( qtff::ColorParameterBox::add( job.fileHandle, _trackIndex, _colorParameterItem )) return herrf( "unable to add colr-box\n" ); break; case TM_ID: if( qtff::ColorParameterBox::add( job.fileHandle, _trackId, _colorParameterItem )) return herrf( "unable to add colr-box\n" ); break; } return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionColorParameterList( JobContext& job ) { job.fileHandle = MP4Read( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for read: %s\n", job.file.c_str() ); ostringstream report; const int widx = 3; const int wid = 3; const int wtype = 8; const int wparm = 6; const string sep = " "; if( _jobCount == 0 ) { report << setw(widx) << right << "IDX" << sep << setw(wid) << "ID" << sep << setw(wtype) << left << "TYPE" << sep << setw(wparm) << right << "PRIMRY" << sep << setw(wparm) << right << "XFERFN" << sep << setw(wparm) << right << "MATRIX" << sep << setw(0) << "FILE" << '\n'; report << setfill('-') << setw(70) << "" << setfill(' ') << '\n'; } qtff::ColorParameterBox::ItemList itemList; if( qtff::ColorParameterBox::list( job.fileHandle, itemList )) return herrf( "unable to fetch list of colr-boxes" ); const qtff::ColorParameterBox::ItemList::size_type max = itemList.size(); for( qtff::ColorParameterBox::ItemList::size_type i = 0; i < max; i++ ) { const qtff::ColorParameterBox::IndexedItem& xitem = itemList[i]; const char* type = MP4GetTrackType( job.fileHandle, xitem.trackId ); if( !type) type = "unknown"; report << right << setw(widx) << xitem.trackIndex << sep << setw(wid) << xitem.trackId << sep << setw(wtype) << left << toStringTrackType( type ) << sep << setw(wparm) << right << xitem.item.primariesIndex << sep << setw(wparm) << right << xitem.item.transferFunctionIndex << sep << setw(wparm) << right << xitem.item.matrixIndex; if( i == 0 ) report << sep << setw(0) << job.file; report << '\n'; } verbose1f( "%s", report.str().c_str() ); return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionColorParameterRemove( JobContext& job ) { ostringstream oss; oss << "removing colr-box from " << job.file; switch( _trackMode ) { case TM_INDEX: oss << " (track index=" << _trackIndex << ')'; break; case TM_ID: oss << " (track id=" << _trackId << ')'; break; case TM_WILDCARD: oss << " (all tracks)"; break; default: return herrf( "track(s) not specified\n" ); } verbose1f( "%s\n", oss.str().c_str() ); if( dryrunAbort() ) return SUCCESS; job.fileHandle = MP4Modify( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for write: %s\n", job.file.c_str() ); switch( _trackMode ) { case TM_INDEX: if( qtff::ColorParameterBox::remove( job.fileHandle, _trackIndex )) return herrf( "unable to remove colr-box\n" ); break; case TM_ID: if( qtff::ColorParameterBox::remove( job.fileHandle, _trackId )) return herrf( "unable to remove colr-box\n" ); break; default: case TM_WILDCARD: { qtff::ColorParameterBox::ItemList itemList; if( qtff::ColorParameterBox::list( job.fileHandle, itemList )) return herrf( "unable to fetch list of colr-boxes" ); _trackMode = TM_INDEX; const qtff::ColorParameterBox::ItemList::size_type max = itemList.size(); for( qtff::ColorParameterBox::ItemList::size_type i = 0; i < max; i++ ) { const qtff::ColorParameterBox::IndexedItem& xitem = itemList[i]; _trackIndex = xitem.trackIndex; actionColorParameterRemove( job ); } break; } } return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionColorParameterSet( JobContext& job ) { ostringstream oss; oss << "setting colr-box(" << _colorParameterItem.convertToCSV() << ") -> " << job.file; switch( _trackMode ) { case TM_INDEX: oss << " (track index=" << _trackIndex << ')'; break; case TM_ID: oss << " (track id=" << _trackId << ')'; break; default: case TM_WILDCARD: return herrf( "track not specified\n" ); } verbose1f( "%s\n", oss.str().c_str() ); if( dryrunAbort() ) return SUCCESS; job.fileHandle = MP4Modify( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for write: %s\n", job.file.c_str() ); switch( _trackMode ) { default: case TM_INDEX: if( qtff::ColorParameterBox::set( job.fileHandle, _trackIndex, _colorParameterItem )) return herrf( "unable to set colr-box\n" ); break; case TM_ID: if( qtff::ColorParameterBox::set( job.fileHandle, _trackId, _colorParameterItem )) return herrf( "unable to set colr-box\n" ); break; } return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionList( JobContext& job ) { if( _jobTotal > 1 ) verbose1f( "file %u of %u: %s\n", _jobCount+1, _jobTotal, job.file.c_str() ); ostringstream report; job.fileHandle = MP4Read( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for read: %s\n", job.file.c_str() ); switch( _trackMode ) { case TM_INDEX: return actionListSingle( job, _trackIndex ); case TM_ID: return actionListSingle( job, MP4FindTrackIndex( job.fileHandle, _trackId )); case TM_WILDCARD: default: { bool result = SUCCESS; const uint16_t trackc = static_cast( MP4GetNumberOfTracks( job.fileHandle )); for( uint16_t i = 0; i < trackc; i++ ) { if( actionListSingle( job, i )) result = FAILURE; } return result; } } } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionListSingle( JobContext& job, uint16_t index ) { TrackModifier tm( job.fileHandle, index ); ostringstream report; tm.dump( report, ( _jobTotal > 1 ? " " : "" )); verbose1f( "%s", report.str().c_str() ); return false; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionPictureAspectRatioAdd( JobContext& job ) { ostringstream oss; oss << "adding pasp-box(" << _pictureAspectRatioItem.convertToCSV() << ") -> " << job.file; switch( _trackMode ) { case TM_INDEX: oss << " (track index=" << _trackIndex << ')'; break; case TM_ID: oss << " (track id=" << _trackId << ')'; break; default: case TM_WILDCARD: return herrf( "track not specified\n" ); } verbose1f( "%s\n", oss.str().c_str() ); if( dryrunAbort() ) return SUCCESS; job.fileHandle = MP4Modify( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for write: %s\n", job.file.c_str() ); switch( _trackMode ) { default: case TM_INDEX: if( qtff::PictureAspectRatioBox::add( job.fileHandle, _trackIndex, _pictureAspectRatioItem )) return herrf( "unable to add pasp-box\n" ); break; case TM_ID: if( qtff::PictureAspectRatioBox::add( job.fileHandle, _trackId, _pictureAspectRatioItem )) return herrf( "unable to add pasp-box\n" ); break; } return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionPictureAspectRatioList( JobContext& job ) { job.fileHandle = MP4Read( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for read: %s\n", job.file.c_str() ); ostringstream report; const int widx = 3; const int wid = 3; const int wtype = 8; const int wparm = 6; const string sep = " "; if( _jobCount == 0 ) { report << setw(widx) << right << "IDX" << sep << setw(wid) << "ID" << sep << setw(wtype) << left << "TYPE" << sep << setw(wparm) << right << "hSPACE" << sep << setw(wparm) << right << "vSPACE" << sep << setw(0) << "FILE" << '\n'; report << setfill('-') << setw(70) << "" << setfill(' ') << '\n'; } qtff::PictureAspectRatioBox::ItemList itemList; if( qtff::PictureAspectRatioBox::list( job.fileHandle, itemList )) return herrf( "unable to fetch list of pasp-boxes" ); const qtff::PictureAspectRatioBox::ItemList::size_type max = itemList.size(); for( qtff::PictureAspectRatioBox::ItemList::size_type i = 0; i < max; i++ ) { const qtff::PictureAspectRatioBox::IndexedItem& xitem = itemList[i]; const char* type = MP4GetTrackType( job.fileHandle, xitem.trackId ); if( !type) type = "unknown"; report << right << setw(widx) << xitem.trackIndex << sep << setw(wid) << xitem.trackId << sep << setw(wtype) << left << toStringTrackType( type ) << sep << setw(wparm) << right << xitem.item.hSpacing << sep << setw(wparm) << right << xitem.item.vSpacing; if( i == 0 ) report << sep << setw(0) << job.file; report << '\n'; } verbose1f( "%s", report.str().c_str() ); return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionPictureAspectRatioRemove( JobContext& job ) { ostringstream oss; oss << "removing pasp-box from " << job.file; switch( _trackMode ) { case TM_INDEX: oss << " (track index=" << _trackIndex << ')'; break; case TM_ID: oss << " (track id=" << _trackId << ')'; break; default: case TM_WILDCARD: oss << " (all tracks)"; } verbose1f( "%s\n", oss.str().c_str() ); if( dryrunAbort() ) return SUCCESS; job.fileHandle = MP4Modify( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for write: %s\n", job.file.c_str() ); switch( _trackMode ) { case TM_INDEX: if( qtff::PictureAspectRatioBox::remove( job.fileHandle, _trackIndex )) return herrf( "unable to remove pasp-box\n" ); break; case TM_ID: if( qtff::PictureAspectRatioBox::remove( job.fileHandle, _trackId )) return herrf( "unable to remove pasp-box\n" ); break; default: case TM_WILDCARD: { qtff::PictureAspectRatioBox::ItemList itemList; if( qtff::PictureAspectRatioBox::list( job.fileHandle, itemList )) return herrf( "unable to fetch list of pasp-boxes" ); _trackMode = TM_INDEX; const qtff::PictureAspectRatioBox::ItemList::size_type max = itemList.size(); for( qtff::PictureAspectRatioBox::ItemList::size_type i = 0; i < max; i++ ) { const qtff::PictureAspectRatioBox::IndexedItem& xitem = itemList[i]; _trackIndex = xitem.trackIndex; actionPictureAspectRatioRemove( job ); } break; } } return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionPictureAspectRatioSet( JobContext& job ) { ostringstream oss; oss << "setting pasp-box(" << _pictureAspectRatioItem.convertToCSV() << ") -> " << job.file; switch( _trackMode ) { case TM_INDEX: oss << " (track index=" << _trackIndex << ')'; break; case TM_ID: oss << " (track id=" << _trackId << ')'; break; default: case TM_WILDCARD: return herrf( "track not specified\n" ); } verbose1f( "%s\n", oss.str().c_str() ); if( dryrunAbort() ) return SUCCESS; job.fileHandle = MP4Modify( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for write: %s\n", job.file.c_str() ); switch( _trackMode ) { default: case TM_INDEX: if( qtff::PictureAspectRatioBox::set( job.fileHandle, _trackIndex, _pictureAspectRatioItem )) return herrf( "unable to set pasp-box\n" ); break; case TM_ID: if( qtff::PictureAspectRatioBox::set( job.fileHandle, _trackId, _pictureAspectRatioItem )) return herrf( "unable to set pasp-box\n" ); break; } return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionTrackModifierRemove( JobContext& job ) { ostringstream oss; oss << "removing " << _actionTrackModifierRemove_name << " -> " << job.file; switch( _trackMode ) { case TM_INDEX: oss << " (track index=" << _trackIndex << ')'; break; case TM_ID: oss << " (track id=" << _trackId << ')'; break; default: case TM_WILDCARD: return herrf( "track not specified\n" ); } verbose1f( "%s\n", oss.str().c_str() ); if( dryrunAbort() ) return SUCCESS; job.fileHandle = MP4Modify( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for write: %s\n", job.file.c_str() ); if( _trackMode == TM_ID ) _trackIndex = MP4FindTrackIndex( job.fileHandle, _trackId ); TrackModifier tm( job.fileHandle, _trackIndex ); (tm.*_actionTrackModifierRemove_function)(); return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::actionTrackModifierSet( JobContext& job ) { ostringstream oss; oss << "setting " << _actionTrackModifierSet_name << "=" << _actionTrackModifierSet_value << " -> " << job.file; switch( _trackMode ) { case TM_INDEX: oss << " (track index=" << _trackIndex << ')'; break; case TM_ID: oss << " (track id=" << _trackId << ')'; break; default: case TM_WILDCARD: return herrf( "track not specified\n" ); } verbose1f( "%s\n", oss.str().c_str() ); if( dryrunAbort() ) return SUCCESS; job.fileHandle = MP4Modify( job.file.c_str() ); if( job.fileHandle == MP4_INVALID_FILE_HANDLE ) return herrf( "unable to open for write: %s\n", job.file.c_str() ); if( _trackMode == TM_ID ) _trackIndex = MP4FindTrackIndex( job.fileHandle, _trackId ); TrackModifier tm( job.fileHandle, _trackIndex ); (tm.*_actionTrackModifierSet_function)( _actionTrackModifierSet_value ); return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::utility_job( JobContext& job ) { if( !_action ) return herrf( "no action specified\n" ); return (this->*_action)( job ); } /////////////////////////////////////////////////////////////////////////////// bool TrackUtility::utility_option( int code, bool& handled ) { handled = true; switch( code ) { case LC_TRACK_WILDCARD: _trackMode = TM_WILDCARD; break; case LC_TRACK_INDEX: { _trackMode = TM_INDEX; istringstream iss( prog::optarg ); iss >> _trackIndex; if( iss.rdstate() != ios::eofbit ) return herrf( "invalid track index: %s\n", prog::optarg ); break; } case LC_TRACK_ID: { _trackMode = TM_ID; istringstream iss( prog::optarg ); iss >> _trackId; if( iss.rdstate() != ios::eofbit ) return herrf( "invalid track id: %s\n", prog::optarg ); break; } case LC_LIST: _action = &TrackUtility::actionList; break; case LC_COLR_PARMS: _colorParameterItem.convertFromCSV( prog::optarg ); break; case LC_COLR_PARM_HD: _colorParameterItem.primariesIndex = 1; _colorParameterItem.transferFunctionIndex = 1; _colorParameterItem.matrixIndex = 1; break; case LC_COLR_PARM_SD: _colorParameterItem.primariesIndex = 6; _colorParameterItem.transferFunctionIndex = 1; _colorParameterItem.matrixIndex = 6; break; case LC_COLR_LIST: _action = &TrackUtility::actionColorParameterList; break; case LC_ENABLED: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setEnabled; _actionTrackModifierSet_name = "enabled"; _actionTrackModifierSet_value = prog::optarg; break; case LC_INMOVIE: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setInMovie; _actionTrackModifierSet_name = "inMovie"; _actionTrackModifierSet_value = prog::optarg; break; case LC_INPREVIEW: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setInPreview; _actionTrackModifierSet_name = "inPreview"; _actionTrackModifierSet_value = prog::optarg; break; case LC_LAYER: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setLayer; _actionTrackModifierSet_name = "layer"; _actionTrackModifierSet_value = prog::optarg; break; case LC_ALTGROUP: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setAlternateGroup; _actionTrackModifierSet_name = "alternateGroup"; _actionTrackModifierSet_value = prog::optarg; break; case LC_VOLUME: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setVolume; _actionTrackModifierSet_name = "volume"; _actionTrackModifierSet_value = prog::optarg; break; case LC_WIDTH: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setWidth; _actionTrackModifierSet_name = "width"; _actionTrackModifierSet_value = prog::optarg; break; case LC_HEIGHT: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setHeight; _actionTrackModifierSet_name = "height"; _actionTrackModifierSet_value = prog::optarg; break; case LC_LANGUAGE: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setLanguage; _actionTrackModifierSet_name = "language"; _actionTrackModifierSet_value = prog::optarg; break; case LC_HDLRNAME: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setHandlerName; _actionTrackModifierSet_name = "handlerName"; _actionTrackModifierSet_value = prog::optarg; break; case LC_UDTANAME: _action = &TrackUtility::actionTrackModifierSet; _actionTrackModifierSet_function = &TrackModifier::setUserDataName; _actionTrackModifierSet_name = "userDataName"; _actionTrackModifierSet_value = prog::optarg; break; case LC_UDTANAME_R: _action = &TrackUtility::actionTrackModifierRemove; _actionTrackModifierRemove_function = &TrackModifier::removeUserDataName; _actionTrackModifierRemove_name = "userDataName"; break; case LC_COLR_ADD: _action = &TrackUtility::actionColorParameterAdd; break; case LC_COLR_SET: _action = &TrackUtility::actionColorParameterSet; break; case LC_COLR_REMOVE: _action = &TrackUtility::actionColorParameterRemove; break; case LC_PASP_PARMS: _pictureAspectRatioItem.convertFromCSV( prog::optarg ); break; case LC_PASP_LIST: _action = &TrackUtility::actionPictureAspectRatioList; break; case LC_PASP_ADD: _action = &TrackUtility::actionPictureAspectRatioAdd; break; case LC_PASP_SET: _action = &TrackUtility::actionPictureAspectRatioSet; break; case LC_PASP_REMOVE: _action = &TrackUtility::actionPictureAspectRatioRemove; break; default: handled = false; break; } return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// string toStringTrackType( string code ) { if( !code.compare( "vide" )) // 14496-12 return "video"; if( !code.compare( "soun" )) // 14496-12 return "audio"; if( !code.compare( "hint" )) // 14496-12 return "hint"; if( !code.compare( "text" )) // QTFF return "text"; if( !code.compare( "tmcd" )) // QTFF return "timecode"; if( !code.compare( "subt" )) // QTFF return "subtitle"; return string( "(" ) + code + ")"; } /////////////////////////////////////////////////////////////////////////////// }} // namespace mp4v2::util /////////////////////////////////////////////////////////////////////////////// extern "C" int main( int argc, char** argv ) { mp4v2::util::TrackUtility util( argc, argv ); return util.process(); }