Skip to content

Fix memory leaks #282

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 58 commits into from
Nov 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
88af737
AudioFrame: fix memory leak when allocating a new audio buffer
Oct 26, 2016
8d0ac3f
VideoFrame: fix memory leak when allocating a new picture
Oct 26, 2016
aade71f
Frame: add isRefCounted method
Oct 26, 2016
58cfca0
Frame: rename clear method to unrefFrame
Oct 26, 2016
6e4d7d7
Frame: add freeAVFrame private method
Oct 26, 2016
6954832
ICodec: refactor how to free the AVCodecContext
Oct 27, 2016
0654fa8
Frame: remove method to ref/unref an other frame
Oct 27, 2016
83a63a6
FormatContext: fix destructor by freeing the streams added
Oct 27, 2016
c2edefe
StreamTranscoder: skip filtering step if there is no filters
Oct 27, 2016
8635b3b
VideoProperties: refactor how to decode the first frames to get info
Oct 27, 2016
6f87435
Video/Audio frames: data buffer needs to be allocated manually
Oct 27, 2016
5d0f51f
Video/Audio transform: add check before converting the data
Oct 27, 2016
fb44ea5
StreamTranscoder: fix process of generated streams
Oct 27, 2016
ebd558d
Video/Audio generators: fix data generated after a transcoded stream
Oct 27, 2016
53eff1d
Video/Audio frames: refactor how to construct frames
Oct 27, 2016
7e20933
Video/Audio frames: remove desc method
Oct 27, 2016
5c788e3
decoded data: raise a bad_alloc when faling to allocate the requested…
Oct 28, 2016
8d4cce5
coded data: raise a bad_alloc when faling to allocate the requested s…
Oct 28, 2016
c662a70
ICodec: raise a bad_alloc when faling to allocate the requested space
Oct 28, 2016
6847185
decoded data: rename class Frame to IFrame
Oct 28, 2016
2a61683
frames: define assign method in the IFrame based class
Oct 28, 2016
a92879d
IFrame: fix memory leak when calling assignValue
Oct 28, 2016
8e2818f
StreamTranscoder: fix seg fault when using a decoder to lengthen a re…
Oct 28, 2016
7ff35fc
AudioDecoder: fix memory leak in demultiplexing cases
Oct 28, 2016
dfaf987
AudioDecoder: refactor how to decodeNextFrame in case of demultiplexing
Oct 28, 2016
b460fce
AudioFrame: add doc to warn about setNbSamplesPerChannel method
Oct 28, 2016
87d11c4
StreamTranscoder: fix video frame to get filtered data when transcoding
Oct 28, 2016
d86ccf3
StreamTranscoder: fix process with a positive offset
Oct 28, 2016
aa9bba3
VideoProperties: fix seg fault when analysing the first GOP
Oct 28, 2016
9203a71
filters: refactor how to allocate/free the objects
Oct 28, 2016
a5ad30e
Video/Audio frames: fix seg fault when process a graph of filters
Oct 28, 2016
9c02a02
readers: fix allocation of buffer of decoded data
Oct 31, 2016
64d74cf
AudioFrame: add getBytesPerSample method
Oct 31, 2016
abb78c0
frames: remove default copy constructors and assignment operator
Oct 31, 2016
a95aa18
pyTest: fix set video/audio frame
Oct 31, 2016
ccdbbea
FormatContext: fix memory leak when adding new streams to an OutputFile
Oct 31, 2016
50d46ad
Video/Audio frames: fix message logged when failing to allocate data
Oct 31, 2016
ca3c386
VideoFrame: update constructors
Oct 31, 2016
e5ee852
AudioFrame: update constructors
Oct 31, 2016
eb3f708
Video/Audio frames: reorder methods
Oct 31, 2016
9c90c2d
pyTest: add tests to check Video/Audio frames
Oct 31, 2016
4f56f1a
VideoFrame: get error description when failing to get AVPicture size
Oct 31, 2016
5cd30bc
pyTest: split reader tests to testVideo/AudioReader.py
Oct 31, 2016
86502f4
pyTest: added test to create an InputFile inside an AudioReader
Oct 31, 2016
173538b
AudioDecoder: check if each extracted channel exists before decoding
Oct 31, 2016
8e5b9ef
AudioDecoder: fix seg fault when trying to extract one channel of a m…
Oct 31, 2016
d9b2f41
avprocessor app: fix conditional jump which depends on uninitialised …
Oct 31, 2016
249bcfb
AudioFrame: refactor how to get a default number of samples
Nov 2, 2016
da013d4
StreamTranscoder: check the next data buffers in case of audio frames
Nov 2, 2016
5d4888f
pyTest: add a test to extract one audio channel from a stream of one …
Nov 2, 2016
3a03cbf
AudioDecoder: refactor how to get bytes per sample
Nov 2, 2016
a66c49d
AudioDecoder: fix the number of channels used to compute the decoded …
Nov 2, 2016
b6dc069
StreamTranscoder: update log message when checking the next audio buf…
Nov 2, 2016
93ce328
StreamTranscoder: fix memory leak in case of generator after a demult…
Nov 2, 2016
11789bb
frames: rename local variables to log messages
Nov 3, 2016
dcf6509
AudioFrame: fix spelling in the doc of getDefaultNbSamples method
Nov 3, 2016
1cea044
IFrame: rename getSize to getDataSize
Nov 3, 2016
cd2db7b
frames: add log to warn about possible data already allocated
Nov 3, 2016
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
2 changes: 1 addition & 1 deletion app/avProcessor/avProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void parseConfigFile(const std::string& configFilename, avtranscoder::Transcoder

std::stringstream ss(streamId);
size_t streamIndex = 0;
char separator;
char separator = 'x';
std::vector<size_t> channelIndexArray;
ss >> streamIndex;
ss >> separator;
Expand Down
4 changes: 3 additions & 1 deletion src/AvTranscoder/codec/AudioCodec.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "AudioCodec.hpp"

#include <AvTranscoder/util.hpp>

#include <cmath>
#include <cassert>

Expand All @@ -24,7 +26,7 @@ AudioCodec::AudioCodec(const ECodecType type, AVCodecContext& avCodecContext)
AudioFrameDesc AudioCodec::getAudioFrameDesc() const
{
assert(_avCodecContext != NULL);
return AudioFrameDesc(_avCodecContext->sample_rate, _avCodecContext->channels, _avCodecContext->sample_fmt);
return AudioFrameDesc(_avCodecContext->sample_rate, _avCodecContext->channels, getSampleFormatName(_avCodecContext->sample_fmt));
}

void AudioCodec::setAudioParameters(const AudioFrameDesc& audioFrameDesc)
Expand Down
5 changes: 3 additions & 2 deletions src/AvTranscoder/codec/ICodec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ ICodec::~ICodec()
if(!_isCodecContextAllocated)
return;

av_free(_avCodecContext);
avcodec_free_context(&_avCodecContext);
_avCodecContext = NULL;
}

Expand Down Expand Up @@ -148,7 +148,8 @@ void ICodec::allocateContext()
_avCodecContext = avcodec_alloc_context3(_avCodec);
if(!_avCodecContext)
{
throw std::runtime_error("Unable to allocate the codecContext and set its fields to default values");
LOG_ERROR("Unable to allocate the codecContext and set its fields to default values.")
throw std::bad_alloc();
}
_avCodecContext->codec = _avCodec;
}
Expand Down
4 changes: 3 additions & 1 deletion src/AvTranscoder/codec/VideoCodec.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "VideoCodec.hpp"

#include <AvTranscoder/util.hpp>

#include <cmath>
#include <cassert>

Expand All @@ -24,7 +26,7 @@ VideoCodec::VideoCodec(const ECodecType type, AVCodecContext& avCodecContext)
VideoFrameDesc VideoCodec::getVideoFrameDesc() const
{
assert(_avCodecContext != NULL);
VideoFrameDesc videoFrameDesc(_avCodecContext->width, _avCodecContext->height, _avCodecContext->pix_fmt);
VideoFrameDesc videoFrameDesc(_avCodecContext->width, _avCodecContext->height, getPixelFormatName(_avCodecContext->pix_fmt));
double fps = 1.0 * _avCodecContext->time_base.den / (_avCodecContext->time_base.num * _avCodecContext->ticks_per_frame);
if(!std::isinf(fps))
videoFrameDesc._fps = fps;
Expand Down
7 changes: 6 additions & 1 deletion src/AvTranscoder/data/coded/CodedData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ CodedData::CodedData()
CodedData::CodedData(const size_t dataSize)
: _avStream(NULL)
{
av_new_packet(&_packet, dataSize);
const int err = av_new_packet(&_packet, dataSize);
if(err != 0)
{
LOG_ERROR("Unable to allocate the payload of a packet and initialize its fields with default values: " << getDescriptionFromErrorCode(err))
throw std::bad_alloc();
}
}

CodedData::CodedData(const AVPacket& avPacket)
Expand Down
4 changes: 2 additions & 2 deletions src/AvTranscoder/data/data.i
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

%{
#include <AvTranscoder/data/coded/CodedData.hpp>
#include <AvTranscoder/data/decoded/Frame.hpp>
#include <AvTranscoder/data/decoded/IFrame.hpp>
#include <AvTranscoder/data/decoded/VideoFrame.hpp>
#include <AvTranscoder/data/decoded/AudioFrame.hpp>
%}

%include <AvTranscoder/data/coded/CodedData.hpp>
%include <AvTranscoder/data/decoded/Frame.hpp>
%include <AvTranscoder/data/decoded/IFrame.hpp>
%include <AvTranscoder/data/decoded/VideoFrame.hpp>
%include <AvTranscoder/data/decoded/AudioFrame.hpp>
113 changes: 69 additions & 44 deletions src/AvTranscoder/data/decoded/AudioFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,19 @@ extern "C" {
namespace avtranscoder
{

AudioFrameDesc::AudioFrameDesc(const size_t sampleRate, const size_t nbChannels, const AVSampleFormat sampleFormat)
AudioFrameDesc::AudioFrameDesc(const size_t sampleRate, const size_t nbChannels, const std::string& sampleFormatName)
: _sampleRate(sampleRate)
, _nbChannels(nbChannels)
, _sampleFormat(sampleFormat)
, _sampleFormat(getAVSampleFormat(sampleFormatName))
{
}

AudioFrameDesc::AudioFrameDesc(const size_t sampleRate, const size_t nbChannels, const std::string& sampleFormatName)
: _sampleRate(sampleRate)
, _nbChannels(nbChannels)
, _sampleFormat(getAVSampleFormat(sampleFormatName))
AudioFrameDesc::AudioFrameDesc(const ProfileLoader::Profile& profile)
: _sampleRate(0)
, _nbChannels(0)
, _sampleFormat(AV_SAMPLE_FMT_NONE)
{
setParameters(profile);
}

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

AudioFrame::AudioFrame(const AudioFrameDesc& ref)
: Frame()
AudioFrame::AudioFrame(const AudioFrameDesc& desc, const bool forceDataAllocation)
: IFrame()
, _desc(desc)
{
allocateAVSample(ref);
}
// Set Frame properties
av_frame_set_sample_rate(_frame, desc._sampleRate);
av_frame_set_channels(_frame, desc._nbChannels);
av_frame_set_channel_layout(_frame, av_get_default_channel_layout(desc._nbChannels));
_frame->format = desc._sampleFormat;
_frame->nb_samples = getDefaultNbSamples();

AudioFrame::AudioFrame(const Frame& otherFrame)
: Frame(otherFrame)
{
if(forceDataAllocation)
allocateData();
}

std::string AudioFrame::getChannelLayoutDesc() const
Expand All @@ -57,75 +62,95 @@ std::string AudioFrame::getChannelLayoutDesc() const
return std::string(buf);
}

size_t AudioFrame::getSize() const
AudioFrame::~AudioFrame()
{
if(_frame->buf[0])
av_frame_unref(_frame);
if(_dataAllocated)
freeData();
}

size_t AudioFrame::getBytesPerSample() const
{
return av_get_bytes_per_sample(getSampleFormat());
}

size_t AudioFrame::getDataSize() const
{
if(getSampleFormat() == AV_SAMPLE_FMT_NONE)
{
LOG_WARN("Incorrect sample format when get size of audio frame: return a size of 0.")
return 0;
}

const size_t size = getNbSamplesPerChannel() * getNbChannels() * av_get_bytes_per_sample(getSampleFormat());
const size_t size = getNbSamplesPerChannel() * getNbChannels() * getBytesPerSample();
if(size == 0)
{
std::stringstream msg;
msg << "Unable to determine audio buffer size:" << std::endl;
msg << "nb sample per channel = " << getNbSamplesPerChannel() << std::endl;
msg << "channels = " << getNbChannels() << std::endl;
msg << "bytes per sample = " << av_get_bytes_per_sample(getSampleFormat()) << std::endl;
msg << "bytes per sample = " << getBytesPerSample() << std::endl;
throw std::runtime_error(msg.str());
}
return size;
}

void AudioFrame::allocateAVSample(const AudioFrameDesc& desc)
void AudioFrame::allocateData()
{
if(_dataAllocated)
LOG_WARN("The AudioFrame seems to already have allocated data. This could lead to memory leaks.")

// Set Frame properties
av_frame_set_sample_rate(_frame, desc._sampleRate);
av_frame_set_channels(_frame, desc._nbChannels);
av_frame_set_channel_layout(_frame, av_get_default_channel_layout(desc._nbChannels));
_frame->format = desc._sampleFormat;
_frame->nb_samples = desc._sampleRate / 25.; // cannot be known before calling avcodec_decode_audio4
av_frame_set_sample_rate(_frame, _desc._sampleRate);
av_frame_set_channels(_frame, _desc._nbChannels);
av_frame_set_channel_layout(_frame, av_get_default_channel_layout(_desc._nbChannels));
_frame->format = _desc._sampleFormat;
if(_frame->nb_samples == 0)
_frame->nb_samples = getDefaultNbSamples();

// Allocate data
const int align = 0;
const int ret =
av_samples_alloc(_frame->data, _frame->linesize, _frame->channels, _frame->nb_samples, desc._sampleFormat, align);
av_samples_alloc(_frame->data, _frame->linesize, _frame->channels, _frame->nb_samples, _desc._sampleFormat, align);
if(ret < 0)
{
std::stringstream os;
os << "Unable to allocate an audio frame of ";
os << "sample rate = " << _frame->sample_rate << ", ";
os << "nb channels = " << _frame->channels << ", ";
os << "channel layout = " << av_get_channel_name(_frame->channels) << ", ";
os << "nb samples = " << _frame->nb_samples << ", ";
os << "sample format = " << getSampleFormatName(desc._sampleFormat);
throw std::runtime_error(os.str());
const std::string formatName = getSampleFormatName(_desc._sampleFormat);
std::stringstream msg;
msg << "Unable to allocate an audio frame of ";
msg << "sample rate = " << _frame->sample_rate << ", ";
msg << "nb channels = " << _frame->channels << ", ";
msg << "channel layout = " << av_get_channel_name(_frame->channels) << ", ";
msg << "nb samples = " << _frame->nb_samples << ", ";
msg << "sample format = " << (formatName.empty() ? "none" : formatName);
LOG_ERROR(msg.str())
throw std::bad_alloc();
}
_dataAllocated = true;
}

void AudioFrame::assign(const unsigned char value)
void AudioFrame::freeData()
{
// Create the audio buffer
// The buffer will be freed in destructor of based class
const int audioSize = getSize();
unsigned char* audioBuffer = new unsigned char[audioSize];
memset(audioBuffer, value, audioSize);

// Fill the picture
assign(audioBuffer);
av_freep(&_frame->data[0]);
_dataAllocated = false;
}

void AudioFrame::assign(const unsigned char* ptrValue)
void AudioFrame::assignBuffer(const unsigned char* ptrValue)
{
const int align = 0;
const int ret = av_samples_fill_arrays(_frame->data, _frame->linesize, ptrValue, getNbChannels(),
getNbSamplesPerChannel(), getSampleFormat(), align);
if(ret < 0)
{
std::stringstream os;
os << "Unable to assign an audio buffer: " << getDescriptionFromErrorCode(ret);
throw std::runtime_error(os.str());
std::stringstream msg;
msg << "Unable to assign an audio buffer: " << getDescriptionFromErrorCode(ret);
throw std::runtime_error(msg.str());
}
}

size_t AudioFrame::getDefaultNbSamples() const
{
return _desc._sampleRate / 25.;
}

}
58 changes: 33 additions & 25 deletions src/AvTranscoder/data/decoded/AudioFrame.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef _AV_TRANSCODER_FRAME_AUDIO_FRAME_HPP_
#define _AV_TRANSCODER_FRAME_AUDIO_FRAME_HPP_

#include "Frame.hpp"
#include "IFrame.hpp"
#include <AvTranscoder/profile/ProfileLoader.hpp>

namespace avtranscoder
Expand All @@ -14,9 +14,8 @@ namespace avtranscoder
struct AvExport AudioFrameDesc
{
public:
AudioFrameDesc(const size_t sampleRate = 0, const size_t channels = 0,
const AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE);
AudioFrameDesc(const size_t sampleRate, const size_t channels, const std::string& sampleFormatName);
AudioFrameDesc(const ProfileLoader::Profile& profile);

/**
* @brief Set the attributes from the given profile.
Expand All @@ -33,50 +32,59 @@ struct AvExport AudioFrameDesc
/**
* @brief This class describes decoded audio data.
*/
class AvExport AudioFrame : public Frame
class AvExport AudioFrame : public IFrame
{
private:
AudioFrame(const AudioFrame& otherFrame);
AudioFrame& operator=(const AudioFrame& otherFrame);

public:
AudioFrame(const AudioFrameDesc& desc, const bool forceDataAllocation = true);
~AudioFrame();

/**
* @note Allocated data will be initialized to silence.
* @brief Allocated data will be initialized to silence.
* @warning The allocated data should be freed by the caller.
* @see freeData
*/
AudioFrame(const AudioFrameDesc& ref);
AudioFrame(const Frame& otherFrame);
void allocateData();
void freeData();
size_t getDataSize() const;

size_t getSampleRate() const { return av_frame_get_sample_rate(_frame); }
size_t getNbChannels() const { return av_frame_get_channels(_frame); }
size_t getChannelLayout() const { return av_frame_get_channel_layout(_frame); }
std::string getChannelLayoutDesc() const; ///< Get a description of a channel layout (example: '5.1').
AVSampleFormat getSampleFormat() const { return static_cast<AVSampleFormat>(_frame->format); }
size_t getBytesPerSample() const; ///< 0 if unknown sample format
size_t getNbSamplesPerChannel() const { return _frame->nb_samples; }
AudioFrameDesc desc() const { return AudioFrameDesc(getSampleRate(), getNbChannels(), getSampleFormat()); }

size_t getSize() const; ///< in bytes

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

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

/**
* @brief Assign the given ptr of data to the data of the audio frame.
* @warning the given ptr should have the size of the audio frame..
* @see getSize
*/
void assign(const unsigned char* ptrValue);
void assignBuffer(const unsigned char* ptrValue);

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

private:
/**
* @note To allocate new audio buffer if needed.
* @see allocateAVSample
* @brief Description of the frame to allocate.
* @warning This description could be different from the current frame (a decoder could have reseted it).
* We need to keep this description to allocate again the frame even if it was reseted.
*/
friend class AudioGenerator;
const AudioFrameDesc _desc;
};
}

Expand Down
Loading