Skip to content

Commit 6f87435

Browse files
author
Clement Champetier
committed
Video/Audio frames: data buffer needs to be allocated manually
* A data buffer is not allocated by default in the constructor. * Frame is now an abstract class: easier to call allocateData and freeData methods. * Depending on the case, we could manipulate frame with data allocated elsewhere. For example, an empty frame is given to a decoder, which is responsible to allocate and free the data buffers.
1 parent 8635b3b commit 6f87435

File tree

9 files changed

+97
-116
lines changed

9 files changed

+97
-116
lines changed

src/AvTranscoder/data/decoded/AudioFrame.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ void AudioFrameDesc::setParameters(const ProfileLoader::Profile& profile)
3939
_sampleFormat = getAVSampleFormat(profile.find(constants::avProfileSampleFormat)->second.c_str());
4040
}
4141

42-
AudioFrame::AudioFrame(const AudioFrameDesc& ref)
42+
AudioFrame::AudioFrame(const AudioFrameDesc& desc)
4343
: Frame()
4444
{
45-
allocateAVSample(ref);
46-
}
47-
48-
AudioFrame::AudioFrame(const Frame& otherFrame)
49-
: Frame(otherFrame)
50-
{
45+
// Set Frame properties
46+
av_frame_set_sample_rate(_frame, desc._sampleRate);
47+
av_frame_set_channels(_frame, desc._nbChannels);
48+
av_frame_set_channel_layout(_frame, av_get_default_channel_layout(desc._nbChannels));
49+
_frame->format = desc._sampleFormat;
50+
_frame->nb_samples = desc._sampleRate / 25.; // cannot be known before calling avcodec_decode_audio4
5151
}
5252

5353
std::string AudioFrame::getChannelLayoutDesc() const
@@ -59,7 +59,8 @@ std::string AudioFrame::getChannelLayoutDesc() const
5959

6060
AudioFrame::~AudioFrame()
6161
{
62-
freeAVSample();
62+
if(_dataAllocated)
63+
freeData();
6364
}
6465

6566
size_t AudioFrame::getSize() const
@@ -83,19 +84,16 @@ size_t AudioFrame::getSize() const
8384
return size;
8485
}
8586

86-
void AudioFrame::allocateAVSample(const AudioFrameDesc& desc)
87+
void AudioFrame::allocateData()
8788
{
88-
// Set Frame properties
89-
av_frame_set_sample_rate(_frame, desc._sampleRate);
90-
av_frame_set_channels(_frame, desc._nbChannels);
91-
av_frame_set_channel_layout(_frame, av_get_default_channel_layout(desc._nbChannels));
92-
_frame->format = desc._sampleFormat;
93-
_frame->nb_samples = desc._sampleRate / 25.; // cannot be known before calling avcodec_decode_audio4
89+
if(_dataAllocated)
90+
return;
9491

9592
// Allocate data
9693
const int align = 0;
94+
const AVSampleFormat format = static_cast<AVSampleFormat>(_frame->format);
9795
const int ret =
98-
av_samples_alloc(_frame->data, _frame->linesize, _frame->channels, _frame->nb_samples, desc._sampleFormat, align);
96+
av_samples_alloc(_frame->data, _frame->linesize, _frame->channels, _frame->nb_samples, format, align);
9997
if(ret < 0)
10098
{
10199
std::stringstream os;
@@ -104,14 +102,16 @@ void AudioFrame::allocateAVSample(const AudioFrameDesc& desc)
104102
os << "nb channels = " << _frame->channels << ", ";
105103
os << "channel layout = " << av_get_channel_name(_frame->channels) << ", ";
106104
os << "nb samples = " << _frame->nb_samples << ", ";
107-
os << "sample format = " << getSampleFormatName(desc._sampleFormat);
105+
os << "sample format = " << getSampleFormatName(format);
108106
throw std::runtime_error(os.str());
109107
}
108+
_dataAllocated = true;
110109
}
111110

112-
void AudioFrame::freeAVSample()
111+
void AudioFrame::freeData()
113112
{
114113
av_freep(&_frame->data[0]);
114+
_dataAllocated = false;
115115
}
116116

117117
void AudioFrame::assign(const unsigned char value)

src/AvTranscoder/data/decoded/AudioFrame.hpp

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,16 @@ struct AvExport AudioFrameDesc
3636
class AvExport AudioFrame : public Frame
3737
{
3838
public:
39+
AudioFrame(const AudioFrameDesc& desc);
40+
~AudioFrame();
41+
3942
/**
40-
* @note Allocated data will be initialized to silence.
43+
* @brief Allocated data will be initialized to silence.
44+
* @warning The allocated data should be freed by the caller.
45+
* @see freeData
4146
*/
42-
AudioFrame(const AudioFrameDesc& ref);
43-
AudioFrame(const Frame& otherFrame);
44-
~AudioFrame();
47+
void allocateData();
48+
void freeData();
4549

4650
size_t getSampleRate() const { return av_frame_get_sample_rate(_frame); }
4751
size_t getNbChannels() const { return av_frame_get_channels(_frame); }
@@ -51,7 +55,7 @@ class AvExport AudioFrame : public Frame
5155
size_t getNbSamplesPerChannel() const { return _frame->nb_samples; }
5256
AudioFrameDesc desc() const { return AudioFrameDesc(getSampleRate(), getNbChannels(), getSampleFormat()); }
5357

54-
size_t getSize() const; ///< in bytes
58+
size_t getSize() const;
5559

5660
void setNbSamplesPerChannel(const size_t nbSamples) { _frame->nb_samples = nbSamples; }
5761

@@ -66,25 +70,6 @@ class AvExport AudioFrame : public Frame
6670
* @see getSize
6771
*/
6872
void assign(const unsigned char* ptrValue);
69-
70-
private:
71-
/**
72-
* @brief Allocate the audio buffer of the frame.
73-
* @warning The allocated data should be freed by the caller.
74-
* @see freeAVSample
75-
*/
76-
void allocateAVSample(const AudioFrameDesc& ref);
77-
78-
/**
79-
* @brief Free the audio buffer of the frame.
80-
*/
81-
void freeAVSample();
82-
83-
/**
84-
* @note To allocate new audio buffer if needed.
85-
* @see allocateAVSample
86-
*/
87-
friend class AudioGenerator;
8873
};
8974
}
9075

src/AvTranscoder/data/decoded/Frame.cpp

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,16 @@ namespace avtranscoder
77

88
Frame::Frame()
99
: _frame(NULL)
10+
, _dataAllocated(false)
1011
{
1112
allocateAVFrame();
1213
}
1314

14-
Frame::Frame(const Frame& otherFrame)
15-
: _frame(NULL)
16-
{
17-
allocateAVFrame();
18-
copyProperties(otherFrame);
19-
copyData(otherFrame);
20-
}
21-
22-
void Frame::operator=(const Frame& otherFrame)
23-
{
24-
allocateAVFrame();
25-
copyProperties(otherFrame);
26-
copyData(otherFrame);
27-
}
28-
2915
Frame::~Frame()
3016
{
3117
freeAVFrame();
3218
}
3319

34-
int Frame::getEncodedSize() const
35-
{
36-
return av_frame_get_pkt_size(_frame);
37-
}
38-
3920
void Frame::copyData(const Frame& frameToRef)
4021
{
4122
const int ret = av_frame_copy(_frame, &frameToRef.getAVFrame());

src/AvTranscoder/data/decoded/Frame.hpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,39 @@ namespace avtranscoder
1212

1313
/**
1414
* @brief This class describes decoded (raw) audio or video data.
15+
* This class is abstract.
16+
* @see VideoFrame
17+
* @see AudioFrame
1518
*/
1619
class AvExport Frame
1720
{
1821
public:
1922
/**
2023
* @brief Allocate an empty frame.
21-
* @warn This only allocates the AVFrame itself, not the data buffers.
24+
* @warning This only allocates the AVFrame itself, not the data buffers.
25+
* Depending on the case, we could manipulate frame with data allocated elsewhere.
26+
* For example, an empty frame is given to a decoder, which is responsible to allocate and free the data buffers.
2227
*/
2328
Frame();
2429

25-
//@{
26-
// @brief Allocate a new frame that references the same data as the given frame.
27-
Frame(const Frame& otherFrame);
28-
void operator=(const Frame& otherFrame);
29-
//@}
30-
3130
virtual ~Frame();
3231

32+
/**
33+
* @brief Allocate the buffer of the frame.
34+
*/
35+
virtual void allocateData() = 0;
36+
37+
/**
38+
* @brief Free the buffer of the frame.
39+
*/
40+
virtual void freeData() = 0;
41+
42+
/**
43+
* @brief Get the size in bytes that a video/audio buffer of the given frame properties would occupy if allocated.
44+
* @warning This methods does not guarantee that the buffer is actually allocated.
45+
*/
46+
virtual size_t getSize() const = 0;
47+
3348
/**
3449
* @brief Get all the data of the frame.
3550
*/
@@ -44,12 +59,6 @@ class AvExport Frame
4459
*/
4560
int* getLineSize() const { return _frame->linesize; }
4661

47-
/**
48-
* @return Size of the corresponding packet containing the compressed frame (in bytes)
49-
* @warning returns a negative value if the size is unknown
50-
*/
51-
int getEncodedSize() const;
52-
5362
/**
5463
* @brief Copy the data of the given Frame.
5564
* This function does not allocate anything: the current frame must be already initialized and
@@ -61,6 +70,7 @@ class AvExport Frame
6170

6271
/**
6372
* @brief Copy all the fields that do not affect the data layout in the buffers.
73+
* @warning The info checked when copying data of an other frame (width/height, channels...) are not copied.
6474
*/
6575
void copyProperties(const Frame& otherFrame);
6676

@@ -88,6 +98,7 @@ class AvExport Frame
8898

8999
protected:
90100
AVFrame* _frame;
101+
bool _dataAllocated;
91102
};
92103
}
93104

src/AvTranscoder/data/decoded/VideoFrame.cpp

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,18 @@ void VideoFrameDesc::setParameters(const ProfileLoader::Profile& profile)
4545
_fps = atof(profile.find(constants::avProfileFrameRate)->second.c_str());
4646
}
4747

48-
VideoFrame::VideoFrame(const VideoFrameDesc& ref)
48+
VideoFrame::VideoFrame(const VideoFrameDesc& desc)
4949
: Frame()
5050
{
51-
allocateAVPicture(ref);
52-
}
53-
54-
VideoFrame::VideoFrame(const Frame& otherFrame)
55-
: Frame(otherFrame)
56-
{
51+
_frame->width = desc._width;
52+
_frame->height = desc._height;
53+
_frame->format = desc._pixelFormat;
5754
}
5855

5956
VideoFrame::~VideoFrame()
6057
{
61-
freeAVPicture();
58+
if(_dataAllocated)
59+
freeData();
6260
}
6361

6462
size_t VideoFrame::getSize() const
@@ -75,26 +73,29 @@ size_t VideoFrame::getSize() const
7573
return size;
7674
}
7775

78-
void VideoFrame::allocateAVPicture(const VideoFrameDesc& desc)
76+
void VideoFrame::allocateData()
7977
{
80-
const int ret = avpicture_alloc(reinterpret_cast<AVPicture*>(_frame), desc._pixelFormat, desc._width, desc._height);
78+
if(_dataAllocated)
79+
return;
80+
81+
const AVPixelFormat format = static_cast<AVPixelFormat>(_frame->format);
82+
const int ret = avpicture_alloc(reinterpret_cast<AVPicture*>(_frame), format, _frame->width, _frame->height);
8183
if(ret < 0)
8284
{
8385
std::stringstream os;
8486
os << "Unable to allocate an image frame of ";
85-
os << "width = " << desc._width << ", ";
86-
os << "height = " << desc._height << ", ";
87-
os << "pixel format = " << desc._pixelFormat;
87+
os << "width = " << _frame->width << ", ";
88+
os << "height = " << _frame->height << ", ";
89+
os << "pixel format = " << getPixelFormatName(format);
8890
throw std::runtime_error(os.str());
8991
}
90-
_frame->width = desc._width;
91-
_frame->height = desc._height;
92-
_frame->format = desc._pixelFormat;
92+
_dataAllocated = true;
9393
}
9494

95-
void VideoFrame::freeAVPicture()
95+
void VideoFrame::freeData()
9696
{
9797
avpicture_free(reinterpret_cast<AVPicture*>(_frame));
98+
_dataAllocated = false;
9899
}
99100

100101
void VideoFrame::assign(const unsigned char value)

src/AvTranscoder/data/decoded/VideoFrame.hpp

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,23 @@ struct AvExport VideoFrameDesc
4343
class AvExport VideoFrame : public Frame
4444
{
4545
public:
46-
VideoFrame(const VideoFrameDesc& ref);
47-
VideoFrame(const Frame& otherFrame);
46+
VideoFrame(const VideoFrameDesc& desc);
4847
~VideoFrame();
4948

49+
/**
50+
* @brief Allocate the image buffer of the frame.
51+
* @warning The allocated data should be freed by the caller.
52+
* @see freeData
53+
*/
54+
void allocateData();
55+
void freeData();
56+
5057
size_t getWidth() const { return _frame->width; }
5158
size_t getHeight() const { return _frame->height; }
5259
AVPixelFormat getPixelFormat() const { return static_cast<AVPixelFormat>(_frame->format); }
5360
VideoFrameDesc desc() const { return VideoFrameDesc(getWidth(), getHeight(), getPixelFormat()); }
5461

55-
size_t getSize() const; ///< in bytes/**
62+
size_t getSize() const;
5663

5764
/**
5865
* @brief Assign the given value to all the data of the picture.
@@ -65,25 +72,6 @@ class AvExport VideoFrame : public Frame
6572
* @see getSize
6673
*/
6774
void assign(const unsigned char* ptrValue);
68-
69-
private:
70-
/**
71-
* @brief Allocate the image buffer of the frame.
72-
* @warning The allocated data should be freed by the caller.
73-
* @see freeAVPicture
74-
*/
75-
void allocateAVPicture(const VideoFrameDesc& desc);
76-
77-
/**
78-
* @brief Free the image buffer of the frame.
79-
*/
80-
void freeAVPicture();
81-
82-
/**
83-
* @note To allocate new image buffer if needed.
84-
* @see allocateAVPicture
85-
*/
86-
friend class VideoGenerator;
8775
};
8876
}
8977

src/AvTranscoder/decoder/AudioDecoder.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ bool AudioDecoder::decodeNextFrame(Frame& frameBuffer, const std::vector<size_t>
132132
return decodeNextFrame(frameBuffer);
133133

134134
// else decode all data in an intermediate buffer
135-
AudioFrame allDataOfNextFrame(frameBuffer);
135+
AudioFrame& audioBuffer = static_cast<AudioFrame&>(frameBuffer);
136+
AudioFrame allDataOfNextFrame(AudioFrameDesc(audioBuffer.getSampleRate(), srcNbChannels, audioBuffer.getSampleFormat()));
136137
if(!decodeNextFrame(allDataOfNextFrame))
137138
return false;
138139

@@ -158,9 +159,10 @@ bool AudioDecoder::decodeNextFrame(Frame& frameBuffer, const std::vector<size_t>
158159
throw std::runtime_error(msg.str());
159160
}
160161
}
162+
// allocate data to store the subpart of the next frame
163+
audioBuffer.allocateData();
161164

162165
// copy frame properties of decoded frame
163-
AudioFrame& audioBuffer = static_cast<AudioFrame&>(frameBuffer);
164166
audioBuffer.copyProperties(allDataOfNextFrame);
165167
av_frame_set_channels(&audioBuffer.getAVFrame(), channelIndexArray.size());
166168
av_frame_set_channel_layout(&audioBuffer.getAVFrame(), av_get_default_channel_layout(channelIndexArray.size()));

src/AvTranscoder/decoder/AudioGenerator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ bool AudioGenerator::decodeNextFrame(Frame& frameBuffer)
3636
if(!_silent)
3737
{
3838
_silent = new AudioFrame(_frameDesc);
39+
_silent->allocateData();
3940

4041
std::stringstream msg;
4142
msg << "Generate a silence with the following features:" << std::endl;

0 commit comments

Comments
 (0)