From 7f979d67ab35e6557821a6fb857a978936d33d93 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 19 Jul 2016 15:18:26 +0200 Subject: [PATCH 01/43] StreamTranscoder: handle array of input streams and decoders * To be able to read data from several source, and encode them in the same output stream. * This will be done in the next commits. --- .../transcoder/StreamTranscoder.cpp | 215 ++++++++++-------- .../transcoder/StreamTranscoder.hpp | 16 +- src/AvTranscoder/transcoder/Transcoder.cpp | 2 +- 3 files changed, 125 insertions(+), 108 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index a6878bc3..cadc9850 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -20,53 +20,56 @@ namespace avtranscoder { StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outputFile, const float offset) - : _inputStream(&inputStream) + : _inputStreamDesc() + , _inputStreams() + , _currentInputStream(&inputStream) , _outputStream(NULL) - , _sourceBuffer(NULL) - , _frameBuffer(NULL) - , _inputDecoder(NULL) - , _generator(NULL) + , _sourceBuffers() + , _frameBuffers() + , _inputDecoders() + , _generators() , _currentDecoder(NULL) , _outputEncoder(NULL) , _transform(NULL) , _filterGraph(NULL) - , _inputStreamDesc() , _offset(offset) , _needToSwitchToGenerator(false) { + _inputStreams.push_back(_currentInputStream); + // create a re-wrapping case - switch(_inputStream->getProperties().getStreamType()) + switch(_currentInputStream->getProperties().getStreamType()) { case AVMEDIA_TYPE_VIDEO: { // output stream - _outputStream = &outputFile.addVideoStream(_inputStream->getVideoCodec()); + _outputStream = &outputFile.addVideoStream(_currentInputStream->getVideoCodec()); try { // filter - _filterGraph = new FilterGraph(_inputStream->getVideoCodec()); + _filterGraph = new FilterGraph(_currentInputStream->getVideoCodec()); - VideoFrameDesc inputFrameDesc(_inputStream->getVideoCodec().getVideoFrameDesc()); + VideoFrameDesc inputFrameDesc(_currentInputStream->getVideoCodec().getVideoFrameDesc()); // generator decoder - _generator = new VideoGenerator(inputFrameDesc); + _generators.push_back(new VideoGenerator(inputFrameDesc)); // buffers to process - _sourceBuffer = new VideoFrame(inputFrameDesc); - _frameBuffer = new VideoFrame(inputFrameDesc); + _sourceBuffers.push_back(new VideoFrame(inputFrameDesc)); + _frameBuffers.push_back(new VideoFrame(inputFrameDesc)); // transform _transform = new VideoTransform(); // output encoder - VideoEncoder* outputVideo = new VideoEncoder(_inputStream->getVideoCodec().getCodecName()); + VideoEncoder* outputVideo = new VideoEncoder(_currentInputStream->getVideoCodec().getCodecName()); outputVideo->setupVideoEncoder(inputFrameDesc); _outputEncoder = outputVideo; } catch(std::runtime_error& e) { - LOG_WARN("Cannot create the video encoder for stream " << _inputStream->getStreamIndex() << " if needed. " + LOG_WARN("Cannot create the video encoder for stream " << _currentInputStream->getStreamIndex() << " if needed. " << e.what()) } @@ -75,34 +78,34 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu case AVMEDIA_TYPE_AUDIO: { // output stream - _outputStream = &outputFile.addAudioStream(_inputStream->getAudioCodec()); + _outputStream = &outputFile.addAudioStream(_currentInputStream->getAudioCodec()); try { // filter - _filterGraph = new FilterGraph(_inputStream->getAudioCodec()); + _filterGraph = new FilterGraph(_currentInputStream->getAudioCodec()); - AudioFrameDesc inputFrameDesc(_inputStream->getAudioCodec().getAudioFrameDesc()); + AudioFrameDesc inputFrameDesc(_currentInputStream->getAudioCodec().getAudioFrameDesc()); // generator decoder - _generator = new AudioGenerator(inputFrameDesc); + _generators.push_back(new AudioGenerator(inputFrameDesc)); // buffers to process - _sourceBuffer = new AudioFrame(inputFrameDesc); - _frameBuffer = new AudioFrame(inputFrameDesc); + _sourceBuffers.push_back(new AudioFrame(inputFrameDesc)); + _frameBuffers.push_back(new AudioFrame(inputFrameDesc)); // transform _transform = new AudioTransform(); // output encoder - AudioEncoder* outputAudio = new AudioEncoder(_inputStream->getAudioCodec().getCodecName()); + AudioEncoder* outputAudio = new AudioEncoder(_currentInputStream->getAudioCodec().getCodecName()); outputAudio->setupAudioEncoder(inputFrameDesc); _outputEncoder = outputAudio; } catch(std::runtime_error& e) { - LOG_WARN("Cannot create the audio encoder for stream " << _inputStream->getStreamIndex() << " if needed. " + LOG_WARN("Cannot create the audio encoder for stream " << _currentInputStream->getStreamIndex() << " if needed. " << e.what()) } @@ -111,7 +114,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu case AVMEDIA_TYPE_DATA: { // @warning: rewrap a data stream can't be lengthen by a generator (end of rewrapping will end the all process) - _outputStream = &outputFile.addDataStream(_inputStream->getDataCodec()); + _outputStream = &outputFile.addDataStream(_currentInputStream->getDataCodec()); break; } default: @@ -122,39 +125,43 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInputStream& inputStream, IOutputFile& outputFile, const ProfileLoader::Profile& profile, const float offset) - : _inputStream(&inputStream) + : _inputStreamDesc() + , _inputStreams() + , _currentInputStream(&inputStream) , _outputStream(NULL) - , _sourceBuffer(NULL) - , _frameBuffer(NULL) - , _inputDecoder(NULL) - , _generator(NULL) + , _sourceBuffers() + , _frameBuffers() + , _inputDecoders() + , _generators() , _currentDecoder(NULL) , _outputEncoder(NULL) , _transform(NULL) , _filterGraph(NULL) - , _inputStreamDesc(inputStreamDesc) , _offset(offset) , _needToSwitchToGenerator(false) { + _inputStreamDesc.push_back(inputStreamDesc); + _inputStreams.push_back(_currentInputStream); + // create a transcode case - switch(_inputStream->getProperties().getStreamType()) + switch(_currentInputStream->getProperties().getStreamType()) { case AVMEDIA_TYPE_VIDEO: { // filter - _filterGraph = new FilterGraph(_inputStream->getVideoCodec()); + _filterGraph = new FilterGraph(_currentInputStream->getVideoCodec()); // input decoder - VideoDecoder* inputVideo = new VideoDecoder(*static_cast(_inputStream)); + VideoDecoder* inputVideo = new VideoDecoder(*static_cast(&inputStream)); inputVideo->setupDecoder(); - _inputDecoder = inputVideo; - _currentDecoder = _inputDecoder; + _inputDecoders.push_back(inputVideo); + _currentDecoder = inputVideo; // output encoder VideoEncoder* outputVideo = new VideoEncoder(profile.at(constants::avProfileCodec)); _outputEncoder = outputVideo; - VideoFrameDesc outputFrameDesc = _inputStream->getVideoCodec().getVideoFrameDesc(); + VideoFrameDesc outputFrameDesc = _currentInputStream->getVideoCodec().getVideoFrameDesc(); outputFrameDesc.setParameters(profile); outputVideo->setupVideoEncoder(outputFrameDesc, profile); @@ -162,54 +169,54 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec()); // buffers to process - _sourceBuffer = new VideoFrame(_inputStream->getVideoCodec().getVideoFrameDesc()); - _frameBuffer = new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc()); + _sourceBuffers.push_back(new VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); + _frameBuffers.push_back(new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc())); // transform _transform = new VideoTransform(); // generator decoder - _generator = new VideoGenerator(outputVideo->getVideoCodec().getVideoFrameDesc()); + _generators.push_back(new VideoGenerator(outputVideo->getVideoCodec().getVideoFrameDesc())); break; } case AVMEDIA_TYPE_AUDIO: { // filter - _filterGraph = new FilterGraph(_inputStream->getAudioCodec()); + _filterGraph = new FilterGraph(_currentInputStream->getAudioCodec()); // input decoder - AudioDecoder* inputAudio = new AudioDecoder(*static_cast(_inputStream)); + AudioDecoder* inputAudio = new AudioDecoder(*static_cast(&inputStream)); inputAudio->setupDecoder(); - _inputDecoder = inputAudio; - _currentDecoder = _inputDecoder; + _inputDecoders.push_back(inputAudio); + _currentDecoder = inputAudio; // output encoder AudioEncoder* outputAudio = new AudioEncoder(profile.at(constants::avProfileCodec)); _outputEncoder = outputAudio; - AudioFrameDesc outputFrameDesc(_inputStream->getAudioCodec().getAudioFrameDesc()); + AudioFrameDesc outputFrameDesc(_currentInputStream->getAudioCodec().getAudioFrameDesc()); outputFrameDesc.setParameters(profile); - if(_inputStreamDesc.demultiplexing()) - outputFrameDesc._nbChannels = _inputStreamDesc._channelIndexArray.size(); + if(inputStreamDesc.demultiplexing()) + outputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); outputAudio->setupAudioEncoder(outputFrameDesc, profile); // output stream _outputStream = &outputFile.addAudioStream(outputAudio->getAudioCodec()); // buffers to process - AudioFrameDesc inputFrameDesc(_inputStream->getAudioCodec().getAudioFrameDesc()); - if(_inputStreamDesc.demultiplexing()) - inputFrameDesc._nbChannels = _inputStreamDesc._channelIndexArray.size(); + AudioFrameDesc inputFrameDesc(_currentInputStream->getAudioCodec().getAudioFrameDesc()); + if(inputStreamDesc.demultiplexing()) + inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); - _sourceBuffer = new AudioFrame(inputFrameDesc); - _frameBuffer = new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc()); + _sourceBuffers.push_back(new AudioFrame(inputFrameDesc)); + _frameBuffers.push_back(new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc())); // transform _transform = new AudioTransform(); // generator decoder - _generator = new AudioGenerator(outputFrameDesc); + _generators.push_back(new AudioGenerator(outputFrameDesc)); break; } @@ -223,17 +230,18 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu } StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader::Profile& profile) - : _inputStream(NULL) + : _inputStreamDesc() + , _inputStreams() + , _currentInputStream(NULL) , _outputStream(NULL) - , _sourceBuffer(NULL) - , _frameBuffer(NULL) - , _inputDecoder(NULL) - , _generator(NULL) + , _sourceBuffers() + , _frameBuffers() + , _inputDecoders() + , _generators() , _currentDecoder(NULL) , _outputEncoder(NULL) , _transform(NULL) , _filterGraph(NULL) - , _inputStreamDesc() , _offset(0) , _needToSwitchToGenerator(false) { @@ -245,8 +253,9 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: inputVideoCodec.setImageParameters(inputFrameDesc); // generator decoder - _generator = new VideoGenerator(inputVideoCodec.getVideoFrameDesc()); - _currentDecoder = _generator; + VideoGenerator* generator = new VideoGenerator(inputVideoCodec.getVideoFrameDesc()); + _generators.push_back(generator); + _currentDecoder = generator; // filter _filterGraph = new FilterGraph(inputVideoCodec); @@ -254,8 +263,8 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: // buffers to process VideoFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); - _sourceBuffer = new VideoFrame(inputFrameDesc); - _frameBuffer = new VideoFrame(outputFrameDesc); + _sourceBuffers.push_back(new VideoFrame(inputFrameDesc)); + _frameBuffers.push_back(new VideoFrame(outputFrameDesc)); // transform _transform = new VideoTransform(); @@ -276,8 +285,9 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: inputAudioCodec.setAudioParameters(inputFrameDesc); // generator decoder - _generator = new AudioGenerator(inputAudioCodec.getAudioFrameDesc()); - _currentDecoder = _generator; + AudioGenerator* generator = new AudioGenerator(inputAudioCodec.getAudioFrameDesc()); + _generators.push_back(generator); + _currentDecoder = generator; // filter _filterGraph = new FilterGraph(inputAudioCodec); @@ -285,8 +295,8 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: // buffers to process AudioFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); - _sourceBuffer = new AudioFrame(inputFrameDesc); - _frameBuffer = new AudioFrame(outputFrameDesc); + _sourceBuffers.push_back(new AudioFrame(inputFrameDesc)); + _frameBuffers.push_back(new AudioFrame(outputFrameDesc)); // transform _transform = new AudioTransform(); @@ -307,13 +317,27 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: StreamTranscoder::~StreamTranscoder() { - delete _sourceBuffer; - delete _frameBuffer; - delete _generator; + for(std::vector::iterator it = _sourceBuffers.begin(); it != _sourceBuffers.end(); ++it) + { + delete(*it); + } + for(std::vector::iterator it = _frameBuffers.begin(); it != _frameBuffers.end(); ++it) + { + delete(*it); + } + + for(std::vector::iterator it = _inputDecoders.begin(); it != _inputDecoders.end(); ++it) + { + delete(*it); + } + for(std::vector::iterator it = _generators.begin(); it != _generators.end(); ++it) + { + delete(*it); + } + delete _outputEncoder; delete _transform; delete _filterGraph; - delete _inputDecoder; } void StreamTranscoder::preProcessCodecLatency() @@ -325,7 +349,7 @@ void StreamTranscoder::preProcessCodecLatency() if(getProcessCase() == eProcessCaseGenerator) msg << "generator"; else - msg << _inputStream->getStreamIndex(); + msg << _currentInputStream->getStreamIndex(); msg << ": will not preProcessCodecLatency."; LOG_WARN(msg.str()) return; @@ -380,7 +404,7 @@ bool StreamTranscoder::processFrame() { LOG_INFO("End of positive offset") - if(_inputDecoder) + if(_inputDecoders.at(0)) switchToInputDecoder(); else _currentDecoder = NULL; @@ -389,14 +413,14 @@ bool StreamTranscoder::processFrame() else { // process generator - if(_currentDecoder != _generator) + if(_currentDecoder != _generators.at(0)) switchToGeneratorDecoder(); } } else if(_offset < 0) { const bool endOfStream = - _outputStream->getStreamDuration() >= (_inputStream->getProperties().getDuration() + _offset); + _outputStream->getStreamDuration() >= (_currentInputStream->getProperties().getDuration() + _offset); if(endOfStream) { LOG_INFO("End of negative offset") @@ -414,20 +438,13 @@ bool StreamTranscoder::processFrame() bool StreamTranscoder::processRewrap() { - assert(_inputStream != NULL); + assert(_inputStreams.size() != 1); assert(_outputStream != NULL); - assert(_inputDecoder == NULL); LOG_DEBUG("StreamTranscoder::processRewrap") - // if switched to generator, process frame - if(_currentDecoder && _currentDecoder == _generator) - { - return processTranscode(); - } - CodedData data; - if(!_inputStream->readNextPacket(data)) + if(!_currentInputStream->readNextPacket(data)) { if(_needToSwitchToGenerator) { @@ -457,30 +474,30 @@ bool StreamTranscoder::processTranscode() assert(_outputStream != NULL); assert(_currentDecoder != NULL); assert(_outputEncoder != NULL); - assert(_sourceBuffer != NULL); - assert(_frameBuffer != NULL); + assert(! _sourceBuffers.empty()); + assert(! _frameBuffers.empty()); assert(_transform != NULL); LOG_DEBUG("StreamTranscoder::processTranscode") LOG_DEBUG("Decode next frame") bool decodingStatus = false; - if(_inputStreamDesc.demultiplexing()) - decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffer, _inputStreamDesc._channelIndexArray); + if(! _inputStreamDesc.empty() && _inputStreamDesc.at(0).demultiplexing()) + decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffers.at(0), _inputStreamDesc.at(0)._channelIndexArray); else - decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffer); + decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffers.at(0)); CodedData data; if(decodingStatus) { LOG_DEBUG("Filtering") - _filterGraph->process(*_sourceBuffer); + _filterGraph->process(*_sourceBuffers.at(0)); LOG_DEBUG("Convert") - _transform->convert(*_sourceBuffer, *_frameBuffer); + _transform->convert(*_sourceBuffers.at(0), *_frameBuffers.at(0)); LOG_DEBUG("Encode") - _outputEncoder->encodeFrame(*_frameBuffer, data); + _outputEncoder->encodeFrame(*_frameBuffers.at(0), data); } else { @@ -516,7 +533,7 @@ void StreamTranscoder::switchToGeneratorDecoder() { LOG_INFO("Switch to generator decoder") - _currentDecoder = _generator; + _currentDecoder = _generators.at(0); assert(_currentDecoder != NULL); } @@ -524,15 +541,15 @@ void StreamTranscoder::switchToInputDecoder() { LOG_INFO("Switch to input decoder") - _currentDecoder = _inputDecoder; + _currentDecoder = _inputDecoders.at(0); assert(_currentDecoder != NULL); } float StreamTranscoder::getDuration() const { - if(_inputStream) + if(! _inputStreams.empty()) { - const StreamProperties& streamProperties = _inputStream->getProperties(); + const StreamProperties& streamProperties = _currentInputStream->getProperties(); const float totalDuration = streamProperties.getDuration() + _offset; if(totalDuration < 0) { @@ -549,7 +566,7 @@ float StreamTranscoder::getDuration() const bool StreamTranscoder::canSwitchToGenerator() { - if(_sourceBuffer && _frameBuffer && _generator && _outputEncoder && _transform) + if(! _sourceBuffers.empty() && ! _frameBuffers.empty() && ! _generators.empty() && _outputEncoder && _transform) return true; return false; } @@ -559,7 +576,7 @@ void StreamTranscoder::needToSwitchToGenerator(const bool needToSwitch) if(needToSwitch && !canSwitchToGenerator()) { std::stringstream os; - os << "The stream at index " << _inputStream->getStreamIndex() << " has a duration of " << getDuration() << "s."; + os << "The stream at index " << _currentInputStream->getStreamIndex() << " has a duration of " << getDuration() << "s."; os << " It needs to switch to a generator during the process, but it cannot. "; throw std::runtime_error(os.str()); } @@ -575,9 +592,9 @@ void StreamTranscoder::setOffset(const float offset) StreamTranscoder::EProcessCase StreamTranscoder::getProcessCase() const { - if(_inputStream && _inputDecoder && _currentDecoder == _inputDecoder) + if(! _inputStreams.empty() && ! _inputDecoders.empty() && _inputDecoders.at(0) == _currentDecoder) return eProcessCaseTranscode; - else if(_inputStream && !_inputDecoder && !_currentDecoder) + else if(! _inputStreams.empty() && _inputDecoders.empty() && !_currentDecoder) return eProcessCaseRewrap; else return eProcessCaseGenerator; diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index bfc1fad3..caaea914 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -83,7 +83,7 @@ class AvExport StreamTranscoder FilterGraph* getFilterGraph() const { return _filterGraph; } /// Returns a pointer to the stream which unwraps data - IInputStream* getInputStream() const { return _inputStream; } + IInputStream* getCurrentInputStream() const { return _currentInputStream; } /// Returns a reference to the stream which wraps data IOutputStream& getOutputStream() const { return *_outputStream; } @@ -122,14 +122,16 @@ class AvExport StreamTranscoder bool processTranscode(); private: - IInputStream* _inputStream; ///< Input stream to read next packet (has link, no ownership) + std::vector _inputStreamDesc; ///< Description of the data to extract from the input stream. + std::vector _inputStreams; ///< List of input stream to read next packet (has link, no ownership) + IInputStream* _currentInputStream; ///< Current input stream (has link, no ownership) IOutputStream* _outputStream; ///< Output stream to wrap next packet (has link, no ownership) - Frame* _sourceBuffer; ///< Has ownership - Frame* _frameBuffer; ///< Has ownership + std::vector _sourceBuffers; ///< Buffer of decoded data (has ownership). + std::vector _frameBuffers; ///< Buffer if transformed data (has ownership). - IDecoder* _inputDecoder; ///< Decoder of packets read from _inputStream (has ownership) - IDecoder* _generator; ///< Generator of audio or video packets (has ownership) + std::vector _inputDecoders; ///< Decoders of packets read from _inputStream (has ownership) + std::vector _generators; ///< Generators of audio or video packets (has ownership) IDecoder* _currentDecoder; ///< Link to _inputDecoder or _generator IEncoder* _outputEncoder; ///< Encoder of packets which will be wrapped by _outputStream (has ownership) @@ -137,8 +139,6 @@ class AvExport StreamTranscoder FilterGraph* _filterGraph; ///< Filter graph (has ownership) - const InputStreamDesc _inputStreamDesc; ///< Description of the data to extract from the input stream. - float _offset; ///< Offset, in seconds, at the beginning of the StreamTranscoder. bool _needToSwitchToGenerator; ///< Set if need to switch to a generator during the process (because, of other streams diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 4e734f0a..9ef555e4 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -463,7 +463,7 @@ void Transcoder::fillProcessStat(ProcessStat& processStat) for(size_t streamIndex = 0; streamIndex < _streamTranscoders.size(); ++streamIndex) { IOutputStream& stream = _streamTranscoders.at(streamIndex)->getOutputStream(); - const IInputStream* inputStream = _streamTranscoders.at(streamIndex)->getInputStream(); + const IInputStream* inputStream = _streamTranscoders.at(streamIndex)->getCurrentInputStream(); if(inputStream == NULL) { LOG_WARN("Cannot process statistics of generated stream.") From 18dcdc47b8981dc844f825a7e6e0e3e8ec57def7 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 19 Jul 2016 16:00:24 +0200 Subject: [PATCH 02/43] FilterGraph: updated process method to specify input/output The buffer could be different. --- src/AvTranscoder/filter/FilterGraph.cpp | 14 +++++++------- src/AvTranscoder/filter/FilterGraph.hpp | 7 ++++--- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/AvTranscoder/filter/FilterGraph.cpp b/src/AvTranscoder/filter/FilterGraph.cpp index 8cd40d5d..cae28bf7 100644 --- a/src/AvTranscoder/filter/FilterGraph.cpp +++ b/src/AvTranscoder/filter/FilterGraph.cpp @@ -35,7 +35,7 @@ FilterGraph::~FilterGraph() avfilter_graph_free(&_graph); } -void FilterGraph::process(Frame& frame) +void FilterGraph::process(const Frame& inputFrame, Frame& outputFrame) { if(!hasFilters()) { @@ -45,10 +45,10 @@ void FilterGraph::process(Frame& frame) // init filter graph if(!_isInit) - init(frame); + init(inputFrame, outputFrame); // setup source frame - int ret = av_buffersrc_write_frame(_filters.at(0)->getAVFilterContext(), &frame.getAVFrame()); + int ret = av_buffersrc_write_frame(_filters.at(0)->getAVFilterContext(), &inputFrame.getAVFrame()); if(ret < 0) { throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " + @@ -58,7 +58,7 @@ void FilterGraph::process(Frame& frame) // pull filtered data from the filter graph for(;;) { - ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &frame.getAVFrame()); + ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &outputFrame.getAVFrame()); if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) break; if(ret < 0) @@ -77,15 +77,15 @@ Filter& FilterGraph::addFilter(const std::string& filterName, const std::string& return *_filters.back(); } -void FilterGraph::init(const Frame& frame) +void FilterGraph::init(const Frame& inputFrame, Frame& outputFrame) { // push filters to the graph - pushInBuffer(frame); + pushInBuffer(inputFrame); for(size_t i = 1; i < _filters.size(); ++i) { pushFilter(*_filters.at(i)); } - pushOutBuffer(frame); + pushOutBuffer(outputFrame); // connect filters for(size_t index = 0; index < _filters.size() - 1; ++index) diff --git a/src/AvTranscoder/filter/FilterGraph.hpp b/src/AvTranscoder/filter/FilterGraph.hpp index bd42f979..ced3206a 100644 --- a/src/AvTranscoder/filter/FilterGraph.hpp +++ b/src/AvTranscoder/filter/FilterGraph.hpp @@ -44,10 +44,11 @@ class AvExport FilterGraph /** * @brief Pull filtered data from the filter graph, and put result to the given frame. - * @param frame: both input and output data of the method. + * @param inputFrame: input data. + * @param inputFrame: output data. * @note Do nothing if there was no filter added. */ - void process(Frame& frame); + void process(const Frame& inputFrame, Frame& outputFrame); private: /** @@ -61,7 +62,7 @@ class AvExport FilterGraph * @see pushInBuffer * @see pushOutBuffer */ - void init(const Frame& frame); + void init(const Frame& inputFrame, Frame& outputFrame); /** * @brief Push the given Filter to the graph. diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index cadc9850..a0b1843c 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -491,7 +491,7 @@ bool StreamTranscoder::processTranscode() if(decodingStatus) { LOG_DEBUG("Filtering") - _filterGraph->process(*_sourceBuffers.at(0)); + _filterGraph->process(*_sourceBuffers.at(0), *_sourceBuffers.at(0)); LOG_DEBUG("Convert") _transform->convert(*_sourceBuffers.at(0), *_frameBuffers.at(0)); From 732791adb1bc8b67f9ec99e119cc0836d97ed749 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 19 Jul 2016 16:55:00 +0200 Subject: [PATCH 03/43] FilterGraph: updated process method to manage several input buffers --- src/AvTranscoder/filter/FilterGraph.cpp | 109 ++++++++++-------- src/AvTranscoder/filter/FilterGraph.hpp | 21 ++-- .../transcoder/StreamTranscoder.cpp | 2 +- 3 files changed, 74 insertions(+), 58 deletions(-) diff --git a/src/AvTranscoder/filter/FilterGraph.cpp b/src/AvTranscoder/filter/FilterGraph.cpp index cae28bf7..9b159322 100644 --- a/src/AvTranscoder/filter/FilterGraph.cpp +++ b/src/AvTranscoder/filter/FilterGraph.cpp @@ -35,7 +35,7 @@ FilterGraph::~FilterGraph() avfilter_graph_free(&_graph); } -void FilterGraph::process(const Frame& inputFrame, Frame& outputFrame) +void FilterGraph::process(const std::vector& inputs, Frame& output) { if(!hasFilters()) { @@ -45,20 +45,23 @@ void FilterGraph::process(const Frame& inputFrame, Frame& outputFrame) // init filter graph if(!_isInit) - init(inputFrame, outputFrame); + init(inputs, output); - // setup source frame - int ret = av_buffersrc_write_frame(_filters.at(0)->getAVFilterContext(), &inputFrame.getAVFrame()); - if(ret < 0) + // setup input frames + for(size_t index = 0; index < inputs.size(); ++index) { - throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " + - getDescriptionFromErrorCode(ret)); + const int ret = av_buffersrc_write_frame(_filters.at(index)->getAVFilterContext(), &inputs.at(index)->getAVFrame()); + if(ret < 0) + { + throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " + + getDescriptionFromErrorCode(ret)); + } } // pull filtered data from the filter graph for(;;) { - ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &outputFrame.getAVFrame()); + const int ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &output.getAVFrame()); if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) break; if(ret < 0) @@ -77,22 +80,27 @@ Filter& FilterGraph::addFilter(const std::string& filterName, const std::string& return *_filters.back(); } -void FilterGraph::init(const Frame& inputFrame, Frame& outputFrame) +void FilterGraph::init(const std::vector& inputs, Frame& output) { // push filters to the graph - pushInBuffer(inputFrame); + pushInBuffer(inputs); for(size_t i = 1; i < _filters.size(); ++i) { pushFilter(*_filters.at(i)); } - pushOutBuffer(outputFrame); + pushOutBuffer(output); // connect filters for(size_t index = 0; index < _filters.size() - 1; ++index) { - LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(index + 1)->getName()) + size_t indexOfFilterToConnect = index + 1; + // handle cases with several inputs + if(index < inputs.size()) + indexOfFilterToConnect = inputs.size(); + + LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(indexOfFilterToConnect)->getName()) const int err = - avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(index + 1)->getAVFilterContext(), 0); + avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(indexOfFilterToConnect)->getAVFilterContext(), 0); if(err < 0) { throw std::runtime_error("Error when connecting filters."); @@ -128,51 +136,54 @@ void FilterGraph::pushFilter(Filter& filter) } } -void FilterGraph::pushInBuffer(const Frame& frame) +void FilterGraph::pushInBuffer(const std::vector& inputs) { - std::string filterName; - std::stringstream filterOptions; - // audio frame - if(frame.isAudioFrame()) - { - filterName = "abuffer"; - const AudioFrame& audioFrame = dynamic_cast(frame); - filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" - << _codec.getAVCodecContext().time_base.den << ":"; - filterOptions << "sample_rate=" << audioFrame.getSampleRate() << ":"; - filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame.getSampleFormat()) << ":"; - filterOptions << "channel_layout=0x" << std::hex << audioFrame.getChannelLayout(); - } - // video frame - else if(frame.isVideoFrame()) + for(std::vector::const_iterator it = inputs.begin(); it != inputs.end(); ++it) { - filterName = "buffer"; - const VideoFrame& videoFrame = dynamic_cast(frame); - filterOptions << "video_size=" << videoFrame.getWidth() << "x" << videoFrame.getHeight() << ":"; - filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame.getPixelFormat()) << ":"; - filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" - << _codec.getAVCodecContext().time_base.den << ":"; - filterOptions << "pixel_aspect=" << _codec.getAVCodecContext().sample_aspect_ratio.num << "/" - << _codec.getAVCodecContext().sample_aspect_ratio.den; + std::string filterName; + std::stringstream filterOptions; + // audio frame + if((*it)->isAudioFrame()) + { + filterName = "abuffer"; + const AudioFrame* audioFrame = dynamic_cast(*it); + filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" + << _codec.getAVCodecContext().time_base.den << ":"; + filterOptions << "sample_rate=" << audioFrame->getSampleRate() << ":"; + filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame->getSampleFormat()) << ":"; + filterOptions << "channel_layout=0x" << std::hex << audioFrame->getChannelLayout(); + } + // video frame + else if((*it)->isVideoFrame()) + { + filterName = "buffer"; + const VideoFrame* videoFrame = dynamic_cast(*it); + filterOptions << "video_size=" << videoFrame->getWidth() << "x" << videoFrame->getHeight() << ":"; + filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame->getPixelFormat()) << ":"; + filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" + << _codec.getAVCodecContext().time_base.den << ":"; + filterOptions << "pixel_aspect=" << _codec.getAVCodecContext().sample_aspect_ratio.num << "/" + << _codec.getAVCodecContext().sample_aspect_ratio.den; + } + // invalid frame + else + throw std::runtime_error("Cannot create input buffer of filter graph: the given frame is invalid."); + + // add in buffer + Filter* in = new Filter(filterName, filterOptions.str(), "in"); + LOG_INFO("Add filter '" << filterName << "' at the beginning of the graph.") + _filters.insert(_filters.begin(), in); + pushFilter(*in); } - // invalid frame - else - throw std::runtime_error("Cannot create input buffer of filter graph: the given frame is invalid."); - - // add in buffer - Filter* in = new Filter(filterName, filterOptions.str(), "in"); - LOG_INFO("Add filter '" << filterName << "' at the beginning of the graph.") - _filters.insert(_filters.begin(), in); - pushFilter(*in); } -void FilterGraph::pushOutBuffer(const Frame& frame) +void FilterGraph::pushOutBuffer(const Frame& output) { std::string filterName; - if(frame.isAudioFrame()) + if(output.isAudioFrame()) filterName = "abuffersink"; - else if(frame.isVideoFrame()) + else if(output.isVideoFrame()) filterName = "buffersink"; else throw std::runtime_error("Cannot create output buffer of filter graph: the given frame is invalid."); diff --git a/src/AvTranscoder/filter/FilterGraph.hpp b/src/AvTranscoder/filter/FilterGraph.hpp index ced3206a..747e8634 100644 --- a/src/AvTranscoder/filter/FilterGraph.hpp +++ b/src/AvTranscoder/filter/FilterGraph.hpp @@ -15,8 +15,6 @@ namespace avtranscoder /** * @brief Manager of filters. - * @warning Currently, the class manages only filters which has one input and one output. - * @note See 'complex graph' definition in ffmpeg documentation. **/ class AvExport FilterGraph { @@ -44,11 +42,18 @@ class AvExport FilterGraph /** * @brief Pull filtered data from the filter graph, and put result to the given frame. - * @param inputFrame: input data. - * @param inputFrame: output data. + * @param inputs: input data buffers. + * @param output: output data buffer. * @note Do nothing if there was no filter added. + * If there is one input buffer, the filter graph is a chain of effects: input -> filter 1 -> filter 2 -> output. + * If there is several input buffers, the filter graph is like this: + * input 1 ---| + * | + * filter 1 -> filter 2 -> output + * | + * input 2 ---| */ - void process(const Frame& inputFrame, Frame& outputFrame); + void process(const std::vector& inputs, Frame& output); private: /** @@ -62,7 +67,7 @@ class AvExport FilterGraph * @see pushInBuffer * @see pushOutBuffer */ - void init(const Frame& inputFrame, Frame& outputFrame); + void init(const std::vector& inputs, Frame& output); /** * @brief Push the given Filter to the graph. @@ -71,8 +76,8 @@ class AvExport FilterGraph ///@{ /// @brief Push the input and output buffer at the beginning and the end of the graph. - void pushInBuffer(const Frame& frame); - void pushOutBuffer(const Frame& frame); + void pushInBuffer(const std::vector& inputs); + void pushOutBuffer(const Frame& output); //@} private: diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index a0b1843c..d1284901 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -491,7 +491,7 @@ bool StreamTranscoder::processTranscode() if(decodingStatus) { LOG_DEBUG("Filtering") - _filterGraph->process(*_sourceBuffers.at(0), *_sourceBuffers.at(0)); + _filterGraph->process(_sourceBuffers, *_sourceBuffers.at(0)); LOG_DEBUG("Convert") _transform->convert(*_sourceBuffers.at(0), *_frameBuffers.at(0)); From 356c166175b6d7a7a0a9ed0f30aef8a5143b7e76 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 19 Jul 2016 17:16:13 +0200 Subject: [PATCH 04/43] StreamTranscoder: renamed Frame buffer attributes * _sourceBuffers to _decodedData. * _frameBuffers to _convertedData. --- .../transcoder/StreamTranscoder.cpp | 56 +++++++++---------- .../transcoder/StreamTranscoder.hpp | 4 +- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index d1284901..c2ec949d 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -24,8 +24,8 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu , _inputStreams() , _currentInputStream(&inputStream) , _outputStream(NULL) - , _sourceBuffers() - , _frameBuffers() + , _decodedData() + , _transformedData() , _inputDecoders() , _generators() , _currentDecoder(NULL) @@ -56,8 +56,8 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _generators.push_back(new VideoGenerator(inputFrameDesc)); // buffers to process - _sourceBuffers.push_back(new VideoFrame(inputFrameDesc)); - _frameBuffers.push_back(new VideoFrame(inputFrameDesc)); + _decodedData.push_back(new VideoFrame(inputFrameDesc)); + _transformedData.push_back(new VideoFrame(inputFrameDesc)); // transform _transform = new VideoTransform(); @@ -91,8 +91,8 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _generators.push_back(new AudioGenerator(inputFrameDesc)); // buffers to process - _sourceBuffers.push_back(new AudioFrame(inputFrameDesc)); - _frameBuffers.push_back(new AudioFrame(inputFrameDesc)); + _decodedData.push_back(new AudioFrame(inputFrameDesc)); + _transformedData.push_back(new AudioFrame(inputFrameDesc)); // transform _transform = new AudioTransform(); @@ -129,8 +129,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu , _inputStreams() , _currentInputStream(&inputStream) , _outputStream(NULL) - , _sourceBuffers() - , _frameBuffers() + , _decodedData() + , _transformedData() , _inputDecoders() , _generators() , _currentDecoder(NULL) @@ -169,8 +169,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec()); // buffers to process - _sourceBuffers.push_back(new VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); - _frameBuffers.push_back(new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc())); + _decodedData.push_back(new VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); + _transformedData.push_back(new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc())); // transform _transform = new VideoTransform(); @@ -209,8 +209,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu if(inputStreamDesc.demultiplexing()) inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); - _sourceBuffers.push_back(new AudioFrame(inputFrameDesc)); - _frameBuffers.push_back(new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc())); + _decodedData.push_back(new AudioFrame(inputFrameDesc)); + _transformedData.push_back(new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc())); // transform _transform = new AudioTransform(); @@ -234,8 +234,8 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: , _inputStreams() , _currentInputStream(NULL) , _outputStream(NULL) - , _sourceBuffers() - , _frameBuffers() + , _decodedData() + , _transformedData() , _inputDecoders() , _generators() , _currentDecoder(NULL) @@ -263,8 +263,8 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: // buffers to process VideoFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); - _sourceBuffers.push_back(new VideoFrame(inputFrameDesc)); - _frameBuffers.push_back(new VideoFrame(outputFrameDesc)); + _decodedData.push_back(new VideoFrame(inputFrameDesc)); + _transformedData.push_back(new VideoFrame(outputFrameDesc)); // transform _transform = new VideoTransform(); @@ -295,8 +295,8 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: // buffers to process AudioFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); - _sourceBuffers.push_back(new AudioFrame(inputFrameDesc)); - _frameBuffers.push_back(new AudioFrame(outputFrameDesc)); + _decodedData.push_back(new AudioFrame(inputFrameDesc)); + _transformedData.push_back(new AudioFrame(outputFrameDesc)); // transform _transform = new AudioTransform(); @@ -317,11 +317,11 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: StreamTranscoder::~StreamTranscoder() { - for(std::vector::iterator it = _sourceBuffers.begin(); it != _sourceBuffers.end(); ++it) + for(std::vector::iterator it = _decodedData.begin(); it != _decodedData.end(); ++it) { delete(*it); } - for(std::vector::iterator it = _frameBuffers.begin(); it != _frameBuffers.end(); ++it) + for(std::vector::iterator it = _transformedData.begin(); it != _transformedData.end(); ++it) { delete(*it); } @@ -474,8 +474,8 @@ bool StreamTranscoder::processTranscode() assert(_outputStream != NULL); assert(_currentDecoder != NULL); assert(_outputEncoder != NULL); - assert(! _sourceBuffers.empty()); - assert(! _frameBuffers.empty()); + assert(! _decodedData.empty()); + assert(! _transformedData.empty()); assert(_transform != NULL); LOG_DEBUG("StreamTranscoder::processTranscode") @@ -483,21 +483,21 @@ bool StreamTranscoder::processTranscode() LOG_DEBUG("Decode next frame") bool decodingStatus = false; if(! _inputStreamDesc.empty() && _inputStreamDesc.at(0).demultiplexing()) - decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffers.at(0), _inputStreamDesc.at(0)._channelIndexArray); + decodingStatus = _currentDecoder->decodeNextFrame(*_decodedData.at(0), _inputStreamDesc.at(0)._channelIndexArray); else - decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffers.at(0)); + decodingStatus = _currentDecoder->decodeNextFrame(*_decodedData.at(0)); CodedData data; if(decodingStatus) { LOG_DEBUG("Filtering") - _filterGraph->process(_sourceBuffers, *_sourceBuffers.at(0)); + _filterGraph->process(_decodedData, *_decodedData.at(0)); LOG_DEBUG("Convert") - _transform->convert(*_sourceBuffers.at(0), *_frameBuffers.at(0)); + _transform->convert(*_decodedData.at(0), *_transformedData.at(0)); LOG_DEBUG("Encode") - _outputEncoder->encodeFrame(*_frameBuffers.at(0), data); + _outputEncoder->encodeFrame(*_transformedData.at(0), data); } else { @@ -566,7 +566,7 @@ float StreamTranscoder::getDuration() const bool StreamTranscoder::canSwitchToGenerator() { - if(! _sourceBuffers.empty() && ! _frameBuffers.empty() && ! _generators.empty() && _outputEncoder && _transform) + if(! _decodedData.empty() && ! _transformedData.empty() && ! _generators.empty() && _outputEncoder && _transform) return true; return false; } diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index caaea914..2cb9cb87 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -127,8 +127,8 @@ class AvExport StreamTranscoder IInputStream* _currentInputStream; ///< Current input stream (has link, no ownership) IOutputStream* _outputStream; ///< Output stream to wrap next packet (has link, no ownership) - std::vector _sourceBuffers; ///< Buffer of decoded data (has ownership). - std::vector _frameBuffers; ///< Buffer if transformed data (has ownership). + std::vector _decodedData; ///< Buffer of decoded data (has ownership). + std::vector _transformedData; ///< Buffer of transformed data (has ownership). std::vector _inputDecoders; ///< Decoders of packets read from _inputStream (has ownership) std::vector _generators; ///< Generators of audio or video packets (has ownership) From 9341a4c583a33a51160e5254e7438c4c48aac913 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 19 Jul 2016 17:28:34 +0200 Subject: [PATCH 05/43] StreamTranscoder: added _filteredData attribute To have a buffer of filtered data. --- src/AvTranscoder/filter/FilterGraph.cpp | 3 ++- src/AvTranscoder/filter/FilterGraph.hpp | 2 +- .../transcoder/StreamTranscoder.cpp | 18 ++++++++++++++++-- .../transcoder/StreamTranscoder.hpp | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/AvTranscoder/filter/FilterGraph.cpp b/src/AvTranscoder/filter/FilterGraph.cpp index 9b159322..ac4c0076 100644 --- a/src/AvTranscoder/filter/FilterGraph.cpp +++ b/src/AvTranscoder/filter/FilterGraph.cpp @@ -39,7 +39,8 @@ void FilterGraph::process(const std::vector& inputs, Frame& output) { if(!hasFilters()) { - LOG_DEBUG("No filter to process.") + LOG_DEBUG("No filter to process: reference first input frame to the given output.") + output.refFrame(*inputs.at(0)); return; } diff --git a/src/AvTranscoder/filter/FilterGraph.hpp b/src/AvTranscoder/filter/FilterGraph.hpp index 747e8634..37c03570 100644 --- a/src/AvTranscoder/filter/FilterGraph.hpp +++ b/src/AvTranscoder/filter/FilterGraph.hpp @@ -42,7 +42,7 @@ class AvExport FilterGraph /** * @brief Pull filtered data from the filter graph, and put result to the given frame. - * @param inputs: input data buffers. + * @param inputs: input data buffers (at least one). * @param output: output data buffer. * @note Do nothing if there was no filter added. * If there is one input buffer, the filter graph is a chain of effects: input -> filter 1 -> filter 2 -> output. diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index c2ec949d..2fcdd0b1 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -25,6 +25,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu , _currentInputStream(&inputStream) , _outputStream(NULL) , _decodedData() + , _filteredData() , _transformedData() , _inputDecoders() , _generators() @@ -57,6 +58,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu // buffers to process _decodedData.push_back(new VideoFrame(inputFrameDesc)); + _filteredData.push_back(new VideoFrame(inputFrameDesc)); _transformedData.push_back(new VideoFrame(inputFrameDesc)); // transform @@ -92,6 +94,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu // buffers to process _decodedData.push_back(new AudioFrame(inputFrameDesc)); + _filteredData.push_back(new AudioFrame(inputFrameDesc)); _transformedData.push_back(new AudioFrame(inputFrameDesc)); // transform @@ -130,6 +133,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu , _currentInputStream(&inputStream) , _outputStream(NULL) , _decodedData() + , _filteredData() , _transformedData() , _inputDecoders() , _generators() @@ -170,6 +174,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu // buffers to process _decodedData.push_back(new VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); + _filteredData.push_back(new VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); _transformedData.push_back(new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc())); // transform @@ -210,6 +215,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); _decodedData.push_back(new AudioFrame(inputFrameDesc)); + _filteredData.push_back(new AudioFrame(inputFrameDesc)); _transformedData.push_back(new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc())); // transform @@ -235,6 +241,7 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: , _currentInputStream(NULL) , _outputStream(NULL) , _decodedData() + , _filteredData() , _transformedData() , _inputDecoders() , _generators() @@ -264,6 +271,7 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: VideoFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); _decodedData.push_back(new VideoFrame(inputFrameDesc)); + _filteredData.push_back(new VideoFrame(inputFrameDesc)); _transformedData.push_back(new VideoFrame(outputFrameDesc)); // transform @@ -296,6 +304,7 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: AudioFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); _decodedData.push_back(new AudioFrame(inputFrameDesc)); + _filteredData.push_back(new AudioFrame(inputFrameDesc)); _transformedData.push_back(new AudioFrame(outputFrameDesc)); // transform @@ -321,6 +330,10 @@ StreamTranscoder::~StreamTranscoder() { delete(*it); } + for(std::vector::iterator it = _filteredData.begin(); it != _filteredData.end(); ++it) + { + delete(*it); + } for(std::vector::iterator it = _transformedData.begin(); it != _transformedData.end(); ++it) { delete(*it); @@ -475,6 +488,7 @@ bool StreamTranscoder::processTranscode() assert(_currentDecoder != NULL); assert(_outputEncoder != NULL); assert(! _decodedData.empty()); + assert(! _filteredData.empty()); assert(! _transformedData.empty()); assert(_transform != NULL); @@ -491,10 +505,10 @@ bool StreamTranscoder::processTranscode() if(decodingStatus) { LOG_DEBUG("Filtering") - _filterGraph->process(_decodedData, *_decodedData.at(0)); + _filterGraph->process(_decodedData, *_filteredData.at(0)); LOG_DEBUG("Convert") - _transform->convert(*_decodedData.at(0), *_transformedData.at(0)); + _transform->convert(*_filteredData.at(0), *_transformedData.at(0)); LOG_DEBUG("Encode") _outputEncoder->encodeFrame(*_transformedData.at(0), data); diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 2cb9cb87..8d07b973 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -128,6 +128,7 @@ class AvExport StreamTranscoder IOutputStream* _outputStream; ///< Output stream to wrap next packet (has link, no ownership) std::vector _decodedData; ///< Buffer of decoded data (has ownership). + std::vector _filteredData; ///< Buffer of filtered data (has ownership). std::vector _transformedData; ///< Buffer of transformed data (has ownership). std::vector _inputDecoders; ///< Decoders of packets read from _inputStream (has ownership) From ecfed3f918143692d26d75cd13225b721993b289 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 19 Jul 2016 17:30:17 +0200 Subject: [PATCH 06/43] StreamTranscoder: fixed processRewrap * In this case, '_inputStreams.size() == 1' is always true! * Anyway, we should check the '_currentInputStream' attribute because it is used in the method. --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 2fcdd0b1..5d4831fe 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -451,7 +451,7 @@ bool StreamTranscoder::processFrame() bool StreamTranscoder::processRewrap() { - assert(_inputStreams.size() != 1); + assert(_currentInputStream != NULL); assert(_outputStream != NULL); LOG_DEBUG("StreamTranscoder::processRewrap") From ecd3ddd9129b14eb38d2ca329fbab52d50dd8aec Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Tue, 19 Jul 2016 17:39:11 +0200 Subject: [PATCH 07/43] StreamTranscoder: updated buffer attributes * No pointers are needed here. * Updated FilterGraph parameters to launch a process. --- src/AvTranscoder/filter/FilterGraph.cpp | 30 +++++----- src/AvTranscoder/filter/FilterGraph.hpp | 6 +- .../transcoder/StreamTranscoder.cpp | 59 ++++++++----------- .../transcoder/StreamTranscoder.hpp | 6 +- 4 files changed, 44 insertions(+), 57 deletions(-) diff --git a/src/AvTranscoder/filter/FilterGraph.cpp b/src/AvTranscoder/filter/FilterGraph.cpp index ac4c0076..27d464e0 100644 --- a/src/AvTranscoder/filter/FilterGraph.cpp +++ b/src/AvTranscoder/filter/FilterGraph.cpp @@ -35,12 +35,12 @@ FilterGraph::~FilterGraph() avfilter_graph_free(&_graph); } -void FilterGraph::process(const std::vector& inputs, Frame& output) +void FilterGraph::process(const std::vector& inputs, Frame& output) { if(!hasFilters()) { LOG_DEBUG("No filter to process: reference first input frame to the given output.") - output.refFrame(*inputs.at(0)); + output.refFrame(inputs.at(0)); return; } @@ -51,7 +51,7 @@ void FilterGraph::process(const std::vector& inputs, Frame& output) // setup input frames for(size_t index = 0; index < inputs.size(); ++index) { - const int ret = av_buffersrc_write_frame(_filters.at(index)->getAVFilterContext(), &inputs.at(index)->getAVFrame()); + const int ret = av_buffersrc_write_frame(_filters.at(index)->getAVFilterContext(), &inputs.at(index).getAVFrame()); if(ret < 0) { throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " + @@ -81,7 +81,7 @@ Filter& FilterGraph::addFilter(const std::string& filterName, const std::string& return *_filters.back(); } -void FilterGraph::init(const std::vector& inputs, Frame& output) +void FilterGraph::init(const std::vector& inputs, Frame& output) { // push filters to the graph pushInBuffer(inputs); @@ -137,30 +137,30 @@ void FilterGraph::pushFilter(Filter& filter) } } -void FilterGraph::pushInBuffer(const std::vector& inputs) +void FilterGraph::pushInBuffer(const std::vector& inputs) { - for(std::vector::const_iterator it = inputs.begin(); it != inputs.end(); ++it) + for(std::vector::const_iterator it = inputs.begin(); it != inputs.end(); ++it) { std::string filterName; std::stringstream filterOptions; // audio frame - if((*it)->isAudioFrame()) + if(it->isAudioFrame()) { filterName = "abuffer"; - const AudioFrame* audioFrame = dynamic_cast(*it); + const AudioFrame& audioFrame = dynamic_cast(*it); filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" << _codec.getAVCodecContext().time_base.den << ":"; - filterOptions << "sample_rate=" << audioFrame->getSampleRate() << ":"; - filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame->getSampleFormat()) << ":"; - filterOptions << "channel_layout=0x" << std::hex << audioFrame->getChannelLayout(); + filterOptions << "sample_rate=" << audioFrame.getSampleRate() << ":"; + filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame.getSampleFormat()) << ":"; + filterOptions << "channel_layout=0x" << std::hex << audioFrame.getChannelLayout(); } // video frame - else if((*it)->isVideoFrame()) + else if(it->isVideoFrame()) { filterName = "buffer"; - const VideoFrame* videoFrame = dynamic_cast(*it); - filterOptions << "video_size=" << videoFrame->getWidth() << "x" << videoFrame->getHeight() << ":"; - filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame->getPixelFormat()) << ":"; + const VideoFrame& videoFrame = dynamic_cast(*it); + filterOptions << "video_size=" << videoFrame.getWidth() << "x" << videoFrame.getHeight() << ":"; + filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame.getPixelFormat()) << ":"; filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" << _codec.getAVCodecContext().time_base.den << ":"; filterOptions << "pixel_aspect=" << _codec.getAVCodecContext().sample_aspect_ratio.num << "/" diff --git a/src/AvTranscoder/filter/FilterGraph.hpp b/src/AvTranscoder/filter/FilterGraph.hpp index 37c03570..01edc619 100644 --- a/src/AvTranscoder/filter/FilterGraph.hpp +++ b/src/AvTranscoder/filter/FilterGraph.hpp @@ -53,7 +53,7 @@ class AvExport FilterGraph * | * input 2 ---| */ - void process(const std::vector& inputs, Frame& output); + void process(const std::vector& inputs, Frame& output); private: /** @@ -67,7 +67,7 @@ class AvExport FilterGraph * @see pushInBuffer * @see pushOutBuffer */ - void init(const std::vector& inputs, Frame& output); + void init(const std::vector& inputs, Frame& output); /** * @brief Push the given Filter to the graph. @@ -76,7 +76,7 @@ class AvExport FilterGraph ///@{ /// @brief Push the input and output buffer at the beginning and the end of the graph. - void pushInBuffer(const std::vector& inputs); + void pushInBuffer(const std::vector& inputs); void pushOutBuffer(const Frame& output); //@} diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 5d4831fe..1a8818e0 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -57,9 +57,9 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _generators.push_back(new VideoGenerator(inputFrameDesc)); // buffers to process - _decodedData.push_back(new VideoFrame(inputFrameDesc)); - _filteredData.push_back(new VideoFrame(inputFrameDesc)); - _transformedData.push_back(new VideoFrame(inputFrameDesc)); + _decodedData.push_back(VideoFrame(inputFrameDesc)); + _filteredData.push_back(VideoFrame(inputFrameDesc)); + _transformedData.push_back(VideoFrame(inputFrameDesc)); // transform _transform = new VideoTransform(); @@ -93,9 +93,9 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _generators.push_back(new AudioGenerator(inputFrameDesc)); // buffers to process - _decodedData.push_back(new AudioFrame(inputFrameDesc)); - _filteredData.push_back(new AudioFrame(inputFrameDesc)); - _transformedData.push_back(new AudioFrame(inputFrameDesc)); + _decodedData.push_back(AudioFrame(inputFrameDesc)); + _filteredData.push_back(AudioFrame(inputFrameDesc)); + _transformedData.push_back(AudioFrame(inputFrameDesc)); // transform _transform = new AudioTransform(); @@ -173,9 +173,9 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec()); // buffers to process - _decodedData.push_back(new VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); - _filteredData.push_back(new VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); - _transformedData.push_back(new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc())); + _decodedData.push_back(VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); + _filteredData.push_back(VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); + _transformedData.push_back(VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc())); // transform _transform = new VideoTransform(); @@ -214,9 +214,9 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu if(inputStreamDesc.demultiplexing()) inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); - _decodedData.push_back(new AudioFrame(inputFrameDesc)); - _filteredData.push_back(new AudioFrame(inputFrameDesc)); - _transformedData.push_back(new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc())); + _decodedData.push_back(AudioFrame(inputFrameDesc)); + _filteredData.push_back(AudioFrame(inputFrameDesc)); + _transformedData.push_back(AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc())); // transform _transform = new AudioTransform(); @@ -270,9 +270,9 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: // buffers to process VideoFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); - _decodedData.push_back(new VideoFrame(inputFrameDesc)); - _filteredData.push_back(new VideoFrame(inputFrameDesc)); - _transformedData.push_back(new VideoFrame(outputFrameDesc)); + _decodedData.push_back(VideoFrame(inputFrameDesc)); + _filteredData.push_back(VideoFrame(inputFrameDesc)); + _transformedData.push_back(VideoFrame(outputFrameDesc)); // transform _transform = new VideoTransform(); @@ -303,9 +303,9 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: // buffers to process AudioFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); - _decodedData.push_back(new AudioFrame(inputFrameDesc)); - _filteredData.push_back(new AudioFrame(inputFrameDesc)); - _transformedData.push_back(new AudioFrame(outputFrameDesc)); + _decodedData.push_back(AudioFrame(inputFrameDesc)); + _filteredData.push_back(AudioFrame(inputFrameDesc)); + _transformedData.push_back(AudioFrame(outputFrameDesc)); // transform _transform = new AudioTransform(); @@ -326,19 +326,6 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: StreamTranscoder::~StreamTranscoder() { - for(std::vector::iterator it = _decodedData.begin(); it != _decodedData.end(); ++it) - { - delete(*it); - } - for(std::vector::iterator it = _filteredData.begin(); it != _filteredData.end(); ++it) - { - delete(*it); - } - for(std::vector::iterator it = _transformedData.begin(); it != _transformedData.end(); ++it) - { - delete(*it); - } - for(std::vector::iterator it = _inputDecoders.begin(); it != _inputDecoders.end(); ++it) { delete(*it); @@ -497,21 +484,21 @@ bool StreamTranscoder::processTranscode() LOG_DEBUG("Decode next frame") bool decodingStatus = false; if(! _inputStreamDesc.empty() && _inputStreamDesc.at(0).demultiplexing()) - decodingStatus = _currentDecoder->decodeNextFrame(*_decodedData.at(0), _inputStreamDesc.at(0)._channelIndexArray); + decodingStatus = _currentDecoder->decodeNextFrame(_decodedData.at(0), _inputStreamDesc.at(0)._channelIndexArray); else - decodingStatus = _currentDecoder->decodeNextFrame(*_decodedData.at(0)); + decodingStatus = _currentDecoder->decodeNextFrame(_decodedData.at(0)); CodedData data; if(decodingStatus) { LOG_DEBUG("Filtering") - _filterGraph->process(_decodedData, *_filteredData.at(0)); + _filterGraph->process(_decodedData, _filteredData.at(0)); LOG_DEBUG("Convert") - _transform->convert(*_filteredData.at(0), *_transformedData.at(0)); + _transform->convert(_filteredData.at(0), _transformedData.at(0)); LOG_DEBUG("Encode") - _outputEncoder->encodeFrame(*_transformedData.at(0), data); + _outputEncoder->encodeFrame(_transformedData.at(0), data); } else { diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 8d07b973..1bddea60 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -127,9 +127,9 @@ class AvExport StreamTranscoder IInputStream* _currentInputStream; ///< Current input stream (has link, no ownership) IOutputStream* _outputStream; ///< Output stream to wrap next packet (has link, no ownership) - std::vector _decodedData; ///< Buffer of decoded data (has ownership). - std::vector _filteredData; ///< Buffer of filtered data (has ownership). - std::vector _transformedData; ///< Buffer of transformed data (has ownership). + std::vector _decodedData; ///< List of buffers of decoded data. + std::vector _filteredData; ///< Buffer of filtered data. + std::vector _transformedData; ///< Buffer of transformed data. std::vector _inputDecoders; ///< Decoders of packets read from _inputStream (has ownership) std::vector _generators; ///< Generators of audio or video packets (has ownership) From 8dbe2d647b553204cb7ca50c9a311904e136c8e9 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 09:13:41 +0200 Subject: [PATCH 08/43] StreamTranscoder: no need to handle vector of filtered and transformed data Need to define 'Frame::operator='. --- src/AvTranscoder/data/decoded/Frame.cpp | 9 +++++ src/AvTranscoder/data/decoded/Frame.hpp | 7 ++-- .../transcoder/StreamTranscoder.cpp | 34 +++++++++---------- .../transcoder/StreamTranscoder.hpp | 4 +-- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/AvTranscoder/data/decoded/Frame.cpp b/src/AvTranscoder/data/decoded/Frame.cpp index 655776c9..69b15ff4 100644 --- a/src/AvTranscoder/data/decoded/Frame.cpp +++ b/src/AvTranscoder/data/decoded/Frame.cpp @@ -23,6 +23,15 @@ Frame::Frame(const Frame& otherFrame) refFrame(otherFrame); } +void Frame::operator=(const Frame& otherFrame) +{ + // check if the frame could be a valid video/audio frame + if(otherFrame.getAVFrame().format == -1) + return; + // reference the other frame + refFrame(otherFrame); +} + Frame::~Frame() { if(_frame != NULL) diff --git a/src/AvTranscoder/data/decoded/Frame.hpp b/src/AvTranscoder/data/decoded/Frame.hpp index 482c92ff..780861a4 100644 --- a/src/AvTranscoder/data/decoded/Frame.hpp +++ b/src/AvTranscoder/data/decoded/Frame.hpp @@ -22,10 +22,11 @@ class AvExport Frame */ Frame(); - /** - * @brief Copy properties and reference data of the other frame - */ + //@{ + // @brief Copy properties and reference data of the other frame. Frame(const Frame& otherFrame); + void operator=(const Frame& otherFrame); + //@} virtual ~Frame(); diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 1a8818e0..6420a2b9 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -58,8 +58,8 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu // buffers to process _decodedData.push_back(VideoFrame(inputFrameDesc)); - _filteredData.push_back(VideoFrame(inputFrameDesc)); - _transformedData.push_back(VideoFrame(inputFrameDesc)); + _filteredData = VideoFrame(inputFrameDesc); + _transformedData = VideoFrame(inputFrameDesc); // transform _transform = new VideoTransform(); @@ -94,8 +94,8 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu // buffers to process _decodedData.push_back(AudioFrame(inputFrameDesc)); - _filteredData.push_back(AudioFrame(inputFrameDesc)); - _transformedData.push_back(AudioFrame(inputFrameDesc)); + _filteredData = AudioFrame(inputFrameDesc); + _transformedData = AudioFrame(inputFrameDesc); // transform _transform = new AudioTransform(); @@ -174,8 +174,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu // buffers to process _decodedData.push_back(VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); - _filteredData.push_back(VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); - _transformedData.push_back(VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc())); + _filteredData = VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc()); + _transformedData = VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc()); // transform _transform = new VideoTransform(); @@ -215,8 +215,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); _decodedData.push_back(AudioFrame(inputFrameDesc)); - _filteredData.push_back(AudioFrame(inputFrameDesc)); - _transformedData.push_back(AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc())); + _filteredData = AudioFrame(inputFrameDesc); + _transformedData = AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc()); // transform _transform = new AudioTransform(); @@ -271,8 +271,8 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: VideoFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); _decodedData.push_back(VideoFrame(inputFrameDesc)); - _filteredData.push_back(VideoFrame(inputFrameDesc)); - _transformedData.push_back(VideoFrame(outputFrameDesc)); + _filteredData = VideoFrame(inputFrameDesc); + _transformedData = VideoFrame(outputFrameDesc); // transform _transform = new VideoTransform(); @@ -304,8 +304,8 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: AudioFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); _decodedData.push_back(AudioFrame(inputFrameDesc)); - _filteredData.push_back(AudioFrame(inputFrameDesc)); - _transformedData.push_back(AudioFrame(outputFrameDesc)); + _filteredData = AudioFrame(inputFrameDesc); + _transformedData = AudioFrame(outputFrameDesc); // transform _transform = new AudioTransform(); @@ -475,8 +475,6 @@ bool StreamTranscoder::processTranscode() assert(_currentDecoder != NULL); assert(_outputEncoder != NULL); assert(! _decodedData.empty()); - assert(! _filteredData.empty()); - assert(! _transformedData.empty()); assert(_transform != NULL); LOG_DEBUG("StreamTranscoder::processTranscode") @@ -492,13 +490,13 @@ bool StreamTranscoder::processTranscode() if(decodingStatus) { LOG_DEBUG("Filtering") - _filterGraph->process(_decodedData, _filteredData.at(0)); + _filterGraph->process(_decodedData, _filteredData); LOG_DEBUG("Convert") - _transform->convert(_filteredData.at(0), _transformedData.at(0)); + _transform->convert(_filteredData, _transformedData); LOG_DEBUG("Encode") - _outputEncoder->encodeFrame(_transformedData.at(0), data); + _outputEncoder->encodeFrame(_transformedData, data); } else { @@ -567,7 +565,7 @@ float StreamTranscoder::getDuration() const bool StreamTranscoder::canSwitchToGenerator() { - if(! _decodedData.empty() && ! _transformedData.empty() && ! _generators.empty() && _outputEncoder && _transform) + if(! _decodedData.empty() && ! _generators.empty() && _outputEncoder && _transform) return true; return false; } diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 1bddea60..f6f3ad5b 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -128,8 +128,8 @@ class AvExport StreamTranscoder IOutputStream* _outputStream; ///< Output stream to wrap next packet (has link, no ownership) std::vector _decodedData; ///< List of buffers of decoded data. - std::vector _filteredData; ///< Buffer of filtered data. - std::vector _transformedData; ///< Buffer of transformed data. + Frame _filteredData; ///< Buffer of filtered data. + Frame _transformedData; ///< Buffer of transformed data. std::vector _inputDecoders; ///< Decoders of packets read from _inputStream (has ownership) std::vector _generators; ///< Generators of audio or video packets (has ownership) From 737a3d1fed5acef70d19378ef99b1f2daf80909c Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 09:56:20 +0200 Subject: [PATCH 09/43] StreamTranscoder: removed _currentInputStream attribute Confusing when we will have several input streams. --- .../transcoder/StreamTranscoder.cpp | 94 ++++++++++--------- .../transcoder/StreamTranscoder.hpp | 5 +- src/AvTranscoder/transcoder/Transcoder.cpp | 2 +- 3 files changed, 52 insertions(+), 49 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 6420a2b9..27ba950f 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -22,7 +22,6 @@ namespace avtranscoder StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outputFile, const float offset) : _inputStreamDesc() , _inputStreams() - , _currentInputStream(&inputStream) , _outputStream(NULL) , _decodedData() , _filteredData() @@ -36,22 +35,22 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu , _offset(offset) , _needToSwitchToGenerator(false) { - _inputStreams.push_back(_currentInputStream); + _inputStreams.push_back(&inputStream); // create a re-wrapping case - switch(_currentInputStream->getProperties().getStreamType()) + switch(inputStream.getProperties().getStreamType()) { case AVMEDIA_TYPE_VIDEO: { // output stream - _outputStream = &outputFile.addVideoStream(_currentInputStream->getVideoCodec()); + _outputStream = &outputFile.addVideoStream(inputStream.getVideoCodec()); try { // filter - _filterGraph = new FilterGraph(_currentInputStream->getVideoCodec()); + _filterGraph = new FilterGraph(inputStream.getVideoCodec()); - VideoFrameDesc inputFrameDesc(_currentInputStream->getVideoCodec().getVideoFrameDesc()); + VideoFrameDesc inputFrameDesc(inputStream.getVideoCodec().getVideoFrameDesc()); // generator decoder _generators.push_back(new VideoGenerator(inputFrameDesc)); @@ -65,13 +64,13 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _transform = new VideoTransform(); // output encoder - VideoEncoder* outputVideo = new VideoEncoder(_currentInputStream->getVideoCodec().getCodecName()); + VideoEncoder* outputVideo = new VideoEncoder(inputStream.getVideoCodec().getCodecName()); outputVideo->setupVideoEncoder(inputFrameDesc); _outputEncoder = outputVideo; } catch(std::runtime_error& e) { - LOG_WARN("Cannot create the video encoder for stream " << _currentInputStream->getStreamIndex() << " if needed. " + LOG_WARN("Cannot create the video encoder for stream " << inputStream.getStreamIndex() << " if needed. " << e.what()) } @@ -80,14 +79,14 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu case AVMEDIA_TYPE_AUDIO: { // output stream - _outputStream = &outputFile.addAudioStream(_currentInputStream->getAudioCodec()); + _outputStream = &outputFile.addAudioStream(inputStream.getAudioCodec()); try { // filter - _filterGraph = new FilterGraph(_currentInputStream->getAudioCodec()); + _filterGraph = new FilterGraph(inputStream.getAudioCodec()); - AudioFrameDesc inputFrameDesc(_currentInputStream->getAudioCodec().getAudioFrameDesc()); + AudioFrameDesc inputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); // generator decoder _generators.push_back(new AudioGenerator(inputFrameDesc)); @@ -101,14 +100,14 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _transform = new AudioTransform(); // output encoder - AudioEncoder* outputAudio = new AudioEncoder(_currentInputStream->getAudioCodec().getCodecName()); + AudioEncoder* outputAudio = new AudioEncoder(inputStream.getAudioCodec().getCodecName()); outputAudio->setupAudioEncoder(inputFrameDesc); _outputEncoder = outputAudio; } catch(std::runtime_error& e) { - LOG_WARN("Cannot create the audio encoder for stream " << _currentInputStream->getStreamIndex() << " if needed. " + LOG_WARN("Cannot create the audio encoder for stream " << inputStream.getStreamIndex() << " if needed. " << e.what()) } @@ -117,7 +116,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu case AVMEDIA_TYPE_DATA: { // @warning: rewrap a data stream can't be lengthen by a generator (end of rewrapping will end the all process) - _outputStream = &outputFile.addDataStream(_currentInputStream->getDataCodec()); + _outputStream = &outputFile.addDataStream(inputStream.getDataCodec()); break; } default: @@ -130,7 +129,6 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu const ProfileLoader::Profile& profile, const float offset) : _inputStreamDesc() , _inputStreams() - , _currentInputStream(&inputStream) , _outputStream(NULL) , _decodedData() , _filteredData() @@ -145,15 +143,15 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu , _needToSwitchToGenerator(false) { _inputStreamDesc.push_back(inputStreamDesc); - _inputStreams.push_back(_currentInputStream); + _inputStreams.push_back(&inputStream); // create a transcode case - switch(_currentInputStream->getProperties().getStreamType()) + switch(inputStream.getProperties().getStreamType()) { case AVMEDIA_TYPE_VIDEO: { // filter - _filterGraph = new FilterGraph(_currentInputStream->getVideoCodec()); + _filterGraph = new FilterGraph(inputStream.getVideoCodec()); // input decoder VideoDecoder* inputVideo = new VideoDecoder(*static_cast(&inputStream)); @@ -165,7 +163,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu VideoEncoder* outputVideo = new VideoEncoder(profile.at(constants::avProfileCodec)); _outputEncoder = outputVideo; - VideoFrameDesc outputFrameDesc = _currentInputStream->getVideoCodec().getVideoFrameDesc(); + VideoFrameDesc outputFrameDesc = inputStream.getVideoCodec().getVideoFrameDesc(); outputFrameDesc.setParameters(profile); outputVideo->setupVideoEncoder(outputFrameDesc, profile); @@ -173,8 +171,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec()); // buffers to process - _decodedData.push_back(VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc())); - _filteredData = VideoFrame(_currentInputStream->getVideoCodec().getVideoFrameDesc()); + _decodedData.push_back(VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc())); + _filteredData = VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc()); _transformedData = VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc()); // transform @@ -188,7 +186,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu case AVMEDIA_TYPE_AUDIO: { // filter - _filterGraph = new FilterGraph(_currentInputStream->getAudioCodec()); + _filterGraph = new FilterGraph(inputStream.getAudioCodec()); // input decoder AudioDecoder* inputAudio = new AudioDecoder(*static_cast(&inputStream)); @@ -200,7 +198,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu AudioEncoder* outputAudio = new AudioEncoder(profile.at(constants::avProfileCodec)); _outputEncoder = outputAudio; - AudioFrameDesc outputFrameDesc(_currentInputStream->getAudioCodec().getAudioFrameDesc()); + AudioFrameDesc outputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); outputFrameDesc.setParameters(profile); if(inputStreamDesc.demultiplexing()) outputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); @@ -210,7 +208,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _outputStream = &outputFile.addAudioStream(outputAudio->getAudioCodec()); // buffers to process - AudioFrameDesc inputFrameDesc(_currentInputStream->getAudioCodec().getAudioFrameDesc()); + AudioFrameDesc inputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); if(inputStreamDesc.demultiplexing()) inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); @@ -238,7 +236,6 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader::Profile& profile) : _inputStreamDesc() , _inputStreams() - , _currentInputStream(NULL) , _outputStream(NULL) , _decodedData() , _filteredData() @@ -345,13 +342,8 @@ void StreamTranscoder::preProcessCodecLatency() if(!_outputEncoder) { std::stringstream msg; - msg << "No encoder found for input stream "; - if(getProcessCase() == eProcessCaseGenerator) - msg << "generator"; - else - msg << _currentInputStream->getStreamIndex(); - msg << ": will not preProcessCodecLatency."; - LOG_WARN(msg.str()) + msg << "No encoder found: will not preProcessCodecLatency."; + LOG_INFO(msg.str()) return; } @@ -419,8 +411,11 @@ bool StreamTranscoder::processFrame() } else if(_offset < 0) { - const bool endOfStream = - _outputStream->getStreamDuration() >= (_currentInputStream->getProperties().getDuration() + _offset); + bool endOfStream = false; + for(size_t index = 0; index < _inputStreams.size(); ++index) + { + endOfStream = endOfStream && _outputStream->getStreamDuration() >= (_inputStreams.at(index)->getProperties().getDuration() + _offset); + } if(endOfStream) { LOG_INFO("End of negative offset") @@ -438,13 +433,13 @@ bool StreamTranscoder::processFrame() bool StreamTranscoder::processRewrap() { - assert(_currentInputStream != NULL); + assert(_inputStreams.size() == 1); assert(_outputStream != NULL); LOG_DEBUG("StreamTranscoder::processRewrap") CodedData data; - if(!_currentInputStream->readNextPacket(data)) + if(! _inputStreams.at(0)->readNextPacket(data)) { if(_needToSwitchToGenerator) { @@ -480,11 +475,14 @@ bool StreamTranscoder::processTranscode() LOG_DEBUG("StreamTranscoder::processTranscode") LOG_DEBUG("Decode next frame") - bool decodingStatus = false; - if(! _inputStreamDesc.empty() && _inputStreamDesc.at(0).demultiplexing()) - decodingStatus = _currentDecoder->decodeNextFrame(_decodedData.at(0), _inputStreamDesc.at(0)._channelIndexArray); - else - decodingStatus = _currentDecoder->decodeNextFrame(_decodedData.at(0)); + bool decodingStatus = true; + for(size_t index = 0; index < _inputDecoders.size(); ++index) + { + if(! _inputStreamDesc.empty() && _inputStreamDesc.at(index).demultiplexing()) + decodingStatus = decodingStatus && _currentDecoder->decodeNextFrame(_decodedData.at(index), _inputStreamDesc.at(index)._channelIndexArray); + else + decodingStatus = decodingStatus && _currentDecoder->decodeNextFrame(_decodedData.at(index)); + } CodedData data; if(decodingStatus) @@ -548,11 +546,17 @@ float StreamTranscoder::getDuration() const { if(! _inputStreams.empty()) { - const StreamProperties& streamProperties = _currentInputStream->getProperties(); - const float totalDuration = streamProperties.getDuration() + _offset; + float minStreamDuration = -1; + for(size_t index = 0; index < _inputStreams.size(); ++index) + { + const StreamProperties& streamProperties = _inputStreams.at(index)->getProperties(); + if(minStreamDuration == -1 || streamProperties.getDuration() < minStreamDuration) + minStreamDuration = streamProperties.getDuration(); + } + const float totalDuration = minStreamDuration + _offset; if(totalDuration < 0) { - LOG_WARN("Offset of " << _offset << "s applied to a stream with a duration of " << streamProperties.getDuration() + LOG_WARN("Offset of " << _offset << "s applied to a stream with a duration of " << minStreamDuration << "s. Set its duration to 0s.") return 0.; } @@ -575,7 +579,7 @@ void StreamTranscoder::needToSwitchToGenerator(const bool needToSwitch) if(needToSwitch && !canSwitchToGenerator()) { std::stringstream os; - os << "The stream at index " << _currentInputStream->getStreamIndex() << " has a duration of " << getDuration() << "s."; + os << "The stream has a duration of " << getDuration() << "s."; os << " It needs to switch to a generator during the process, but it cannot. "; throw std::runtime_error(os.str()); } diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index f6f3ad5b..2e150e1f 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -65,7 +65,7 @@ class AvExport StreamTranscoder //@} /** - * @brief Get the total duration (in seconds), ie. duration of the stream and the offset applies + * @brief Get the total duration (in seconds), ie. duration of the shortest input stream and the offset applies * @note if it's a generated stream, return limit of double. * @note if offset > duration of the stream, return 0 */ @@ -83,7 +83,7 @@ class AvExport StreamTranscoder FilterGraph* getFilterGraph() const { return _filterGraph; } /// Returns a pointer to the stream which unwraps data - IInputStream* getCurrentInputStream() const { return _currentInputStream; } + std::vector getInputStreams() const { return _inputStreams; } /// Returns a reference to the stream which wraps data IOutputStream& getOutputStream() const { return *_outputStream; } @@ -124,7 +124,6 @@ class AvExport StreamTranscoder private: std::vector _inputStreamDesc; ///< Description of the data to extract from the input stream. std::vector _inputStreams; ///< List of input stream to read next packet (has link, no ownership) - IInputStream* _currentInputStream; ///< Current input stream (has link, no ownership) IOutputStream* _outputStream; ///< Output stream to wrap next packet (has link, no ownership) std::vector _decodedData; ///< List of buffers of decoded data. diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 9ef555e4..bde914c7 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -463,7 +463,7 @@ void Transcoder::fillProcessStat(ProcessStat& processStat) for(size_t streamIndex = 0; streamIndex < _streamTranscoders.size(); ++streamIndex) { IOutputStream& stream = _streamTranscoders.at(streamIndex)->getOutputStream(); - const IInputStream* inputStream = _streamTranscoders.at(streamIndex)->getCurrentInputStream(); + const IInputStream* inputStream = _streamTranscoders.at(streamIndex)->getInputStreams().at(0); if(inputStream == NULL) { LOG_WARN("Cannot process statistics of generated stream.") From 935ed64dc526ab222b5963e4774882365d918b40 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 10:43:33 +0200 Subject: [PATCH 10/43] VideoGenerator: removed VideoFrameDesc parameter in constructor The VideoFrameDesc could be found from the given frame when decoding. --- src/AvTranscoder/decoder/VideoGenerator.cpp | 39 ++++++------------- src/AvTranscoder/decoder/VideoGenerator.hpp | 12 ++++-- src/AvTranscoder/reader/VideoReader.cpp | 2 +- .../transcoder/StreamTranscoder.cpp | 6 +-- 4 files changed, 24 insertions(+), 35 deletions(-) diff --git a/src/AvTranscoder/decoder/VideoGenerator.cpp b/src/AvTranscoder/decoder/VideoGenerator.cpp index bdaf645f..94febd70 100644 --- a/src/AvTranscoder/decoder/VideoGenerator.cpp +++ b/src/AvTranscoder/decoder/VideoGenerator.cpp @@ -1,17 +1,17 @@ #include "VideoGenerator.hpp" #include -#include #include +#include namespace avtranscoder { -VideoGenerator::VideoGenerator(const VideoFrameDesc& frameDesc) +VideoGenerator::VideoGenerator() : _inputFrame(NULL) , _blackImage(NULL) - , _frameDesc(frameDesc) + , _videoTransform() { } @@ -23,12 +23,8 @@ VideoGenerator::~VideoGenerator() bool VideoGenerator::decodeNextFrame(Frame& frameBuffer) { // check the given frame - if(!frameBuffer.isVideoFrame()) - { - LOG_WARN("The given frame is not a valid video frame: allocate a new AVPicture to put generated data into it."); - frameBuffer.clear(); - static_cast(frameBuffer).allocateAVPicture(_frameDesc); - } + if(! frameBuffer.isVideoFrame()) + throw std::runtime_error("The given frame is not a valid video frame: allocate a new AVPicture to put generated data into it."); // Generate black image if(!_inputFrame) @@ -38,30 +34,19 @@ bool VideoGenerator::decodeNextFrame(Frame& frameBuffer) { std::stringstream msg; msg << "Generate a black image with the following features:" << std::endl; - msg << "width = " << _frameDesc._width << std::endl; - msg << "height = " << _frameDesc._height << std::endl; + msg << "width = " << frameBuffer.getAVFrame().width << std::endl; + msg << "height = " << frameBuffer.getAVFrame().height << std::endl; msg << "pixel format = rgb24" << std::endl; LOG_INFO(msg.str()) - VideoFrame& imageBuffer = static_cast(frameBuffer); - - // Input of convert - // @todo support PAL (0 to 255) and NTFS (16 to 235) - VideoFrameDesc desc(_frameDesc); - desc._pixelFormat = getAVPixelFormat("rgb24"); - VideoFrame intermediateBuffer(desc); + // Create the black RGB image + _blackImage = new VideoFrame(VideoFrameDesc(frameBuffer.getAVFrame().width, frameBuffer.getAVFrame().height, "rgb24")); const unsigned char fillChar = 0; - intermediateBuffer.assign(fillChar); - - // Output of convert - _blackImage = new VideoFrame(imageBuffer.desc()); - - // Convert and store the black image - VideoTransform videoTransform; - videoTransform.convert(intermediateBuffer, *_blackImage); + _blackImage->assign(fillChar); } LOG_DEBUG("Copy data of the black image when decode next frame") - frameBuffer.copyData(*_blackImage); + // Convert the black image to the configuration of the given frame + _videoTransform.convert(*_blackImage, frameBuffer); } // Take image from _inputFrame else diff --git a/src/AvTranscoder/decoder/VideoGenerator.hpp b/src/AvTranscoder/decoder/VideoGenerator.hpp index c9053047..58783b0c 100644 --- a/src/AvTranscoder/decoder/VideoGenerator.hpp +++ b/src/AvTranscoder/decoder/VideoGenerator.hpp @@ -3,6 +3,7 @@ #include "IDecoder.hpp" #include +#include namespace avtranscoder { @@ -14,19 +15,22 @@ class AvExport VideoGenerator : public IDecoder VideoGenerator& operator=(const VideoGenerator& videoGenerator); public: - VideoGenerator(const VideoFrameDesc& frameDesc); - + VideoGenerator(); ~VideoGenerator(); bool decodeNextFrame(Frame& frameBuffer); bool decodeNextFrame(Frame& frameBuffer, const std::vector channelIndexArray); + /** + * @brief Force to return this frame when calling the decoding methods. + * @param inputFrame: should have the same properties as the given frames when decoding. + */ void setNextFrame(Frame& inputFrame) { _inputFrame = &inputFrame; } private: Frame* _inputFrame; ///< A frame given from outside (has link, no ownership) - VideoFrame* _blackImage; ///< The generated black image (has ownership) - const VideoFrameDesc _frameDesc; ///< The description of the black image (width, height...) + VideoFrame* _blackImage; ///< The generated RGB black image (has ownership) + VideoTransform _videoTransform; ///< To transform data of the back image to the given Frame when decoding. }; } diff --git a/src/AvTranscoder/reader/VideoReader.cpp b/src/AvTranscoder/reader/VideoReader.cpp index 304a5d22..024d4e7d 100644 --- a/src/AvTranscoder/reader/VideoReader.cpp +++ b/src/AvTranscoder/reader/VideoReader.cpp @@ -44,7 +44,7 @@ void VideoReader::init() _currentDecoder = _decoder; // generator - _generator = new VideoGenerator(_inputFile->getStream(_streamIndex).getVideoCodec().getVideoFrameDesc()); + _generator = new VideoGenerator(); // create transform _transform = new VideoTransform(); diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 27ba950f..75d1d7d1 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -53,7 +53,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu VideoFrameDesc inputFrameDesc(inputStream.getVideoCodec().getVideoFrameDesc()); // generator decoder - _generators.push_back(new VideoGenerator(inputFrameDesc)); + _generators.push_back(new VideoGenerator()); // buffers to process _decodedData.push_back(VideoFrame(inputFrameDesc)); @@ -179,7 +179,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _transform = new VideoTransform(); // generator decoder - _generators.push_back(new VideoGenerator(outputVideo->getVideoCodec().getVideoFrameDesc())); + _generators.push_back(new VideoGenerator()); break; } @@ -257,7 +257,7 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: inputVideoCodec.setImageParameters(inputFrameDesc); // generator decoder - VideoGenerator* generator = new VideoGenerator(inputVideoCodec.getVideoFrameDesc()); + VideoGenerator* generator = new VideoGenerator(); _generators.push_back(generator); _currentDecoder = generator; From 924bf5be5462f3f0c25a4fa5ff43f14da97d2cdd Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 10:51:55 +0200 Subject: [PATCH 11/43] AudioGenerator: removed AudioFrameDesc parameter in constructor The AudioFrameDesc could be found from the given frame when decoding. --- src/AvTranscoder/decoder/AudioGenerator.cpp | 12 ++++-------- src/AvTranscoder/decoder/AudioGenerator.hpp | 3 +-- src/AvTranscoder/reader/AudioReader.cpp | 2 +- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 6 +++--- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/AvTranscoder/decoder/AudioGenerator.cpp b/src/AvTranscoder/decoder/AudioGenerator.cpp index f13b880f..c614e843 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.cpp +++ b/src/AvTranscoder/decoder/AudioGenerator.cpp @@ -3,14 +3,14 @@ #include #include +#include namespace avtranscoder { -AudioGenerator::AudioGenerator(const AudioFrameDesc& frameDesc) +AudioGenerator::AudioGenerator() : _inputFrame(NULL) , _silent(NULL) - , _frameDesc(frameDesc) { } @@ -22,12 +22,8 @@ AudioGenerator::~AudioGenerator() bool AudioGenerator::decodeNextFrame(Frame& frameBuffer) { // check the given frame - if(!frameBuffer.isAudioFrame()) - { - LOG_WARN("The given frame is not a valid audio frame: allocate a new AVSample to put generated data into it."); - frameBuffer.clear(); - static_cast(frameBuffer).allocateAVSample(_frameDesc); - } + if(! frameBuffer.isAudioFrame()) + throw std::runtime_error("The given frame is not a valid audio frame: allocate a new AVSample to put generated data into it."); // Check channel layout of the given frame to be able to copy audio data to it. // @see Frame.copyData method diff --git a/src/AvTranscoder/decoder/AudioGenerator.hpp b/src/AvTranscoder/decoder/AudioGenerator.hpp index ba80ab69..7a45564e 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.hpp +++ b/src/AvTranscoder/decoder/AudioGenerator.hpp @@ -14,7 +14,7 @@ class AvExport AudioGenerator : public IDecoder AudioGenerator(const AudioGenerator& audioGenerator); public: - AudioGenerator(const AudioFrameDesc& frameDesc); + AudioGenerator(); ~AudioGenerator(); @@ -26,7 +26,6 @@ class AvExport AudioGenerator : public IDecoder private: Frame* _inputFrame; ///< Has link (no ownership) AudioFrame* _silent; ///< The generated silent (has ownership) - const AudioFrameDesc _frameDesc; ///< The description of the silence (sampleRate, channels...) }; } diff --git a/src/AvTranscoder/reader/AudioReader.cpp b/src/AvTranscoder/reader/AudioReader.cpp index b7b487c4..d9cc63cd 100644 --- a/src/AvTranscoder/reader/AudioReader.cpp +++ b/src/AvTranscoder/reader/AudioReader.cpp @@ -45,7 +45,7 @@ void AudioReader::init() _currentDecoder = _decoder; // generator - _generator = new AudioGenerator(_inputFile->getStream(_streamIndex).getAudioCodec().getAudioFrameDesc()); + _generator = new AudioGenerator(); // create transform _transform = new AudioTransform(); diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 75d1d7d1..b28fde0a 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -89,7 +89,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu AudioFrameDesc inputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); // generator decoder - _generators.push_back(new AudioGenerator(inputFrameDesc)); + _generators.push_back(new AudioGenerator()); // buffers to process _decodedData.push_back(AudioFrame(inputFrameDesc)); @@ -220,7 +220,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _transform = new AudioTransform(); // generator decoder - _generators.push_back(new AudioGenerator(outputFrameDesc)); + _generators.push_back(new AudioGenerator()); break; } @@ -290,7 +290,7 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: inputAudioCodec.setAudioParameters(inputFrameDesc); // generator decoder - AudioGenerator* generator = new AudioGenerator(inputAudioCodec.getAudioFrameDesc()); + AudioGenerator* generator = new AudioGenerator(); _generators.push_back(generator); _currentDecoder = generator; From 1753141e0281fa98f9d9005196fcbd5146c0209e Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 10:55:07 +0200 Subject: [PATCH 12/43] AudioGenerator: reference silent Frame instead of copying its data --- src/AvTranscoder/decoder/AudioGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/decoder/AudioGenerator.cpp b/src/AvTranscoder/decoder/AudioGenerator.cpp index c614e843..d152fdc0 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.cpp +++ b/src/AvTranscoder/decoder/AudioGenerator.cpp @@ -57,7 +57,7 @@ bool AudioGenerator::decodeNextFrame(Frame& frameBuffer) _silent->setNbSamplesPerChannel(frameBuffer.getAVFrame().nb_samples); } LOG_DEBUG("Copy data of the silence when decode next frame") - frameBuffer.copyData(*_silent); + frameBuffer.refFrame(*_silent); } // Take audio frame from _inputFrame else From 3e85e3195c9462f3c52c219c33872d8ca4c7ed99 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 11:12:26 +0200 Subject: [PATCH 13/43] StreamTranscoder: refactored how to add decoder * Add provate method 'addDecoder'. * Will be used to add several decoders. --- .../transcoder/StreamTranscoder.cpp | 69 ++++++++++++++----- .../transcoder/StreamTranscoder.hpp | 7 ++ 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index b28fde0a..8da2364d 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -145,6 +145,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _inputStreamDesc.push_back(inputStreamDesc); _inputStreams.push_back(&inputStream); + addDecoder(inputStreamDesc, inputStream); + // create a transcode case switch(inputStream.getProperties().getStreamType()) { @@ -153,12 +155,6 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu // filter _filterGraph = new FilterGraph(inputStream.getVideoCodec()); - // input decoder - VideoDecoder* inputVideo = new VideoDecoder(*static_cast(&inputStream)); - inputVideo->setupDecoder(); - _inputDecoders.push_back(inputVideo); - _currentDecoder = inputVideo; - // output encoder VideoEncoder* outputVideo = new VideoEncoder(profile.at(constants::avProfileCodec)); _outputEncoder = outputVideo; @@ -171,16 +167,12 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec()); // buffers to process - _decodedData.push_back(VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc())); _filteredData = VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc()); _transformedData = VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc()); // transform _transform = new VideoTransform(); - // generator decoder - _generators.push_back(new VideoGenerator()); - break; } case AVMEDIA_TYPE_AUDIO: @@ -188,12 +180,6 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu // filter _filterGraph = new FilterGraph(inputStream.getAudioCodec()); - // input decoder - AudioDecoder* inputAudio = new AudioDecoder(*static_cast(&inputStream)); - inputAudio->setupDecoder(); - _inputDecoders.push_back(inputAudio); - _currentDecoder = inputAudio; - // output encoder AudioEncoder* outputAudio = new AudioEncoder(profile.at(constants::avProfileCodec)); _outputEncoder = outputAudio; @@ -212,25 +198,70 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu if(inputStreamDesc.demultiplexing()) inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); - _decodedData.push_back(AudioFrame(inputFrameDesc)); _filteredData = AudioFrame(inputFrameDesc); _transformedData = AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc()); // transform _transform = new AudioTransform(); + break; + } + default: + { + throw std::runtime_error("unupported stream type"); + break; + } + } + setOffset(offset); +} + +void StreamTranscoder::addDecoder(const InputStreamDesc& inputStreamDesc, IInputStream& inputStream) +{ + // create a transcode case + switch(inputStream.getProperties().getStreamType()) + { + case AVMEDIA_TYPE_VIDEO: + { + // corresponding input decoder + VideoDecoder* inputVideo = new VideoDecoder(static_cast(inputStream)); + inputVideo->setupDecoder(); + _inputDecoders.push_back(inputVideo); + _currentDecoder = inputVideo; + + // generator decoder + _generators.push_back(new VideoGenerator()); + + // buffers to process + _decodedData.push_back(VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc())); + + break; + } + case AVMEDIA_TYPE_AUDIO: + { + // corresponding input decoder + AudioDecoder* inputAudio = new AudioDecoder(static_cast(inputStream)); + inputAudio->setupDecoder(); + _inputDecoders.push_back(inputAudio); + _currentDecoder = inputAudio; + // generator decoder _generators.push_back(new AudioGenerator()); + // buffers to process + AudioFrameDesc inputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); + if(inputStreamDesc.demultiplexing()) + inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); + + _decodedData.push_back(AudioFrame(inputFrameDesc)); + break; } default: { - throw std::runtime_error("unupported stream type"); + throw std::runtime_error("Unupported stream type"); break; } } - setOffset(offset); } StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader::Profile& profile) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 2e150e1f..1349c26a 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -118,6 +118,13 @@ class AvExport StreamTranscoder //@} private: + /** + * @brief Create the decoder (and the other related objects needed) which decodes the given input stream. + * @param inputStreamDesc + * @param inputStream + */ + void addDecoder(const InputStreamDesc& inputStreamDesc, IInputStream& inputStream); + bool processRewrap(); bool processTranscode(); From b013d4c57285db084dbee891dd281d79ed944708 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 14:24:47 +0200 Subject: [PATCH 14/43] FilterGraph: fixed process with several inputs --- src/AvTranscoder/filter/FilterGraph.cpp | 28 +++++++++++++------------ src/AvTranscoder/filter/FilterGraph.hpp | 8 +++---- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/AvTranscoder/filter/FilterGraph.cpp b/src/AvTranscoder/filter/FilterGraph.cpp index 27d464e0..dcfffacd 100644 --- a/src/AvTranscoder/filter/FilterGraph.cpp +++ b/src/AvTranscoder/filter/FilterGraph.cpp @@ -84,24 +84,28 @@ Filter& FilterGraph::addFilter(const std::string& filterName, const std::string& void FilterGraph::init(const std::vector& inputs, Frame& output) { // push filters to the graph - pushInBuffer(inputs); - for(size_t i = 1; i < _filters.size(); ++i) + addInBuffer(inputs); + addOutBuffer(output); + for(size_t i = 0; i < _filters.size(); ++i) { pushFilter(*_filters.at(i)); } - pushOutBuffer(output); // connect filters for(size_t index = 0; index < _filters.size() - 1; ++index) { - size_t indexOfFilterToConnect = index + 1; + size_t indexOfOutputFilterToConnect = index + 1; + size_t indexOfInputPadOfDestinationFilter = 0; // handle cases with several inputs if(index < inputs.size()) - indexOfFilterToConnect = inputs.size(); + { + indexOfOutputFilterToConnect = inputs.size(); + indexOfInputPadOfDestinationFilter = index; + } - LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(indexOfFilterToConnect)->getName()) + LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(indexOfOutputFilterToConnect)->getName()) const int err = - avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(indexOfFilterToConnect)->getAVFilterContext(), 0); + avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(indexOfOutputFilterToConnect)->getAVFilterContext(), indexOfInputPadOfDestinationFilter); if(err < 0) { throw std::runtime_error("Error when connecting filters."); @@ -137,9 +141,9 @@ void FilterGraph::pushFilter(Filter& filter) } } -void FilterGraph::pushInBuffer(const std::vector& inputs) +void FilterGraph::addInBuffer(const std::vector& inputs) { - for(std::vector::const_iterator it = inputs.begin(); it != inputs.end(); ++it) + for(std::vector::const_reverse_iterator it = inputs.rbegin(); it != inputs.rend(); ++it) { std::string filterName; std::stringstream filterOptions; @@ -174,11 +178,10 @@ void FilterGraph::pushInBuffer(const std::vector& inputs) Filter* in = new Filter(filterName, filterOptions.str(), "in"); LOG_INFO("Add filter '" << filterName << "' at the beginning of the graph.") _filters.insert(_filters.begin(), in); - pushFilter(*in); } } -void FilterGraph::pushOutBuffer(const Frame& output) +void FilterGraph::addOutBuffer(const Frame& output) { std::string filterName; @@ -190,7 +193,6 @@ void FilterGraph::pushOutBuffer(const Frame& output) throw std::runtime_error("Cannot create output buffer of filter graph: the given frame is invalid."); // add out buffer - Filter& out = addFilter(filterName, "", "out"); - pushFilter(out); + addFilter(filterName, "", "out"); } } diff --git a/src/AvTranscoder/filter/FilterGraph.hpp b/src/AvTranscoder/filter/FilterGraph.hpp index 01edc619..b00e4450 100644 --- a/src/AvTranscoder/filter/FilterGraph.hpp +++ b/src/AvTranscoder/filter/FilterGraph.hpp @@ -45,7 +45,7 @@ class AvExport FilterGraph * @param inputs: input data buffers (at least one). * @param output: output data buffer. * @note Do nothing if there was no filter added. - * If there is one input buffer, the filter graph is a chain of effects: input -> filter 1 -> filter 2 -> output. + * If there is one input buffer, the filter graph is a chain of effects: input -> filter 1 -> filter 2 -> output. * If there is several input buffers, the filter graph is like this: * input 1 ---| * | @@ -75,9 +75,9 @@ class AvExport FilterGraph void pushFilter(Filter& filter); ///@{ - /// @brief Push the input and output buffer at the beginning and the end of the graph. - void pushInBuffer(const std::vector& inputs); - void pushOutBuffer(const Frame& output); + /// @brief Add the input and output buffers at the beginning and the end of the list of filters. + void addInBuffer(const std::vector& inputs); + void addOutBuffer(const Frame& output); //@} private: From 966d949391e6d26a58a514716d3bdcf014cf6a98 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 14:27:18 +0200 Subject: [PATCH 15/43] Transcoder: updated log when a stream transcoder failed to process --- src/AvTranscoder/transcoder/Transcoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index bde914c7..15928fe3 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -112,7 +112,7 @@ bool Transcoder::processFrame() // if a stream failed to process if(!_streamTranscoders.at(streamIndex)->processFrame()) { - LOG_WARN("Failed to process stream at index " << streamIndex) + LOG_WARN("Failed to process the stream transcoder at index " << streamIndex) // if this is the end of the main stream if(streamIndex == _mainStreamIndex) { From f506f1896383c0cefd32e8fec93d13cda77f4534 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 14:44:30 +0200 Subject: [PATCH 16/43] StreamTranscoder: updated buffer attributes * Need pointers here to be able to use polymorphism. * Updated FilterGraph parameters to launch a process. * Almost a revert of commit ecd3ddd9129b14eb38d2ca329fbab52d50dd8aec --- src/AvTranscoder/filter/FilterGraph.cpp | 30 ++++----- src/AvTranscoder/filter/FilterGraph.hpp | 6 +- .../transcoder/StreamTranscoder.cpp | 65 ++++++++++--------- .../transcoder/StreamTranscoder.hpp | 6 +- 4 files changed, 57 insertions(+), 50 deletions(-) diff --git a/src/AvTranscoder/filter/FilterGraph.cpp b/src/AvTranscoder/filter/FilterGraph.cpp index dcfffacd..f2a9bd51 100644 --- a/src/AvTranscoder/filter/FilterGraph.cpp +++ b/src/AvTranscoder/filter/FilterGraph.cpp @@ -35,12 +35,12 @@ FilterGraph::~FilterGraph() avfilter_graph_free(&_graph); } -void FilterGraph::process(const std::vector& inputs, Frame& output) +void FilterGraph::process(const std::vector& inputs, Frame& output) { if(!hasFilters()) { LOG_DEBUG("No filter to process: reference first input frame to the given output.") - output.refFrame(inputs.at(0)); + output.refFrame(*inputs.at(0)); return; } @@ -51,7 +51,7 @@ void FilterGraph::process(const std::vector& inputs, Frame& output) // setup input frames for(size_t index = 0; index < inputs.size(); ++index) { - const int ret = av_buffersrc_write_frame(_filters.at(index)->getAVFilterContext(), &inputs.at(index).getAVFrame()); + const int ret = av_buffersrc_write_frame(_filters.at(index)->getAVFilterContext(), &inputs.at(index)->getAVFrame()); if(ret < 0) { throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " + @@ -81,7 +81,7 @@ Filter& FilterGraph::addFilter(const std::string& filterName, const std::string& return *_filters.back(); } -void FilterGraph::init(const std::vector& inputs, Frame& output) +void FilterGraph::init(const std::vector& inputs, Frame& output) { // push filters to the graph addInBuffer(inputs); @@ -141,30 +141,30 @@ void FilterGraph::pushFilter(Filter& filter) } } -void FilterGraph::addInBuffer(const std::vector& inputs) +void FilterGraph::addInBuffer(const std::vector& inputs) { - for(std::vector::const_reverse_iterator it = inputs.rbegin(); it != inputs.rend(); ++it) + for(std::vector::const_reverse_iterator it = inputs.rbegin(); it != inputs.rend(); ++it) { std::string filterName; std::stringstream filterOptions; // audio frame - if(it->isAudioFrame()) + if((*it)->isAudioFrame()) { filterName = "abuffer"; - const AudioFrame& audioFrame = dynamic_cast(*it); + const AudioFrame* audioFrame = dynamic_cast(*it); filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" << _codec.getAVCodecContext().time_base.den << ":"; - filterOptions << "sample_rate=" << audioFrame.getSampleRate() << ":"; - filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame.getSampleFormat()) << ":"; - filterOptions << "channel_layout=0x" << std::hex << audioFrame.getChannelLayout(); + filterOptions << "sample_rate=" << audioFrame->getSampleRate() << ":"; + filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame->getSampleFormat()) << ":"; + filterOptions << "channel_layout=0x" << std::hex << audioFrame->getChannelLayout(); } // video frame - else if(it->isVideoFrame()) + else if((*it)->isVideoFrame()) { filterName = "buffer"; - const VideoFrame& videoFrame = dynamic_cast(*it); - filterOptions << "video_size=" << videoFrame.getWidth() << "x" << videoFrame.getHeight() << ":"; - filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame.getPixelFormat()) << ":"; + const VideoFrame* videoFrame = dynamic_cast(*it); + filterOptions << "video_size=" << videoFrame->getWidth() << "x" << videoFrame->getHeight() << ":"; + filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame->getPixelFormat()) << ":"; filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" << _codec.getAVCodecContext().time_base.den << ":"; filterOptions << "pixel_aspect=" << _codec.getAVCodecContext().sample_aspect_ratio.num << "/" diff --git a/src/AvTranscoder/filter/FilterGraph.hpp b/src/AvTranscoder/filter/FilterGraph.hpp index b00e4450..4ae9274c 100644 --- a/src/AvTranscoder/filter/FilterGraph.hpp +++ b/src/AvTranscoder/filter/FilterGraph.hpp @@ -53,7 +53,7 @@ class AvExport FilterGraph * | * input 2 ---| */ - void process(const std::vector& inputs, Frame& output); + void process(const std::vector& inputs, Frame& output); private: /** @@ -67,7 +67,7 @@ class AvExport FilterGraph * @see pushInBuffer * @see pushOutBuffer */ - void init(const std::vector& inputs, Frame& output); + void init(const std::vector& inputs, Frame& output); /** * @brief Push the given Filter to the graph. @@ -76,7 +76,7 @@ class AvExport FilterGraph ///@{ /// @brief Add the input and output buffers at the beginning and the end of the list of filters. - void addInBuffer(const std::vector& inputs); + void addInBuffer(const std::vector& inputs); void addOutBuffer(const Frame& output); //@} diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 8da2364d..c7631fff 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -24,8 +24,8 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu , _inputStreams() , _outputStream(NULL) , _decodedData() - , _filteredData() - , _transformedData() + , _filteredData(NULL) + , _transformedData(NULL) , _inputDecoders() , _generators() , _currentDecoder(NULL) @@ -56,9 +56,9 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _generators.push_back(new VideoGenerator()); // buffers to process - _decodedData.push_back(VideoFrame(inputFrameDesc)); - _filteredData = VideoFrame(inputFrameDesc); - _transformedData = VideoFrame(inputFrameDesc); + _decodedData.push_back(new VideoFrame(inputFrameDesc)); + _filteredData = new VideoFrame(inputFrameDesc); + _transformedData = new VideoFrame(inputFrameDesc); // transform _transform = new VideoTransform(); @@ -92,9 +92,9 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _generators.push_back(new AudioGenerator()); // buffers to process - _decodedData.push_back(AudioFrame(inputFrameDesc)); - _filteredData = AudioFrame(inputFrameDesc); - _transformedData = AudioFrame(inputFrameDesc); + _decodedData.push_back(new AudioFrame(inputFrameDesc)); + _filteredData = new AudioFrame(inputFrameDesc); + _transformedData = new AudioFrame(inputFrameDesc); // transform _transform = new AudioTransform(); @@ -131,8 +131,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu , _inputStreams() , _outputStream(NULL) , _decodedData() - , _filteredData() - , _transformedData() + , _filteredData(NULL) + , _transformedData(NULL) , _inputDecoders() , _generators() , _currentDecoder(NULL) @@ -167,8 +167,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec()); // buffers to process - _filteredData = VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc()); - _transformedData = VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc()); + _filteredData = new VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc()); + _transformedData = new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc()); // transform _transform = new VideoTransform(); @@ -198,8 +198,8 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu if(inputStreamDesc.demultiplexing()) inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); - _filteredData = AudioFrame(inputFrameDesc); - _transformedData = AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc()); + _filteredData = new AudioFrame(inputFrameDesc); + _transformedData = new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc()); // transform _transform = new AudioTransform(); @@ -232,7 +232,7 @@ void StreamTranscoder::addDecoder(const InputStreamDesc& inputStreamDesc, IInput _generators.push_back(new VideoGenerator()); // buffers to process - _decodedData.push_back(VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc())); + _decodedData.push_back(new VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc())); break; } @@ -252,7 +252,7 @@ void StreamTranscoder::addDecoder(const InputStreamDesc& inputStreamDesc, IInput if(inputStreamDesc.demultiplexing()) inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); - _decodedData.push_back(AudioFrame(inputFrameDesc)); + _decodedData.push_back(new AudioFrame(inputFrameDesc)); break; } @@ -269,8 +269,8 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: , _inputStreams() , _outputStream(NULL) , _decodedData() - , _filteredData() - , _transformedData() + , _filteredData(NULL) + , _transformedData(NULL) , _inputDecoders() , _generators() , _currentDecoder(NULL) @@ -298,9 +298,9 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: // buffers to process VideoFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); - _decodedData.push_back(VideoFrame(inputFrameDesc)); - _filteredData = VideoFrame(inputFrameDesc); - _transformedData = VideoFrame(outputFrameDesc); + _decodedData.push_back(new VideoFrame(inputFrameDesc)); + _filteredData = new VideoFrame(inputFrameDesc); + _transformedData = new VideoFrame(outputFrameDesc); // transform _transform = new VideoTransform(); @@ -331,9 +331,9 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: // buffers to process AudioFrameDesc outputFrameDesc = inputFrameDesc; outputFrameDesc.setParameters(profile); - _decodedData.push_back(AudioFrame(inputFrameDesc)); - _filteredData = AudioFrame(inputFrameDesc); - _transformedData = AudioFrame(outputFrameDesc); + _decodedData.push_back(new AudioFrame(inputFrameDesc)); + _filteredData = new AudioFrame(inputFrameDesc); + _transformedData = new AudioFrame(outputFrameDesc); // transform _transform = new AudioTransform(); @@ -354,6 +354,13 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: StreamTranscoder::~StreamTranscoder() { + for(std::vector::iterator it = _decodedData.begin(); it != _decodedData.end(); ++it) + { + delete(*it); + } + delete _filteredData; + delete _transformedData; + for(std::vector::iterator it = _inputDecoders.begin(); it != _inputDecoders.end(); ++it) { delete(*it); @@ -510,22 +517,22 @@ bool StreamTranscoder::processTranscode() for(size_t index = 0; index < _inputDecoders.size(); ++index) { if(! _inputStreamDesc.empty() && _inputStreamDesc.at(index).demultiplexing()) - decodingStatus = decodingStatus && _currentDecoder->decodeNextFrame(_decodedData.at(index), _inputStreamDesc.at(index)._channelIndexArray); + decodingStatus = decodingStatus && _currentDecoder->decodeNextFrame(*_decodedData.at(index), _inputStreamDesc.at(index)._channelIndexArray); else - decodingStatus = decodingStatus && _currentDecoder->decodeNextFrame(_decodedData.at(index)); + decodingStatus = decodingStatus && _currentDecoder->decodeNextFrame(*_decodedData.at(index)); } CodedData data; if(decodingStatus) { LOG_DEBUG("Filtering") - _filterGraph->process(_decodedData, _filteredData); + _filterGraph->process(_decodedData, *_filteredData); LOG_DEBUG("Convert") - _transform->convert(_filteredData, _transformedData); + _transform->convert(*_filteredData, *_transformedData); LOG_DEBUG("Encode") - _outputEncoder->encodeFrame(_transformedData, data); + _outputEncoder->encodeFrame(*_transformedData, data); } else { diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 1349c26a..729d4c08 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -133,9 +133,9 @@ class AvExport StreamTranscoder std::vector _inputStreams; ///< List of input stream to read next packet (has link, no ownership) IOutputStream* _outputStream; ///< Output stream to wrap next packet (has link, no ownership) - std::vector _decodedData; ///< List of buffers of decoded data. - Frame _filteredData; ///< Buffer of filtered data. - Frame _transformedData; ///< Buffer of transformed data. + std::vector _decodedData; ///< List of buffers of decoded data (has ownership). + Frame* _filteredData; ///< Buffer of filtered data (has ownership). + Frame* _transformedData; ///< Buffer of transformed data (has ownership). std::vector _inputDecoders; ///< Decoders of packets read from _inputStream (has ownership) std::vector _generators; ///< Generators of audio or video packets (has ownership) From 44f62ace60a02f09f9df9d05fd39e26ab20d6756 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 14:48:41 +0200 Subject: [PATCH 17/43] StreamTranscoder: fixed getProcessCase in case of transcoding The _currentDecoder could be one of the decoder in the _inputDecoders list. --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index c7631fff..65a7c8a8 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace avtranscoder { @@ -633,7 +634,7 @@ void StreamTranscoder::setOffset(const float offset) StreamTranscoder::EProcessCase StreamTranscoder::getProcessCase() const { - if(! _inputStreams.empty() && ! _inputDecoders.empty() && _inputDecoders.at(0) == _currentDecoder) + if(! _inputStreams.empty() && ! _inputDecoders.empty() && std::find(_inputDecoders.begin(), _inputDecoders.end(), _currentDecoder) != _inputDecoders.end() ) return eProcessCaseTranscode; else if(! _inputStreams.empty() && _inputDecoders.empty() && !_currentDecoder) return eProcessCaseRewrap; From 6a62a212f674e34b9967c0296301c7b81d971e86 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 15:05:14 +0200 Subject: [PATCH 18/43] Transcoder: updated how to get profile from a file * Renamed private method 'getProfileFromFile' to 'getProfileFromInput'. * Removed private method 'addTranscodeStream'. --- src/AvTranscoder/transcoder/Transcoder.cpp | 48 ++++++++++------------ src/AvTranscoder/transcoder/Transcoder.hpp | 8 ++-- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 15928fe3..e9d53838 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -48,7 +48,10 @@ void Transcoder::addStream(const InputStreamDesc& inputStreamDesc, const std::st addRewrapStream(inputStreamDesc, offset); // Transcode (transparent for the user) else - addTranscodeStream(inputStreamDesc, offset); + { + const ProfileLoader::Profile profile = getProfileFromInput(inputStreamDesc); + addStream(inputStreamDesc, profile, offset); + } } // Transcode else @@ -203,24 +206,6 @@ void Transcoder::addRewrapStream(const InputStreamDesc& inputStreamDesc, const f _streamTranscoders.push_back(_streamTranscodersAllocated.back()); } -void Transcoder::addTranscodeStream(const InputStreamDesc& inputStreamDesc, const float offset) -{ - // Get profile from input file - InputFile inputFile(inputStreamDesc._filename); - ProfileLoader::Profile profile = getProfileFromFile(inputFile, inputStreamDesc._streamIndex); - - // override number of channels parameters to manage demultiplexing - if(inputStreamDesc.demultiplexing()) - { - // number of channels - std::stringstream ss; - ss << inputStreamDesc._channelIndexArray.size(); - profile[constants::avProfileChannel] = ss.str(); - } - - addTranscodeStream(inputStreamDesc, profile, offset); -} - void Transcoder::addTranscodeStream(const InputStreamDesc& inputStreamDesc, const ProfileLoader::Profile& profile, const float offset) { @@ -296,12 +281,14 @@ InputFile* Transcoder::addInputFile(const std::string& filename, const int strea return referenceFile; } -ProfileLoader::Profile Transcoder::getProfileFromFile(InputFile& inputFile, const size_t streamIndex) -{ - const StreamProperties* streamProperties = &inputFile.getProperties().getStreamPropertiesWithIndex(streamIndex); +ProfileLoader::Profile Transcoder::getProfileFromInput(const InputStreamDesc& inputStreamDesc) +{ + InputFile inputFile(inputStreamDesc._filename); + + const StreamProperties* streamProperties = &inputFile.getProperties().getStreamPropertiesWithIndex(inputStreamDesc._streamIndex); const VideoProperties* videoProperties = NULL; const AudioProperties* audioProperties = NULL; - switch(inputFile.getStream(streamIndex).getProperties().getStreamType()) + switch(inputFile.getStream(inputStreamDesc._streamIndex).getProperties().getStreamType()) { case AVMEDIA_TYPE_VIDEO: { @@ -343,9 +330,18 @@ ProfileLoader::Profile Transcoder::getProfileFromFile(InputFile& inputFile, cons std::stringstream ss; ss << audioProperties->getSampleRate(); profile[constants::avProfileSampleRate] = ss.str(); - ss.str(""); - ss << audioProperties->getNbChannels(); - profile[constants::avProfileChannel] = ss.str(); + ss.str(""); + // override number of channels parameters to manage demultiplexing + if(inputStreamDesc.demultiplexing()) + { + ss << inputStreamDesc._channelIndexArray.size(); + profile[constants::avProfileChannel] = ss.str(); + } + else + { + ss << audioProperties->getNbChannels(); + profile[constants::avProfileChannel] = ss.str(); + } } return profile; diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index 0fc94c92..15429935 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -129,8 +129,6 @@ class AvExport Transcoder private: void addRewrapStream(const InputStreamDesc& inputStreamDesc, const float offset); - - void addTranscodeStream(const InputStreamDesc& inputStreamDesc, const float offset); void addTranscodeStream(const InputStreamDesc& inputStreamDesc, const ProfileLoader::Profile& profile, const float offset = 0); @@ -139,8 +137,10 @@ class AvExport Transcoder */ InputFile* addInputFile(const std::string& filename, const int streamIndex, const float offset); - ProfileLoader::Profile getProfileFromFile(InputFile& inputFile, - const size_t streamIndex); ///< The function analyses the inputFile + /** + * @return The profile from the given input. + */ + ProfileLoader::Profile getProfileFromInput(const InputStreamDesc& inputStreamDesc); /** * @brief Get the duration of the stream, in seconds From b81e1984647bc1ba99521b8718af151320bc4349 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 15:35:28 +0200 Subject: [PATCH 19/43] transcoder: added methods to transcode several inputs to one output stream --- .../transcoder/StreamTranscoder.cpp | 27 +++++++---- .../transcoder/StreamTranscoder.hpp | 5 ++- src/AvTranscoder/transcoder/Transcoder.cpp | 45 +++++++++---------- src/AvTranscoder/transcoder/Transcoder.hpp | 8 +++- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 65a7c8a8..b0ecf05a 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -126,10 +126,10 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu setOffset(offset); } -StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInputStream& inputStream, IOutputFile& outputFile, +StreamTranscoder::StreamTranscoder(const std::vector& inputStreamsDesc, std::vector& inputStreams, IOutputFile& outputFile, const ProfileLoader::Profile& profile, const float offset) - : _inputStreamDesc() - , _inputStreams() + : _inputStreamDesc(inputStreamsDesc) + , _inputStreams(inputStreams) , _outputStream(NULL) , _decodedData() , _filteredData(NULL) @@ -143,10 +143,16 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu , _offset(offset) , _needToSwitchToGenerator(false) { - _inputStreamDesc.push_back(inputStreamDesc); - _inputStreams.push_back(&inputStream); + // add as many decoders as input streams + size_t nbOutputChannels = 0; + for(size_t index = 0; index < inputStreams.size(); ++index) + { + addDecoder(_inputStreamDesc.at(index), *_inputStreams.at(index)); + nbOutputChannels += _inputStreamDesc.at(index)._channelIndexArray.size(); + } - addDecoder(inputStreamDesc, inputStream); + IInputStream& inputStream = *_inputStreams.at(0); + const InputStreamDesc& inputStreamDesc = inputStreamsDesc.at(0); // create a transcode case switch(inputStream.getProperties().getStreamType()) @@ -168,7 +174,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu _outputStream = &outputFile.addVideoStream(outputVideo->getVideoCodec()); // buffers to process - _filteredData = new VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc()); + _filteredData = new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc()); _transformedData = new VideoFrame(outputVideo->getVideoCodec().getVideoFrameDesc()); // transform @@ -180,6 +186,9 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu { // filter _filterGraph = new FilterGraph(inputStream.getAudioCodec()); + // merge two or more audio streams into a single multi-channel stream. + if(inputStreams.size() > 1) + _filterGraph->addFilter("amerge"); // output encoder AudioEncoder* outputAudio = new AudioEncoder(profile.at(constants::avProfileCodec)); @@ -188,7 +197,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu AudioFrameDesc outputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); outputFrameDesc.setParameters(profile); if(inputStreamDesc.demultiplexing()) - outputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); + outputFrameDesc._nbChannels = nbOutputChannels; outputAudio->setupAudioEncoder(outputFrameDesc, profile); // output stream @@ -197,7 +206,7 @@ StreamTranscoder::StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInpu // buffers to process AudioFrameDesc inputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); if(inputStreamDesc.demultiplexing()) - inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); + inputFrameDesc._nbChannels = nbOutputChannels; _filteredData = new AudioFrame(inputFrameDesc); _transformedData = new AudioFrame(outputAudio->getAudioCodec().getAudioFrameDesc()); diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 729d4c08..623fea8c 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -33,9 +33,10 @@ class AvExport StreamTranscoder StreamTranscoder(IInputStream& inputStream, IOutputFile& outputFile, const float offset = 0); /** - * @brief Transcode the given stream. + * @brief Transcode the given streams. + * @note The data are wrapped to one output stream. **/ - StreamTranscoder(const InputStreamDesc& inputStreamDesc, IInputStream& inputStream, IOutputFile& outputFile, + StreamTranscoder(const std::vector& inputStreamsDesc, std::vector& inputStreams, IOutputFile& outputFile, const ProfileLoader::Profile& profile, const float offset = 0); /** diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index e9d53838..73487bc6 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -67,7 +67,14 @@ void Transcoder::addStream(const InputStreamDesc& inputStreamDesc, const Profile if(!inputStreamDesc._filename.length()) throw std::runtime_error("Can't transcode a stream without a filename indicated."); - addTranscodeStream(inputStreamDesc, profile, offset); + std::vector inputStreamDescArray; + inputStreamDescArray.push_back(inputStreamDesc); + addStream(inputStreamDescArray, profile, offset); +} + +void Transcoder::addStream(const std::vector& inputStreamDescArray, const ProfileLoader::Profile& profile, const float offset) +{ + addTranscodeStream(inputStreamDescArray, profile, offset); } void Transcoder::addGeneratedStream(const std::string& encodingProfileName) @@ -206,39 +213,31 @@ void Transcoder::addRewrapStream(const InputStreamDesc& inputStreamDesc, const f _streamTranscoders.push_back(_streamTranscodersAllocated.back()); } -void Transcoder::addTranscodeStream(const InputStreamDesc& inputStreamDesc, const ProfileLoader::Profile& profile, +void Transcoder::addTranscodeStream(const std::vector& inputStreamDescArray, const ProfileLoader::Profile& profile, const float offset) { // Add profile if(!_profileLoader.hasProfile(profile)) _profileLoader.loadProfile(profile); - LOG_INFO("Add transcode stream from " << inputStreamDesc << "with encodingProfile=" - << profile.at(constants::avProfileIdentificatorHuman) << std::endl + std::stringstream sources; + for(size_t index = 0; index < inputStreamDescArray.size(); ++index) + sources << inputStreamDescArray.at(index); + LOG_INFO("Add transcode stream from the following inputs:" << std::endl << sources.str() + << "with encodingProfile=" << profile.at(constants::avProfileIdentificatorHuman) << std::endl << "and offset=" << offset << "s") // Add input file - InputFile* referenceFile = addInputFile(inputStreamDesc._filename, inputStreamDesc._streamIndex, offset); - IInputStream& inputStream = referenceFile->getStream(inputStreamDesc._streamIndex); - - switch(inputStream.getProperties().getStreamType()) + std::vector inputStreams; + for(std::vector::const_iterator it = inputStreamDescArray.begin(); it != inputStreamDescArray.end(); ++it) { - case AVMEDIA_TYPE_VIDEO: - case AVMEDIA_TYPE_AUDIO: - { - _streamTranscodersAllocated.push_back( - new StreamTranscoder(inputStreamDesc, inputStream, _outputFile, profile, offset)); - _streamTranscoders.push_back(_streamTranscodersAllocated.back()); - break; - } - case AVMEDIA_TYPE_DATA: - case AVMEDIA_TYPE_SUBTITLE: - case AVMEDIA_TYPE_ATTACHMENT: - default: - { - throw std::runtime_error("unsupported media type in transcode setup"); - } + InputFile* referenceFile = addInputFile(it->_filename, it->_streamIndex, offset); + inputStreams.push_back(&referenceFile->getStream(it->_streamIndex)); } + + _streamTranscodersAllocated.push_back( + new StreamTranscoder(inputStreamDescArray, inputStreams, _outputFile, profile, offset)); + _streamTranscoders.push_back(_streamTranscodersAllocated.back()); } InputFile* Transcoder::addInputFile(const std::string& filename, const int streamIndex, const float offset) diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index 15429935..b686c137 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -65,6 +65,12 @@ class AvExport Transcoder void addStream(const InputStreamDesc& inputStreamDesc, const ProfileLoader::Profile& profile, const float offset = 0); //@} + //@{ + // @brief Add a new stream to the output file, created from the given input description to process. + // @param inputStreamDescArray: the type of the described streams should be of the same type. + void addStream(const std::vector& inputStreamDescArray, const ProfileLoader::Profile& profile, const float offset = 0); + //@} + //@{ // @brief Add a new generated stream to the output file, created from the given encoding profile. void addGeneratedStream(const std::string& encodingProfileName); @@ -129,7 +135,7 @@ class AvExport Transcoder private: void addRewrapStream(const InputStreamDesc& inputStreamDesc, const float offset); - void addTranscodeStream(const InputStreamDesc& inputStreamDesc, const ProfileLoader::Profile& profile, + void addTranscodeStream(const std::vector& inputStreamDescArray, const ProfileLoader::Profile& profile, const float offset = 0); /** From 19663c361664e0a2cc2a41cc08d0720f5b70271d Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 16:13:54 +0200 Subject: [PATCH 20/43] ProfileLoader: renamed 'loadProfile' methods to 'addProfile' --- src/AvTranscoder/profile/ProfileLoader.cpp | 12 ++++++------ src/AvTranscoder/profile/ProfileLoader.hpp | 12 ++++++------ src/AvTranscoder/transcoder/Transcoder.cpp | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/AvTranscoder/profile/ProfileLoader.cpp b/src/AvTranscoder/profile/ProfileLoader.cpp index d73fe252..c9d7e2d3 100644 --- a/src/AvTranscoder/profile/ProfileLoader.cpp +++ b/src/AvTranscoder/profile/ProfileLoader.cpp @@ -12,10 +12,10 @@ namespace avtranscoder ProfileLoader::ProfileLoader(const bool autoload) { if(autoload) - loadProfiles(); + addProfiles(); } -void ProfileLoader::loadProfile(const std::string& avProfileFileName) +void ProfileLoader::addProfile(const std::string& avProfileFileName) { std::ifstream infile; infile.open(avProfileFileName.c_str(), std::ifstream::in); @@ -30,10 +30,10 @@ void ProfileLoader::loadProfile(const std::string& avProfileFileName) if(keyValue.size() == 2) customProfile[keyValue.at(0)] = keyValue.at(1); } - loadProfile(customProfile); + addProfile(customProfile); } -void ProfileLoader::loadProfiles(const std::string& avProfilesPath) +void ProfileLoader::addProfiles(const std::string& avProfilesPath) { std::string realAvProfilesPath = avProfilesPath; if(realAvProfilesPath.empty()) @@ -59,7 +59,7 @@ void ProfileLoader::loadProfiles(const std::string& avProfilesPath) const std::string absPath = (*dirIt) + "/" + (*fileIt); try { - loadProfile(absPath); + addProfile(absPath); } catch(const std::exception& e) { @@ -69,7 +69,7 @@ void ProfileLoader::loadProfiles(const std::string& avProfilesPath) } } -void ProfileLoader::loadProfile(const Profile& profile) +void ProfileLoader::addProfile(const Profile& profile) { // check profile identificator if(!profile.count(constants::avProfileIdentificator)) diff --git a/src/AvTranscoder/profile/ProfileLoader.hpp b/src/AvTranscoder/profile/ProfileLoader.hpp index 6670e69e..fb87ca87 100644 --- a/src/AvTranscoder/profile/ProfileLoader.hpp +++ b/src/AvTranscoder/profile/ProfileLoader.hpp @@ -45,21 +45,21 @@ class AvExport ProfileLoader ProfileLoader(const bool autoload = true); /** - * @brief Load profiles from files in avProfilesPath directory + * @brief Add profiles from files in avProfilesPath directory * @param avProfilesPath: if empty, the path is replaced by value of AVPROFILES environment variable */ - void loadProfiles(const std::string& avProfilesPath = ""); + void addProfiles(const std::string& avProfilesPath = ""); /** - * @brief Load the profile defines in the given file + * @brief Add the profile defines in the given file */ - void loadProfile(const std::string& avProfileFileName); + void addProfile(const std::string& avProfileFileName); /** - * @brief Load the given profile + * @brief Add the given profile * @exception throw std::runtime_error if the profile is invalid */ - void loadProfile(const Profile& profile); + void addProfile(const Profile& profile); bool hasProfile(const Profile& profile) const; diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 73487bc6..acee0d25 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -87,7 +87,7 @@ void Transcoder::addGeneratedStream(const ProfileLoader::Profile& encodingProfil { // Add profile if(!_profileLoader.hasProfile(encodingProfile)) - _profileLoader.loadProfile(encodingProfile); + _profileLoader.addProfile(encodingProfile); LOG_INFO("Add generated stream with encodingProfile=" << encodingProfile.at(constants::avProfileIdentificatorHuman)) @@ -218,7 +218,7 @@ void Transcoder::addTranscodeStream(const std::vector& inputStr { // Add profile if(!_profileLoader.hasProfile(profile)) - _profileLoader.loadProfile(profile); + _profileLoader.addProfile(profile); std::stringstream sources; for(size_t index = 0; index < inputStreamDescArray.size(); ++index) From 72e6d5b22db6eedfe227522d8320d9f947b5e1bd Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 16:35:35 +0200 Subject: [PATCH 21/43] FilterGraph: fixed memory deallocation refFrame method allocates new data that will be freed by calling clear method or the destructor of the referenced frame. --- src/AvTranscoder/data/decoded/Frame.hpp | 3 ++- src/AvTranscoder/filter/FilterGraph.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AvTranscoder/data/decoded/Frame.hpp b/src/AvTranscoder/data/decoded/Frame.hpp index 780861a4..53d5ce00 100644 --- a/src/AvTranscoder/data/decoded/Frame.hpp +++ b/src/AvTranscoder/data/decoded/Frame.hpp @@ -64,7 +64,8 @@ class AvExport Frame /** * @brief Copy frame properties and create a new reference to data of the given frame. - * @warning This method allocates new data that will be freed only by calling the destructor of the referenced frame. + * @warning This method allocates new data that will be freed by calling clear method or the destructor of the referenced frame. + * @see clear */ void refFrame(const Frame& otherFrame); diff --git a/src/AvTranscoder/filter/FilterGraph.cpp b/src/AvTranscoder/filter/FilterGraph.cpp index f2a9bd51..c629c81d 100644 --- a/src/AvTranscoder/filter/FilterGraph.cpp +++ b/src/AvTranscoder/filter/FilterGraph.cpp @@ -40,6 +40,7 @@ void FilterGraph::process(const std::vector& inputs, Frame& output) if(!hasFilters()) { LOG_DEBUG("No filter to process: reference first input frame to the given output.") + output.clear(); output.refFrame(*inputs.at(0)); return; } From e623e29b8221043b4c6a4f04a6dbca5af171f6f0 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 16:46:29 +0200 Subject: [PATCH 22/43] StreamTranscoder: fixed transcode in case of generator Avoid switching if the current case is a generator. --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 3 +++ src/AvTranscoder/transcoder/StreamTranscoder.hpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index b0ecf05a..72e0a5db 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -526,6 +526,9 @@ bool StreamTranscoder::processTranscode() bool decodingStatus = true; for(size_t index = 0; index < _inputDecoders.size(); ++index) { + if(getProcessCase() == eProcessCaseTranscode) + _currentDecoder = _inputDecoders.at(index); + if(! _inputStreamDesc.empty() && _inputStreamDesc.at(index).demultiplexing()) decodingStatus = decodingStatus && _currentDecoder->decodeNextFrame(*_decodedData.at(index), _inputStreamDesc.at(index)._channelIndexArray); else diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.hpp b/src/AvTranscoder/transcoder/StreamTranscoder.hpp index 623fea8c..4dceff17 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.hpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.hpp @@ -60,7 +60,7 @@ class AvExport StreamTranscoder bool processFrame(); //@{ - /** Switch decoder */ + // Switch current decoder. void switchToGeneratorDecoder(); void switchToInputDecoder(); //@} From 27a65ac9aa2f94b55694e61f690acf60b1edb834 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 17:01:24 +0200 Subject: [PATCH 23/43] AudioDecoder: fixed channel layout value after decoding After calling 'avcodec_decode_audio4', sometimes the channel layout of the frame is set to 0. I could be a problem in the next steps of the process. --- src/AvTranscoder/decoder/AudioDecoder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/AvTranscoder/decoder/AudioDecoder.cpp b/src/AvTranscoder/decoder/AudioDecoder.cpp index 99d6a8a6..8d0490e7 100644 --- a/src/AvTranscoder/decoder/AudioDecoder.cpp +++ b/src/AvTranscoder/decoder/AudioDecoder.cpp @@ -78,6 +78,7 @@ void AudioDecoder::setupDecoder(const ProfileLoader::Profile& profile) bool AudioDecoder::decodeNextFrame(Frame& frameBuffer) { bool decodeNextFrame = false; + const size_t channelLayout = frameBuffer.getAVFrame().channel_layout; if(!_isSetup) setupDecoder(); @@ -100,6 +101,9 @@ bool AudioDecoder::decodeNextFrame(Frame& frameBuffer) throw std::runtime_error("An error occurred during audio decoding: " + getDescriptionFromErrorCode(ret)); } + // fixed channel layout value after decoding + frameBuffer.getAVFrame().channel_layout = channelLayout; + // if no frame could be decompressed if(!nextPacketRead && ret == 0 && got_frame == 0) decodeNextFrame = false; From 2d066751880fc80c80dc0dfa9820f289f7dc6e91 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 17:25:53 +0200 Subject: [PATCH 24/43] StreamTranscoder: fixed amerge option if there are more than 2 inputs 2 inputs is the default value for this filter. --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 72e0a5db..97ff2c86 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -188,7 +188,11 @@ StreamTranscoder::StreamTranscoder(const std::vector& inputStre _filterGraph = new FilterGraph(inputStream.getAudioCodec()); // merge two or more audio streams into a single multi-channel stream. if(inputStreams.size() > 1) - _filterGraph->addFilter("amerge"); + { + std::stringstream mergeOptions; + mergeOptions << "inputs=" << inputStreams.size(); + _filterGraph->addFilter("amerge", mergeOptions.str()); + } // output encoder AudioEncoder* outputAudio = new AudioEncoder(profile.at(constants::avProfileCodec)); From 41ca62069876bbd8d072dafb790836fce5b8c03d Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 17:27:19 +0200 Subject: [PATCH 25/43] Transcoder: added addStream method to add several inputs and handle the profile as a string --- src/AvTranscoder/transcoder/Transcoder.cpp | 6 ++++++ src/AvTranscoder/transcoder/Transcoder.hpp | 1 + 2 files changed, 7 insertions(+) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index acee0d25..9c17bd0f 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -72,6 +72,12 @@ void Transcoder::addStream(const InputStreamDesc& inputStreamDesc, const Profile addStream(inputStreamDescArray, profile, offset); } +void Transcoder::addStream(const std::vector& inputStreamDescArray, const std::string& profileName, const float offset) +{ + const ProfileLoader::Profile& encodingProfile = _profileLoader.getProfile(profileName); + addStream(inputStreamDescArray, encodingProfile, offset); +} + void Transcoder::addStream(const std::vector& inputStreamDescArray, const ProfileLoader::Profile& profile, const float offset) { addTranscodeStream(inputStreamDescArray, profile, offset); diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index b686c137..e112e1cd 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -68,6 +68,7 @@ class AvExport Transcoder //@{ // @brief Add a new stream to the output file, created from the given input description to process. // @param inputStreamDescArray: the type of the described streams should be of the same type. + void addStream(const std::vector& inputStreamDescArray, const std::string& profileName, float offset = 0); void addStream(const std::vector& inputStreamDescArray, const ProfileLoader::Profile& profile, const float offset = 0); //@} From 736e17fe0db0cf8fcb1d607b51a03fe65d9ba401 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 17:31:44 +0200 Subject: [PATCH 26/43] pyTest: added testAddSeveralInputsToCreateOneOutput Added vector in the SWIG interface. --- src/AvTranscoder/transcoder/transcoder.i | 1 + test/pyTest/testTranscoderAdd.py | 40 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/AvTranscoder/transcoder/transcoder.i b/src/AvTranscoder/transcoder/transcoder.i index 229cd227..5288dcad 100644 --- a/src/AvTranscoder/transcoder/transcoder.i +++ b/src/AvTranscoder/transcoder/transcoder.i @@ -5,6 +5,7 @@ %} %template(StreamTranscoderVector) std::vector< avtranscoder::StreamTranscoder* >; +%template(InputStreamDescVector) std::vector< avtranscoder::InputStreamDesc >; %include %include diff --git a/test/pyTest/testTranscoderAdd.py b/test/pyTest/testTranscoderAdd.py index 2c359aa4..c51906b5 100644 --- a/test/pyTest/testTranscoderAdd.py +++ b/test/pyTest/testTranscoderAdd.py @@ -51,3 +51,43 @@ def testAddAllStreamsOfFileWhichDoesNotExist(): # process transcoder.process() + + +def testAddSeveralInputsToCreateOneOutput(): + """ + Add several audio inputs and create one output stream. + """ + # inputs + inputs = av.InputStreamDescVector() + inputFileName = os.environ['AVTRANSCODER_TEST_AUDIO_WAVE_FILE'] + inputFile = av.InputFile(inputFileName) + src_audioStream = inputFile.getProperties().getAudioProperties()[0] + src_audioStreamIndex = src_audioStream.getStreamIndex() + inputs.append(av.InputStreamDesc(inputFileName, src_audioStreamIndex, (0,1))) + inputs.append(av.InputStreamDesc(inputFileName, src_audioStreamIndex, (2,3))) + inputs.append(av.InputStreamDesc(inputFileName, src_audioStreamIndex, (4,5))) + + # output + outputFileName = "testAddSeveralInputsToCreateOneOutput.mov" + ouputFile = av.OutputFile(outputFileName) + + transcoder = av.Transcoder(ouputFile) + transcoder.addStream(inputs, "wave24b48kstereo") + + # process + processStat = transcoder.process() + + # check process stat returned + audioStat = processStat.getAudioStat(0) + assert_equals(src_audioStream.getDuration(), audioStat.getDuration()) + + # get dst file of transcode + dst_inputFile = av.InputFile(outputFileName) + dst_properties = dst_inputFile.getProperties() + dst_audioStream = dst_properties.getAudioProperties()[0] + + assert_equals( "pcm_s24le", dst_audioStream.getCodecName() ) + assert_equals( "s32", dst_audioStream.getSampleFormatName() ) + assert_equals( "signed 32 bits", dst_audioStream.getSampleFormatLongName() ) + assert_equals( 48000, dst_audioStream.getSampleRate() ) + assert_equals( 2, dst_audioStream.getNbChannels() ) From 383143abc3e249302134458326a25a16523d2ada Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 17:59:06 +0200 Subject: [PATCH 27/43] Transcoder: fixed fillProcessStat in case of generated streams --- src/AvTranscoder/transcoder/Transcoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 9c17bd0f..397a250f 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -464,12 +464,12 @@ void Transcoder::fillProcessStat(ProcessStat& processStat) for(size_t streamIndex = 0; streamIndex < _streamTranscoders.size(); ++streamIndex) { IOutputStream& stream = _streamTranscoders.at(streamIndex)->getOutputStream(); - const IInputStream* inputStream = _streamTranscoders.at(streamIndex)->getInputStreams().at(0); - if(inputStream == NULL) + if(_streamTranscoders.at(streamIndex)->getInputStreams().empty()) { LOG_WARN("Cannot process statistics of generated stream.") continue; } + const IInputStream* inputStream = _streamTranscoders.at(streamIndex)->getInputStreams().at(0); const AVMediaType mediaType = inputStream->getProperties().getStreamType(); switch(mediaType) { From 83bea1a6c6efa570d42addacc49074863996c32f Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 18:02:06 +0200 Subject: [PATCH 28/43] StreamTranscoder: fixed decoding in case of generated stream --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 97ff2c86..4f4915f1 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -528,10 +528,12 @@ bool StreamTranscoder::processTranscode() LOG_DEBUG("Decode next frame") bool decodingStatus = true; - for(size_t index = 0; index < _inputDecoders.size(); ++index) + for(size_t index = 0; index < _generators.size(); ++index) { if(getProcessCase() == eProcessCaseTranscode) _currentDecoder = _inputDecoders.at(index); + else + _currentDecoder = _generators.at(index); if(! _inputStreamDesc.empty() && _inputStreamDesc.at(index).demultiplexing()) decodingStatus = decodingStatus && _currentDecoder->decodeNextFrame(*_decodedData.at(index), _inputStreamDesc.at(index)._channelIndexArray); From 9fd9e9d3b57d6decdef1b00d9a904fe2cf034c3b Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 18:10:14 +0200 Subject: [PATCH 29/43] StreamTranscoder: fixed end of offset in case of rewrap --- src/AvTranscoder/transcoder/StreamTranscoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 4f4915f1..079e0d83 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -448,7 +448,7 @@ bool StreamTranscoder::processFrame() { LOG_INFO("End of positive offset") - if(_inputDecoders.at(0)) + if(! _inputDecoders.empty()) switchToInputDecoder(); else _currentDecoder = NULL; From fe7b3af5323f1b0d037ed6abaf4602fa3c29e8ec Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 18:37:37 +0200 Subject: [PATCH 30/43] pyTest: fixed testSetFrame --- test/pyTest/testSetFrame.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/pyTest/testSetFrame.py b/test/pyTest/testSetFrame.py index 2d5085e0..c1d7008e 100644 --- a/test/pyTest/testSetFrame.py +++ b/test/pyTest/testSetFrame.py @@ -23,7 +23,7 @@ def testSetVideoFrame(): # create transcoder and add a video stream transcoder = av.Transcoder( ouputFile ) - transcoder.addStream( encodingProfile ) + transcoder.addGeneratedStream( encodingProfile ) videoDecoder = transcoder.getStreamTranscoder( 0 ).getCurrentDecoder() # start process @@ -69,7 +69,7 @@ def testSetAudioFrame(): # create transcoder and add a video stream transcoder = av.Transcoder( ouputFile ) - transcoder.addStream( "wave24b48kmono" ) + transcoder.addGeneratedStream( "wave24b48kmono" ) audioDecoder = transcoder.getStreamTranscoder( 0 ).getCurrentDecoder() # start process From 7a8bed3814a283b07301295cf6073f0a0235ade4 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Wed, 20 Jul 2016 18:38:00 +0200 Subject: [PATCH 31/43] pyTest: clean testTranscoderGenerateStream --- test/pyTest/testTranscoderGenerateStream.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/pyTest/testTranscoderGenerateStream.py b/test/pyTest/testTranscoderGenerateStream.py index 89edf87b..6df44e14 100644 --- a/test/pyTest/testTranscoderGenerateStream.py +++ b/test/pyTest/testTranscoderGenerateStream.py @@ -13,8 +13,7 @@ def testTranscodeNoStream(): ouputFile = av.OutputFile( outputFileName ) transcoder = av.Transcoder( ouputFile ) - progress = av.NoDisplayProgress() - transcoder.process( progress ) + transcoder.process() @raises(RuntimeError) From 24f820f39802b0e0258992e91ab0aef973ca2d7f Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 09:50:56 +0200 Subject: [PATCH 32/43] generators: added FrameDesc parameter in constructor * Need to have a description of the given frame buffer when decoding, because the buffer could be invalid (clear at the end of decoding of an other stream). This attribute could be seen as a backup. * Almost a revert of commits 935ed64 and 924bf5b. --- src/AvTranscoder/decoder/AudioGenerator.cpp | 13 ++++++---- src/AvTranscoder/decoder/AudioGenerator.hpp | 3 ++- src/AvTranscoder/decoder/VideoGenerator.cpp | 26 ++++++++++++------- src/AvTranscoder/decoder/VideoGenerator.hpp | 3 ++- src/AvTranscoder/reader/AudioReader.cpp | 12 ++++----- src/AvTranscoder/reader/VideoReader.cpp | 12 ++++----- .../transcoder/StreamTranscoder.cpp | 26 +++++++++---------- 7 files changed, 53 insertions(+), 42 deletions(-) diff --git a/src/AvTranscoder/decoder/AudioGenerator.cpp b/src/AvTranscoder/decoder/AudioGenerator.cpp index d152fdc0..5163aa78 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.cpp +++ b/src/AvTranscoder/decoder/AudioGenerator.cpp @@ -3,14 +3,14 @@ #include #include -#include namespace avtranscoder { -AudioGenerator::AudioGenerator() +AudioGenerator::AudioGenerator(const AudioFrameDesc& frameDesc) : _inputFrame(NULL) , _silent(NULL) + , _frameDesc(frameDesc) { } @@ -23,7 +23,11 @@ bool AudioGenerator::decodeNextFrame(Frame& frameBuffer) { // check the given frame if(! frameBuffer.isAudioFrame()) - throw std::runtime_error("The given frame is not a valid audio frame: allocate a new AVSample to put generated data into it."); + { + LOG_WARN("The given frame to put data is not a valid audio frame: try to reallocate it.") + frameBuffer.clear(); + static_cast(frameBuffer).allocateAVSample(_frameDesc); + } // Check channel layout of the given frame to be able to copy audio data to it. // @see Frame.copyData method @@ -41,8 +45,7 @@ bool AudioGenerator::decodeNextFrame(Frame& frameBuffer) // Generate the silent only once if(!_silent) { - AudioFrame& audioBuffer = static_cast(frameBuffer); - _silent = new AudioFrame(audioBuffer.desc()); + _silent = new AudioFrame(_frameDesc); std::stringstream msg; msg << "Generate a silence with the following features:" << std::endl; diff --git a/src/AvTranscoder/decoder/AudioGenerator.hpp b/src/AvTranscoder/decoder/AudioGenerator.hpp index 7a45564e..0b1d51ec 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.hpp +++ b/src/AvTranscoder/decoder/AudioGenerator.hpp @@ -14,7 +14,7 @@ class AvExport AudioGenerator : public IDecoder AudioGenerator(const AudioGenerator& audioGenerator); public: - AudioGenerator(); + AudioGenerator(const AudioFrameDesc& frameDesc); ~AudioGenerator(); @@ -26,6 +26,7 @@ class AvExport AudioGenerator : public IDecoder private: Frame* _inputFrame; ///< Has link (no ownership) AudioFrame* _silent; ///< The generated silent (has ownership) + const AudioFrameDesc _frameDesc; ///< The description of the given frame buffer when decoding. }; } diff --git a/src/AvTranscoder/decoder/VideoGenerator.cpp b/src/AvTranscoder/decoder/VideoGenerator.cpp index 94febd70..d55db6df 100644 --- a/src/AvTranscoder/decoder/VideoGenerator.cpp +++ b/src/AvTranscoder/decoder/VideoGenerator.cpp @@ -3,14 +3,14 @@ #include #include -#include namespace avtranscoder { -VideoGenerator::VideoGenerator() +VideoGenerator::VideoGenerator(const VideoFrameDesc& frameDesc) : _inputFrame(NULL) , _blackImage(NULL) + , _frameDesc(frameDesc) , _videoTransform() { } @@ -24,7 +24,11 @@ bool VideoGenerator::decodeNextFrame(Frame& frameBuffer) { // check the given frame if(! frameBuffer.isVideoFrame()) - throw std::runtime_error("The given frame is not a valid video frame: allocate a new AVPicture to put generated data into it."); + { + LOG_WARN("The given frame to put data is not a valid video frame: try to reallocate it.") + frameBuffer.clear(); + static_cast(frameBuffer).allocateAVPicture(_frameDesc); + } // Generate black image if(!_inputFrame) @@ -32,17 +36,19 @@ bool VideoGenerator::decodeNextFrame(Frame& frameBuffer) // Generate the black image only once if(!_blackImage) { + // Create the black RGB image + VideoFrameDesc blackDesc(_frameDesc._width, _frameDesc._height, "rgb24"); + _blackImage = new VideoFrame(blackDesc); + const unsigned char fillChar = 0; + _blackImage->assign(fillChar); + std::stringstream msg; msg << "Generate a black image with the following features:" << std::endl; - msg << "width = " << frameBuffer.getAVFrame().width << std::endl; - msg << "height = " << frameBuffer.getAVFrame().height << std::endl; - msg << "pixel format = rgb24" << std::endl; + msg << "width = " << _blackImage->getWidth() << std::endl; + msg << "height = " << _blackImage->getHeight() << std::endl; + msg << "pixel format = " << getPixelFormatName(_blackImage->getPixelFormat()) << std::endl; LOG_INFO(msg.str()) - // Create the black RGB image - _blackImage = new VideoFrame(VideoFrameDesc(frameBuffer.getAVFrame().width, frameBuffer.getAVFrame().height, "rgb24")); - const unsigned char fillChar = 0; - _blackImage->assign(fillChar); } LOG_DEBUG("Copy data of the black image when decode next frame") // Convert the black image to the configuration of the given frame diff --git a/src/AvTranscoder/decoder/VideoGenerator.hpp b/src/AvTranscoder/decoder/VideoGenerator.hpp index 58783b0c..47796daa 100644 --- a/src/AvTranscoder/decoder/VideoGenerator.hpp +++ b/src/AvTranscoder/decoder/VideoGenerator.hpp @@ -15,7 +15,7 @@ class AvExport VideoGenerator : public IDecoder VideoGenerator& operator=(const VideoGenerator& videoGenerator); public: - VideoGenerator(); + VideoGenerator(const VideoFrameDesc& frameDesc); ~VideoGenerator(); bool decodeNextFrame(Frame& frameBuffer); @@ -30,6 +30,7 @@ class AvExport VideoGenerator : public IDecoder private: Frame* _inputFrame; ///< A frame given from outside (has link, no ownership) VideoFrame* _blackImage; ///< The generated RGB black image (has ownership) + const VideoFrameDesc _frameDesc; ///< The description of the given frame buffer when decoding. VideoTransform _videoTransform; ///< To transform data of the back image to the given Frame when decoding. }; } diff --git a/src/AvTranscoder/reader/AudioReader.cpp b/src/AvTranscoder/reader/AudioReader.cpp index d9cc63cd..ea154447 100644 --- a/src/AvTranscoder/reader/AudioReader.cpp +++ b/src/AvTranscoder/reader/AudioReader.cpp @@ -44,12 +44,6 @@ void AudioReader::init() _decoder->setupDecoder(); _currentDecoder = _decoder; - // generator - _generator = new AudioGenerator(); - - // create transform - _transform = new AudioTransform(); - // create src frame _srcFrame = new AudioFrame(_inputFile->getStream(_streamIndex).getAudioCodec().getAudioFrameDesc()); AudioFrame* srcFrame = static_cast(_srcFrame); @@ -57,6 +51,12 @@ void AudioReader::init() _outputSampleRate = srcFrame->getSampleRate(); _outputNbChannels = (_channelIndex == -1) ? srcFrame->getNbChannels() : 1; _dstFrame = new AudioFrame(AudioFrameDesc(_outputSampleRate, _outputNbChannels, _outputSampleFormat)); + + // generator + _generator = new AudioGenerator(srcFrame->desc()); + + // create transform + _transform = new AudioTransform(); } AudioReader::~AudioReader() diff --git a/src/AvTranscoder/reader/VideoReader.cpp b/src/AvTranscoder/reader/VideoReader.cpp index 024d4e7d..98feff89 100644 --- a/src/AvTranscoder/reader/VideoReader.cpp +++ b/src/AvTranscoder/reader/VideoReader.cpp @@ -43,12 +43,6 @@ void VideoReader::init() _decoder->setupDecoder(); _currentDecoder = _decoder; - // generator - _generator = new VideoGenerator(); - - // create transform - _transform = new VideoTransform(); - // create src frame _srcFrame = new VideoFrame(_inputFile->getStream(_streamIndex).getVideoCodec().getVideoFrameDesc()); VideoFrame* srcFrame = static_cast(_srcFrame); @@ -56,6 +50,12 @@ void VideoReader::init() _outputWidth = srcFrame->getWidth(); _outputHeight = srcFrame->getHeight(); _dstFrame = new VideoFrame(VideoFrameDesc(_outputWidth, _outputHeight, getOutputPixelFormat())); + + // generator + _generator = new VideoGenerator(srcFrame->desc()); + + // create transform + _transform = new VideoTransform(); } VideoReader::~VideoReader() diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index 079e0d83..9b72ec49 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -54,7 +54,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu VideoFrameDesc inputFrameDesc(inputStream.getVideoCodec().getVideoFrameDesc()); // generator decoder - _generators.push_back(new VideoGenerator()); + _generators.push_back(new VideoGenerator(inputFrameDesc)); // buffers to process _decodedData.push_back(new VideoFrame(inputFrameDesc)); @@ -90,7 +90,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu AudioFrameDesc inputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); // generator decoder - _generators.push_back(new AudioGenerator()); + _generators.push_back(new AudioGenerator(inputFrameDesc)); // buffers to process _decodedData.push_back(new AudioFrame(inputFrameDesc)); @@ -242,11 +242,12 @@ void StreamTranscoder::addDecoder(const InputStreamDesc& inputStreamDesc, IInput _inputDecoders.push_back(inputVideo); _currentDecoder = inputVideo; - // generator decoder - _generators.push_back(new VideoGenerator()); + // buffers to get the decoded data + VideoFrame* inputFrame = new VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc()); + _decodedData.push_back(inputFrame); - // buffers to process - _decodedData.push_back(new VideoFrame(inputStream.getVideoCodec().getVideoFrameDesc())); + // generator decoder + _generators.push_back(new VideoGenerator(inputFrame->desc())); break; } @@ -258,16 +259,15 @@ void StreamTranscoder::addDecoder(const InputStreamDesc& inputStreamDesc, IInput _inputDecoders.push_back(inputAudio); _currentDecoder = inputAudio; - // generator decoder - _generators.push_back(new AudioGenerator()); - - // buffers to process + // buffers to get the decoded data AudioFrameDesc inputFrameDesc(inputStream.getAudioCodec().getAudioFrameDesc()); if(inputStreamDesc.demultiplexing()) inputFrameDesc._nbChannels = inputStreamDesc._channelIndexArray.size(); - _decodedData.push_back(new AudioFrame(inputFrameDesc)); + // generator decoder + _generators.push_back(new AudioGenerator(inputFrameDesc)); + break; } default: @@ -302,7 +302,7 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: inputVideoCodec.setImageParameters(inputFrameDesc); // generator decoder - VideoGenerator* generator = new VideoGenerator(); + VideoGenerator* generator = new VideoGenerator(inputFrameDesc); _generators.push_back(generator); _currentDecoder = generator; @@ -335,7 +335,7 @@ StreamTranscoder::StreamTranscoder(IOutputFile& outputFile, const ProfileLoader: inputAudioCodec.setAudioParameters(inputFrameDesc); // generator decoder - AudioGenerator* generator = new AudioGenerator(); + AudioGenerator* generator = new AudioGenerator(inputFrameDesc); _generators.push_back(generator); _currentDecoder = generator; From c18072c153e05fc1d2ce25af1efa41700d0f8592 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 12:48:24 +0200 Subject: [PATCH 33/43] Transcoder: refactored how to check string parameters when addStream --- src/AvTranscoder/transcoder/Transcoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 6128cdcb..7d0872ff 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -38,10 +38,10 @@ Transcoder::~Transcoder() void Transcoder::addStream(const InputStreamDesc& inputStreamDesc, const std::string& profileName, const float offset) { // Check filename - if(inputStreamDesc._filename.length() == 0) + if(inputStreamDesc._filename.empty()) throw std::runtime_error("Can't process a stream without a filename indicated."); - if(profileName.length() == 0) + if(profileName.empty()) { // Re-wrap if(!inputStreamDesc.demultiplexing()) From 07469213e503220791c492f92f5329e8821c0f73 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 12:54:50 +0200 Subject: [PATCH 34/43] Transcoder: added possibility to add several inputs without any profile The profile is found from the inputs. --- src/AvTranscoder/transcoder/Transcoder.cpp | 52 +++++++++++++++++----- src/AvTranscoder/transcoder/Transcoder.hpp | 6 ++- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 7d0872ff..b18951c8 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -74,12 +75,26 @@ void Transcoder::addStream(const InputStreamDesc& inputStreamDesc, const Profile void Transcoder::addStream(const std::vector& inputStreamDescArray, const std::string& profileName, const float offset) { - const ProfileLoader::Profile& encodingProfile = _profileLoader.getProfile(profileName); + // Check number of inputs + if(inputStreamDescArray.empty()) + throw std::runtime_error("Need a description of at least one input stream to start the process."); + + // Get encoding profile + ProfileLoader::Profile encodingProfile; + if(profileName.empty()) + encodingProfile = getProfileFromInputs(inputStreamDescArray); + else + encodingProfile = _profileLoader.getProfile(profileName); + addStream(inputStreamDescArray, encodingProfile, offset); } void Transcoder::addStream(const std::vector& inputStreamDescArray, const ProfileLoader::Profile& profile, const float offset) { + // Check number of inputs + if(inputStreamDescArray.empty()) + throw std::runtime_error("Need a description of at least one input stream to start the process."); + addTranscodeStream(inputStreamDescArray, profile, offset); } @@ -287,7 +302,18 @@ InputFile* Transcoder::addInputFile(const std::string& filename, const int strea } ProfileLoader::Profile Transcoder::getProfileFromInput(const InputStreamDesc& inputStreamDesc) -{ +{ + std::vector inputStreamDescArray; + inputStreamDescArray.push_back(inputStreamDesc); + return getProfileFromInputs(inputStreamDescArray); +} + +ProfileLoader::Profile Transcoder::getProfileFromInputs(const std::vector& inputStreamDescArray) +{ + assert(inputStreamDescArray.size() >= 1); + + // Get properties from the first input + const InputStreamDesc& inputStreamDesc = inputStreamDescArray.at(0); InputFile inputFile(inputStreamDesc._filename); const StreamProperties* streamProperties = &inputFile.getProperties().getStreamPropertiesWithIndex(inputStreamDesc._streamIndex); @@ -335,18 +361,22 @@ ProfileLoader::Profile Transcoder::getProfileFromInput(const InputStreamDesc& in std::stringstream ss; ss << audioProperties->getSampleRate(); profile[constants::avProfileSampleRate] = ss.str(); - ss.str(""); + ss.str(""); // override number of channels parameters to manage demultiplexing - if(inputStreamDesc.demultiplexing()) - { - ss << inputStreamDesc._channelIndexArray.size(); - profile[constants::avProfileChannel] = ss.str(); - } - else + size_t nbChannels = 0; + for(std::vector::const_iterator it = inputStreamDescArray.begin(); it != inputStreamDescArray.end(); ++it) { - ss << audioProperties->getNbChannels(); - profile[constants::avProfileChannel] = ss.str(); + if(inputStreamDesc.demultiplexing()) + nbChannels += it->_channelIndexArray.size(); + else + { + InputFile inputFile(it->_filename); + const AudioProperties& audioStream = dynamic_cast(inputFile.getProperties().getStreamPropertiesWithIndex(inputStreamDesc._streamIndex)); + nbChannels += audioStream.getNbChannels(); + } } + ss << nbChannels; + profile[constants::avProfileChannel] = ss.str(); } return profile; diff --git a/src/AvTranscoder/transcoder/Transcoder.hpp b/src/AvTranscoder/transcoder/Transcoder.hpp index e15b92f4..986ce45c 100644 --- a/src/AvTranscoder/transcoder/Transcoder.hpp +++ b/src/AvTranscoder/transcoder/Transcoder.hpp @@ -68,7 +68,8 @@ class AvExport Transcoder //@{ // @brief Add a new stream to the output file, created from the given input description to process. // @param inputStreamDescArray: the type of the described streams should be of the same type. - void addStream(const std::vector& inputStreamDescArray, const std::string& profileName, float offset = 0); + // @param profile: if empty, get the profile from the inputs. + void addStream(const std::vector& inputStreamDescArray, const std::string& profileName = "", float offset = 0); void addStream(const std::vector& inputStreamDescArray, const ProfileLoader::Profile& profile, const float offset = 0); //@} @@ -145,9 +146,10 @@ class AvExport Transcoder InputFile* addInputFile(const std::string& filename, const int streamIndex, const float offset); /** - * @return The profile from the given input. + * @return The profile from the given inputs. */ ProfileLoader::Profile getProfileFromInput(const InputStreamDesc& inputStreamDesc); + ProfileLoader::Profile getProfileFromInputs(const std::vector& inputStreamDescArray); /** * @brief Get the duration of the stream, in seconds From 69604e5e80abb1bb4d223338826683dd9de5febc Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 14:12:30 +0200 Subject: [PATCH 35/43] AudioGenerator: removed check of channel layout when decode next frame This code was never reach, since the previous intructions already check if the frame is a valid audio frame. --- src/AvTranscoder/decoder/AudioGenerator.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/AvTranscoder/decoder/AudioGenerator.cpp b/src/AvTranscoder/decoder/AudioGenerator.cpp index 5163aa78..29ec5dd8 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.cpp +++ b/src/AvTranscoder/decoder/AudioGenerator.cpp @@ -29,16 +29,6 @@ bool AudioGenerator::decodeNextFrame(Frame& frameBuffer) static_cast(frameBuffer).allocateAVSample(_frameDesc); } - // Check channel layout of the given frame to be able to copy audio data to it. - // @see Frame.copyData method - if(frameBuffer.getAVFrame().channel_layout == 0) - { - const size_t channelLayout = av_get_default_channel_layout(frameBuffer.getAVFrame().channels); - LOG_WARN("Channel layout en the audio frame is not set. Set it to '" << channelLayout - << "' to be able to copy silence data.") - av_frame_set_channel_layout(&frameBuffer.getAVFrame(), channelLayout); - } - // Generate silent if(!_inputFrame) { From 0db7c2eab76c999b23c1c3b329d1bce9fe92f601 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 14:24:38 +0200 Subject: [PATCH 36/43] pyTest: updated testAddSeveralInputsToCreateOneOutput Better to check a more complicated case, when the encoding profile is found from the inputs. --- test/pyTest/testTranscoderAdd.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/pyTest/testTranscoderAdd.py b/test/pyTest/testTranscoderAdd.py index c51906b5..38427070 100644 --- a/test/pyTest/testTranscoderAdd.py +++ b/test/pyTest/testTranscoderAdd.py @@ -72,7 +72,7 @@ def testAddSeveralInputsToCreateOneOutput(): ouputFile = av.OutputFile(outputFileName) transcoder = av.Transcoder(ouputFile) - transcoder.addStream(inputs, "wave24b48kstereo") + transcoder.addStream(inputs) # process processStat = transcoder.process() @@ -86,8 +86,8 @@ def testAddSeveralInputsToCreateOneOutput(): dst_properties = dst_inputFile.getProperties() dst_audioStream = dst_properties.getAudioProperties()[0] - assert_equals( "pcm_s24le", dst_audioStream.getCodecName() ) - assert_equals( "s32", dst_audioStream.getSampleFormatName() ) - assert_equals( "signed 32 bits", dst_audioStream.getSampleFormatLongName() ) - assert_equals( 48000, dst_audioStream.getSampleRate() ) - assert_equals( 2, dst_audioStream.getNbChannels() ) + assert_equals( src_audioStream.getCodecName(), dst_audioStream.getCodecName() ) + assert_equals( src_audioStream.getSampleFormatName(), dst_audioStream.getSampleFormatName() ) + assert_equals( src_audioStream.getSampleFormatLongName(), dst_audioStream.getSampleFormatLongName() ) + assert_equals( src_audioStream.getSampleRate(), dst_audioStream.getSampleRate() ) + assert_equals( src_audioStream.getNbChannels(), dst_audioStream.getNbChannels() ) From b9bc00f3cdcda56374fd1a99fe367378de6c0a1f Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 14:26:10 +0200 Subject: [PATCH 37/43] AudioProperties: fixed getChannelLayout If channel_layout attribute is not indicated, the method returns the default channel layout which corresponds to the given number of channels. --- src/AvTranscoder/properties/AudioProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/properties/AudioProperties.cpp b/src/AvTranscoder/properties/AudioProperties.cpp index 5fbb9daf..2ec52828 100644 --- a/src/AvTranscoder/properties/AudioProperties.cpp +++ b/src/AvTranscoder/properties/AudioProperties.cpp @@ -73,7 +73,7 @@ std::string AudioProperties::getChannelLayout() const throw std::runtime_error("unknown codec context"); char buf1[512]; - av_get_channel_layout_string(buf1, sizeof(buf1), -1, _codecContext->channel_layout); + av_get_channel_layout_string(buf1, sizeof(buf1), getNbChannels(), _codecContext->channel_layout); return std::string(buf1); } From 06053fd4fec49c8aa9dd44e70934f2bc61e7d474 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 14:41:18 +0200 Subject: [PATCH 38/43] pyTest: renamed testAddAllStreamsOfFileWhichDoesNotExist To testAddAStreamFromAFileWhichDoesNotExist --- test/pyTest/testTranscoderAdd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/pyTest/testTranscoderAdd.py b/test/pyTest/testTranscoderAdd.py index 38427070..9ce9b8e7 100644 --- a/test/pyTest/testTranscoderAdd.py +++ b/test/pyTest/testTranscoderAdd.py @@ -35,7 +35,7 @@ def testAddStreamTranscoder(): @raises(IOError) -def testAddAllStreamsOfFileWhichDoesNotExist(): +def testAddAStreamFromAFileWhichDoesNotExist(): """ Add all streams from a given file. """ @@ -43,7 +43,7 @@ def testAddAllStreamsOfFileWhichDoesNotExist(): inputFileName = "fileWhichDoesNotExist.mov" # output - outputFileName = "testAddAllStreamsOfFileWhichDoesNotExist.mov" + outputFileName = "testAddAStreamFromAFileWhichDoesNotExist.mov" ouputFile = av.OutputFile( outputFileName ) transcoder = av.Transcoder( ouputFile ) From 2ffb8b81dda158a3fc1109dae3a35b13398c9100 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 14:45:16 +0200 Subject: [PATCH 39/43] pyTest: added a test to check the behavior when adding an empty list of inputs --- test/pyTest/testTranscoderAdd.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/pyTest/testTranscoderAdd.py b/test/pyTest/testTranscoderAdd.py index 9ce9b8e7..c11642f3 100644 --- a/test/pyTest/testTranscoderAdd.py +++ b/test/pyTest/testTranscoderAdd.py @@ -53,6 +53,22 @@ def testAddAStreamFromAFileWhichDoesNotExist(): transcoder.process() +@raises(RuntimeError) +def testEmptyListOfInputs(): + """ + Add an empty list of inputs. + """ + # inputs + inputs = av.InputStreamDescVector() + + # output + outputFileName = "testEmptyListOfInputs.mov" + ouputFile = av.OutputFile(outputFileName) + + transcoder = av.Transcoder(ouputFile) + transcoder.addStream(inputs) + + def testAddSeveralInputsToCreateOneOutput(): """ Add several audio inputs and create one output stream. From dc82a7bebc7a4c34946871efab3753c8b32bdc80 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 14:46:19 +0200 Subject: [PATCH 40/43] Transcoder: fixed rewrap case when we add a list of one input --- src/AvTranscoder/transcoder/Transcoder.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index b18951c8..232a9abd 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -79,6 +79,13 @@ void Transcoder::addStream(const std::vector& inputStreamDescAr if(inputStreamDescArray.empty()) throw std::runtime_error("Need a description of at least one input stream to start the process."); + // If there is one input, switch to an easier case + if(inputStreamDescArray.size() == 1) + { + addStream(inputStreamDescArray.at(0), profileName, offset); + return; + } + // Get encoding profile ProfileLoader::Profile encodingProfile; if(profileName.empty()) From ab34bdef142290d06a2f6eee8e5ce73b0bdb59d9 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 14:47:03 +0200 Subject: [PATCH 41/43] Transcoder: fixed video profile computed from the inputs The width and height should be added as string. --- src/AvTranscoder/transcoder/Transcoder.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 232a9abd..97e6bd53 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -356,8 +356,10 @@ ProfileLoader::Profile Transcoder::getProfileFromInputs(const std::vectorgetFps(); profile[constants::avProfileFrameRate] = ss.str(); - profile[constants::avProfileWidth] = videoProperties->getWidth(); - profile[constants::avProfileHeight] = videoProperties->getHeight(); + ss.str(""); ss << videoProperties->getWidth(); + profile[constants::avProfileWidth] = ss.str(); + ss.str(""); ss << videoProperties->getHeight(); + profile[constants::avProfileHeight] = ss.str(); } // audio else if(audioProperties != NULL) From 21b89b26c37c322f3c372d7169812eb91a05d911 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 15:14:48 +0200 Subject: [PATCH 42/43] PixelProperties: fixed getPixelFormatName with pixel format YUV420P * AV_PIX_FMT_NONE = -1 * YUV420P = 0 --- src/AvTranscoder/properties/PixelProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AvTranscoder/properties/PixelProperties.cpp b/src/AvTranscoder/properties/PixelProperties.cpp index bef52cd4..90428d5d 100644 --- a/src/AvTranscoder/properties/PixelProperties.cpp +++ b/src/AvTranscoder/properties/PixelProperties.cpp @@ -39,7 +39,7 @@ std::string PixelProperties::getPixelName() const std::string PixelProperties::getPixelFormatName() const { - if(!_pixelFormat) + if(_pixelFormat == AV_PIX_FMT_NONE) throw std::runtime_error("unable to find pixel format."); const char* formatName = av_get_pix_fmt_name(_pixelFormat); From f05574bfcf3bf873292fd685c46cf34ef7fdba13 Mon Sep 17 00:00:00 2001 From: Clement Champetier Date: Thu, 21 Jul 2016 15:17:26 +0200 Subject: [PATCH 43/43] Transcoder: added a check of the stream type when adding a list of inputs Added a python test to check this behavior. --- src/AvTranscoder/transcoder/Transcoder.cpp | 17 ++++++++++++++--- test/pyTest/testTranscoderAdd.py | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/AvTranscoder/transcoder/Transcoder.cpp b/src/AvTranscoder/transcoder/Transcoder.cpp index 97e6bd53..fe9d1829 100644 --- a/src/AvTranscoder/transcoder/Transcoder.cpp +++ b/src/AvTranscoder/transcoder/Transcoder.cpp @@ -255,12 +255,21 @@ void Transcoder::addTranscodeStream(const std::vector& inputStr << "with encodingProfile=" << profile.at(constants::avProfileIdentificatorHuman) << std::endl << "and offset=" << offset << "s") - // Add input file + // Create all streams from the given inputs std::vector inputStreams; + AVMediaType commonStreamType = AVMEDIA_TYPE_UNKNOWN; for(std::vector::const_iterator it = inputStreamDescArray.begin(); it != inputStreamDescArray.end(); ++it) { InputFile* referenceFile = addInputFile(it->_filename, it->_streamIndex, offset); inputStreams.push_back(&referenceFile->getStream(it->_streamIndex)); + + // Check stream type + const AVMediaType currentStreamType = referenceFile->getProperties().getStreamPropertiesWithIndex(it->_streamIndex).getStreamType(); + if(commonStreamType == AVMEDIA_TYPE_UNKNOWN) + commonStreamType = currentStreamType; + else if(currentStreamType != commonStreamType) + throw std::runtime_error("All the given inputs should be of the same type (video, audio...)."); + } _streamTranscodersAllocated.push_back( @@ -380,8 +389,10 @@ ProfileLoader::Profile Transcoder::getProfileFromInputs(const std::vector_filename); - const AudioProperties& audioStream = dynamic_cast(inputFile.getProperties().getStreamPropertiesWithIndex(inputStreamDesc._streamIndex)); - nbChannels += audioStream.getNbChannels(); + const StreamProperties& currentStream = inputFile.getProperties().getStreamPropertiesWithIndex(inputStreamDesc._streamIndex); + if(currentStream.getStreamType() != AVMEDIA_TYPE_AUDIO) + throw std::runtime_error("All the given inputs should be audio streams."); + nbChannels += dynamic_cast(currentStream).getNbChannels(); } } ss << nbChannels; diff --git a/test/pyTest/testTranscoderAdd.py b/test/pyTest/testTranscoderAdd.py index c11642f3..bb0efbc5 100644 --- a/test/pyTest/testTranscoderAdd.py +++ b/test/pyTest/testTranscoderAdd.py @@ -69,6 +69,24 @@ def testEmptyListOfInputs(): transcoder.addStream(inputs) +@raises(RuntimeError) +def testAllSeveralInputsWithDifferentType(): + """ + Add one video and one audio to create one output stream. + """ + # inputs + inputs = av.InputStreamDescVector() + inputs.append(av.InputStreamDesc(os.environ['AVTRANSCODER_TEST_AUDIO_MOV_FILE'], 0)) + inputs.append(av.InputStreamDesc(os.environ['AVTRANSCODER_TEST_AUDIO_WAVE_FILE'], 0)) + + # output + outputFileName = "testAllSeveralInputsWithDifferentType.mov" + ouputFile = av.OutputFile(outputFileName) + + transcoder = av.Transcoder(ouputFile) + transcoder.addStream(inputs) + + def testAddSeveralInputsToCreateOneOutput(): """ Add several audio inputs and create one output stream.