我正在尝试使用 FFmpeg.autogen 4.3.0.3 库https://github.com/Ruslan-B/FFmpeg.AutoGen中有关解码视频(FFmpeg.AutoGen.Example)的基本示例来解码 GPU 上的多个视频(AMD Radeon R7 430)。我的主要功能如下:
private static void Main(string[] args)
{
var url = @".\abc.mp4";
for (int i = 0; i < 11; i++)
{
url = @"D:\video\abc" + i + ".mp4";
new Thread(() =>
{
DecodeAllFramesToImages(AVHWDeviceType.AV_HWDEVICE_TYPE_D3D11VA, url);
}).Start();
}
}
我尝试使用 GPU 硬件加速解码视频 abc.mp4。但是,当我运行线程数大于 10 时会发生错误。错误图像如下:
- “System.AccessViolationException:试图读取或写入受保护的内存。这通常表明存在其他内存。” 在此处输入图像描述
- 并且在控制台屏幕中出现错误消息“无法创建 D3D11VA 视频解码器”和“格式 d3d11 设置失败:hwaccel 初始化返回错误” 在此处输入图像描述。
我最近是 ffmpeg 库的新手,所以我不太清楚这个问题,我很想得到你的帮助来解决这个错误!
private static unsafe void DecodeAllFramesToImages(AVHWDeviceType HWDevice, string url)
{
using (var vsd = new VideoStreamDecoder(url,HWDevice))
{
Console.WriteLine($"codec name: {vsd.CodecName}");
var info = vsd.GetContextInfo();
info.ToList().ForEach(x => Console.WriteLine($"{x.Key} = {x.Value}"));
var sourceSize = vsd.FrameSize;
var sourcePixelFormat = HWDevice == AVHWDeviceType.AV_HWDEVICE_TYPE_NONE ? vsd.PixelFormat : GetHWPixelFormat(HWDevice);
var destinationSize = sourceSize;
var destinationPixelFormat = AVPixelFormat.AV_PIX_FMT_YUV420P;
using (var vfc = new VideoFrameConverter(sourceSize, sourcePixelFormat, destinationSize, destinationPixelFormat))
{
var frameNumber = 0;
while (vsd.TryDecodeNextFrame(out var frame))
{
//var convertedFrame = vfc.Convert(frame);
// using (var bitmap = new Bitmap(convertedFrame.width, convertedFrame.height, convertedFrame.linesize[0], PixelFormat.Format24bppRgb, (IntPtr) convertedFrame.data[0]))
// bitmap.Save($"frame.{frameNumber:D8}.jpg", ImageFormat.Jpeg);
Console.WriteLine($"frame: {frameNumber}");
frameNumber++;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
namespace FFmpeg.AutoGen.Example
{
public sealed unsafe class VideoStreamDecoder : IDisposable
{
private readonly AVCodecContext* _pCodecContext;
private readonly AVFormatContext* _pFormatContext;
private readonly int _streamIndex;
private readonly AVFrame* _pFrame;
private readonly AVFrame* _receivedFrame;
private readonly AVPacket* _pPacket;
public VideoStreamDecoder(string url, AVHWDeviceType HWDeviceType = AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
{
_pFormatContext = ffmpeg.avformat_alloc_context();
_receivedFrame = ffmpeg.av_frame_alloc();
var pFormatContext = _pFormatContext;
ffmpeg.avformat_open_input(&pFormatContext, 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 (HWDeviceType != AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
{
ffmpeg.av_hwdevice_ctx_create(&_pCodecContext->hw_device_ctx, HWDeviceType, 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 string CodecName { get; }
public Size FrameSize { get; }
public AVPixelFormat PixelFormat { get; }
public void Dispose()
{
ffmpeg.av_frame_unref(_pFrame);
ffmpeg.av_free(_pFrame);
ffmpeg.av_packet_unref(_pPacket);
ffmpeg.av_free(_pPacket);
ffmpeg.avcodec_close(_pCodecContext);
var pFormatContext = _pFormatContext;
ffmpeg.avformat_close_input(&pFormatContext);
}
public bool TryDecodeNextFrame(out AVFrame frame)
{
ffmpeg.av_frame_unref(_pFrame);
ffmpeg.av_frame_unref(_receivedFrame);
int error;
do
{
try
{
do
{
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 IReadOnlyDictionary<string, string> GetContextInfo()
{
AVDictionaryEntry* tag = null;
var result = new Dictionary<string, string>();
while ((tag = ffmpeg.av_dict_get(_pFormatContext->metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null)
{
var key = Marshal.PtrToStringAnsi((IntPtr) tag->key);
var value = Marshal.PtrToStringAnsi((IntPtr) tag->value);
result.Add(key, value);
}
return result;
}
}
}