diff --git a/src/AvTranscoder/data/decoded/AudioFrame.hpp b/src/AvTranscoder/data/decoded/AudioFrame.hpp index f3a89a17..132d8224 100644 --- a/src/AvTranscoder/data/decoded/AudioFrame.hpp +++ b/src/AvTranscoder/data/decoded/AudioFrame.hpp @@ -66,7 +66,16 @@ class AvExport AudioFrame : public Frame void assign(const unsigned char* ptrValue); private: + /** + * @brief Allocate the audio buffer of the frame. + */ void allocateAVSample(const AudioFrameDesc& ref); + + /** + * @note To allocate new audio buffer if needed. + * @see allocateAVSample + */ + friend class AudioGenerator; }; } diff --git a/src/AvTranscoder/data/decoded/Frame.hpp b/src/AvTranscoder/data/decoded/Frame.hpp index 58a72a3f..aa3e45b1 100644 --- a/src/AvTranscoder/data/decoded/Frame.hpp +++ b/src/AvTranscoder/data/decoded/Frame.hpp @@ -18,6 +18,7 @@ class AvExport Frame public: /** * @brief Allocate an empty frame. + * @warn This only allocates the AVFrame itself, not the data buffers. */ Frame(); diff --git a/src/AvTranscoder/data/decoded/VideoFrame.hpp b/src/AvTranscoder/data/decoded/VideoFrame.hpp index ae9e22f9..eeea4b09 100644 --- a/src/AvTranscoder/data/decoded/VideoFrame.hpp +++ b/src/AvTranscoder/data/decoded/VideoFrame.hpp @@ -66,7 +66,16 @@ class AvExport VideoFrame : public Frame void assign(const unsigned char* ptrValue); private: + /** + * @brief Allocate the image buffer of the frame. + */ void allocateAVPicture(const VideoFrameDesc& desc); + + /** + * @note To allocate new image buffer if needed. + * @see allocateAVPicture + */ + friend class VideoGenerator; }; } diff --git a/src/AvTranscoder/decoder/AudioDecoder.cpp b/src/AvTranscoder/decoder/AudioDecoder.cpp index 9c8695fd..3b20e8bc 100644 --- a/src/AvTranscoder/decoder/AudioDecoder.cpp +++ b/src/AvTranscoder/decoder/AudioDecoder.cpp @@ -87,13 +87,8 @@ bool AudioDecoder::decodeNextFrame(Frame& frameBuffer) { CodedData data; + // reading const bool nextPacketRead = _inputStream->readNextPacket(data); - // if error or end of file - if(!nextPacketRead && !decodeNextFrame) - { - data.clear(); - return false; - } // decoding // @note could be called several times to return the remaining frames (last call with an empty packet) @@ -110,6 +105,13 @@ bool AudioDecoder::decodeNextFrame(Frame& frameBuffer) decodeNextFrame = false; else decodeNextFrame = true; + + // if no frame read and decompressed + if(!nextPacketRead && !decodeNextFrame) + { + data.clear(); + return false; + } } return decodeNextFrame; } diff --git a/src/AvTranscoder/decoder/AudioGenerator.cpp b/src/AvTranscoder/decoder/AudioGenerator.cpp index a50611bb..297ee009 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.cpp +++ b/src/AvTranscoder/decoder/AudioGenerator.cpp @@ -7,37 +7,28 @@ namespace avtranscoder { -AudioGenerator::AudioGenerator() +AudioGenerator::AudioGenerator(const AudioFrameDesc& frameDesc) : _inputFrame(NULL) , _silent(NULL) + , _frameDesc(frameDesc) { } -AudioGenerator::AudioGenerator(const AudioGenerator& audioGenerator) - : _inputFrame(NULL) - , _silent(NULL) -{ -} - -AudioGenerator& AudioGenerator::operator=(const AudioGenerator& audioGenerator) -{ - _inputFrame = NULL; - _silent = NULL; - return *this; -} - AudioGenerator::~AudioGenerator() { delete _silent; } -void AudioGenerator::setNextFrame(Frame& inputFrame) -{ - _inputFrame = &inputFrame; -} - 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); + } + // 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) diff --git a/src/AvTranscoder/decoder/AudioGenerator.hpp b/src/AvTranscoder/decoder/AudioGenerator.hpp index 5c5631ad..e12b2eba 100644 --- a/src/AvTranscoder/decoder/AudioGenerator.hpp +++ b/src/AvTranscoder/decoder/AudioGenerator.hpp @@ -9,21 +9,24 @@ namespace avtranscoder class AvExport AudioGenerator : public IDecoder { -public: - AudioGenerator(); - AudioGenerator(const AudioGenerator& audioGenerator); +private: AudioGenerator& operator=(const AudioGenerator& audioGenerator); + AudioGenerator(const AudioGenerator& audioGenerator); + +public: + AudioGenerator(const AudioFrameDesc& frameDesc); ~AudioGenerator(); bool decodeNextFrame(Frame& frameBuffer); bool decodeNextFrame(Frame& frameBuffer, const size_t subStreamIndex); - void setNextFrame(Frame& inputFrame); + void setNextFrame(Frame& inputFrame) { _inputFrame = &inputFrame; } 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/decoder/IDecoder.hpp b/src/AvTranscoder/decoder/IDecoder.hpp index c9af9148..a373a9be 100644 --- a/src/AvTranscoder/decoder/IDecoder.hpp +++ b/src/AvTranscoder/decoder/IDecoder.hpp @@ -23,6 +23,9 @@ class AvExport IDecoder /** * @brief Decode next frame * @param frameBuffer: the frame decoded + * @warn the frameBuffer reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. * @return status of decoding */ virtual bool decodeNextFrame(Frame& frameBuffer) = 0; diff --git a/src/AvTranscoder/decoder/VideoDecoder.cpp b/src/AvTranscoder/decoder/VideoDecoder.cpp index 5affcb56..51363466 100644 --- a/src/AvTranscoder/decoder/VideoDecoder.cpp +++ b/src/AvTranscoder/decoder/VideoDecoder.cpp @@ -85,13 +85,8 @@ bool VideoDecoder::decodeNextFrame(Frame& frameBuffer) { CodedData data; + // reading const bool nextPacketRead = _inputStream->readNextPacket(data); - // if error or end of file - if(!nextPacketRead && !decodeNextFrame) - { - data.clear(); - return false; - } // decoding // @note could be called several times to return the remaining frames (last call with an empty packet) @@ -108,6 +103,13 @@ bool VideoDecoder::decodeNextFrame(Frame& frameBuffer) decodeNextFrame = false; else decodeNextFrame = true; + + // if no frame read and decompressed + if(!nextPacketRead && !decodeNextFrame) + { + data.clear(); + return false; + } } return decodeNextFrame; } diff --git a/src/AvTranscoder/decoder/VideoGenerator.cpp b/src/AvTranscoder/decoder/VideoGenerator.cpp index 32092077..0d35df0e 100644 --- a/src/AvTranscoder/decoder/VideoGenerator.cpp +++ b/src/AvTranscoder/decoder/VideoGenerator.cpp @@ -8,45 +8,28 @@ namespace avtranscoder { -VideoGenerator::VideoGenerator() +VideoGenerator::VideoGenerator(const VideoFrameDesc& frameDesc) : _inputFrame(NULL) , _blackImage(NULL) - , _frameDesc() + , _frameDesc(frameDesc) { } -VideoGenerator::VideoGenerator(const VideoGenerator& videoGenerator) - : _inputFrame(NULL) - , _blackImage(NULL) - , _frameDesc(videoGenerator.getVideoFrameDesc()) -{ -} - -VideoGenerator& VideoGenerator::operator=(const VideoGenerator& videoGenerator) -{ - _inputFrame = NULL; - _blackImage = NULL; - _frameDesc = videoGenerator.getVideoFrameDesc(); - return *this; -} - VideoGenerator::~VideoGenerator() { delete _blackImage; } -void VideoGenerator::setVideoFrameDesc(const VideoFrameDesc& frameDesc) -{ - _frameDesc = frameDesc; -} - -void VideoGenerator::setNextFrame(Frame& inputFrame) -{ - _inputFrame = &inputFrame; -} - 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); + } + // Generate black image if(!_inputFrame) { diff --git a/src/AvTranscoder/decoder/VideoGenerator.hpp b/src/AvTranscoder/decoder/VideoGenerator.hpp index 888c2c3c..b6a7a556 100644 --- a/src/AvTranscoder/decoder/VideoGenerator.hpp +++ b/src/AvTranscoder/decoder/VideoGenerator.hpp @@ -9,25 +9,24 @@ namespace avtranscoder class AvExport VideoGenerator : public IDecoder { -public: - VideoGenerator(); +private: VideoGenerator(const VideoGenerator& videoGenerator); VideoGenerator& operator=(const VideoGenerator& videoGenerator); +public: + VideoGenerator(const VideoFrameDesc& frameDesc); + ~VideoGenerator(); bool decodeNextFrame(Frame& frameBuffer); bool decodeNextFrame(Frame& frameBuffer, const size_t channelIndex); - const VideoFrameDesc& getVideoFrameDesc() const { return _frameDesc; } - void setVideoFrameDesc(const VideoFrameDesc& frameDesc); - - void setNextFrame(Frame& inputFrame); + 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) - VideoFrameDesc _frameDesc; ///< The description of the black image (width, height...) + const VideoFrameDesc _frameDesc; ///< The description of the black image (width, height...) }; } diff --git a/src/AvTranscoder/file/InputFile.cpp b/src/AvTranscoder/file/InputFile.cpp index 93dcaddb..e20ffd84 100644 --- a/src/AvTranscoder/file/InputFile.cpp +++ b/src/AvTranscoder/file/InputFile.cpp @@ -68,7 +68,7 @@ bool InputFile::readNextPacket(CodedData& data, const size_t streamIndex) const int ret = av_read_frame(&_formatContext.getAVFormatContext(), &data.getAVPacket()); if(ret < 0) // error or end of file { - LOG_INFO("No more data to read on file '" << _filename << "' for stream " << streamIndex) + LOG_INFO("Stop reading the next frame of file '" << _filename << "', stream " << streamIndex << " (" << getDescriptionFromErrorCode(ret) << ")") return false; } diff --git a/src/AvTranscoder/reader/AudioReader.cpp b/src/AvTranscoder/reader/AudioReader.cpp index 9495d8b5..b7b487c4 100644 --- a/src/AvTranscoder/reader/AudioReader.cpp +++ b/src/AvTranscoder/reader/AudioReader.cpp @@ -42,9 +42,10 @@ void AudioReader::init() // setup decoder _decoder = new AudioDecoder(_inputFile->getStream(_streamIndex)); _decoder->setupDecoder(); + _currentDecoder = _decoder; // generator - _generator = new AudioGenerator(); + _generator = new AudioGenerator(_inputFile->getStream(_streamIndex).getAudioCodec().getAudioFrameDesc()); // create transform _transform = new AudioTransform(); diff --git a/src/AvTranscoder/reader/IReader.cpp b/src/AvTranscoder/reader/IReader.cpp index 76bed7ff..c950571e 100644 --- a/src/AvTranscoder/reader/IReader.cpp +++ b/src/AvTranscoder/reader/IReader.cpp @@ -9,6 +9,8 @@ IReader::IReader(const std::string& filename, const size_t streamIndex, const in : _inputFile(NULL) , _streamProperties(NULL) , _decoder(NULL) + , _generator(NULL) + , _currentDecoder(NULL) , _srcFrame(NULL) , _dstFrame(NULL) , _transform(NULL) @@ -25,6 +27,8 @@ IReader::IReader(InputFile& inputFile, const size_t streamIndex, const int chann : _inputFile(&inputFile) , _streamProperties(NULL) , _decoder(NULL) + , _generator(NULL) + , _currentDecoder(NULL) , _srcFrame(NULL) , _dstFrame(NULL) , _transform(NULL) @@ -54,8 +58,7 @@ Frame* IReader::readPrevFrame() Frame* IReader::readFrameAt(const size_t frame) { - assert(_decoder != NULL); - assert(_generator != NULL); + assert(_currentDecoder != NULL); assert(_transform != NULL); assert(_srcFrame != NULL); assert(_dstFrame != NULL); @@ -70,16 +73,17 @@ Frame* IReader::readFrameAt(const size_t frame) // decode bool decodingStatus = false; if(_channelIndex != -1) - decodingStatus = _decoder->decodeNextFrame(*_srcFrame, _channelIndex); + decodingStatus = _currentDecoder->decodeNextFrame(*_srcFrame, _channelIndex); else - decodingStatus = _decoder->decodeNextFrame(*_srcFrame); + decodingStatus = _currentDecoder->decodeNextFrame(*_srcFrame); // if decoding failed if(!decodingStatus) { // generate data (ie silence or black) if(_continueWithGenerator) { - _generator->decodeNextFrame(*_srcFrame); + _currentDecoder = _generator; + return readFrameAt(frame); } // or return NULL else diff --git a/src/AvTranscoder/reader/IReader.hpp b/src/AvTranscoder/reader/IReader.hpp index 8d53b647..696e38d5 100644 --- a/src/AvTranscoder/reader/IReader.hpp +++ b/src/AvTranscoder/reader/IReader.hpp @@ -68,6 +68,7 @@ class AvExport IReader const StreamProperties* _streamProperties; IDecoder* _decoder; IDecoder* _generator; + IDecoder* _currentDecoder; ///< Link to _inputDecoder or _generator Frame* _srcFrame; Frame* _dstFrame; diff --git a/src/AvTranscoder/reader/VideoReader.cpp b/src/AvTranscoder/reader/VideoReader.cpp index 53fc00f1..304a5d22 100644 --- a/src/AvTranscoder/reader/VideoReader.cpp +++ b/src/AvTranscoder/reader/VideoReader.cpp @@ -41,11 +41,10 @@ void VideoReader::init() // setup decoder _decoder = new VideoDecoder(_inputFile->getStream(_streamIndex)); _decoder->setupDecoder(); + _currentDecoder = _decoder; // generator - VideoGenerator* generator = new VideoGenerator(); - generator->setVideoFrameDesc(_inputFile->getStream(_streamIndex).getVideoCodec().getVideoFrameDesc()); - _generator = generator; + _generator = new VideoGenerator(_inputFile->getStream(_streamIndex).getVideoCodec().getVideoFrameDesc()); // create transform _transform = new VideoTransform(); diff --git a/src/AvTranscoder/transcoder/StreamTranscoder.cpp b/src/AvTranscoder/transcoder/StreamTranscoder.cpp index c88870b5..67f3e8a4 100644 --- a/src/AvTranscoder/transcoder/StreamTranscoder.cpp +++ b/src/AvTranscoder/transcoder/StreamTranscoder.cpp @@ -51,9 +51,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu VideoFrameDesc inputFrameDesc(_inputStream->getVideoCodec().getVideoFrameDesc()); // generator decoder - VideoGenerator* generatorVideo = new VideoGenerator(); - generatorVideo->setVideoFrameDesc(inputFrameDesc); - _generator = generatorVideo; + _generator = new VideoGenerator(inputFrameDesc); // buffers to process _sourceBuffer = new VideoFrame(inputFrameDesc); @@ -88,8 +86,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu AudioFrameDesc inputFrameDesc(_inputStream->getAudioCodec().getAudioFrameDesc()); // generator decoder - AudioGenerator* generatorAudio = new AudioGenerator(); - _generator = generatorAudio; + _generator = new AudioGenerator(inputFrameDesc); // buffers to process _sourceBuffer = new AudioFrame(inputFrameDesc); @@ -173,9 +170,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _transform = new VideoTransform(); // generator decoder - VideoGenerator* generatorVideo = new VideoGenerator(); - generatorVideo->setVideoFrameDesc(outputVideo->getVideoCodec().getVideoFrameDesc()); - _generator = generatorVideo; + _generator = new VideoGenerator(outputVideo->getVideoCodec().getVideoFrameDesc()); break; } @@ -218,8 +213,7 @@ StreamTranscoder::StreamTranscoder(IInputStream& inputStream, IOutputFile& outpu _transform = new AudioTransform(); // generator decoder - AudioGenerator* generatorAudio = new AudioGenerator(); - _generator = generatorAudio; + _generator = new AudioGenerator(outputFrameDesc); break; } @@ -249,11 +243,9 @@ StreamTranscoder::StreamTranscoder(const ICodec& inputCodec, IOutputFile& output { if(profile.find(constants::avProfileType)->second == constants::avProfileTypeVideo) { - // generator decoder - VideoGenerator* generatorVideo = new VideoGenerator(); const VideoCodec& inputVideoCodec = static_cast(inputCodec); - generatorVideo->setVideoFrameDesc(inputVideoCodec.getVideoFrameDesc()); - _generator = generatorVideo; + // generator decoder + _generator = new VideoGenerator(inputVideoCodec.getVideoFrameDesc()); _currentDecoder = _generator; // filter @@ -279,10 +271,9 @@ StreamTranscoder::StreamTranscoder(const ICodec& inputCodec, IOutputFile& output } else if(profile.find(constants::avProfileType)->second == constants::avProfileTypeAudio) { - // generator decoder - AudioGenerator* generatorAudio = new AudioGenerator(); const AudioCodec& inputAudioCodec = static_cast(inputCodec); - _generator = generatorAudio; + // generator decoder + _generator = new AudioGenerator(inputAudioCodec.getAudioFrameDesc()); _currentDecoder = _generator; // filter @@ -483,12 +474,12 @@ bool StreamTranscoder::processTranscode(const int subStreamIndex) else decodingStatus = _currentDecoder->decodeNextFrame(*_sourceBuffer, subStreamIndex); - LOG_DEBUG("Filtering") - _filterGraph->process(*_sourceBuffer); - CodedData data; if(decodingStatus) { + LOG_DEBUG("Filtering") + _filterGraph->process(*_sourceBuffer); + LOG_DEBUG("Convert") _transform->convert(*_sourceBuffer, *_frameBuffer);