FFmpeg是纯C语法的,内部结构体内存分配和释放需要调用专门的函数,比如avformat_alloc_context,avformat_free_context等。使用起来不太方便,如果调用的时候忘记了一一对应的,很容易造成内存泄漏。 因此用C++的模板把ffmpeg中的内存分配进行了封装。下面的例子只是对AVFormatContext, AVCodecContext进行了封装,其他结构体封装起来也很方便,只需重载FFmpegPtrTraits类就可以。
template<typename T>
class FFmpegPtrTraits;
template<>
class FFmpegPtrTraits<AVCodecContext>
{
public:
static void Create(AVCodecContext* avCodecContx)
{
}
static void Destroy(AVCodecContext* avCodecContx)
{
avcodec_free_context(&avCodecContx);
}
};
template<>
class FFmpegPtrTraits<AVPacket>
{
public:
static AVPacket* Create()
{
return (AVPacket *)av_malloc(sizeof(AVPacket));
}
static void Destroy(AVPacket* avPacket)
{
av_free(avPacket);
}
};
template<>
class FFmpegPtrTraits<AVFormatContext>
{
public:
static void Create(AVFormatContext* avFormatContext)
{
avFormatContext = avformat_alloc_context();
}
static void Destroy(AVFormatContext* avFormatContx)
{
}
};
template<typename T,typename TTraits = FFmpegPtrTraits<T>>
class FFmpegPtr
{
public:
typedef T interfaceType;
FFmpegPtr() : ptr_(nullptr), nRefCount(0)
{
ptr = TTraits::Create();
nRefCount = 1;
}
FFmpegPtr(T* other) : ptr_(other), nRefCount(0)
{
if(ptr_ != nullptr)
{
nRefCount = 1;
}
}
~FFmpegPtr()
{
if(nRefCount != 0)
{
nRefCount--;
if(nRefCount == 0 && ptr_)
{
TTraits::Destroy(ptr_);
ptr_ = nullptr;
}
}
}
FFmpegPtr& operator=(T* other)
{
if(ptr_ != other)
{
FFmpegPtr(other).Swap(*this);
}
return *this;
}
interfaceType* operator->() const
{
return ptr_;
}
T** GetAddressOf()
{
return &ptr_;
}
void Swap(FFmpegPtr &&other)
{
T* tmp = ptr_;
ptr_ = other.ptr_;
other.ptr_ = tmp;
}
void Swap(FFmpegPtr &other)
{
T* tmp = ptr_;
ptr_ = other.ptr_;
other.ptr_ = tmp;
}
T* Get() const
{
return ptr_;
}
protected:
interfaceType* ptr_;
private:
unsigned long nRefCount;
};