Skip to content

Commit 6b535b3

Browse files
authored
Merge pull request #282 from cchampet/fix_memoryLeakWhenGenerateData
Fix memory leaks
2 parents 103c33f + cd2db7b commit 6b535b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+948
-670
lines changed

app/avProcessor/avProcessor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ void parseConfigFile(const std::string& configFilename, avtranscoder::Transcoder
2828

2929
std::stringstream ss(streamId);
3030
size_t streamIndex = 0;
31-
char separator;
31+
char separator = 'x';
3232
std::vector<size_t> channelIndexArray;
3333
ss >> streamIndex;
3434
ss >> separator;

src/AvTranscoder/codec/AudioCodec.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "AudioCodec.hpp"
22

3+
#include <AvTranscoder/util.hpp>
4+
35
#include <cmath>
46
#include <cassert>
57

@@ -24,7 +26,7 @@ AudioCodec::AudioCodec(const ECodecType type, AVCodecContext& avCodecContext)
2426
AudioFrameDesc AudioCodec::getAudioFrameDesc() const
2527
{
2628
assert(_avCodecContext != NULL);
27-
return AudioFrameDesc(_avCodecContext->sample_rate, _avCodecContext->channels, _avCodecContext->sample_fmt);
29+
return AudioFrameDesc(_avCodecContext->sample_rate, _avCodecContext->channels, getSampleFormatName(_avCodecContext->sample_fmt));
2830
}
2931

3032
void AudioCodec::setAudioParameters(const AudioFrameDesc& audioFrameDesc)

src/AvTranscoder/codec/ICodec.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ ICodec::~ICodec()
4949
if(!_isCodecContextAllocated)
5050
return;
5151

52-
av_free(_avCodecContext);
52+
avcodec_free_context(&_avCodecContext);
5353
_avCodecContext = NULL;
5454
}
5555

@@ -148,7 +148,8 @@ void ICodec::allocateContext()
148148
_avCodecContext = avcodec_alloc_context3(_avCodec);
149149
if(!_avCodecContext)
150150
{
151-
throw std::runtime_error("Unable to allocate the codecContext and set its fields to default values");
151+
LOG_ERROR("Unable to allocate the codecContext and set its fields to default values.")
152+
throw std::bad_alloc();
152153
}
153154
_avCodecContext->codec = _avCodec;
154155
}

src/AvTranscoder/codec/VideoCodec.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "VideoCodec.hpp"
22

3+
#include <AvTranscoder/util.hpp>
4+
35
#include <cmath>
46
#include <cassert>
57

@@ -24,7 +26,7 @@ VideoCodec::VideoCodec(const ECodecType type, AVCodecContext& avCodecContext)
2426
VideoFrameDesc VideoCodec::getVideoFrameDesc() const
2527
{
2628
assert(_avCodecContext != NULL);
27-
VideoFrameDesc videoFrameDesc(_avCodecContext->width, _avCodecContext->height, _avCodecContext->pix_fmt);
29+
VideoFrameDesc videoFrameDesc(_avCodecContext->width, _avCodecContext->height, getPixelFormatName(_avCodecContext->pix_fmt));
2830
double fps = 1.0 * _avCodecContext->time_base.den / (_avCodecContext->time_base.num * _avCodecContext->ticks_per_frame);
2931
if(!std::isinf(fps))
3032
videoFrameDesc._fps = fps;

src/AvTranscoder/data/coded/CodedData.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ CodedData::CodedData()
1414
CodedData::CodedData(const size_t dataSize)
1515
: _avStream(NULL)
1616
{
17-
av_new_packet(&_packet, dataSize);
17+
const int err = av_new_packet(&_packet, dataSize);
18+
if(err != 0)
19+
{
20+
LOG_ERROR("Unable to allocate the payload of a packet and initialize its fields with default values: " << getDescriptionFromErrorCode(err))
21+
throw std::bad_alloc();
22+
}
1823
}
1924

2025
CodedData::CodedData(const AVPacket& avPacket)

src/AvTranscoder/data/data.i

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
%{
44
#include <AvTranscoder/data/coded/CodedData.hpp>
5-
#include <AvTranscoder/data/decoded/Frame.hpp>
5+
#include <AvTranscoder/data/decoded/IFrame.hpp>
66
#include <AvTranscoder/data/decoded/VideoFrame.hpp>
77
#include <AvTranscoder/data/decoded/AudioFrame.hpp>
88
%}
99

1010
%include <AvTranscoder/data/coded/CodedData.hpp>
11-
%include <AvTranscoder/data/decoded/Frame.hpp>
11+
%include <AvTranscoder/data/decoded/IFrame.hpp>
1212
%include <AvTranscoder/data/decoded/VideoFrame.hpp>
1313
%include <AvTranscoder/data/decoded/AudioFrame.hpp>

src/AvTranscoder/data/decoded/AudioFrame.cpp

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,19 @@ extern "C" {
1212
namespace avtranscoder
1313
{
1414

15-
AudioFrameDesc::AudioFrameDesc(const size_t sampleRate, const size_t nbChannels, const AVSampleFormat sampleFormat)
15+
AudioFrameDesc::AudioFrameDesc(const size_t sampleRate, const size_t nbChannels, const std::string& sampleFormatName)
1616
: _sampleRate(sampleRate)
1717
, _nbChannels(nbChannels)
18-
, _sampleFormat(sampleFormat)
18+
, _sampleFormat(getAVSampleFormat(sampleFormatName))
1919
{
2020
}
2121

22-
AudioFrameDesc::AudioFrameDesc(const size_t sampleRate, const size_t nbChannels, const std::string& sampleFormatName)
23-
: _sampleRate(sampleRate)
24-
, _nbChannels(nbChannels)
25-
, _sampleFormat(getAVSampleFormat(sampleFormatName))
22+
AudioFrameDesc::AudioFrameDesc(const ProfileLoader::Profile& profile)
23+
: _sampleRate(0)
24+
, _nbChannels(0)
25+
, _sampleFormat(AV_SAMPLE_FMT_NONE)
2626
{
27+
setParameters(profile);
2728
}
2829

2930
void AudioFrameDesc::setParameters(const ProfileLoader::Profile& profile)
@@ -39,15 +40,19 @@ void AudioFrameDesc::setParameters(const ProfileLoader::Profile& profile)
3940
_sampleFormat = getAVSampleFormat(profile.find(constants::avProfileSampleFormat)->second.c_str());
4041
}
4142

42-
AudioFrame::AudioFrame(const AudioFrameDesc& ref)
43-
: Frame()
43+
AudioFrame::AudioFrame(const AudioFrameDesc& desc, const bool forceDataAllocation)
44+
: IFrame()
45+
, _desc(desc)
4446
{
45-
allocateAVSample(ref);
46-
}
47+
// Set Frame properties
48+
av_frame_set_sample_rate(_frame, desc._sampleRate);
49+
av_frame_set_channels(_frame, desc._nbChannels);
50+
av_frame_set_channel_layout(_frame, av_get_default_channel_layout(desc._nbChannels));
51+
_frame->format = desc._sampleFormat;
52+
_frame->nb_samples = getDefaultNbSamples();
4753

48-
AudioFrame::AudioFrame(const Frame& otherFrame)
49-
: Frame(otherFrame)
50-
{
54+
if(forceDataAllocation)
55+
allocateData();
5156
}
5257

5358
std::string AudioFrame::getChannelLayoutDesc() const
@@ -57,75 +62,95 @@ std::string AudioFrame::getChannelLayoutDesc() const
5762
return std::string(buf);
5863
}
5964

60-
size_t AudioFrame::getSize() const
65+
AudioFrame::~AudioFrame()
66+
{
67+
if(_frame->buf[0])
68+
av_frame_unref(_frame);
69+
if(_dataAllocated)
70+
freeData();
71+
}
72+
73+
size_t AudioFrame::getBytesPerSample() const
74+
{
75+
return av_get_bytes_per_sample(getSampleFormat());
76+
}
77+
78+
size_t AudioFrame::getDataSize() const
6179
{
6280
if(getSampleFormat() == AV_SAMPLE_FMT_NONE)
6381
{
6482
LOG_WARN("Incorrect sample format when get size of audio frame: return a size of 0.")
6583
return 0;
6684
}
6785

68-
const size_t size = getNbSamplesPerChannel() * getNbChannels() * av_get_bytes_per_sample(getSampleFormat());
86+
const size_t size = getNbSamplesPerChannel() * getNbChannels() * getBytesPerSample();
6987
if(size == 0)
7088
{
7189
std::stringstream msg;
7290
msg << "Unable to determine audio buffer size:" << std::endl;
7391
msg << "nb sample per channel = " << getNbSamplesPerChannel() << std::endl;
7492
msg << "channels = " << getNbChannels() << std::endl;
75-
msg << "bytes per sample = " << av_get_bytes_per_sample(getSampleFormat()) << std::endl;
93+
msg << "bytes per sample = " << getBytesPerSample() << std::endl;
7694
throw std::runtime_error(msg.str());
7795
}
7896
return size;
7997
}
8098

81-
void AudioFrame::allocateAVSample(const AudioFrameDesc& desc)
99+
void AudioFrame::allocateData()
82100
{
101+
if(_dataAllocated)
102+
LOG_WARN("The AudioFrame seems to already have allocated data. This could lead to memory leaks.")
103+
83104
// Set Frame properties
84-
av_frame_set_sample_rate(_frame, desc._sampleRate);
85-
av_frame_set_channels(_frame, desc._nbChannels);
86-
av_frame_set_channel_layout(_frame, av_get_default_channel_layout(desc._nbChannels));
87-
_frame->format = desc._sampleFormat;
88-
_frame->nb_samples = desc._sampleRate / 25.; // cannot be known before calling avcodec_decode_audio4
105+
av_frame_set_sample_rate(_frame, _desc._sampleRate);
106+
av_frame_set_channels(_frame, _desc._nbChannels);
107+
av_frame_set_channel_layout(_frame, av_get_default_channel_layout(_desc._nbChannels));
108+
_frame->format = _desc._sampleFormat;
109+
if(_frame->nb_samples == 0)
110+
_frame->nb_samples = getDefaultNbSamples();
89111

90112
// Allocate data
91113
const int align = 0;
92114
const int ret =
93-
av_samples_alloc(_frame->data, _frame->linesize, _frame->channels, _frame->nb_samples, desc._sampleFormat, align);
115+
av_samples_alloc(_frame->data, _frame->linesize, _frame->channels, _frame->nb_samples, _desc._sampleFormat, align);
94116
if(ret < 0)
95117
{
96-
std::stringstream os;
97-
os << "Unable to allocate an audio frame of ";
98-
os << "sample rate = " << _frame->sample_rate << ", ";
99-
os << "nb channels = " << _frame->channels << ", ";
100-
os << "channel layout = " << av_get_channel_name(_frame->channels) << ", ";
101-
os << "nb samples = " << _frame->nb_samples << ", ";
102-
os << "sample format = " << getSampleFormatName(desc._sampleFormat);
103-
throw std::runtime_error(os.str());
118+
const std::string formatName = getSampleFormatName(_desc._sampleFormat);
119+
std::stringstream msg;
120+
msg << "Unable to allocate an audio frame of ";
121+
msg << "sample rate = " << _frame->sample_rate << ", ";
122+
msg << "nb channels = " << _frame->channels << ", ";
123+
msg << "channel layout = " << av_get_channel_name(_frame->channels) << ", ";
124+
msg << "nb samples = " << _frame->nb_samples << ", ";
125+
msg << "sample format = " << (formatName.empty() ? "none" : formatName);
126+
LOG_ERROR(msg.str())
127+
throw std::bad_alloc();
104128
}
129+
_dataAllocated = true;
105130
}
106131

107-
void AudioFrame::assign(const unsigned char value)
132+
void AudioFrame::freeData()
108133
{
109-
// Create the audio buffer
110-
// The buffer will be freed in destructor of based class
111-
const int audioSize = getSize();
112-
unsigned char* audioBuffer = new unsigned char[audioSize];
113-
memset(audioBuffer, value, audioSize);
114-
115-
// Fill the picture
116-
assign(audioBuffer);
134+
av_freep(&_frame->data[0]);
135+
_dataAllocated = false;
117136
}
118137

119-
void AudioFrame::assign(const unsigned char* ptrValue)
138+
void AudioFrame::assignBuffer(const unsigned char* ptrValue)
120139
{
121140
const int align = 0;
122141
const int ret = av_samples_fill_arrays(_frame->data, _frame->linesize, ptrValue, getNbChannels(),
123142
getNbSamplesPerChannel(), getSampleFormat(), align);
124143
if(ret < 0)
125144
{
126-
std::stringstream os;
127-
os << "Unable to assign an audio buffer: " << getDescriptionFromErrorCode(ret);
128-
throw std::runtime_error(os.str());
145+
std::stringstream msg;
146+
msg << "Unable to assign an audio buffer: " << getDescriptionFromErrorCode(ret);
147+
throw std::runtime_error(msg.str());
129148
}
130149
}
150+
151+
size_t AudioFrame::getDefaultNbSamples() const
152+
{
153+
return _desc._sampleRate / 25.;
154+
}
155+
131156
}

src/AvTranscoder/data/decoded/AudioFrame.hpp

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef _AV_TRANSCODER_FRAME_AUDIO_FRAME_HPP_
22
#define _AV_TRANSCODER_FRAME_AUDIO_FRAME_HPP_
33

4-
#include "Frame.hpp"
4+
#include "IFrame.hpp"
55
#include <AvTranscoder/profile/ProfileLoader.hpp>
66

77
namespace avtranscoder
@@ -14,9 +14,8 @@ namespace avtranscoder
1414
struct AvExport AudioFrameDesc
1515
{
1616
public:
17-
AudioFrameDesc(const size_t sampleRate = 0, const size_t channels = 0,
18-
const AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE);
1917
AudioFrameDesc(const size_t sampleRate, const size_t channels, const std::string& sampleFormatName);
18+
AudioFrameDesc(const ProfileLoader::Profile& profile);
2019

2120
/**
2221
* @brief Set the attributes from the given profile.
@@ -33,50 +32,59 @@ struct AvExport AudioFrameDesc
3332
/**
3433
* @brief This class describes decoded audio data.
3534
*/
36-
class AvExport AudioFrame : public Frame
35+
class AvExport AudioFrame : public IFrame
3736
{
37+
private:
38+
AudioFrame(const AudioFrame& otherFrame);
39+
AudioFrame& operator=(const AudioFrame& otherFrame);
40+
3841
public:
42+
AudioFrame(const AudioFrameDesc& desc, const bool forceDataAllocation = true);
43+
~AudioFrame();
44+
3945
/**
40-
* @note Allocated data will be initialized to silence.
46+
* @brief Allocated data will be initialized to silence.
47+
* @warning The allocated data should be freed by the caller.
48+
* @see freeData
4149
*/
42-
AudioFrame(const AudioFrameDesc& ref);
43-
AudioFrame(const Frame& otherFrame);
50+
void allocateData();
51+
void freeData();
52+
size_t getDataSize() const;
4453

4554
size_t getSampleRate() const { return av_frame_get_sample_rate(_frame); }
4655
size_t getNbChannels() const { return av_frame_get_channels(_frame); }
4756
size_t getChannelLayout() const { return av_frame_get_channel_layout(_frame); }
4857
std::string getChannelLayoutDesc() const; ///< Get a description of a channel layout (example: '5.1').
4958
AVSampleFormat getSampleFormat() const { return static_cast<AVSampleFormat>(_frame->format); }
59+
size_t getBytesPerSample() const; ///< 0 if unknown sample format
5060
size_t getNbSamplesPerChannel() const { return _frame->nb_samples; }
51-
AudioFrameDesc desc() const { return AudioFrameDesc(getSampleRate(), getNbChannels(), getSampleFormat()); }
52-
53-
size_t getSize() const; ///< in bytes
54-
55-
void setNbSamplesPerChannel(const size_t nbSamples) { _frame->nb_samples = nbSamples; }
5661

5762
/**
58-
* @brief Assign the given value to all the data of the audio frame.
63+
* @brief This methods dynamically updates the size that the data buffer would occupy if allocated.
64+
* @warning If the data buffer is already allocated, this could lead to memory leaks or seg fault.
5965
*/
60-
void assign(const unsigned char value);
66+
void setNbSamplesPerChannel(const size_t nbSamples) { _frame->nb_samples = nbSamples; }
6167

62-
/**
63-
* @brief Assign the given ptr of data to the data of the audio frame.
64-
* @warning the given ptr should have the size of the audio frame..
65-
* @see getSize
66-
*/
67-
void assign(const unsigned char* ptrValue);
68+
void assignBuffer(const unsigned char* ptrValue);
6869

6970
private:
7071
/**
71-
* @brief Allocate the audio buffer of the frame.
72+
* @brief The number of samples of a frame cannot be known before calling avcodec_decode_audio4,
73+
* and can be variable in a same stream. Because we need to allocate some frames without knowing this parameter,
74+
* we access here a default number of samples.
75+
* @note This value depends on the sample rate (example: 1920 samples at 48kHz).
76+
* @return the number of samples of our default AudioFrame.
77+
* @see setNbSamplesPerChannel
7278
*/
73-
void allocateAVSample(const AudioFrameDesc& ref);
79+
size_t getDefaultNbSamples() const;
7480

81+
private:
7582
/**
76-
* @note To allocate new audio buffer if needed.
77-
* @see allocateAVSample
83+
* @brief Description of the frame to allocate.
84+
* @warning This description could be different from the current frame (a decoder could have reseted it).
85+
* We need to keep this description to allocate again the frame even if it was reseted.
7886
*/
79-
friend class AudioGenerator;
87+
const AudioFrameDesc _desc;
8088
};
8189
}
8290

0 commit comments

Comments
 (0)