FFmpegPtr – FFmpeg的智能指针

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;
};