IntPtr to Callback function

2019-02-19 13:33发布

问题:

I am using FFMPEG in C# and have the following function prototpe:

public static extern AVIOContext* avio_alloc_context(byte* buffer, int buffer_size, int write_flag, void* opaque, IntPtr read_packet, IntPtr write_packet, IntPtr seek);

In C/C++ this function is declared as follows:

avio_alloc_context (unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))

In C/C++ I can do the following to call this function:

int readFunction(void* opaque, uint8_t* buf, int buf_size)
{
    // Do something here
    int numBytes = CalcBytes();
    return numBytes;
}

int64_t seekFunction(void* opaque, int64_t offset, int whence)
{
   // Do seeking here
   return pos;
}

AVIOContext * avioContext = avio_alloc_context(ioBuffer, ioBufferSize, 0, (void*)(&fileStream), &readFunction, NULL, &seekFunction);

Where the readFunction and seekFunction are callback functions that are used in reading/seeking etc.

I am unsure how to copy this behaviour in the C# version of the code when it expects an IntPtr. How can I create the callback functions and pass them in the C# version?

回答1:

Turns out you can do this, however it is not entirely intuitive.

First you need to create a delegate with the UnmanagedFunctionPointer and ensure the params can be passed back from the callee to the caller after being modified using [In, Out]

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int av_read_function_callback(IntPtr opaque, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), In, Out] byte[] endData, int bufSize);

In the function we can then marshal this delegate as follows:

private av_read_function_callback mReadCallbackFunc;

mReadCallbackFunc = new av_read_function_callback(ReadPacket);

mAvioContext = FFmpegInvoke.avio_alloc_context(mReadBuffer, mBufferSize, 0, null, Marshal.GetFunctionPointerForDelegate(mReadCallbackFunc), IntPtr.Zero, IntPtr.Zero);

where ReadPacket looks something like

public int ReadPacket(IntPtr opaque, byte[] endData, int bufSize)
{
    // Do stuff here
}

This results in the same behaviour as a function pointer in C++.



标签: c# c++ ffmpeg