ffmpeg c ++ / cli包装器,用于在c#中使用。通过它的指针调用dll函数后的AccessViolationException

时间:2015-07-21 10:18:42

标签: ffmpeg c++-cli

我的目标是编写一个c ++ / cli wrap arount ffmpeg库,使用从dll-modules导入ffmpeg函数。 稍后我将在c#中使用此接口。 这是我的挑战,不要问我为什么))

所以我已经实现了Wrap类,如下所示:

namespace FFMpegWrapLib 
{
    public class Wrap
    {
    private:

    public:
        //wstring libavcodecDllName = "avcodec-56.dll";
        //wstring libavformatDllName = "avformat-56.dll";
        //wstring libswscaleDllName = "swscale-3.dll";
        //wstring libavutilDllName = "avutil-54.dll";

        HMODULE libavcodecDLL;
        HMODULE libavformatDLL; 
        HMODULE libswsscaleDLL;
        HMODULE libavutilDLL;

        AVFormatContext     **pFormatCtx = nullptr;
        AVCodecContext      *pCodecCtxOrig = nullptr;
        AVCodecContext      *pCodecCtx = nullptr;
        AVCodec             **pCodec = nullptr;
        AVFrame             **pFrame = nullptr;
        AVFrame             **pFrameRGB = nullptr;
        AVPacket            *packet = nullptr;
        int                 *frameFinished;
        int                 numBytes;
        uint8_t             *buffer = nullptr;
        struct SwsContext   *sws_ctx = nullptr;

        void                Init();
        void                AVRegisterAll();
        void                Release();
        bool                SaveFrame(const char *pFileName, AVFrame * frame, int w, int h);
        bool                GetStreamInfo();
        int                 FindVideoStream();
        bool                OpenInput(const char* file);
        AVCodec*            FindDecoder();
        AVCodecContext*     AllocContext3();
        bool                CopyContext();
        bool                OpenCodec2();
        AVFrame*            AllocFrame();
        int                 PictureGetSize();
        void*               Alloc(size_t size);
        int                 PictureFill(AVPicture *, const uint8_t *, enum AVPixelFormat, int, int);
        SwsContext*         GetSwsContext(int, int, enum AVPixelFormat, int, int, enum AVPixelFormat, int, SwsFilter *, SwsFilter *, const double *);
        int                 ReadFrame(AVFormatContext *s, AVPacket *pkt);
        int                 DecodeVideo2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt);
        int                 SwsScale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[]);
        void                PacketFree(AVPacket *pkt);
        void                BufferFree(void *ptr);
        void                FrameFree(AVFrame **frame);
        int                 CodecClose(AVCodecContext *);
        void                CloseInput(AVFormatContext **);
        bool                SeekFrame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);

        Wrap();
        ~Wrap();

        bool                GetVideoFrame(char* str_in_file, char* str_out_img, uint64_t time);
    };

    public ref class managedWrap
    {
    public:

        managedWrap(){}
        ~managedWrap(){ delete unmanagedWrap; }

        bool GetVideoFrameToFile(char* str_in_file, char* str_out_img, uint64_t time)
        {
            return unmanagedWrap->GetVideoFrame(str_in_file, str_out_img, time);
        }

        static Wrap* unmanagedWrap = new Wrap();
    };
}

因此,对libavcodec等的导入是成功的。 在调用dll func期间,问题出在AccessViolationException中,例如,在OpenInput中(即本机ffmpeg库中的av_open_input)

OpenInput函数代码如下:

bool FFMpegWrapLib::Wrap::OpenInput(const char* file)
{
    typedef int avformat_open_input(AVFormatContext **, const char *, AVInputFormat *, AVDictionary **);

    avformat_open_input* pavformat_open_input = (avformat_open_input *)GetProcAddress(libavformatDLL, "avformat_open_input");
    if (pavformat_open_input == nullptr)
    {
        throw exception("Unable to find avformat_open_input function address in libavformat module");
        return false;
    }

    //pin_ptr<AVFormatContext *> pinFormatContext = &(new interior_ptr<AVFormatContext *>(pCodecCtx));
    pFormatCtx = new AVFormatContext*;
    //*pFormatCtx = new AVFormatContext;


    int ret = pavformat_open_input(pFormatCtx, file, NULL, NULL); // here it fails

    return ret == 0;
}

所以问题,我认为,Wrap类的类字段在安全的内存中。 ffmpeg使用本机内存,通过它的地址初始化pFormatCtx变量。 我能避免这种情况,还是不可能?

1 个答案:

答案 0 :(得分:0)

遇到同样的问题,你需要初始化AVFormatContext对象。

好例子:

AVFormatContext *pFormatCtx = avformat_alloc_context();

错误的例子:

AVFormatContext *pFormatCtx = NULL;