/////////////////////////////////////////////////////////////////////////////// // // 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 FileUtility : public Utility { private: enum FileLongCode { LC_LIST = _LC_MAX, LC_OPTIMIZE, LC_DUMP, }; public: FileUtility( int, char** ); protected: // delegates implementation bool utility_option( int, bool& ); bool utility_job( JobContext& ); private: bool actionList ( JobContext& ); bool actionOptimize ( JobContext& ); bool actionDump ( JobContext& ); private: Group _actionGroup; bool (FileUtility::*_action)( JobContext& ); }; /////////////////////////////////////////////////////////////////////////////// FileUtility::FileUtility( int argc, char** argv ) : Utility ( "mp4file", argc, argv ) , _actionGroup ( "ACTIONS" ) , _action ( NULL ) { // add standard options which make sense for this utility _group.add( STD_DRYRUN ); _group.add( STD_KEEPGOING ); _group.add( STD_QUIET ); _group.add( STD_DEBUG ); _group.add( STD_VERBOSE ); _group.add( STD_HELP ); _group.add( STD_VERSION ); _group.add( STD_VERSIONX ); _actionGroup.add( "list", false, LC_LIST, "list (summary information)" ); _actionGroup.add( "optimize", false, LC_OPTIMIZE, "optimize mp4 structure" ); _actionGroup.add( "dump", false, LC_DUMP, "dump mp4 structure in human-readable format" ); _groups.push_back( &_actionGroup ); _usage = "[OPTION]... 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 FileUtility::actionDump( 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() ); if( !MP4Dump( job.fileHandle, _debugImplicits )) return herrf( "dump failed: %s\n", job.file.c_str() ); return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool FileUtility::actionList( JobContext& job ) { ostringstream report; const int wbrand = 5; const int wcompat = 18; const int wsizing = 6; const string sep = " "; if( _jobCount == 0 ) { report << setw(wbrand) << left << "BRAND" << sep << setw(wcompat) << left << "COMPAT" << sep << setw(wsizing) << left << "SIZING" << sep << setw(0) << "FILE" << '\n'; report << setfill('-') << setw(70) << "" << setfill(' ') << '\n'; } 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() ); FileSummaryInfo info; if( fileFetchSummaryInfo( job.fileHandle, info )) return herrf( "unable to fetch file summary info" ); string compat; { const FileSummaryInfo::BrandSet::iterator ie = info.compatible_brands.end(); int count = 0; for( FileSummaryInfo::BrandSet::iterator it = info.compatible_brands.begin(); it != ie; it++, count++ ) { if( count > 0 ) compat += ','; compat += *it; } } const bool sizing = info.nlargesize | info.nversion1 | info.nspecial; report << setw(wbrand) << left << info.major_brand << sep << setw(wcompat) << left << compat << sep << setw(wsizing) << left << (sizing ? "64-bit" : "32-bit") << sep << job.file << '\n'; verbose1f( "%s", report.str().c_str() ); return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool FileUtility::actionOptimize( JobContext& job ) { verbose1f( "optimizing %s\n", job.file.c_str() ); if( dryrunAbort() ) return SUCCESS; if( !MP4Optimize( job.file.c_str(), NULL )) return herrf( "optimize failed: %s\n", job.file.c_str() ); return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// bool FileUtility::utility_job( JobContext& job ) { if( !_action ) return herrf( "no action specified\n" ); return (this->*_action)( job ); } /////////////////////////////////////////////////////////////////////////////// bool FileUtility::utility_option( int code, bool& handled ) { handled = true; switch( code ) { case LC_LIST: _action = &FileUtility::actionList; break; case LC_OPTIMIZE: _action = &FileUtility::actionOptimize; break; case LC_DUMP: _action = &FileUtility::actionDump; break; default: handled = false; break; } return SUCCESS; } /////////////////////////////////////////////////////////////////////////////// }} // namespace mp4v2::util /////////////////////////////////////////////////////////////////////////////// extern "C" int main( int argc, char** argv ) { mp4v2::util::FileUtility util( argc, argv ); return util.process(); }