diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 8676a24e..2f43938a 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(avProcessor) add_subdirectory(pyProcessor) add_subdirectory(pyThumbnail) add_subdirectory(pyRewrap) +add_subdirectory(pyConcat) diff --git a/app/pyConcat/CMakeLists.txt b/app/pyConcat/CMakeLists.txt new file mode 100644 index 00000000..0727b3a8 --- /dev/null +++ b/app/pyConcat/CMakeLists.txt @@ -0,0 +1,12 @@ +### python/pyConcat + +# Install app +install( + FILES "pyconcat.py" + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE + DESTINATION "bin/python" +) + +if(UNIX) + install( CODE "EXECUTE_PROCESS(COMMAND ln -sf python/pyconcat.py ${CMAKE_INSTALL_PREFIX}/bin/pyconcat)" ) +endif(UNIX) diff --git a/app/pyConcat/pyconcat.py b/app/pyConcat/pyconcat.py new file mode 100644 index 00000000..badc92e0 --- /dev/null +++ b/app/pyConcat/pyconcat.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +from pyAvTranscoder import avtranscoder as av + +from sets import Set + + +# Get command line arguments +args = [] +try: + # python2.7+ + import argparse + + # Create command-line interface + parser = argparse.ArgumentParser( + prog='pyconcat', + description='''Concatenate first stream of each given file to create an output file.''', + ) + + # requirements + parser.add_argument('inputs', nargs='+', action='store', help='list of files to concatenate') + # options + parser.add_argument("-o", "--outputFile", dest="outputFileName", type=str, default="output.mov", help="Set the output filename (output.mov by default).") + # Parse command-line + args = parser.parse_args() + +except ImportError: + print("pyconcat currently expects python2.7+") + exit(1) + +# setup avtranscoder +logger = av.Logger().setLogLevel(av.AV_LOG_QUIET) +av.preloadCodecsAndFormats() + +streamTypeToConcat = Set() +codecToConcat = Set() +# get all input files +inputFiles = [] +for input in args.inputs: + inputFile = av.InputFile(input) + streamTypeToConcat.add( inputFile.getStream(0).getProperties().getStreamType() ) + codecToConcat.add( inputFile.getStream(0).getProperties().getCodecName() ) + inputFiles.append(inputFile) + +# Check type of streams to rewrap +if len(streamTypeToConcat) > 1: + raise RuntimeError("Cannot concatenate streams of different type.") +if len(codecToConcat) > 1: + raise RuntimeError("Cannot concatenate streams of different codec: ", [codec for codec in codecToConcat]) + +# Create the output +outputFile = av.OutputFile( args.outputFileName ); +if av.AVMEDIA_TYPE_VIDEO in streamTypeToConcat: + outputFile.addVideoStream( inputFiles[-1].getStream(0).getVideoCodec() ) +elif av.AVMEDIA_TYPE_AUDIO in streamTypeToConcat: + outputFile.addVideoStream( inputFiles[-1].getStream(0).getAudioCodec() ) + +### process +outputFile.beginWrap() + +data = av.Frame() +# for each input +for inputFile in inputFiles: + packetRead = True + # read all packets of first stream + while packetRead: + # read + packetRead = inputFile.readNextPacket( data, 0 ) + # wrap + outputFile.wrap( data, 0 ) + +outputFile.endWrap() diff --git a/app/pyRewrap/pyrewrap.py b/app/pyRewrap/pyrewrap.py index 23fe7ab3..8218c7a3 100644 --- a/app/pyRewrap/pyrewrap.py +++ b/app/pyRewrap/pyrewrap.py @@ -18,7 +18,7 @@ # requirements parser.add_argument('inputFileName', type=str, help='It could be any video file. Support file without extension.') # options - parser.add_argument("-o", "--outputFile", dest="outputFileName", type=str, default="output.mov", help="Set the output filename (thumbnail.jpg by default). Must be with jpg extension!") + parser.add_argument("-o", "--outputFile", dest="outputFileName", type=str, default="output.mov", help="Set the output filename (output.mov by default).") parser.add_argument("-c", "--format", dest="format", type=str, default="mov", help="Specify the output format.") parser.add_argument("-f", "--faststart", dest="faststart", action="store_true", default=False, help="Specify if the faststart option must be apply during rewrapping process (warning: 'mov' specific option).") # Parse command-line @@ -37,7 +37,7 @@ # requirements parser.add_option("-i", "--inputFile", dest='inputFileName', type="string", help='It could be any video file. Support file without extension.') # options - parser.add_option("-o", "--outputFile", dest="outputFileName", type="string", default="output.mov", help="Set the output filename (thumbnail.jpg by default). Must be with jpg extension!") + parser.add_option("-o", "--outputFile", dest="outputFileName", type="string", default="output.mov", help="Set the output filename (output.mov by default).") parser.add_option("-c", "--format", dest="format", type="string", default="mov", help="Specify the output format.") parser.add_option("-f", "--faststart", dest="faststart", action="store_true", default=False, help="Specify if the faststart option must be apply during rewrapping process (warning: 'mov' specific option).") # Parse command-line diff --git a/src/AvTranscoder/mediaProperty/AudioProperties.cpp b/src/AvTranscoder/mediaProperty/AudioProperties.cpp index 8cdace84..edd9e492 100644 --- a/src/AvTranscoder/mediaProperty/AudioProperties.cpp +++ b/src/AvTranscoder/mediaProperty/AudioProperties.cpp @@ -16,25 +16,6 @@ namespace avtranscoder AudioProperties::AudioProperties( const FormatContext& formatContext, const size_t index ) : StreamProperties( formatContext, index ) { - if( _formatContext ) - _codecContext = _formatContext->streams[index]->codec; - - if( _formatContext && _codecContext ) - _codec = avcodec_find_decoder( _codecContext->codec_id ); -} - -std::string AudioProperties::getCodecName() const -{ - if( ! _codec || ! _codec->name ) - throw std::runtime_error( "unknown codec name" ); - return std::string( _codec->name ); -} - -std::string AudioProperties::getCodecLongName() const -{ - if( ! _codec || ! _codec->long_name ) - throw std::runtime_error( "unknown codec long name" ); - return std::string( _codec->long_name ); } std::string AudioProperties::getSampleFormatName() const @@ -121,13 +102,6 @@ std::string AudioProperties::getChannelDescription() const #endif } -size_t AudioProperties::getCodecId() const -{ - if( ! _codecContext ) - throw std::runtime_error( "unknown codec context" ); - return _codecContext->codec_id; -} - size_t AudioProperties::getSampleRate() const { if( ! _codecContext ) @@ -181,9 +155,6 @@ PropertyVector AudioProperties::getPropertiesAsVector() const PropertyVector basedProperty = StreamProperties::getPropertiesAsVector(); data.insert( data.begin(), basedProperty.begin(), basedProperty.end() ); - addProperty( data, "codecId", &AudioProperties::getCodecId ); - addProperty( data, "codecName", &AudioProperties::getCodecName ); - addProperty( data, "codecLongName", &AudioProperties::getCodecLongName ); addProperty( data, "sampleFormatName", &AudioProperties::getSampleFormatName ); addProperty( data, "sampleFormatLongName", &AudioProperties::getSampleFormatLongName ); addProperty( data, "sampleRate", &AudioProperties::getSampleRate ); diff --git a/src/AvTranscoder/mediaProperty/AudioProperties.hpp b/src/AvTranscoder/mediaProperty/AudioProperties.hpp index f1eda58b..e6e8a1d4 100644 --- a/src/AvTranscoder/mediaProperty/AudioProperties.hpp +++ b/src/AvTranscoder/mediaProperty/AudioProperties.hpp @@ -13,15 +13,12 @@ class AvExport AudioProperties : public StreamProperties public: AudioProperties( const FormatContext& formatContext, const size_t index ); - std::string getCodecName() const; - std::string getCodecLongName() const; std::string getSampleFormatName() const; std::string getSampleFormatLongName() const; std::string getChannelLayout() const; std::string getChannelName() const; std::string getChannelDescription() const; - size_t getCodecId() const; size_t getSampleRate() const; size_t getChannels() const; size_t getBitRate() const; ///< 0 if unknown @@ -50,10 +47,6 @@ class AvExport AudioProperties : public StreamProperties } } #endif - -private: - AVCodecContext* _codecContext; ///< Has link (no ownership) - AVCodec* _codec; ///< Has link (no ownership) }; } diff --git a/src/AvTranscoder/mediaProperty/StreamProperties.cpp b/src/AvTranscoder/mediaProperty/StreamProperties.cpp index 196e425d..0682727c 100644 --- a/src/AvTranscoder/mediaProperty/StreamProperties.cpp +++ b/src/AvTranscoder/mediaProperty/StreamProperties.cpp @@ -7,10 +7,26 @@ namespace avtranscoder StreamProperties::StreamProperties( const FormatContext& formatContext, const size_t index ) : _formatContext( &formatContext.getAVFormatContext() ) + , _codecContext( NULL ) + , _codec( NULL ) , _streamIndex( index ) { if( _formatContext ) detail::fillMetadataDictionnary( _formatContext->streams[index]->metadata, _metadatas ); + + if( _formatContext ) + { + if( _streamIndex > _formatContext->nb_streams ) + { + std::stringstream ss; + ss << "Stream at index " << _streamIndex << " does not exist."; + throw std::runtime_error( ss.str() ); + } + _codecContext = _formatContext->streams[_streamIndex]->codec; + } + + if( _formatContext && _codecContext ) + _codec = avcodec_find_decoder( _codecContext->codec_id ); } StreamProperties::~StreamProperties() @@ -50,6 +66,41 @@ AVMediaType StreamProperties::getStreamType() const return _formatContext->streams[_streamIndex]->codec->codec_type; } +size_t StreamProperties::getCodecId() const +{ + if( ! _codecContext ) + throw std::runtime_error( "unknown codec context" ); + return _codecContext->codec_id; +} + +std::string StreamProperties::getCodecName() const +{ + if( ! _codecContext || ! _codec ) + throw std::runtime_error( "unknown codec" ); + + if( _codec->capabilities & CODEC_CAP_TRUNCATED ) + _codecContext->flags |= CODEC_FLAG_TRUNCATED; + + if( ! _codec->name ) + throw std::runtime_error( "unknown codec name" ); + + return std::string( _codec->name ); +} + +std::string StreamProperties::getCodecLongName() const +{ + if( ! _codecContext || ! _codec ) + throw std::runtime_error( "unknown codec" ); + + if( _codec->capabilities & CODEC_CAP_TRUNCATED ) + _codecContext->flags |= CODEC_FLAG_TRUNCATED; + + if( ! _codec->long_name ) + throw std::runtime_error( "unknown codec long name" ); + + return std::string( _codec->long_name ); +} + PropertyVector StreamProperties::getPropertiesAsVector() const { PropertyVector data; @@ -58,6 +109,9 @@ PropertyVector StreamProperties::getPropertiesAsVector() const addProperty( data, "streamIndex", &StreamProperties::getStreamIndex ); addProperty( data, "timeBase", &StreamProperties::getTimeBase ); addProperty( data, "duration", &StreamProperties::getDuration ); + addProperty( data, "codecId", &StreamProperties::getCodecId ); + addProperty( data, "codecName", &StreamProperties::getCodecName ); + addProperty( data, "codecLongName", &StreamProperties::getCodecLongName ); for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) { diff --git a/src/AvTranscoder/mediaProperty/StreamProperties.hpp b/src/AvTranscoder/mediaProperty/StreamProperties.hpp index a70a9dbe..675d14d7 100644 --- a/src/AvTranscoder/mediaProperty/StreamProperties.hpp +++ b/src/AvTranscoder/mediaProperty/StreamProperties.hpp @@ -20,6 +20,11 @@ class AvExport StreamProperties Rational getTimeBase() const; float getDuration() const; ///< in seconds AVMediaType getStreamType() const; + + size_t getCodecId() const; + std::string getCodecName() const; + std::string getCodecLongName() const; + const PropertyVector& getMetadatas() const { return _metadatas; } #ifndef SWIG @@ -47,6 +52,8 @@ class AvExport StreamProperties protected: const AVFormatContext* _formatContext; ///< Has link (no ownership) + AVCodecContext* _codecContext; ///< Has link (no ownership) + AVCodec* _codec; ///< Has link (no ownership) size_t _streamIndex; PropertyVector _metadatas; diff --git a/src/AvTranscoder/mediaProperty/VideoProperties.cpp b/src/AvTranscoder/mediaProperty/VideoProperties.cpp index d67329ff..fa88f765 100644 --- a/src/AvTranscoder/mediaProperty/VideoProperties.cpp +++ b/src/AvTranscoder/mediaProperty/VideoProperties.cpp @@ -17,28 +17,12 @@ namespace avtranscoder VideoProperties::VideoProperties( const FormatContext& formatContext, const size_t index, IProgress& progress, const EAnalyseLevel level ) : StreamProperties( formatContext, index ) - , _codecContext( NULL ) - , _codec( NULL ) , _pixelProperties() , _isInterlaced( false ) , _isTopFieldFirst( false ) , _gopStructure() , _firstGopTimeCode( -1 ) { - if( _formatContext ) - { - if( _streamIndex > _formatContext->nb_streams ) - { - std::stringstream ss; - ss << "video stream at index " << _streamIndex << " does not exist"; - throw std::runtime_error( ss.str() ); - } - _codecContext = _formatContext->streams[_streamIndex]->codec; - } - - if( _formatContext && _codecContext ) - _codec = avcodec_find_decoder( _codecContext->codec_id ); - if( _codecContext ) { _pixelProperties = PixelProperties( _codecContext->pix_fmt ); @@ -49,34 +33,6 @@ VideoProperties::VideoProperties( const FormatContext& formatContext, const size analyseGopStructure( progress ); } -std::string VideoProperties::getCodecName() const -{ - if( ! _codecContext || ! _codec ) - throw std::runtime_error( "unknown codec" ); - - if( _codec->capabilities & CODEC_CAP_TRUNCATED ) - _codecContext->flags|= CODEC_FLAG_TRUNCATED; - - if( ! _codec->name ) - throw std::runtime_error( "unknown codec name" ); - - return std::string( _codec->name ); -} - -std::string VideoProperties::getCodecLongName() const -{ - if( ! _codecContext || ! _codec ) - throw std::runtime_error( "unknown codec" ); - - if( _codec->capabilities & CODEC_CAP_TRUNCATED ) - _codecContext->flags|= CODEC_FLAG_TRUNCATED; - - if( ! _codec->long_name ) - throw std::runtime_error( "unknown codec long name" ); - - return std::string( _codec->long_name ); -} - std::string VideoProperties::getProfileName() const { if( ! _codecContext || ! _codec ) @@ -365,13 +321,6 @@ Rational VideoProperties::getDar() const return dar; } -size_t VideoProperties::getCodecId() const -{ - if( ! _codecContext ) - throw std::runtime_error( "unknown codec context" ); - return _codecContext->codec_id; -} - size_t VideoProperties::getBitRate() const { if( ! _codecContext ) @@ -606,9 +555,6 @@ PropertyVector VideoProperties::getPropertiesAsVector() const PropertyVector basedProperty = StreamProperties::getPropertiesAsVector(); data.insert( data.begin(), basedProperty.begin(), basedProperty.end() ); - addProperty( data, "codecId", &VideoProperties::getCodecId ); - addProperty( data, "codecName", &VideoProperties::getCodecName ); - addProperty( data, "codecLongName", &VideoProperties::getCodecLongName ); addProperty( data, "profile", &VideoProperties::getProfile ); addProperty( data, "profileName", &VideoProperties::getProfileName ); addProperty( data, "level", &VideoProperties::getLevel ); diff --git a/src/AvTranscoder/mediaProperty/VideoProperties.hpp b/src/AvTranscoder/mediaProperty/VideoProperties.hpp index a357e4c5..ee047f9f 100644 --- a/src/AvTranscoder/mediaProperty/VideoProperties.hpp +++ b/src/AvTranscoder/mediaProperty/VideoProperties.hpp @@ -23,8 +23,6 @@ class AvExport VideoProperties : public StreamProperties public: VideoProperties( const FormatContext& formatContext, const size_t index, IProgress& progress, const EAnalyseLevel level = eAnalyseLevelFirstGop ); - std::string getCodecName() const; - std::string getCodecLongName() const; std::string getProfileName() const; std::string getColorTransfert() const; std::string getColorspace() const; @@ -41,7 +39,6 @@ class AvExport VideoProperties : public StreamProperties Rational getSar() const; // sample/pixel aspect ratio Rational getDar() const; // display aspect ratio - size_t getCodecId() const; size_t getBitRate() const; ///< in bits/s size_t getMaxBitRate() const; size_t getMinBitRate() const; @@ -106,9 +103,6 @@ class AvExport VideoProperties : public StreamProperties #endif private: - AVCodecContext* _codecContext; ///< Has link (no ownership) - AVCodec* _codec; ///< Has link (no ownership) - PixelProperties _pixelProperties; //@{ // Can acces these data when analyse first gop