Мне нужно написать код с использованием Libav, где я могу:
- Передавайте кадры один за другим, используя AVIOContext (или что-то подобное).
- Захватите декодированный кадр.
- Нарисуйте его в окне ( Не имеет отношения к вопросу, пишу для контекста).
Код: Выделить всё
AppSrc -> H264Parser -> H264Decoder -> FrameGrabber
Код: Выделить всё
using System.Runtime.InteropServices;
using FFmpeg.AutoGen;
namespace AvIoCtxExperiment;
public static unsafe class Program
{
public static void Main()
{
ffmpeg.avdevice_register_all();
Console.WriteLine($"FFmpeg v: {ffmpeg.av_version_info()}");
// Generous buffer size for I frames (~43KB)
const int bufferSize = 50 * 1024;
var buff = (byte*)ffmpeg.av_malloc(bufferSize);
if (buff == null)
throw new Exception("Buffer is null");
// A mock frame provider. Frames are stored in separate files and this reads & returns them one-by-one.
var frameProvider = new FrameProvider(@"D:\Frames-1", 700);
var gch = GCHandle.Alloc(frameProvider);
var avioCtx = ffmpeg.avio_alloc_context(
buffer: buff,
buffer_size: bufferSize,
write_flag: 0,
opaque: (void*)GCHandle.ToIntPtr(gch),
read_packet: new avio_alloc_context_read_packet(ReadFunc),
write_packet: null,
seek: null);
var formatContext = ffmpeg.avformat_alloc_context();
formatContext->pb = avioCtx;
formatContext->flags |= ffmpeg.AVFMT_FLAG_CUSTOM_IO;
var openResult = ffmpeg.avformat_open_input(&formatContext, null, null, null);
if (openResult < 0)
throw new Exception("Open Input Failed");
if (ffmpeg.avformat_find_stream_info(formatContext, null) < 0)
throw new Exception("Find StreamInfo Failed");
AVPacket packet;
while (ffmpeg.av_read_frame(formatContext, &packet) >= 0)
{
Console.WriteLine($"GRAB: {packet.buf->size}");
ffmpeg.av_packet_unref(&packet);
}
}
private static int ReadFunc(void* opaque, byte* buf, int bufSize)
{
var frameProvider = (FrameProvider?)GCHandle.FromIntPtr((IntPtr)opaque).Target;
if (frameProvider == null)
{
return 0;
}
byte[] managedBuffer = new byte[bufSize];
var fBuff = frameProvider.NextFrame();
if (fBuff == null)
{
return ffmpeg.AVERROR_EOF;
}
int bytesRead = fBuff.Length;
fBuff.CopyTo(managedBuffer, 0);
if (bytesRead > 0)
{
Marshal.Copy(managedBuffer, 0, (IntPtr)buf, bytesRead);
Console.WriteLine($"READ size: {fBuff.Length}");
return bytesRead;
}
return ffmpeg.AVERROR_EOF;
}
}
Любая помощь будет очень признательна. Спасибо.
P.S. Я пишу приложение на C#, но пример кода на C подойдет, я могу адаптировать код самостоятельно.
Подробнее здесь: https://stackoverflow.com/questions/789 ... sing-libav