Custom `AVIOContext` fails to open input file
I'm submitting a bug report.
-
Do you want to request a feature or report a bug? This could be a bug with ffmpeg, but seems to be a failure with the managed/native callbacks. Our code worked under ffmpeg 4.3, and broke in 5.0. I checked again and it's still broken in ffmpeg6. I will work on a repro example, but wanted to get this filed.
-
What is the current behavior?
- Custom
AVIOContextfails to open for reading a file. - The Read callback executes once, but then an
AccessViolationExceptionis thrown.
-
*If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem:
-
What is the expected behavior? Reading a file with a custom IO context should work. (Interestingly, it does work for writing a file)
-
Please tell us about your environment:
- version: ffmpeg6, Windows 11, .NET6.0 WPF application.
Here is a sample project, just a small console app that tries to open the file. FfmegCustomIO.zip
- Fill in the ffmpeg.RootPath with your environment.
- Fill in the file path to some mp4, avi, etc.
- Run the app - should blow up on
avformat_open_input. Breakpoints will show that theReadcallback is executed once.
Interesting, removing this line appears to resolve it but also calls Seek (which I wouldn't expect)
Reference->seekable = stream.CanSeek ? 1 : 0;
I haven't tried your code, but it looks very suspicious that write_flag: stream.CanWrite ? 1 : 0, and write_packet: null,
I think you should set the write flag to 0 if the write delegate is null.
True, I didn't get that line entirely pulled out of the minimum repro. But that will also always be 0 because the file is being opened readonly.
I think it could be related issue #217
I'll try to check integrity of AVIOContext structure.
As indeed when commenting out Reference->seekable = stream.CanSeek ? 1 : 0; it seems to be working fine.
The crash in avformat_open_input() seems to be happening somewhere around here: https://github.com/FFmpeg/FFmpeg/blob/5bad4856035ca5ed571e9d7d9b1d503a5c9ef0a5/libavformat/demux.c#L258-L272
The C# struct layout for AVIOContext seem to mismatch the one in the Win32 build. In particular, the field pb->seekable (at offset 0x90 in the C# struct) is swapped with pb->xxx_whitelist.
I didn't want to build ffmpeg myself, so I confirmed this by setting a dummy value like pb->seekable = 0x1234567, which ends up being passed to av_strdup() via rcx:

Also I don't think that the C# layout is wrong as it matches the clang output, so the maybe the problem is specific to Windows builds?
Edit: note that it's not necessary to set seekable manually because avio_alloc_context() already does so when you pass a non-null seek callback (ref). There seems to be no other way to check for the AVIO_SEEKABLE_NORMAL flag, so I'm just checking for pb->seek.Pointer != IntPtr.Zero; instead.
I updated state of research and passible actions in #217
btw i encountered this with ffmpeg 5 feeding it a buffer of FLAC and consequently getting free() invalid pointer every time. i have been hitting my head against GDB for the past day trying to do something like this:
/// buffer comes from network,
uint8_t buffer[4096] = // assume mock read
AVFormatContext* pFormat = avformat_alloc_context()
AVIOContext* pAvioCtx = avio_alloc_context(buffer, 4096, 0, nullptr, nullptr, nullptr, nullptr);
pFormat->pb = pAvioCtx;
// SIGABRT free() invalid pointer occurs every time inside this ->
if (avformat_open_input(&pFormat, nullptr, nullptr, nullptr)) {
log("couldn't open input");
}