| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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<uint16_t>( 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(); |
| } |