Skip to content

Commit 236ebe0

Browse files
committed
Merge pull request #242 from cchampet/fix_decoding
Video/Audio decoding: fix decoding if the reading process failed
2 parents 550e1ff + fd3be2c commit 236ebe0

16 files changed

+97
-99
lines changed

src/AvTranscoder/data/decoded/AudioFrame.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,16 @@ class AvExport AudioFrame : public Frame
6666
void assign(const unsigned char* ptrValue);
6767

6868
private:
69+
/**
70+
* @brief Allocate the audio buffer of the frame.
71+
*/
6972
void allocateAVSample(const AudioFrameDesc& ref);
73+
74+
/**
75+
* @note To allocate new audio buffer if needed.
76+
* @see allocateAVSample
77+
*/
78+
friend class AudioGenerator;
7079
};
7180
}
7281

src/AvTranscoder/data/decoded/Frame.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class AvExport Frame
1818
public:
1919
/**
2020
* @brief Allocate an empty frame.
21+
* @warn This only allocates the AVFrame itself, not the data buffers.
2122
*/
2223
Frame();
2324

src/AvTranscoder/data/decoded/VideoFrame.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,16 @@ class AvExport VideoFrame : public Frame
6666
void assign(const unsigned char* ptrValue);
6767

6868
private:
69+
/**
70+
* @brief Allocate the image buffer of the frame.
71+
*/
6972
void allocateAVPicture(const VideoFrameDesc& desc);
73+
74+
/**
75+
* @note To allocate new image buffer if needed.
76+
* @see allocateAVPicture
77+
*/
78+
friend class VideoGenerator;
7079
};
7180
}
7281

src/AvTranscoder/decoder/AudioDecoder.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,8 @@ bool AudioDecoder::decodeNextFrame(Frame& frameBuffer)
8787
{
8888
CodedData data;
8989

90+
// reading
9091
const bool nextPacketRead = _inputStream->readNextPacket(data);
91-
// if error or end of file
92-
if(!nextPacketRead && !decodeNextFrame)
93-
{
94-
data.clear();
95-
return false;
96-
}
9792

9893
// decoding
9994
// @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)
110105
decodeNextFrame = false;
111106
else
112107
decodeNextFrame = true;
108+
109+
// if no frame read and decompressed
110+
if(!nextPacketRead && !decodeNextFrame)
111+
{
112+
data.clear();
113+
return false;
114+
}
113115
}
114116
return decodeNextFrame;
115117
}

src/AvTranscoder/decoder/AudioGenerator.cpp

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,28 @@
77
namespace avtranscoder
88
{
99

10-
AudioGenerator::AudioGenerator()
10+
AudioGenerator::AudioGenerator(const AudioFrameDesc& frameDesc)
1111
: _inputFrame(NULL)
1212
, _silent(NULL)
13+
, _frameDesc(frameDesc)
1314
{
1415
}
1516

16-
AudioGenerator::AudioGenerator(const AudioGenerator& audioGenerator)
17-
: _inputFrame(NULL)
18-
, _silent(NULL)
19-
{
20-
}
21-
22-
AudioGenerator& AudioGenerator::operator=(const AudioGenerator& audioGenerator)
23-
{
24-
_inputFrame = NULL;
25-
_silent = NULL;
26-
return *this;
27-
}
28-
2917
AudioGenerator::~AudioGenerator()
3018
{
3119
delete _silent;
3220
}
3321

34-
void AudioGenerator::setNextFrame(Frame& inputFrame)
35-
{
36-
_inputFrame = &inputFrame;
37-
}
38-
3922
bool AudioGenerator::decodeNextFrame(Frame& frameBuffer)
4023
{
24+
// check the given frame
25+
if(!frameBuffer.isAudioFrame())
26+
{
27+
LOG_WARN("The given frame is not a valid audio frame: allocate a new AVSample to put generated data into it.");
28+
frameBuffer.clear();
29+
static_cast<AudioFrame&>(frameBuffer).allocateAVSample(_frameDesc);
30+
}
31+
4132
// Check channel layout of the given frame to be able to copy audio data to it.
4233
// @see Frame.copyData method
4334
if(frameBuffer.getAVFrame().channel_layout == 0)

src/AvTranscoder/decoder/AudioGenerator.hpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,24 @@ namespace avtranscoder
99

1010
class AvExport AudioGenerator : public IDecoder
1111
{
12-
public:
13-
AudioGenerator();
14-
AudioGenerator(const AudioGenerator& audioGenerator);
12+
private:
1513
AudioGenerator& operator=(const AudioGenerator& audioGenerator);
14+
AudioGenerator(const AudioGenerator& audioGenerator);
15+
16+
public:
17+
AudioGenerator(const AudioFrameDesc& frameDesc);
1618

1719
~AudioGenerator();
1820

1921
bool decodeNextFrame(Frame& frameBuffer);
2022
bool decodeNextFrame(Frame& frameBuffer, const size_t subStreamIndex);
2123

22-
void setNextFrame(Frame& inputFrame);
24+
void setNextFrame(Frame& inputFrame) { _inputFrame = &inputFrame; }
2325

2426
private:
2527
Frame* _inputFrame; ///< Has link (no ownership)
2628
AudioFrame* _silent; ///< The generated silent (has ownership)
29+
const AudioFrameDesc _frameDesc; ///< The description of the silence (sampleRate, channels...)
2730
};
2831
}
2932

src/AvTranscoder/decoder/IDecoder.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ class AvExport IDecoder
2323
/**
2424
* @brief Decode next frame
2525
* @param frameBuffer: the frame decoded
26+
* @warn the frameBuffer reference belongs to the decoder and is valid only until the
27+
* next call to this function or until closing or flushing the
28+
* decoder. The caller may not write to it.
2629
* @return status of decoding
2730
*/
2831
virtual bool decodeNextFrame(Frame& frameBuffer) = 0;

src/AvTranscoder/decoder/VideoDecoder.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,8 @@ bool VideoDecoder::decodeNextFrame(Frame& frameBuffer)
8585
{
8686
CodedData data;
8787

88+
// reading
8889
const bool nextPacketRead = _inputStream->readNextPacket(data);
89-
// if error or end of file
90-
if(!nextPacketRead && !decodeNextFrame)
91-
{
92-
data.clear();
93-
return false;
94-
}
9590

9691
// decoding
9792
// @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)
108103
decodeNextFrame = false;
109104
else
110105
decodeNextFrame = true;
106+
107+
// if no frame read and decompressed
108+
if(!nextPacketRead && !decodeNextFrame)
109+
{
110+
data.clear();
111+
return false;
112+
}
111113
}
112114
return decodeNextFrame;
113115
}

src/AvTranscoder/decoder/VideoGenerator.cpp

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,28 @@
88
namespace avtranscoder
99
{
1010

11-
VideoGenerator::VideoGenerator()
11+
VideoGenerator::VideoGenerator(const VideoFrameDesc& frameDesc)
1212
: _inputFrame(NULL)
1313
, _blackImage(NULL)
14-
, _frameDesc()
14+
, _frameDesc(frameDesc)
1515
{
1616
}
1717

18-
VideoGenerator::VideoGenerator(const VideoGenerator& videoGenerator)
19-
: _inputFrame(NULL)
20-
, _blackImage(NULL)
21-
, _frameDesc(videoGenerator.getVideoFrameDesc())
22-
{
23-
}
24-
25-
VideoGenerator& VideoGenerator::operator=(const VideoGenerator& videoGenerator)
26-
{
27-
_inputFrame = NULL;
28-
_blackImage = NULL;
29-
_frameDesc = videoGenerator.getVideoFrameDesc();
30-
return *this;
31-
}
32-
3318
VideoGenerator::~VideoGenerator()
3419
{
3520
delete _blackImage;
3621
}
3722

38-
void VideoGenerator::setVideoFrameDesc(const VideoFrameDesc& frameDesc)
39-
{
40-
_frameDesc = frameDesc;
41-
}
42-
43-
void VideoGenerator::setNextFrame(Frame& inputFrame)
44-
{
45-
_inputFrame = &inputFrame;
46-
}
47-
4823
bool VideoGenerator::decodeNextFrame(Frame& frameBuffer)
4924
{
25+
// check the given frame
26+
if(!frameBuffer.isVideoFrame())
27+
{
28+
LOG_WARN("The given frame is not a valid video frame: allocate a new AVPicture to put generated data into it.");
29+
frameBuffer.clear();
30+
static_cast<VideoFrame&>(frameBuffer).allocateAVPicture(_frameDesc);
31+
}
32+
5033
// Generate black image
5134
if(!_inputFrame)
5235
{

src/AvTranscoder/decoder/VideoGenerator.hpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,24 @@ namespace avtranscoder
99

1010
class AvExport VideoGenerator : public IDecoder
1111
{
12-
public:
13-
VideoGenerator();
12+
private:
1413
VideoGenerator(const VideoGenerator& videoGenerator);
1514
VideoGenerator& operator=(const VideoGenerator& videoGenerator);
1615

16+
public:
17+
VideoGenerator(const VideoFrameDesc& frameDesc);
18+
1719
~VideoGenerator();
1820

1921
bool decodeNextFrame(Frame& frameBuffer);
2022
bool decodeNextFrame(Frame& frameBuffer, const size_t channelIndex);
2123

22-
const VideoFrameDesc& getVideoFrameDesc() const { return _frameDesc; }
23-
void setVideoFrameDesc(const VideoFrameDesc& frameDesc);
24-
25-
void setNextFrame(Frame& inputFrame);
24+
void setNextFrame(Frame& inputFrame) { _inputFrame = &inputFrame; }
2625

2726
private:
2827
Frame* _inputFrame; ///< A frame given from outside (has link, no ownership)
2928
VideoFrame* _blackImage; ///< The generated black image (has ownership)
30-
VideoFrameDesc _frameDesc; ///< The description of the black image (width, height...)
29+
const VideoFrameDesc _frameDesc; ///< The description of the black image (width, height...)
3130
};
3231
}
3332

src/AvTranscoder/file/InputFile.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ bool InputFile::readNextPacket(CodedData& data, const size_t streamIndex)
6868
const int ret = av_read_frame(&_formatContext.getAVFormatContext(), &data.getAVPacket());
6969
if(ret < 0) // error or end of file
7070
{
71-
LOG_INFO("No more data to read on file '" << _filename << "' for stream " << streamIndex)
71+
LOG_INFO("Stop reading the next frame of file '" << _filename << "', stream " << streamIndex << " (" << getDescriptionFromErrorCode(ret) << ")")
7272
return false;
7373
}
7474

src/AvTranscoder/reader/AudioReader.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ void AudioReader::init()
4242
// setup decoder
4343
_decoder = new AudioDecoder(_inputFile->getStream(_streamIndex));
4444
_decoder->setupDecoder();
45+
_currentDecoder = _decoder;
4546

4647
// generator
47-
_generator = new AudioGenerator();
48+
_generator = new AudioGenerator(_inputFile->getStream(_streamIndex).getAudioCodec().getAudioFrameDesc());
4849

4950
// create transform
5051
_transform = new AudioTransform();

src/AvTranscoder/reader/IReader.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ IReader::IReader(const std::string& filename, const size_t streamIndex, const in
99
: _inputFile(NULL)
1010
, _streamProperties(NULL)
1111
, _decoder(NULL)
12+
, _generator(NULL)
13+
, _currentDecoder(NULL)
1214
, _srcFrame(NULL)
1315
, _dstFrame(NULL)
1416
, _transform(NULL)
@@ -25,6 +27,8 @@ IReader::IReader(InputFile& inputFile, const size_t streamIndex, const int chann
2527
: _inputFile(&inputFile)
2628
, _streamProperties(NULL)
2729
, _decoder(NULL)
30+
, _generator(NULL)
31+
, _currentDecoder(NULL)
2832
, _srcFrame(NULL)
2933
, _dstFrame(NULL)
3034
, _transform(NULL)
@@ -54,8 +58,7 @@ Frame* IReader::readPrevFrame()
5458

5559
Frame* IReader::readFrameAt(const size_t frame)
5660
{
57-
assert(_decoder != NULL);
58-
assert(_generator != NULL);
61+
assert(_currentDecoder != NULL);
5962
assert(_transform != NULL);
6063
assert(_srcFrame != NULL);
6164
assert(_dstFrame != NULL);
@@ -70,16 +73,17 @@ Frame* IReader::readFrameAt(const size_t frame)
7073
// decode
7174
bool decodingStatus = false;
7275
if(_channelIndex != -1)
73-
decodingStatus = _decoder->decodeNextFrame(*_srcFrame, _channelIndex);
76+
decodingStatus = _currentDecoder->decodeNextFrame(*_srcFrame, _channelIndex);
7477
else
75-
decodingStatus = _decoder->decodeNextFrame(*_srcFrame);
78+
decodingStatus = _currentDecoder->decodeNextFrame(*_srcFrame);
7679
// if decoding failed
7780
if(!decodingStatus)
7881
{
7982
// generate data (ie silence or black)
8083
if(_continueWithGenerator)
8184
{
82-
_generator->decodeNextFrame(*_srcFrame);
85+
_currentDecoder = _generator;
86+
return readFrameAt(frame);
8387
}
8488
// or return NULL
8589
else

src/AvTranscoder/reader/IReader.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class AvExport IReader
6868
const StreamProperties* _streamProperties;
6969
IDecoder* _decoder;
7070
IDecoder* _generator;
71+
IDecoder* _currentDecoder; ///< Link to _inputDecoder or _generator
7172

7273
Frame* _srcFrame;
7374
Frame* _dstFrame;

src/AvTranscoder/reader/VideoReader.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,10 @@ void VideoReader::init()
4141
// setup decoder
4242
_decoder = new VideoDecoder(_inputFile->getStream(_streamIndex));
4343
_decoder->setupDecoder();
44+
_currentDecoder = _decoder;
4445

4546
// generator
46-
VideoGenerator* generator = new VideoGenerator();
47-
generator->setVideoFrameDesc(_inputFile->getStream(_streamIndex).getVideoCodec().getVideoFrameDesc());
48-
_generator = generator;
47+
_generator = new VideoGenerator(_inputFile->getStream(_streamIndex).getVideoCodec().getVideoFrameDesc());
4948

5049
// create transform
5150
_transform = new VideoTransform();

0 commit comments

Comments
 (0)