diff --git a/src/AvTranscoder/codedStream/AvOutputStream.cpp b/src/AvTranscoder/codedStream/AvOutputStream.cpp index f4503006..67933274 100644 --- a/src/AvTranscoder/codedStream/AvOutputStream.cpp +++ b/src/AvTranscoder/codedStream/AvOutputStream.cpp @@ -14,7 +14,7 @@ AvOutputStream::AvOutputStream( OutputFile& outputFile, const size_t streamIndex { } -bool AvOutputStream::wrap( const CodedData& data ) +IOutputStream::EWrappingStatus AvOutputStream::wrap( const CodedData& data ) { assert( _outputFile != NULL ); return _outputFile->wrap( data, _streamIndex ); diff --git a/src/AvTranscoder/codedStream/AvOutputStream.hpp b/src/AvTranscoder/codedStream/AvOutputStream.hpp index 499c50ba..2b23ea83 100644 --- a/src/AvTranscoder/codedStream/AvOutputStream.hpp +++ b/src/AvTranscoder/codedStream/AvOutputStream.hpp @@ -15,7 +15,7 @@ class AvExport AvOutputStream : public IOutputStream size_t getStreamIndex() const { return _streamIndex; } - bool wrap( const CodedData& data ); + IOutputStream::EWrappingStatus wrap( const CodedData& data ); private: OutputFile* _outputFile; diff --git a/src/AvTranscoder/codedStream/IOutputStream.hpp b/src/AvTranscoder/codedStream/IOutputStream.hpp index 3919d5f2..33093152 100644 --- a/src/AvTranscoder/codedStream/IOutputStream.hpp +++ b/src/AvTranscoder/codedStream/IOutputStream.hpp @@ -11,11 +11,22 @@ namespace avtranscoder class IOutputStream { public: + + /** + * @brief define wrapping result status + **/ + enum EWrappingStatus + { + eWrappingSuccess = 0, + eWrappingWaitingForData, + eWrappingError, + }; + virtual ~IOutputStream() {}; virtual size_t getStreamIndex() const = 0; - virtual bool wrap( const CodedData& data ) = 0; + virtual EWrappingStatus wrap( const CodedData& data ) = 0; }; } diff --git a/src/AvTranscoder/file/OutputFile.cpp b/src/AvTranscoder/file/OutputFile.cpp index 40c33e3b..617c1867 100644 --- a/src/AvTranscoder/file/OutputFile.cpp +++ b/src/AvTranscoder/file/OutputFile.cpp @@ -20,6 +20,7 @@ OutputFile::OutputFile( const std::string& filename ) , _stream ( NULL ) , _filename ( filename ) , _packetCount ( 0 ) + , _previousProcessedStreamDuration( 0.0 ) , _verbose ( false ) { if( ( _formatContext = avformat_alloc_context() ) == NULL ) @@ -66,12 +67,13 @@ IOutputStream& OutputFile::addVideoStream( const VideoCodec& videoDesc ) _stream->codec->width = videoDesc.getAVCodecContext()->width; _stream->codec->height = videoDesc.getAVCodecContext()->height; _stream->codec->bit_rate = videoDesc.getAVCodecContext()->bit_rate; - _stream->codec->ticks_per_frame = videoDesc.getAVCodecContext()->ticks_per_frame; _stream->codec->pix_fmt = videoDesc.getAVCodecContext()->pix_fmt; _stream->codec->profile = videoDesc.getAVCodecContext()->profile; _stream->codec->level = videoDesc.getAVCodecContext()->level; - // need to set the time_base on the AVCodecContext and the AVStream... + // need to set the time_base on the AVCodecContext and the AVStream + // compensating the frame rate with the ticks_per_frame and keeping + // a coherent reading speed. av_reduce( &_stream->codec->time_base.num, &_stream->codec->time_base.den, @@ -145,10 +147,10 @@ bool OutputFile::beginWrap( ) return true; } -bool OutputFile::wrap( const CodedData& data, const size_t streamId ) +IOutputStream::EWrappingStatus OutputFile::wrap( const CodedData& data, const size_t streamId ) { if( ! data.getSize() ) - return true; + return IOutputStream::eWrappingSuccess; if( _verbose ) std::cout << "wrap on stream " << streamId << " (" << data.getSize() << " bytes for frame " << _frameCount.at( streamId ) << ")" << std::endl; AVPacket packet; @@ -174,14 +176,27 @@ bool OutputFile::wrap( const CodedData& data, const size_t streamId ) msg += err; // throw std::runtime_error( msg ); std::cout << msg << std::endl; - return false; + return IOutputStream::eWrappingError; } av_free_packet( &packet ); + // get the current streams + AVStream* currentStream = _formatContext->streams[ streamId ]; + // compute its duration + double currentStreamDuration = (double)currentStream->cur_dts * currentStream->time_base.num / currentStream->time_base.den; + + if( currentStreamDuration < _previousProcessedStreamDuration ) + { + // if the current stream is strictly shorter than the previous, wait for more data + return IOutputStream::eWrappingWaitingForData; + } + + _previousProcessedStreamDuration = currentStreamDuration; + _packetCount++; _frameCount.at( streamId )++; - return true; + return IOutputStream::eWrappingSuccess; } bool OutputFile::endWrap( ) diff --git a/src/AvTranscoder/file/OutputFile.hpp b/src/AvTranscoder/file/OutputFile.hpp index fb49717c..99cfd6f8 100644 --- a/src/AvTranscoder/file/OutputFile.hpp +++ b/src/AvTranscoder/file/OutputFile.hpp @@ -86,7 +86,7 @@ class AvExport OutputFile * @param data coded packet information for the current stream * @param streamId refers to the stream in output ressource **/ - virtual bool wrap( const CodedData& data, const size_t streamId ); + virtual IOutputStream::EWrappingStatus wrap( const CodedData& data, const size_t streamId ); /** * @brief Finalize the end of the wrapping @@ -123,6 +123,8 @@ class AvExport OutputFile std::string _filename; size_t _packetCount; + + double _previousProcessedStreamDuration; bool _verbose; }; diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 35455665..63c427db 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -303,7 +303,19 @@ bool StreamTranscoder::processRewrap() if( ! _inputStream->readNextPacket( data ) ) return false; - _outputStream->wrap( data ); + IOutputStream::EWrappingStatus wrappingStatus = _outputStream->wrap( data ); + + switch( wrappingStatus ) + { + case IOutputStream::eWrappingSuccess: + return true; + case IOutputStream::eWrappingWaitingForData: + // the wrapper needs more data to write the current packet + return processRewrap(); + case IOutputStream::eWrappingError: + return false; + } + return true; } @@ -355,7 +367,20 @@ bool StreamTranscoder::processTranscode() if( _verbose ) std::cout << "wrap (" << data.getSize() << ")" << std::endl; - _outputStream->wrap( data ); + + IOutputStream::EWrappingStatus wrappingStatus = _outputStream->wrap( data ); + + switch( wrappingStatus ) + { + case IOutputStream::eWrappingSuccess: + return true; + case IOutputStream::eWrappingWaitingForData: + // the wrapper needs more data to write the current packet + return processTranscode(); + case IOutputStream::eWrappingError: + return false; + } + return true; } @@ -406,7 +431,20 @@ bool StreamTranscoder::processTranscode( const int subStreamIndex ) } if( _verbose ) std::cout << "wrap (" << data.getSize() << ")" << std::endl; - _outputStream->wrap( data ); + + IOutputStream::EWrappingStatus wrappingStatus = _outputStream->wrap( data ); + + switch( wrappingStatus ) + { + case IOutputStream::eWrappingSuccess: + return true; + case IOutputStream::eWrappingWaitingForData: + // the wrapper needs more data to write the current packet + return processTranscode( subStreamIndex ); + case IOutputStream::eWrappingError: + return false; + } + return true; } diff --git a/src/AvTranscoder/transform/AudioTransform.cpp b/src/AvTranscoder/transform/AudioTransform.cpp index 5c68a776..ebc6c5bd 100644 --- a/src/AvTranscoder/transform/AudioTransform.cpp +++ b/src/AvTranscoder/transform/AudioTransform.cpp @@ -32,6 +32,7 @@ namespace avtranscoder AudioTransform::AudioTransform() : _audioConvertContext( NULL ) + , _previousProcessedAudioFrameSize( 0 ) , _isInit ( false ) { } @@ -64,11 +65,25 @@ bool AudioTransform::init( const Frame& srcFrame, const Frame& dstFrame ) return true; } +bool AudioTransform::initFrames( const Frame& srcFrame, Frame& dstFrame ) +{ + const AudioFrame& src = static_cast( srcFrame ); + const AudioFrame& dst = static_cast( dstFrame ); + + int dstSampleSize = av_get_bytes_per_sample( dst.desc().getAVSampleFormat() ); + dstFrame.getBuffer().resize( src.getNbSamples() * dstSampleSize ); + _previousProcessedAudioFrameSize = srcFrame.getSize(); + return true; +} + void AudioTransform::convert( const Frame& srcFrame, Frame& dstFrame ) { if( ! _isInit ) _isInit = init( srcFrame, dstFrame ); + if( srcFrame.getSize() != _previousProcessedAudioFrameSize ) + initFrames( srcFrame, dstFrame ); + const unsigned char* srcData = srcFrame.getPtr(); unsigned char* dstData = dstFrame.getPtr(); diff --git a/src/AvTranscoder/transform/AudioTransform.hpp b/src/AvTranscoder/transform/AudioTransform.hpp index c33665cd..a2d1d1a4 100644 --- a/src/AvTranscoder/transform/AudioTransform.hpp +++ b/src/AvTranscoder/transform/AudioTransform.hpp @@ -26,8 +26,11 @@ class AvExport AudioTransform : public ITransform private: bool init( const Frame& srcFrame, const Frame& dstFrame ); + bool initFrames( const Frame& srcFrame, Frame& dstFrame ); ResampleContext* _audioConvertContext; + + size_t _previousProcessedAudioFrameSize; bool _isInit; };