From 434b31c29f54b0f4c763fef2fb8d6141e9f2c557 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 21 Apr 2015 17:20:55 +0200 Subject: [PATCH 01/53] StreamTranscoder: add private functions to check the current processing case --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 15 +++++++++++++++ src/AvTranscoder/transcoder/StreamTranscoder.hpp | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index db20b1ab..9e13e6f0 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -464,4 +464,19 @@ double StreamTranscoder::getDuration() const return std::numeric_limits::max(); } +bool StreamTranscoder::isTranscodeCase() const +{ + return _inputStream && _inputDecoder; +} + +bool StreamTranscoder::isRewrapCase() const +{ + return _inputStream && ! _inputDecoder; +} + +bool StreamTranscoder::isGeneratorCase() const +{ + return ! _inputStream; +} + } diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index eb968b13..5af53bf9 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -94,6 +94,10 @@ class AvExport StreamTranscoder bool processRewrap(); bool processTranscode( const int subStreamIndex = -1 ); ///< By default transcode all channels + bool isTranscodeCase() const; + bool isRewrapCase() const; + bool isGeneratorCase() const; + 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 8da854967be270f1c2bd9df473e413b977471f4d Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 21 Apr 2015 17:43:41 +0200 Subject: [PATCH 02/53] StreamTranscoder: fix preProcessCodecLatency on rewrap cases A rewrap case can need to transcode at specific moments: * if there is an offset at the beginning * if it continues with a generator at the end of the rewrap. --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 9e13e6f0..8941cf0c 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -305,10 +305,6 @@ StreamTranscoder::~StreamTranscoder() void StreamTranscoder::preProcessCodecLatency() { - // rewrap case: no need to take care of the latency of codec - if( ! _currentDecoder ) - return; - int latency = _outputEncoder->getCodec().getLatency(); LOG_DEBUG( "Latency of stream: " << latency ) @@ -317,6 +313,10 @@ void StreamTranscoder::preProcessCodecLatency() latency < _outputEncoder->getCodec().getAVCodecContext().frame_number ) return; + // set a decoder to preload generated frames + if( isRewrapCase() ) + switchToGeneratorDecoder(); + while( ( latency-- ) > 0 ) { processFrame(); @@ -325,7 +325,7 @@ void StreamTranscoder::preProcessCodecLatency() bool StreamTranscoder::processFrame() { - if( ! _currentDecoder ) + if( isRewrapCase() ) { return processRewrap(); } From df5231e59858c9b9321fa510882788bcdef834a8 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 21 Apr 2015 17:44:57 +0200 Subject: [PATCH 03/53] StreamTranscoder: clean call of processTranscode --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 8 +------- src/AvTranscoder/transcoder/StreamTranscoder.hpp | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 8941cf0c..3f94e4b9 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -326,14 +326,8 @@ void StreamTranscoder::preProcessCodecLatency() bool StreamTranscoder::processFrame() { if( isRewrapCase() ) - { return processRewrap(); - } - if( _subStreamIndex < 0 ) - { - return processTranscode(); - } return processTranscode( _subStreamIndex ); } @@ -396,7 +390,7 @@ bool StreamTranscoder::processTranscode( const int subStreamIndex ) } bool decodingStatus = false; - if( subStreamIndex == -1 ) + if( subStreamIndex < 0 ) decodingStatus = _currentDecoder->decodeNextFrame( *_sourceBuffer ); else decodingStatus = _currentDecoder->decodeNextFrame( *_sourceBuffer, subStreamIndex ); diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 5af53bf9..b2f24943 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -112,7 +112,7 @@ class AvExport StreamTranscoder ITransform* _transform; ///< Video or audio transform (has ownership) - int _subStreamIndex; ///< Index of channel that is processed from the input stream (-1 if no demultiplexing). + int _subStreamIndex; ///< Index of channel that is processed from the input stream (<0 if no demultiplexing). double _offset; ///< Offset, in seconds, at the beginning of the StreamTranscoder. From 382f9be2935ee228d8659fb7db47f8dd5b32bc7a Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 21 Apr 2015 17:45:58 +0200 Subject: [PATCH 04/53] StreamTranscoder: set _generator when instanciate a generator processing case --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 3f94e4b9..83bf9747 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -241,7 +241,8 @@ StreamTranscoder::StreamTranscoder( VideoGenerator* generatorVideo = new VideoGenerator(); const VideoCodec& inputVideoCodec = static_cast( inputCodec ); generatorVideo->setVideoFrameDesc( inputVideoCodec.getVideoFrameDesc() ); - _currentDecoder = generatorVideo; + _generator = generatorVideo; + _currentDecoder = _generator; // buffers to process VideoFrameDesc inputFrameDesc = inputVideoCodec.getVideoFrameDesc(); @@ -267,7 +268,8 @@ StreamTranscoder::StreamTranscoder( AudioGenerator* generatorAudio = new AudioGenerator(); const AudioCodec& inputAudioCodec = static_cast( inputCodec ); generatorAudio->setAudioFrameDesc( inputAudioCodec.getAudioFrameDesc() ); - _currentDecoder = generatorAudio; + _generator = generatorAudio; + _currentDecoder = _generator; // buffers to process AudioFrameDesc inputFrameDesc = inputAudioCodec.getAudioFrameDesc(); From 9e0c9426010bf10e53abcf07a8d121532e90321e Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 21 Apr 2015 17:50:36 +0200 Subject: [PATCH 05/53] OutputStream: fix getStreamDuration (use av_stream_get_end_pts) Fix #165 --- src/AvTranscoder/stream/OutputStream.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/AvTranscoder/stream/OutputStream.cpp b/src/AvTranscoder/stream/OutputStream.cpp index 228dd44c..1563c75b 100644 --- a/src/AvTranscoder/stream/OutputStream.cpp +++ b/src/AvTranscoder/stream/OutputStream.cpp @@ -17,7 +17,12 @@ OutputStream::OutputStream( OutputFile& outputFile, const size_t streamIndex ) double OutputStream::getStreamDuration() const { AVStream& outputStream = _outputFile->getFormatContext().getAVStream( _streamIndex ); - return av_q2d( outputStream.time_base ) * outputStream.cur_dts; +#if AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 40, 100) + // returns the pts of the last muxed packet, converted from timebase to seconds + return av_q2d( outputStream.time_base ) * av_stream_get_end_pts( &outputStream ); +#else + return av_q2d( outputStream.time_base ) * ( outputStream.pts.val + ( outputStream.pts.num / outputStream.pts.den ) ); +#endif } IOutputStream::EWrappingStatus OutputStream::wrap( const CodedData& data ) From 05a6237e3e3c5be4e4ba03f693554e657a08428a Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 21 Apr 2015 11:27:14 +0200 Subject: [PATCH 06/53] mediaProperty: get timeBase and duration from base class Add properties of base class if the derived class override getPropertiesAsVector (for Video and Audio). --- .../mediaProperty/AudioProperties.cpp | 32 +++---------------- .../mediaProperty/AudioProperties.hpp | 2 -- .../mediaProperty/StreamProperties.cpp | 32 +++++++++++++------ .../mediaProperty/StreamProperties.hpp | 18 +++++++++++ .../mediaProperty/VideoProperties.cpp | 32 +++---------------- .../mediaProperty/VideoProperties.hpp | 2 -- 6 files changed, 49 insertions(+), 69 deletions(-) diff --git a/src/AvTranscoder/mediaProperty/AudioProperties.cpp b/src/AvTranscoder/mediaProperty/AudioProperties.cpp index ac0412bd..beb97c63 100644 --- a/src/AvTranscoder/mediaProperty/AudioProperties.cpp +++ b/src/AvTranscoder/mediaProperty/AudioProperties.cpp @@ -180,31 +180,14 @@ size_t AudioProperties::getTicksPerFrame() const return _codecContext->ticks_per_frame; } -Rational AudioProperties::getTimeBase() const -{ - if( ! _formatContext ) - throw std::runtime_error( "unknown format context" ); - - Rational timeBase = { - _formatContext->streams[_streamIndex]->time_base.num, - _formatContext->streams[_streamIndex]->time_base.den, - }; - return timeBase; -} - -double AudioProperties::getDuration() const -{ - Rational timeBase = getTimeBase(); - double duration = ( timeBase.num / (double) timeBase.den ) * _formatContext->streams[_streamIndex]->duration; - return duration; -} - PropertyVector AudioProperties::getPropertiesAsVector() const { PropertyVector data; - addProperty( data, "streamId", &AudioProperties::getStreamId ); - detail::add( data, "streamIndex", getStreamIndex() ); + // Add properties of base class + 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 ); @@ -218,13 +201,6 @@ PropertyVector AudioProperties::getPropertiesAsVector() const addProperty( data, "channelName", &AudioProperties::getChannelName ); addProperty( data, "channelDescription", &AudioProperties::getChannelDescription ); addProperty( data, "ticksPerFrame", &AudioProperties::getTicksPerFrame ); - addProperty( data, "timeBase", &AudioProperties::getTimeBase ); - addProperty( data, "duration", &AudioProperties::getDuration ); - - for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) - { - detail::add( data, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); - } return data; } diff --git a/src/AvTranscoder/mediaProperty/AudioProperties.hpp b/src/AvTranscoder/mediaProperty/AudioProperties.hpp index 06952be9..a53df387 100644 --- a/src/AvTranscoder/mediaProperty/AudioProperties.hpp +++ b/src/AvTranscoder/mediaProperty/AudioProperties.hpp @@ -29,8 +29,6 @@ class AvExport AudioProperties : public StreamProperties size_t getNbSamples() const; ///< 0 if unknown size_t getTicksPerFrame() const; - Rational getTimeBase() const; - double getDuration() const; #ifndef SWIG AVCodecContext& getAVCodecContext() { return *_codecContext; } diff --git a/src/AvTranscoder/mediaProperty/StreamProperties.cpp b/src/AvTranscoder/mediaProperty/StreamProperties.cpp index dbfca9eb..94e4e34b 100644 --- a/src/AvTranscoder/mediaProperty/StreamProperties.cpp +++ b/src/AvTranscoder/mediaProperty/StreamProperties.cpp @@ -25,19 +25,33 @@ size_t StreamProperties::getStreamId() const return _formatContext->streams[_streamIndex]->id; } +Rational StreamProperties::getTimeBase() const +{ + if( ! _formatContext ) + throw std::runtime_error( "unknown format context" ); + + Rational timeBase = { + _formatContext->streams[_streamIndex]->time_base.num, + _formatContext->streams[_streamIndex]->time_base.den, + }; + return timeBase; +} + +double StreamProperties::getDuration() const +{ + Rational timeBase = getTimeBase(); + double duration = ( timeBase.num / (double) timeBase.den ) * _formatContext->streams[_streamIndex]->duration; + return duration; +} + PropertyVector StreamProperties::getPropertiesAsVector() const { PropertyVector data; - try - { - detail::add( data, "streamId", getStreamId() ); - } - catch( const std::exception& e ) - { - detail::add( data, "streamId", e.what() ); - } - detail::add( data, "streamIndex", getStreamIndex() ); + addProperty( data, "streamId", &StreamProperties::getStreamId ); + addProperty( data, "streamIndex", &StreamProperties::getStreamIndex ); + addProperty( data, "timeBase", &StreamProperties::getTimeBase ); + addProperty( data, "duration", &StreamProperties::getDuration ); for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) { diff --git a/src/AvTranscoder/mediaProperty/StreamProperties.hpp b/src/AvTranscoder/mediaProperty/StreamProperties.hpp index 773ca70f..d4e0e05b 100644 --- a/src/AvTranscoder/mediaProperty/StreamProperties.hpp +++ b/src/AvTranscoder/mediaProperty/StreamProperties.hpp @@ -17,6 +17,8 @@ class AvExport StreamProperties size_t getStreamIndex() const { return _streamIndex; } size_t getStreamId() const; + Rational getTimeBase() const; + double getDuration() const; ///< in seconds PropertyVector& getMetadatas() { return _metadatas; } #ifndef SWIG @@ -26,6 +28,22 @@ class AvExport StreamProperties PropertyMap getPropertiesAsMap() const; ///< Return all properties as a map (name of property, value) PropertyVector getPropertiesAsVector() const; ///< Same data with a specific order +private: +#ifndef SWIG + template + void addProperty( PropertyVector& dataVector, const std::string& key, T (StreamProperties::*getter)(void) const ) const + { + try + { + detail::add( dataVector, key, (this->*getter)() ); + } + catch( const std::exception& e ) + { + detail::add( dataVector, key, e.what() ); + } + } +#endif + protected: const AVFormatContext* _formatContext; ///< Has link (no ownership) diff --git a/src/AvTranscoder/mediaProperty/VideoProperties.cpp b/src/AvTranscoder/mediaProperty/VideoProperties.cpp index 289bfcb3..98c8d3c4 100644 --- a/src/AvTranscoder/mediaProperty/VideoProperties.cpp +++ b/src/AvTranscoder/mediaProperty/VideoProperties.cpp @@ -334,18 +334,6 @@ std::string VideoProperties::getStartTimecodeString() const return os.str(); } -Rational VideoProperties::getTimeBase() const -{ - if( ! _formatContext ) - throw std::runtime_error( "unknown format context" ); - - Rational timeBase = { - _formatContext->streams[_streamIndex]->time_base.num, - _formatContext->streams[_streamIndex]->time_base.den, - }; - return timeBase; -} - Rational VideoProperties::getSar() const { if( ! _codecContext ) @@ -554,13 +542,6 @@ double VideoProperties::getFps() const return fps; } -double VideoProperties::getDuration() const -{ - Rational timeBase = getTimeBase(); - double duration = ( timeBase.num / (double) timeBase.den ) * _formatContext->streams[_streamIndex]->duration; - return duration; -} - bool VideoProperties::hasBFrames() const { if( ! _codecContext ) @@ -644,8 +625,10 @@ PropertyVector VideoProperties::getPropertiesAsVector() const { PropertyVector data; - addProperty( data, "streamId", &VideoProperties::getStreamId ); - detail::add( data, "streamIndex", getStreamIndex() ); + // Add properties of base class + 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 ); @@ -666,8 +649,6 @@ PropertyVector VideoProperties::getPropertiesAsVector() const addProperty( data, "interlaced ", &VideoProperties::isInterlaced ); addProperty( data, "topFieldFirst", &VideoProperties::isTopFieldFirst ); addProperty( data, "fieldOrder", &VideoProperties::getFieldOrder ); - addProperty( data, "timeBase", &VideoProperties::getTimeBase ); - addProperty( data, "duration", &VideoProperties::getDuration ); addProperty( data, "fps", &VideoProperties::getFps ); addProperty( data, "nbFrame", &VideoProperties::getNbFrames ); addProperty( data, "ticksPerFrame", &VideoProperties::getTicksPerFrame ); @@ -688,11 +669,6 @@ PropertyVector VideoProperties::getPropertiesAsVector() const addProperty( data, "hasBFrames", &VideoProperties::hasBFrames ); addProperty( data, "referencesFrames", &VideoProperties::getReferencesFrames ); - for( size_t metadataIndex = 0; metadataIndex < _metadatas.size(); ++metadataIndex ) - { - detail::add( data, _metadatas.at( metadataIndex ).first, _metadatas.at( metadataIndex ).second ); - } - // Add properties of the pixel PropertyVector pixelProperties = _pixelProperties.getPropertiesAsVector(); data.insert( data.end(), pixelProperties.begin(), pixelProperties.end() ); diff --git a/src/AvTranscoder/mediaProperty/VideoProperties.hpp b/src/AvTranscoder/mediaProperty/VideoProperties.hpp index adddb098..8c3eba0b 100644 --- a/src/AvTranscoder/mediaProperty/VideoProperties.hpp +++ b/src/AvTranscoder/mediaProperty/VideoProperties.hpp @@ -38,7 +38,6 @@ class AvExport VideoProperties : public StreamProperties int64_t getStartTimecode() const; std::string getStartTimecodeString() const; - Rational getTimeBase() const; Rational getSar() const; // sample/pixel aspect ratio Rational getDar() const; // display aspect ratio @@ -58,7 +57,6 @@ class AvExport VideoProperties : public StreamProperties int getLevel() const; double getFps() const; - double getDuration() const; ///< in seconds bool hasBFrames() const; //bool isClosedGop() const; From 108b7dffe7e0055ccbf3775d79126609c6eb8089 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 21 Apr 2015 18:02:21 +0200 Subject: [PATCH 07/53] Move InputFile::seek to FormatContext::seek Note: remove useless InputStreams clearBuffering call. --- src/AvTranscoder/file/FormatContext.cpp | 11 +++++++++++ src/AvTranscoder/file/FormatContext.hpp | 7 +++++++ src/AvTranscoder/file/InputFile.cpp | 20 ++------------------ src/AvTranscoder/file/InputFile.hpp | 7 ------- 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/AvTranscoder/file/FormatContext.cpp b/src/AvTranscoder/file/FormatContext.cpp index b90a37d8..f19f3102 100644 --- a/src/AvTranscoder/file/FormatContext.cpp +++ b/src/AvTranscoder/file/FormatContext.cpp @@ -133,6 +133,17 @@ AVStream& FormatContext::addAVStream( const AVCodec& avCodec ) return *stream; } +void FormatContext::seek( uint64_t position ) +{ + if( (int)getStartTime() != AV_NOPTS_VALUE ) + position += getStartTime(); + + if( av_seek_frame( _avFormatContext, -1, position, AVSEEK_FLAG_BACKWARD ) < 0 ) + { + LOG_ERROR( "Error when seek at " << position << " (in AV_TIME_BASE units) in file" ) + } +} + std::vector