### Initialize FFmpeg Bindings Dynamically
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Installs NuGet packages and configures the FFmpeg library path for dynamic loading. Ensure the correct DLLs are present in the specified path before initialization.
```csharp
// NuGet packages:
//
//
using FFmpeg.AutoGen.Abstractions;
using FFmpeg.AutoGen.Bindings.DynamicallyLoaded;
using System.Runtime.InteropServices;
// Point to the directory containing avcodec-61.dll, avutil-59.dll, etc.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
DynamicallyLoadedBindings.LibrariesPath = @"C:\ffmpeg\bin\x64";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
DynamicallyLoadedBindings.LibrariesPath = "/usr/lib/x86_64-linux-gnu";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
DynamicallyLoadedBindings.LibrariesPath = "/opt/homebrew/lib";
}
// Resolve all function pointers from the native shared libraries
DynamicallyLoadedBindings.Initialize();
// Verify FFmpeg is loaded correctly
Console.WriteLine($"FFmpeg version: {ffmpeg.av_version_info()}");
// Output: FFmpeg version: 7.1.1
```
--------------------------------
### Configure FFmpeg Logging Callback
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Sets the global log verbosity and installs a managed delegate as the FFmpeg log sink. The callback processes raw format strings and va_list, rendering messages using av_log_format_line.
```csharp
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
unsafe void SetupLogging()
{
ffmpeg.av_log_set_level(ffmpeg.AV_LOG_WARNING);
av_log_set_callback_callback logCallback = (p0, level, format, vl) =>
{
if (level > ffmpeg.av_log_get_level()) return;
const int bufSize = 1024;
var buf = stackalloc byte[bufSize];
var printPrefix = 1;
ffmpeg.av_log_format_line(p0, level, format, vl, buf, bufSize, &printPrefix);
var line = Marshal.PtrToStringAnsi((IntPtr)buf);
Console.Error.Write(line);
};
ffmpeg.av_log_set_callback(logCallback);
}
```
--------------------------------
### Create a new feature branch
Source: https://github.com/ruslan-b/ffmpeg.autogen/blob/main/CONTRIBUTING.md
Use this command to create a new branch for your feature development, starting from the main branch.
```bash
git checkout -b feature/my-new-feature
```
--------------------------------
### Install FFmpeg on macOS
Source: https://github.com/ruslan-b/ffmpeg.autogen/blob/main/README.md
Install FFmpeg on macOS using Homebrew. You may need to set the static ffmpeg.RootPath to the full path of the FFmpeg libraries.
```bash
brew install ffmpeg
```
--------------------------------
### Build the project
Source: https://github.com/ruslan-b/ffmpeg.autogen/blob/main/CONTRIBUTING.md
Compile the project in Release mode using the .NET CLI.
```bash
dotnet build -c Release
```
--------------------------------
### Build and test the project
Source: https://github.com/ruslan-b/ffmpeg.autogen/blob/main/CONTRIBUTING.md
Build the project in Release configuration and run tests to ensure changes are functional and do not introduce regressions.
```bash
dotnet build -c Release
```
```bash
dotnet test -c Release
```
--------------------------------
### Initialize and Use VideoStreamDecoder
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Demonstrates how to instantiate VideoStreamDecoder to open a media URL and decode video frames one by one. Hardware acceleration can be optionally enabled during initialization. Ensure FFmpeg libraries are correctly set up.
```csharp
using System;
using System.Drawing;
using FFmpeg.AutoGen.Abstractions;
public sealed unsafe class VideoStreamDecoder : IDisposable
{
private readonly AVCodecContext* _pCodecContext;
private readonly AVFormatContext* _pFormatContext;
private readonly AVFrame* _pFrame;
private readonly AVPacket* _pPacket;
private readonly AVFrame* _receivedFrame;
private readonly int _streamIndex;
public string CodecName { get; }
public Size FrameSize { get; }
public AVPixelFormat PixelFormat { get; }
public VideoStreamDecoder(string url,
AVHWDeviceType hwDevice = AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
{
_pFormatContext = ffmpeg.avformat_alloc_context();
_receivedFrame = ffmpeg.av_frame_alloc();
var pFmtCtx = _pFormatContext;
ffmpeg.avformat_open_input(&pFmtCtx, url, null, null).ThrowExceptionIfError();
ffmpeg.avformat_find_stream_info(_pFormatContext, null).ThrowExceptionIfError();
AVCodec* codec = null;
_streamIndex = ffmpeg
.av_find_best_stream(_pFormatContext, AVMediaType.AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0)
.ThrowExceptionIfError();
_pCodecContext = ffmpeg.avcodec_alloc_context3(codec);
if (hwDevice != AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
ffmpeg.av_hwdevice_ctx_create(&_pCodecContext->hw_device_ctx, hwDevice, null, null, 0)
.ThrowExceptionIfError();
ffmpeg.avcodec_parameters_to_context(_pCodecContext,
_pFormatContext->streams[_streamIndex]->codecpar).ThrowExceptionIfError();
ffmpeg.avcodec_open2(_pCodecContext, codec, null).ThrowExceptionIfError();
CodecName = ffmpeg.avcodec_get_name(codec->id);
FrameSize = new Size(_pCodecContext->width, _pCodecContext->height);
PixelFormat = _pCodecContext->pix_fmt;
_pPacket = ffmpeg.av_packet_alloc();
_pFrame = ffmpeg.av_frame_alloc();
}
public bool TryDecodeNextFrame(out AVFrame frame)
{
ffmpeg.av_frame_unref(_pFrame);
ffmpeg.av_frame_unref(_receivedFrame);
int error;
do
{
try
{
do
{
ffmpeg.av_packet_unref(_pPacket);
error = ffmpeg.av_read_frame(_pFormatContext, _pPacket);
if (error == ffmpeg.AVERROR_EOF) { frame = *_pFrame; return false; }
error.ThrowExceptionIfError();
} while (_pPacket->stream_index != _streamIndex);
ffmpeg.avcodec_send_packet(_pCodecContext, _pPacket).ThrowExceptionIfError();
}
finally { ffmpeg.av_packet_unref(_pPacket); }
error = ffmpeg.avcodec_receive_frame(_pCodecContext, _pFrame);
} while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));
error.ThrowExceptionIfError();
if (_pCodecContext->hw_device_ctx != null)
{
ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0).ThrowExceptionIfError();
frame = *_receivedFrame;
}
else
frame = *_pFrame;
return true;
}
public void Dispose()
{
var pFrame = _pFrame; ffmpeg.av_frame_free(&pFrame);
var pPacket = _pPacket; ffmpeg.av_packet_free(&pPacket);
AVCodecContext** avctx = stackalloc[] { _pCodecContext };
ffmpeg.avcodec_free_context(avctx);
var pFmtCtx = _pFormatContext;
ffmpeg.avformat_close_input(&pFmtCtx);
}
}
// --- Usage ---
var url = "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_1MB.mp4";
using var decoder = new VideoStreamDecoder(url, AVHWDeviceType.AV_HWDEVICE_TYPE_NONE);
Console.WriteLine($"Codec: {decoder.CodecName}, Size: {decoder.FrameSize}");
// Output: Codec: h264, Size: {Width=1920, Height=1080}
int n = 0;
while (decoder.TryDecodeNextFrame(out var frame))
Console.WriteLine($"Decoded frame #{n++}, pts={frame.pts}");
```
--------------------------------
### Run project tests
Source: https://github.com/ruslan-b/ffmpeg.autogen/blob/main/CONTRIBUTING.md
Execute all tests in the project using the .NET CLI to verify functionality.
```bash
dotnet test -c Release
```
--------------------------------
### Download FFmpeg binaries
Source: https://github.com/ruslan-b/ffmpeg.autogen/blob/main/CONTRIBUTING.md
Execute this PowerShell script to download the necessary FFmpeg DLLs for development.
```powershell
.\FFmpeg\download-ffmpeg.ps1
```
--------------------------------
### Enumerate and Create HW Decode Contexts
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Call `av_hwdevice_iterate_types` to discover supported hardware acceleration types on the host system. Pass the chosen `AVHWDeviceType` to the decoder constructor. Defaults to DXVA2 on Windows, falling back to the first available type.
```csharp
using System;
using System.Collections.Generic;
using FFmpeg.AutoGen.Abstractions;
static AVHWDeviceType ChooseHWDecoder()
{
var available = new Dictionary();
var type = AVHWDeviceType.AV_HWDEVICE_TYPE_NONE;
int n = 0;
while ((type = ffmpeg.av_hwdevice_iterate_types(type)) != AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
{
Console.WriteLine($" [{++n}] {type}");
available[n] = type;
}
if (available.Count == 0) return AVHWDeviceType.AV_HWDEVICE_TYPE_NONE;
// Default: prefer DXVA2 on Windows, fallback to first available
var preferred = available
.Where(kv => kv.Value == AVHWDeviceType.AV_HWDEVICE_TYPE_DXVA2)
.Select(kv => kv.Value)
.FirstOrDefault();
return preferred != AVHWDeviceType.AV_HWDEVICE_TYPE_NONE
? preferred
: available[1];
}
// Map HW device type to its surface pixel format
static AVPixelFormat HWPixelFormat(AVHWDeviceType dev) => dev switch
{
AVHWDeviceType.AV_HWDEVICE_TYPE_CUDA => AVPixelFormat.AV_PIX_FMT_CUDA,
AVHWDeviceType.AV_HWDEVICE_TYPE_VAAPI => AVPixelFormat.AV_PIX_FMT_VAAPI,
AVHWDeviceType.AV_HWDEVICE_TYPE_DXVA2 => AVPixelFormat.AV_PIX_FMT_NV12,
AVHWDeviceType.AV_HWDEVICE_TYPE_D3D11VA => AVPixelFormat.AV_PIX_FMT_NV12,
AVHWDeviceType.AV_HWDEVICE_TYPE_VIDEOTOOLBOX => AVPixelFormat.AV_PIX_FMT_VIDEOTOOLBOX,
AVHWDeviceType.AV_HWDEVICE_TYPE_QSV => AVPixelFormat.AV_PIX_FMT_QSV,
AVHWDeviceType.AV_HWDEVICE_TYPE_OPENCL => AVPixelFormat.AV_PIX_FMT_OPENCL,
_ => AVPixelFormat.AV_PIX_FMT_NONE
};
// Example: decode with the best available HW accelerator
var hwType = ChooseHWDecoder();
using var decoder = new VideoStreamDecoder("input.mp4", hwType);
var srcFmt = hwType == AVHWDeviceType.AV_HWDEVICE_TYPE_NONE
? decoder.PixelFormat
: HWPixelFormat(hwType);
```
--------------------------------
### Rescale and Convert Pixel Formats Between AVFrames
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
`sws_getContext` creates a software scaler context for resizing and converting pixel formats. `sws_scale` applies the transformation into a pre-allocated output buffer. This class handles the context creation, buffer allocation, and scaling operations.
```csharp
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
public sealed unsafe class VideoFrameConverter : IDisposable
{
private readonly IntPtr _bufferPtr;
private readonly Size _dstSize;
private readonly byte_ptr4 _dstData;
private readonly int4 _dstLinesize;
private readonly SwsContext* _pSws;
public VideoFrameConverter(Size srcSize, AVPixelFormat srcFmt,
Size dstSize, AVPixelFormat dstFmt)
{
_dstSize = dstSize;
_pSws = ffmpeg.sws_getContext(
srcSize.Width, srcSize.Height, srcFmt,
dstSize.Width, dstSize.Height, dstFmt,
(int)SwsFlags.SWS_FAST_BILINEAR, null, null, null);
if (_pSws == null)
throw new ApplicationException("Could not initialize sws context.");
var bufferSize = ffmpeg.av_image_get_buffer_size(dstFmt, dstSize.Width, dstSize.Height, 1);
_bufferPtr = Marshal.AllocHGlobal(bufferSize);
_dstData = new byte_ptr4();
_dstLinesize = new int4();
ffmpeg.av_image_fill_arrays(ref _dstData, ref _dstLinesize,
(byte*)_bufferPtr, dstFmt, dstSize.Width, dstSize.Height, 1);
}
public AVFrame Convert(AVFrame src)
{
ffmpeg.sws_scale(_pSws, src.data, src.linesize, 0, src.height, _dstData, _dstLinesize);
var data = new byte_ptr8();
data.UpdateFrom(_dstData);
var linesize = new int8();
linesize.UpdateFrom(_dstLinesize);
return new AVFrame
{
data = data,
linesize = linesize,
width = _dstSize.Width,
height = _dstSize.Height
};
}
public void Dispose()
{
Marshal.FreeHGlobal(_bufferPtr);
ffmpeg.sws_freeContext(_pSws);
}
}
// --- Usage: decode and extract BGRA frames ---
using var decoder = new VideoStreamDecoder("clip.mp4");
using var converter = new VideoFrameConverter(
decoder.FrameSize, decoder.PixelFormat,
decoder.FrameSize, AVPixelFormat.@AV_PIX_FMT_BGRA);
while (decoder.TryDecodeNextFrame(out var raw))
{
var bgra = converter.Convert(raw);
// bgra.data[0] now points to BGRA pixel rows
}
```
--------------------------------
### Populate AVFrame Data and Linesize with Fixed-Size Arrays
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Manually populate `AVFrame`'s `data` and `linesize` using `byte_ptr8` and `int8`. These types implement `IFixedArray` for indexer access and conversion to managed arrays. Ensure correct buffer calculations for YUV420P planes.
```csharp
using FFmpeg.AutoGen.Abstractions;
// Manually populate an AVFrame data/linesize for a YUV420P frame
unsafe void FillFrameFromBuffer(byte* yuvBuffer, int width, int height)
{
var data = new byte_ptr8();
var linesize = new int8();
// Plane 0: Y, Plane 1: U, Plane 2: V
data[0] = yuvBuffer;
data[1] = yuvBuffer + width * height;
data[2] = yuvBuffer + width * height * 5 / 4;
linesize[0] = width;
linesize[1] = width / 2;
linesize[2] = width / 2;
var frame = new AVFrame
{
data = data,
linesize = linesize,
width = width,
height = height,
format = (int)AVPixelFormat.AV_PIX_FMT_YUV420P
};
// Copy data/linesize out as managed arrays
byte*[] dataArray = data.ToArray(); // length 8
int[] linesizeArray = linesize.ToArray(); // length 8
Console.WriteLine($"Y linesize: {linesizeArray[0]}"); // 1920
}
// Bridging byte_ptr4 ↔ byte_ptr8 (used by VideoFrameConverter)
var src4 = new byte_ptr4();
var dst8 = new byte_ptr8();
dst8.UpdateFrom(src4); // copies first 4 pointers
```
--------------------------------
### Decode Video URL and Save Frames as JPEG
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
This snippet shows how to initialize FFmpeg bindings, decode frames from a video URL, convert them to BGRA format, and save them as JPEG images. Ensure FFmpeg libraries are accessible and the output directory 'frames' exists.
```csharp
using System;
using System.IO;
using FFmpeg.AutoGen.Abstractions;
using FFmpeg.AutoGen.Bindings.DynamicallyLoaded;
using SkiaSharp;
// 1. Bootstrap
DynamicallyLoadedBindings.LibrariesPath = "/usr/lib/x86_64-linux-gnu";
DynamicallyLoadedBindings.Initialize();
ffmpeg.av_log_set_level(ffmpeg.AV_LOG_WARNING);
Directory.CreateDirectory("frames");
// 2. Decode
var url = "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_1MB.mp4";
using var decoder = new VideoStreamDecoder(url);
Console.WriteLine($"Codec: {decoder.CodecName}, {decoder.FrameSize.Width}×{decoder.FrameSize.Height}");
// 3. Convert YUV → BGRA
using var converter = new VideoFrameConverter(
decoder.FrameSize, decoder.PixelFormat,
decoder.FrameSize, AVPixelFormat.@AV_PIX_FMT_BGRA);
// 4. Save frames as JPEG
int i = 0;
while (decoder.TryDecodeNextFrame(out var raw) && i < 250)
{
unsafe
{
var bgra = converter.Convert(raw);
var info = new SKImageInfo(bgra.width, bgra.height, SKColorType.Bgra8888, SKAlphaType.Opaque);
using var bmp = new SKBitmap();
bmp.InstallPixels(info, (IntPtr)bgra.data[0]);
using var fs = File.Create($"frames/frame.{i:D8}.jpg");
bmp.Encode(fs, SKEncodedImageFormat.Jpeg, 90);
}
Console.WriteLine($"Saved frame {i++}");
}
// Output: frames/frame.00000000.jpg … frames/frame.00000249.jpg
```
--------------------------------
### Generate Bindings with CppSharp
Source: https://github.com/ruslan-b/ffmpeg.autogen/blob/main/README.md
Steps to regenerate the *.g.cs files using the FFmpeg.AutoGen.CppSharpUnsafeGenerator. Requires Visual Studio 2022 with C# and C++ workloads.
```csharp
FFmpeg.AutoGen.CppSharpUnsafeGenerator;
```
--------------------------------
### Iterate container metadata tags using C#
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Iterates through key/value metadata tags embedded in container formats using `av_dict_get`. Requires `AV_DICT_IGNORE_SUFFIX` flag and an empty key to walk all entries.
```csharp
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
static unsafe IReadOnlyDictionary GetMetadata(AVFormatContext* pFmtCtx)
{
var result = new Dictionary();
AVDictionaryEntry* tag = null;
while ((tag = ffmpeg.av_dict_get(
pFmtCtx->metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null)
{
var key = Marshal.PtrToStringAnsi((IntPtr)tag->key);
var value = Marshal.PtrToStringAnsi((IntPtr)tag->value);
result[key] = value;
}
return result;
}
// Example output for a typical MP4:
// title = Big Buck Bunny
// artist = Blender Foundation
// date = 2008
// encoder = Lavf61.7.100
```
--------------------------------
### Resolve FFmpeg Function Pointers Dynamically
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Dynamically load FFmpeg shared libraries at runtime and resolve native function pointers using `FunctionResolverBase.GetFunctionDelegate`. This process respects library dependencies and caches function pointers. Initialization can use a custom library path.
```csharp
// This is handled automatically by DynamicallyLoadedBindings.Initialize(),
// but the resolver can also be used directly for custom scenarios.
using FFmpeg.AutoGen.Bindings.DynamicallyLoaded;
// Library dependency order is managed automatically:
// avutil → swresample → avcodec → avformat → avfilter → avdevice
Console.WriteLine("Dependency map:");
foreach (var (lib, deps) in FunctionResolverBase.LibraryDependenciesMap)
Console.WriteLine($" {lib,-14} depends on: [{string.Join(", ", deps)}]");
// Platform detection
var platform = FunctionResolverFactory.GetPlatformId();
Console.WriteLine($"Platform: {platform}");
// Output on Linux: Platform: Unix
// Initialize with a custom path
DynamicallyLoadedBindings.LibrariesPath = "/opt/custom-ffmpeg/lib";
DynamicallyLoadedBindings.Initialize();
// All ffmpeg.* calls now dispatch through the custom build
```
--------------------------------
### Encode AVFrames to H.264 NAL units using C#
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Configures the libx264 encoder and drives the `avcodec_send_frame` / `avcodec_receive_packet` loop. Call `Drain()` after all frames are submitted to flush the encoder's internal buffer.
```csharp
using System;
using System.Drawing;
using System.IO;
using FFmpeg.AutoGen.Abstractions;
public sealed unsafe class H264VideoStreamEncoder : IDisposable
{
private readonly AVCodec* _pCodec;
private readonly AVCodecContext* _pCodecContext;
private readonly Stream _output;
private readonly Size _frameSize;
public H264VideoStreamEncoder(Stream output, int fps, Size frameSize)
{
_output = output;
_frameSize = frameSize;
_pCodec = ffmpeg.avcodec_find_encoder(AVCodecID.AV_CODEC_ID_H264);
if (_pCodec == null) throw new InvalidOperationException("H.264 encoder not found.");
_pCodecContext = ffmpeg.avcodec_alloc_context3(_pCodec);
_pCodecContext->width = frameSize.Width;
_pCodecContext->height = frameSize.Height;
_pCodecContext->time_base = new AVRational { num = 1, den = fps };
_pCodecContext->pix_fmt = AVPixelFormat.AV_PIX_FMT_YUV420P;
ffmpeg.av_opt_set(_pCodecContext->priv_data, "preset", "veryslow", 0);
ffmpeg.avcodec_open2(_pCodecContext, _pCodec, null).ThrowExceptionIfError();
}
public void Encode(AVFrame frame)
{
var pkt = ffmpeg.av_packet_alloc();
try
{
ffmpeg.avcodec_send_frame(_pCodecContext, &frame).ThrowExceptionIfError();
int res;
do
{
ffmpeg.av_packet_unref(pkt);
res = ffmpeg.avcodec_receive_packet(_pCodecContext, pkt);
if (res == 0)
{
using var ms = new UnmanagedMemoryStream(pkt->data, pkt->size);
ms.CopyTo(_output);
}
} while (res == 0);
}
finally { ffmpeg.av_packet_free(&pkt); }
}
public void Drain()
{
var pkt = ffmpeg.av_packet_alloc();
try
{
ffmpeg.avcodec_send_frame(_pCodecContext, null).ThrowExceptionIfError();
int res;
do
{
ffmpeg.av_packet_unref(pkt);
res = ffmpeg.avcodec_receive_packet(_pCodecContext, pkt);
if (res == 0)
{
using var ms = new UnmanagedMemoryStream(pkt->data, pkt->size);
ms.CopyTo(_output);
}
} while (res == 0);
}
finally { ffmpeg.av_packet_free(&pkt); }
}
public void Dispose() => ffmpeg.av_free(_pCodecContext);
}
// --- Usage: transcode JPEG frames to H.264 raw stream ---
var frames = Directory.GetFiles("./frames", "frame.*.jpg").OrderBy(x => x).ToArray();
using var outFile = File.Open("output.h264", FileMode.Create);
using var encoder = new H264VideoStreamEncoder(outFile, fps: 25, frameSize: new Size(1920, 1080));
int n = 0;
foreach (var jpg in frames)
{
// Load BGRA bitmap, convert to YUV420P via VideoFrameConverter, then encode
var frame = LoadAndConvertFrame(jpg); // returns AVFrame in YUV420P
frame.pts = n++ * 25;
encoder.Encode(frame);
}
encoder.Drain();
Console.WriteLine("Encoding complete → output.h264");
```
--------------------------------
### ffmpeg.av_dict_get
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Iterates through container metadata tags. This function is used to retrieve key-value pairs of metadata embedded within media container formats.
```APIDOC
## `ffmpeg.av_dict_get` — Iterate container metadata tags
### Description
Container formats (MP4, MKV, etc.) embed metadata as key/value dictionaries on `AVFormatContext::metadata`. Iterate using `av_dict_get` with the `AV_DICT_IGNORE_SUFFIX` flag and an empty key to walk all entries.
### Method
`AVDictionaryEntry* av_dict_get(AVDictionary *m, const char *key, AVDictionaryEntry *prev, int flags)`
### Parameters
#### `m` (AVDictionary *)
- The dictionary to iterate over.
#### `key` (const char *)
- An empty string (`""`) is used to iterate through all entries.
#### `prev` (AVDictionaryEntry *)
- The previous entry returned, or `null` for the first entry.
#### `flags` (int)
- `AV_DICT_IGNORE_SUFFIX` flag is recommended for iterating all entries.
### Return Value
- Returns a pointer to an `AVDictionaryEntry` for the next matching key-value pair, or `null` if no more entries are found.
### Usage Example
```csharp
using System.Collections.Generic;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
static unsafe IReadOnlyDictionary GetMetadata(AVFormatContext* pFmtCtx)
{
var result = new Dictionary();
AVDictionaryEntry* tag = null;
while ((tag = ffmpeg.av_dict_get(pFmtCtx->metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null)
{
var key = Marshal.PtrToStringAnsi((IntPtr)tag->key);
var value = Marshal.PtrToStringAnsi((IntPtr)tag->value);
result[key] = value;
}
return result;
}
```
### Example Output
```
title = Big Buck Bunny
artist = Blender Foundation
date = 2008
encoder = Lavf61.7.100
```
```
--------------------------------
### FFmpeg Error Handling with ThrowExceptionIfError
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Converts negative FFmpeg error codes into managed exceptions. The `av_strerror` helper provides human-readable messages for error codes.
```csharp
using System;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
internal static class FFmpegHelper
{
public static unsafe string av_strerror(int error)
{
const int bufSize = 1024;
var buf = stackalloc byte[bufSize];
ffmpeg.av_strerror(error, buf, (ulong)bufSize);
return Marshal.PtrToStringAnsi((IntPtr)buf);
}
// Usage: ffmpeg.avformat_open_input(&pFmtCtx, url, null, null).ThrowExceptionIfError();
public static int ThrowExceptionIfError(this int error)
{
if (error < 0) throw new ApplicationException(av_strerror(error));
return error;
}
}
// Example: handle AVERROR_EOF explicitly
unsafe void ReadPackets(AVFormatContext* pFmtCtx, AVPacket* pkt)
{
int ret;
while ((ret = ffmpeg.av_read_frame(pFmtCtx, pkt)) >= 0)
{
// process packet
ffmpeg.av_packet_unref(pkt);
}
if (ret != ffmpeg.AVERROR_EOF)
ret.ThrowExceptionIfError(); // throws for real errors only
}
```
--------------------------------
### H264VideoStreamEncoder
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
Configures the libx264 encoder and drives the avcodec_send_frame / avcodec_receive_packet loop to produce compressed packets. Call Drain() after all frames are submitted to flush the encoder's internal buffer.
```APIDOC
## `H264VideoStreamEncoder` Class
### Description
This class provides functionality to encode raw video frames into H.264 NAL units using FFmpeg's `libx264` encoder. It manages the encoder context, sending frames for encoding, and receiving compressed packets. The `Drain()` method is crucial for flushing any buffered data after all frames have been sent.
### Methods
#### `Encode(AVFrame frame)`
Sends an `AVFrame` to the encoder for processing.
#### `Drain()`
Flushes the encoder's internal buffer by sending a null frame, ensuring all encoded data is retrieved.
#### `Dispose()`
Frees the encoder's context resources.
### Usage Example
```csharp
// Initialize encoder
using var outFile = File.Open("output.h264", FileMode.Create);
using var encoder = new H264VideoStreamEncoder(outFile, fps: 25, frameSize: new Size(1920, 1080));
// Encode frames
int n = 0;
foreach (var jpg in frames)
{
var frame = LoadAndConvertFrame(jpg); // returns AVFrame in YUV420P
frame.pts = n++ * 25;
encoder.Encode(frame);
}
// Drain the encoder
encoder.Drain();
```
```
--------------------------------
### VideoStreamDecoder Class
Source: https://context7.com/ruslan-b/ffmpeg.autogen/llms.txt
This class decodes video frames from a given media URL. It supports optional hardware acceleration and provides properties for codec name, frame size, and pixel format.
```APIDOC
## Class: VideoStreamDecoder
### Description
Wraps the `avformat` / `avcodec` open+decode loop. It selects the best video stream, optionally creates a hardware accelerator context, and exposes `TryDecodeNextFrame` which drives the `avcodec_send_packet` / `avcodec_receive_frame` API. Hardware frames are automatically transferred to system memory via `av_hwframe_transfer_data`.
### Constructor
`VideoStreamDecoder(string url, AVHWDeviceType hwDevice = AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)`
Opens a media URL and initializes the decoder. Optionally configures hardware acceleration.
### Properties
- **CodecName** (string): The name of the video codec.
- **FrameSize** (Size): The dimensions (width and height) of the video frames.
- **PixelFormat** (AVPixelFormat): The pixel format of the decoded frames.
### Methods
- **TryDecodeNextFrame()** (out AVFrame): Attempts to decode and return the next video frame. Returns `true` if a frame is successfully decoded, `false` if the end of the stream is reached.
- **Dispose()**: Releases all resources held by the decoder.
### Usage Example
```csharp
var url = "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_1MB.mp4";
using var decoder = new VideoStreamDecoder(url, AVHWDeviceType.AV_HWDEVICE_TYPE_NONE);
Console.WriteLine($"Codec: {decoder.CodecName}, Size: {decoder.FrameSize}");
int n = 0;
while (decoder.TryDecodeNextFrame(out var frame))
Console.WriteLine($"Decoded frame #{n++}, pts={frame.pts}");
```
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.