From 75d6c30b9607c5bde03cc784ebcc633955223493 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 15:39:04 +0100 Subject: [PATCH 01/11] 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 ef0c996cfe11adc7b47955c09fad8ac98327acf3 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:03:05 +0100 Subject: [PATCH 02/11] 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 28fcd823cd26d1494bf1712588a890251a524100 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:05:26 +0100 Subject: [PATCH 03/11] 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 a5b2348136e63c7c254cc61c4826009436b9d557 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:24:22 +0100 Subject: [PATCH 04/11] 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 95d9d420c91188c32e3c517ab09dfbdf07fbe5eb Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:28:19 +0100 Subject: [PATCH 05/11] 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 b17eede9..bfbae42a 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; } From 087c3aa76dcbde89ac1dfef8672feaf2d2455635 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:35:09 +0100 Subject: [PATCH 06/11] Transcoder: fixed how to get the progressDuration during a process Added getCurrentOutputDuration private method. --- src/AvTranscoder/transcoder/Transcoder.cpp | 16 +++++++++++++++- src/AvTranscoder/transcoder/Transcoder.hpp | 7 +++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index bfbae42a..76140422 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -265,7 +265,7 @@ ProcessStat Transcoder::process( IProgress& progress ) bool frameProcessed = true; while( frameProcessed ) { - const float progressDuration = _outputFile.getStream( 0 ).getStreamDuration(); + const float progressDuration = getCurrentOutputDuration(); // check if JobStatusCancel if( progress.progress( ( progressDuration > outputDuration ) ? outputDuration : progressDuration, outputDuration ) == eJobStatusCancel ) @@ -501,6 +501,20 @@ float Transcoder::getOutputDuration() const } } +float Transcoder::getCurrentOutputDuration() const +{ + float currentOutputDuration = -1; + for( size_t streamIndex = 0; streamIndex < _streamTranscoders.size(); ++streamIndex ) + { + const float currentStreamDuration = _outputFile.getStream( streamIndex ).getStreamDuration(); + if( currentOutputDuration == -1 ) + currentOutputDuration = currentStreamDuration; + else if( currentStreamDuration < currentOutputDuration ) + currentOutputDuration = currentStreamDuration; + } + return currentOutputDuration; +} + void Transcoder::manageSwitchToGenerator() { for( size_t i = 0; i < _streamTranscoders.size(); ++i ) diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index b0407859..5a106be3 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -185,6 +185,13 @@ class AvExport Transcoder */ float getOutputDuration() const; + /** + * @brief Get the current duration of the output program + * @note Returns the duration of the smallest stream. + * @return -1 if there is no output stream. + */ + float getCurrentOutputDuration() const; + /** * @brief Set for each StreamTranscoder if it can switch to generator at the end. */ From fbdc5329aeb1f6c90947f8d123224f6f1f1c8aea Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 16:38:47 +0100 Subject: [PATCH 07/11] Transcoder: renamed private method getOutputDuration to getExpectedOutputDuration --- src/AvTranscoder/transcoder/Transcoder.cpp | 12 ++++++------ src/AvTranscoder/transcoder/Transcoder.hpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 76140422..4a71dbb1 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -258,8 +258,8 @@ ProcessStat Transcoder::process( IProgress& progress ) preProcessCodecLatency(); - const float outputDuration = getOutputDuration(); - LOG_INFO( "Output duration of the process will be " << outputDuration << "s." ) + const float expectedOutputDuration = getExpectedOutputDuration(); + LOG_INFO( "Output duration of the process will be " << expectedOutputDuration << "s." ) size_t frame = 0; bool frameProcessed = true; @@ -268,16 +268,16 @@ ProcessStat Transcoder::process( IProgress& progress ) const float progressDuration = getCurrentOutputDuration(); // check if JobStatusCancel - if( progress.progress( ( progressDuration > outputDuration ) ? outputDuration : progressDuration, outputDuration ) == eJobStatusCancel ) + if( progress.progress( ( progressDuration > expectedOutputDuration ) ? expectedOutputDuration : progressDuration, expectedOutputDuration ) == eJobStatusCancel ) { LOG_INFO( "End of process because the job was canceled." ) break; } // check progressDuration - if( progressDuration >= outputDuration ) + if( progressDuration >= expectedOutputDuration ) { - LOG_INFO( "End of process because the output program duration (" << progressDuration << "s) is equal or upper than " << outputDuration << "s." ) + LOG_INFO( "End of process because the output program duration (" << progressDuration << "s) is equal or upper than " << expectedOutputDuration << "s." ) break; } @@ -482,7 +482,7 @@ float Transcoder::getMaxTotalDuration() const return maxTotalDuration; } -float Transcoder::getOutputDuration() const +float Transcoder::getExpectedOutputDuration() const { switch( _eProcessMethod ) { diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index 5a106be3..0f89c662 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -180,10 +180,10 @@ class AvExport Transcoder float getMaxTotalDuration() const; /** - * @brief Get the duration of the output program + * @brief Get the expected duration of the output program * @note Depends on the streams, the process method, and the main stream index. */ - float getOutputDuration() const; + float getExpectedOutputDuration() const; /** * @brief Get the current duration of the output program From 534be5a18ad6ad578f1e820b27ce8d7042f3d792 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 18:06:16 +0100 Subject: [PATCH 08/11] 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 wgen we use the 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 4a71dbb1..49bf3403 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 ) {} @@ -275,7 +275,7 @@ ProcessStat Transcoder::process( IProgress& progress ) } // check progressDuration - if( progressDuration >= expectedOutputDuration ) + if( _eProcessMethod != eProcessMethodProcessAll && progressDuration >= expectedOutputDuration ) { LOG_INFO( "End of process because the output program duration (" << progressDuration << "s) is equal or upper than " << expectedOutputDuration << "s." ) break; diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index 0f89c662..6b03a9dc 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, }; @@ -211,7 +213,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 3266a27468b1196f3fd6f2d8a0a7ab860ea9b179 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 18:07:24 +0100 Subject: [PATCH 09/11] 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 6b03a9dc..6023d18a 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 { @@ -213,7 +213,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 812dcb8b6f8ac708ec489ee1f6b9f6e1e7747b07 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 18:07:44 +0100 Subject: [PATCH 10/11] 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 5dc447ef060155e667772b3d8068651894f5fdc4 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Mon, 4 Jan 2016 18:31:20 +0100 Subject: [PATCH 11/11] pyTest: updated testEProcessMethod when check the output duration Check the duration of the stream instead of the duration of the file. --- test/pyTest/testEProcessMethod.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/pyTest/testEProcessMethod.py b/test/pyTest/testEProcessMethod.py index 3ff947d8..62b0d637 100644 --- a/test/pyTest/testEProcessMethod.py +++ b/test/pyTest/testEProcessMethod.py @@ -43,7 +43,7 @@ def testEProcessMethodShortest(): dst_inputFile = av.InputFile( outputFileName ) dst_properties = dst_inputFile.getProperties() - assert_equals( dst_properties.getDuration(), src_properties_shortest.getDuration() ) + assert_equals( src_properties_shortest.getStreamProperties()[0].getDuration(), dst_properties.getStreamProperties()[1].getDuration() ) def testEProcessMethodLongest(): @@ -72,7 +72,7 @@ def testEProcessMethodLongest(): dst_inputFile = av.InputFile( outputFileName ) dst_properties = dst_inputFile.getProperties() - assert_equals( dst_properties.getDuration(), src_properties_longest.getDuration() ) + assert_equals( src_properties_longest.getStreamProperties()[0].getDuration(), dst_properties.getStreamProperties()[0].getDuration() ) def testEProcessMethodBasedOnStream(): @@ -161,4 +161,4 @@ def testEProcessMethodBasedOnDuration(): dst_inputFile = av.InputFile( outputFileName ) dst_properties = dst_inputFile.getProperties() - assert_equals( dst_properties.getDuration(), outputDuration ) + assert_equals( dst_properties.getStreamProperties()[0].getDuration(), outputDuration )