Is there a set of working P/Invoke declarations for FFMpeg, libavutil, libavformat and libavcodec in .NET?
I'm currently looking to access libavutil, libavformat and libavcodec (all part of FFMpeg) from .NET.
Currently, I'm getting the libraries from the automated builds of the shared FFMpeg package performed every night for Windows 32-bit.
I am also using the code from the ffmpeg-sharp project. In that project, I have removed a number of classes that were not compiling (they are wrapper classes not the P/Invoke declarations).
The code compiles fine, but I am running into a few issues.
First, it appears that the build of av*.dll uses the cdecl calling convention, as I was receiving a number of PInvokeStackImbalanceException
when trying to call av_open_input_file
. This was easy enough to change to get it to work right. The AVFormatContext
structure is populated.
After that, I want to call av_find_stream_info
to get information about the streams in the file. However, when calling that with the AVFormatContext
retrieved from the call to av_open开发者_如何转开发_input_file
, an AccessViolationException
is thrown indicating that I am trying to read or write from protected memory.
Has anyone used P/Invoke to access the libavutil, libavformat and libavcodec dll libraries through P/Invoke and have gotten it to work?
I should mention that working with the command-line version of FFMpeg, while a solution, is not a viable solution in this case, access needs to occur through the libraries. The reason for this is that I'd have to thrash the disk way too much to do what I need to do (I have to do a frame-by-frame analysis of some very high definition video) and I want to avoid the disk as much as possible.
This is what I figured out - namely, a good amount of the P/Invoke declarations in the ffmpeg-sharp project are incorrect. There are a good number of places where they use structures in the declaration which are marshaled back, but subsequently, have to be passed to deallocation routines later.
Because the pointer has been lost as part of the marshaling, this is what was causing the AccessViolationException
to be thrown when trying to pass that stucture to other methods that are accepting a valid pointer (like a handle in Windows). Instead of treating them as opaque (as they should, like Windows APIs do) they marshal the structures back and lose the pointer in the process.
The solution is to change their API declarations to take/return an IntPtr
and perform marshaling of the structures as needed, not to include them in the P/Invoke declarations.
See Auto Generated FFmpeg wrapper for C#/.NET and Mono.
I've steered clear from any of those libraries/projects. All info I found at the time pointed to those breaking too easily with new versions and/or just being too out of date.
What I did is was run the ffmpeg process directly, as I mentioned on this answer, by modifying a sample in a blog post I link there. To this date we've not had trouble with it :)
If the above doesn't work for your scenario, good luck.
SharpFFmpeg imports c++ libraries. C++ code is an unmanaged code. It needs pointers to the unmanaged memory. "Marshal" class provides some method to allocate unmanaged memory. For example:
IntPtr buffer = Marshal.AllocHGlobal(buf.Length + FFmpeg.FF_INPUT_BUFFER_PADDING_SIZE); //buf is a byte array
Also, if you want to send a managed variable (any C# variable) to the function, you have to marshal (copy) this variable to the unmanaged memory.
for (int i = 0; i < buf.Length; i++)
Marshal.StructureToPtr(buf[i], buffer + i, true);
Now you can send a pointer to the function.
FFmpeg.avcodec_decode_video(codecContextUnmanaged, frame, ref success, buffer, buf.Length);
It's possible that you'll need to modify some unmanaged structures. To do this you have to copy structure to a managed memory (Marshal.PtrToStructure method), then modify it, and copy it to an unmanaged memory again.
I was tormented by the same problem a lot. I solved it, but I can't decode video anyway)) I hope my solution will help anybody.
精彩评论