Skip to content

Video/Audio decoding: fix decoding if the reading process failed #242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Apr 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/AvTranscoder/data/decoded/AudioFrame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
}

Expand Down
1 change: 1 addition & 0 deletions src/AvTranscoder/data/decoded/Frame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
9 changes: 9 additions & 0 deletions src/AvTranscoder/data/decoded/VideoFrame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
}

Expand Down
14 changes: 8 additions & 6 deletions src/AvTranscoder/decoder/AudioDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}
Expand Down
29 changes: 10 additions & 19 deletions src/AvTranscoder/decoder/AudioGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<AudioFrame&>(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)
Expand Down
11 changes: 7 additions & 4 deletions src/AvTranscoder/decoder/AudioGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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...)
};
}

Expand Down
3 changes: 3 additions & 0 deletions src/AvTranscoder/decoder/IDecoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caller may not write into it.

* @return status of decoding
*/
virtual bool decodeNextFrame(Frame& frameBuffer) = 0;
Expand Down
14 changes: 8 additions & 6 deletions src/AvTranscoder/decoder/VideoDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}
Expand Down
37 changes: 10 additions & 27 deletions src/AvTranscoder/decoder/VideoGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<VideoFrame&>(frameBuffer).allocateAVPicture(_frameDesc);
}

// Generate black image
if(!_inputFrame)
{
Expand Down
13 changes: 6 additions & 7 deletions src/AvTranscoder/decoder/VideoGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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...)
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/AvTranscoder/file/InputFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion src/AvTranscoder/reader/AudioReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
14 changes: 9 additions & 5 deletions src/AvTranscoder/reader/IReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/AvTranscoder/reader/IReader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 2 additions & 3 deletions src/AvTranscoder/reader/VideoReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading