From ee03968a646d1365cfa069c4c953a182d7d33910 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 15:39:04 +0100 Subject: [PATCH 1/8] InputFile: updated log when no more data to read on file --- src/AvTranscoder/file/InputFile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/file/InputFile.cpp b/src/AvTranscoder/file/InputFile.cpp index 38086a24..72e95f77 100644 --- a/src/AvTranscoder/file/InputFile.cpp +++ b/src/AvTranscoder/file/InputFile.cpp @@ -63,7 +63,7 @@ bool InputFile::readNextPacket( CodedData& data, const size_t streamIndex ) const int ret = av_read_frame( &_formatContext.getAVFormatContext(), &data.getAVPacket() ); if( ret < 0 ) // error or end of file { - LOG_INFO( "No more data to read on file '" << _filename << "'" ) + LOG_INFO( "No more data to read on file '" << _filename << "' for stream " << streamIndex ) return false; } From 67526aefa581464a812dabcad5689d571c8a04ce Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:03:05 +0100 Subject: [PATCH 2/8] StreamTranscoder: fixed private method getProcessCase The process case of a StreamTranscoder could change during the process (depending on the state of the _currentDecoder attribute). --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 4e90eead..7acb815b 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -556,9 +556,9 @@ void StreamTranscoder::setOffset( const float offset ) StreamTranscoder::EProcessCase StreamTranscoder::getProcessCase() const { - if( _inputStream && _inputDecoder ) + if( _inputStream && _inputDecoder && _currentDecoder == _inputDecoder ) return eProcessCaseTranscode; - else if( _inputStream && ! _inputDecoder ) + else if( _inputStream && ! _inputDecoder && ! _currentDecoder ) return eProcessCaseRewrap; else return eProcessCaseGenerator; From 36c747349d3236c4dbb40b03499cf509439d2f96 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:24:22 +0100 Subject: [PATCH 3/8] Transcoder: added log when a process ended --- src/AvTranscoder/transcoder/Transcoder.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 984bf34d..b17eede9 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -252,21 +252,26 @@ ProcessStat Transcoder::process( IProgress& progress ) // check if JobStatusCancel if( progress.progress( ( progressDuration > outputDuration ) ? outputDuration : progressDuration, outputDuration ) == eJobStatusCancel ) + { + LOG_INFO( "End of process because the job was canceled." ) break; + } // check progressDuration if( progressDuration >= outputDuration ) + { + LOG_INFO( "End of process because the output program duration (" << progressDuration << "s) is equal or upper than " << outputDuration << "s." ) break; + } LOG_DEBUG( "Process frame " << frame ) frameProcessed = processFrame(); - ++frame; } _outputFile.endWrap(); - LOG_INFO( "End of process" ) + LOG_INFO( "End of process: " << frame << " frames processed" ) LOG_INFO( "Get process statistics" ) ProcessStat processStat; From f951e0734dc2b53d3705d18302b581a255696ca1 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 18:06:16 +0100 Subject: [PATCH 4/8] Transcoder: added eProcessMethodProcessAll process method * To stop the process when all the input data are read. * This is the default process method. * Do not check the output program duration when we use this process policy. --- src/AvTranscoder/transcoder/Transcoder.cpp | 4 ++-- src/AvTranscoder/transcoder/Transcoder.hpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index b17eede9..67a67c88 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -16,7 +16,7 @@ Transcoder::Transcoder( IOutputFile& outputFile ) , _streamTranscoders() , _streamTranscodersAllocated() , _profileLoader( true ) - , _eProcessMethod ( eProcessMethodBasedOnStream ) + , _eProcessMethod ( eProcessMethodProcessAll ) , _mainStreamIndex( 0 ) , _outputDuration( 0 ) {} @@ -258,7 +258,7 @@ ProcessStat Transcoder::process( IProgress& progress ) } // check progressDuration - if( progressDuration >= outputDuration ) + if( _eProcessMethod != eProcessMethodProcessAll && progressDuration >= outputDuration ) { LOG_INFO( "End of process because the output program duration (" << progressDuration << "s) is equal or upper than " << outputDuration << "s." ) break; diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index b0407859..3ef709a7 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -22,6 +22,7 @@ namespace avtranscoder * eProcessMethodLongest: stop transcode at the end of the longest stream. * eProcessMethodBasedOnStream: stop transcode at the end of an indicated stream (@see _indexBasedStream attribute of Transcoder). * eProcessMethodBasedOnDuration: stop transcode at the end of an indicated duration, in seconds (@see _outputDuration attribute of Transcoder). + * eProcessMethodProcessAll: stop the process when all the input data are read. * eProcessMethodInfinity: stop transcode by outside of avTranscoder (streaming mode) */ enum EProcessMethod @@ -30,6 +31,7 @@ enum EProcessMethod eProcessMethodLongest, eProcessMethodBasedOnStream, eProcessMethodBasedOnDuration, + eProcessMethodProcessAll, eProcessMethodInfinity, }; @@ -204,7 +206,7 @@ class AvExport Transcoder ProfileLoader _profileLoader; ///< Objet to get existing profiles, and add new ones for the Transcoder. - EProcessMethod _eProcessMethod; ///< Transcoding policy + EProcessMethod _eProcessMethod; ///< Transcoding policy (eProcessMethodProcessAll by default) size_t _mainStreamIndex; ///< Index of stream used to stop the process of transcode in case of eProcessMethodBasedOnStream. float _outputDuration; ///< Duration of output media used to stop the process of transcode in case of eProcessMethodBasedOnDuration. }; From e802464cb7b5fcece74c70e58562b1751963ba72 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 18:07:24 +0100 Subject: [PATCH 5/8] Transcoder: updated doc of the processing policy --- src/AvTranscoder/transcoder/Transcoder.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index 3ef709a7..70de33e5 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -17,13 +17,13 @@ namespace avtranscoder { /** - * @brief Enum to set a policy of how we manage the transcode in case of several streams. - * eProcessMethodShortest: stop transcode at the end of the shortest stream. - * eProcessMethodLongest: stop transcode at the end of the longest stream. - * eProcessMethodBasedOnStream: stop transcode at the end of an indicated stream (@see _indexBasedStream attribute of Transcoder). - * eProcessMethodBasedOnDuration: stop transcode at the end of an indicated duration, in seconds (@see _outputDuration attribute of Transcoder). + * @brief Enum to set a policy of how we manage the process in case of several streams. + * eProcessMethodShortest: stop the process at the end of the shortest stream. + * eProcessMethodLongest: stop the process at the end of the longest stream. + * eProcessMethodBasedOnStream: stop the process at the end of an indicated stream (@see _indexBasedStream attribute of Transcoder). + * eProcessMethodBasedOnDuration: stop the process at the end of an indicated duration, in seconds (@see _outputDuration attribute of Transcoder). * eProcessMethodProcessAll: stop the process when all the input data are read. - * eProcessMethodInfinity: stop transcode by outside of avTranscoder (streaming mode) + * eProcessMethodInfinity: stop the process by outside of avTranscoder (streaming mode) */ enum EProcessMethod { @@ -206,7 +206,7 @@ class AvExport Transcoder ProfileLoader _profileLoader; ///< Objet to get existing profiles, and add new ones for the Transcoder. - EProcessMethod _eProcessMethod; ///< Transcoding policy (eProcessMethodProcessAll by default) + EProcessMethod _eProcessMethod; ///< Processing policy (eProcessMethodProcessAll by default) size_t _mainStreamIndex; ///< Index of stream used to stop the process of transcode in case of eProcessMethodBasedOnStream. float _outputDuration; ///< Duration of output media used to stop the process of transcode in case of eProcessMethodBasedOnDuration. }; From 2e2008727132e2e92e2884594b7822d4449ee9d1 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 18:07:44 +0100 Subject: [PATCH 6/8] pyTest: added test to check EProcessMethodProcessAll processing policy --- test/pyTest/testEProcessMethod.py | 32 ++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/test/pyTest/testEProcessMethod.py b/test/pyTest/testEProcessMethod.py index 2a431120..3ff947d8 100644 --- a/test/pyTest/testEProcessMethod.py +++ b/test/pyTest/testEProcessMethod.py @@ -2,11 +2,13 @@ # Check if environment is setup to run the tests if os.environ.get('AVTRANSCODER_TEST_VIDEO_AVI_FILE') is None or \ + os.environ.get('AVTRANSCODER_TEST_VIDEO_MOV_FILE') is None or \ os.environ.get('AVTRANSCODER_TEST_AUDIO_MOV_FILE') is None or \ os.environ.get('AVTRANSCODER_TEST_AUDIO_WAVE_FILE') is None: from nose.plugins.skip import SkipTest raise SkipTest("Need to define environment variables " "AVTRANSCODER_TEST_VIDEO_AVI_FILE and " + "AVTRANSCODER_TEST_VIDEO_MOV_FILE and " "AVTRANSCODER_TEST_AUDIO_MOV_FILE and " "AVTRANSCODER_TEST_AUDIO_WAVE_FILE") @@ -105,6 +107,35 @@ def testEProcessMethodBasedOnStream(): assert_almost_equals( dst_stream_properties.getDuration(), src_properties_second.getDuration(), delta=0.05 ) +def testEProcessMethodProcessAll(): + """ + Process with method eProcessMethodProcessAll, check the duration of each output stream (which could be differentes). + """ + inputFileName = os.environ['AVTRANSCODER_TEST_VIDEO_MOV_FILE'] + outputFileName = "testEProcessMethodProcessAll.mov" + + ouputFile = av.OutputFile( outputFileName ) + transcoder = av.Transcoder( ouputFile ) + transcoder.setProcessMethod( av.eProcessMethodProcessAll ) + + transcoder.add( inputFileName, 0 ) + transcoder.add( inputFileName, 1 ) + + progress = av.ConsoleProgress() + transcoder.process( progress ) + + # get src file + src_inputFile = av.InputFile( inputFileName ) + src_properties = src_inputFile.getProperties() + + # get dst file + dst_inputFile = av.InputFile( outputFileName ) + dst_properties = dst_inputFile.getProperties() + + assert_equals( src_properties.getStreamProperties()[0].getDuration(), dst_properties.getStreamProperties()[0].getDuration() ) + assert_equals( src_properties.getStreamProperties()[1].getDuration(), dst_properties.getStreamProperties()[1].getDuration() ) + + def testEProcessMethodBasedOnDuration(): """ Process with method eProcessMethodBasedOnDuration, check output duration. @@ -131,4 +162,3 @@ def testEProcessMethodBasedOnDuration(): dst_properties = dst_inputFile.getProperties() assert_equals( dst_properties.getDuration(), outputDuration ) - From 1755cb08e538cb90cd07a0627b064c1b8670f5e9 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:05:26 +0100 Subject: [PATCH 7/8] StreamTranscoder: updated accessor of getProcessCase scope The method is now public. --- src/AvTranscoder/transcoder/StreamTranscoder.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 912af924..181a90e3 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -101,10 +101,6 @@ class AvExport StreamTranscoder */ void setOffset( const float offset ); -private: - bool processRewrap(); - bool processTranscode( const int subStreamIndex = -1 ); ///< By default transcode all channels - //@{ // Get the current process case. enum EProcessCase { @@ -115,6 +111,10 @@ class AvExport StreamTranscoder EProcessCase getProcessCase() const; //@} +private: + bool processRewrap(); + bool processTranscode( const int subStreamIndex = -1 ); ///< By default transcode all channels + private: IInputStream* _inputStream; ///< Input stream to read next packet (has link, no ownership) IOutputStream* _outputStream; ///< Output stream to wrap next packet (has link, no ownership) From 8d4bfe0f788178e72fb9bfb4bb450f1e833d2893 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:28:19 +0100 Subject: [PATCH 8/8] Transcoder: fixed how to process a frame for each stream * Try to process a new frame for each stream (do not exit the method if a stream failed to process). * Skip the generated streams because they always succeed. --- src/AvTranscoder/transcoder/Transcoder.cpp | 25 ++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 67a67c88..b79190e3 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -209,16 +209,33 @@ bool Transcoder::processFrame() if( _streamTranscoders.size() == 0 ) return false; + // For each stream, process a frame + size_t nbStreamProcessStatusFailed = 0; for( size_t streamIndex = 0; streamIndex < _streamTranscoders.size(); ++streamIndex ) { LOG_DEBUG( "Process stream " << streamIndex << "/" << ( _streamTranscoders.size() - 1 ) ) - - bool streamProcessStatus = _streamTranscoders.at( streamIndex )->processFrame(); - if( ! streamProcessStatus ) + const bool currentStreamProcessStatus = _streamTranscoders.at( streamIndex )->processFrame(); + if( ! currentStreamProcessStatus ) { - return false; + LOG_WARN( "Failed to process stream " << streamIndex ) + ++nbStreamProcessStatusFailed; } } + + // Get the number of streams without the generators (they always succeed) + size_t nbStreamsWithoutGenerator = _streamTranscoders.size(); + for( size_t streamIndex = 0; streamIndex < _streamTranscoders.size(); ++streamIndex ) + { + if( _streamTranscoders.at( streamIndex )->getProcessCase() == StreamTranscoder::eProcessCaseGenerator ) + --nbStreamsWithoutGenerator; + } + + // If all streams failed to process a new frame + if( nbStreamsWithoutGenerator != 0 && nbStreamProcessStatusFailed == nbStreamsWithoutGenerator ) + { + LOG_INFO( "End of process because all streams (except generators) failed to process a new frame." ) + return false; + } return true; }