C# winui3 можно ли использовать FFMPEG для декодирования с использованием аппаратного обеспечения, а затем рендеринг с пC#

Место общения программистов C#
Ответить
Anonymous
 C# winui3 можно ли использовать FFMPEG для декодирования с использованием аппаратного обеспечения, а затем рендеринг с п

Сообщение Anonymous »

Я использую ffmpeg.autogen и microsoft.graphics.win2d в C# для декодирования и рендеринга из события кадров H264 []. В настоящее время я достиг гладкого экрана экрана, используя программное обеспечение CanvasanimatedControl и FFMPEG Decoding, но он использует много процессора (не заметно на 5% на моей машине разработки, но на 30% на моем другом менее мощном ноутбуке). https://github.com/natsurainko/airplay. ... ctx_create(&hwCtx,
AVHWDeviceType.AV_HWDEVICE_TYPE_D3D11VA,
null, null, 0);
< /code>
to decode an AVFrame[/code] with AVPixelFormat.AV_PIX_FMT_D3D11, and then trying to extract its data[0] ID3D11Texture and convert it to Windows.Graphics.DirectX.Direct3D11.IDirect3DSurface (because win2d supports Canvasbitmap.createfromDirect3d11surface ),

, но после того, как попробовал многие методы, было показано, что компонент id3d11texture , данное FFMPEG, не имел интерфейса idiRect3drafface (

Код: Выделить всё

QueryInterface
Метод всегда сообщал об ошибке)
Моя текущая реализация заключается в следующем
using FFmpeg.AutoGen.Abstractions;
using System;

namespace AirPlay.App.FFmpeg;

public unsafe partial class H264HardwareDecoder : IDisposable
{
private readonly AVCodecContext* _codecContext;
private readonly AVFrame* _frame;
private readonly AVPacket* _packet;
private readonly AVBufferRef* _hwDeviceCtx;

public IntPtr _d3d11Device;
public IntPtr _d3d11DeviceContext;

public bool Disposed { get; private set; }

public H264HardwareDecoder()
{
AVCodec* codec = ffmpeg.avcodec_find_decoder(AVCodecID.AV_CODEC_ID_H264);
_codecContext = ffmpeg.avcodec_alloc_context3(codec);

AVBufferRef* hwCtx = null;
int ret = ffmpeg.av_hwdevice_ctx_create(&hwCtx,
AVHWDeviceType.AV_HWDEVICE_TYPE_D3D11VA,
null, null, 0);

if (ret < 0)
throw new ApplicationException("Failed to create D3D11VA device");

_hwDeviceCtx = hwCtx;
_codecContext->hw_device_ctx = ffmpeg.av_buffer_ref(_hwDeviceCtx);

AVHWDeviceContext* hwDeviceCtx = (AVHWDeviceContext*)_hwDeviceCtx->data;
AVD3D11VADeviceContext* d3d11vaCtx = (AVD3D11VADeviceContext*)hwDeviceCtx->hwctx;

_d3d11Device = (IntPtr)d3d11vaCtx->device;
_d3d11DeviceContext = (IntPtr)d3d11vaCtx->device_context;

ffmpeg.avcodec_open2(_codecContext, codec, null);

_frame = ffmpeg.av_frame_alloc();
_packet = ffmpeg.av_packet_alloc();
}

public bool DecodeFrame(byte[] h264Data, out IntPtr d3d11Texture, out int textureIndex, out int width, out int height)
{
d3d11Texture = IntPtr.Zero;
textureIndex = 0;
width = height = 0;

fixed (byte* p = h264Data)
{
ffmpeg.av_packet_unref(_packet);
_packet->data = p;
_packet->size = h264Data.Length;

if (ffmpeg.avcodec_send_packet(_codecContext, _packet) < 0)
return false;

if (ffmpeg.avcodec_receive_frame(_codecContext, _frame) < 0)
return false;

width = _frame->width;
height = _frame->height;

if (_frame->format == (int)AVPixelFormat.AV_PIX_FMT_D3D11)
{
d3d11Texture = (IntPtr)_frame->data[0];
textureIndex = (int)_frame->data[1];

return true;
}

return false;
}
}

public IntPtr GetD3D11Device() => _d3d11Device;
public IntPtr GetD3D11DeviceContext() => _d3d11DeviceContext;

public void Dispose()
{
if (_frame != null)
{
fixed (AVFrame** f = &_frame) ffmpeg.av_frame_free(f);
}
if (_packet != null)
{
fixed (AVPacket** p = &_packet) ffmpeg.av_packet_free(p);
}
if (_codecContext != null)
{
fixed (AVCodecContext** c = &_codecContext) ffmpeg.avcodec_free_context(c);
}
if (_hwDeviceCtx != null)
{
fixed (AVBufferRef** h = &_hwDeviceCtx) ffmpeg.av_buffer_unref(h);
}

Disposed = true;
}
}
< /code>
public static class D3D11Interop
{
[DllImport("d3d11.dll", ExactSpelling = true)]
public static extern int CreateDirect3D11SurfaceFromDXGISurface(
IntPtr dxgiSurface,
out IntPtr direct3DSurface);

public static IDirect3DSurface CreateDirect3DSurfaceFromDXGISurface(IntPtr d3d11Texture)
{
Texture2D texture2D = CppObject.FromPointer(d3d11Texture);
texture2D.QueryInterface(new("cafcb56c-6ac3-4889-bf47-9e23bbd260ec"), out var outPtr);

IntPtr direct3DSurfacePtr;
int hr = CreateDirect3D11SurfaceFromDXGISurface(d3d11Texture, out direct3DSurfacePtr);
if (hr < 0)
{
Marshal.ThrowExceptionForHR(hr);
}

var direct3DSurface = Marshal.GetObjectForIUnknown(direct3DSurfacePtr) as IDirect3DSurface;
Marshal.Release(direct3DSurfacePtr);

return direct3DSurface;
}
}
< /code>
Then my call is as follows
if (UseGpuDecoder)
{
H264HardwareDecoder h264HardwareDecoder = new();
decoder = h264HardwareDecoder;

session.MirrorController!.H264DataReceived += (_, e) =>
{
if (h264HardwareDecoder.DecodeFrame(e.Data, out IntPtr d3d11Texture, out int textureIndex, out var width, out var height))
{
var surface = D3D11Interop.CreateDirect3DSurfaceFromDXGISurface(d3d11Texture);
mirrorWindow?.OnFrameDataReceived(surface);
}
else Debug.WriteLine($"H264 Hardware Decode Failed");
};
}
< /code>
public void OnFrameDataReceived(IDirect3DSurface direct3DSurface)
{
Interlocked.Increment(ref _decodedFrames);

if (_isDisposed || _canvasDevice == null) return;
if (this.WindowState == WindowState.Minimized)
{
Canvas.Paused = true;
return;
}
if (_isRendering)
{
Interlocked.Increment(ref _droppedFrames);
return;
}

_isRendering = true;

DispatcherQueue.TryEnqueue(() =>
{
try
{
if (_isDisposed || _canvasDevice == null) return;

lock (_bitmapLock)
{
if (_currentBitmap == null ||
_currentBitmap.Size.Width != _frameSize.Width ||
_currentBitmap.Size.Height != _frameSize.Height)
{
_currentBitmap?.Dispose();
_currentBitmap = CanvasBitmap.CreateFromDirect3D11Surface(
_canvasDevice,
direct3DSurface
);
}
}

if (Canvas.Paused) Canvas.Paused = false;
}
catch (Exception ex)
{
Debug.WriteLine($"OnFrameDataReceived error: {ex.Message}");
}
finally
{
_isRendering = false;
}
});
}
< /code>
An exception is thrown in the CanvasBitmap.CreateFromDirect3D11Surface< /code> Метод. < /p>

"system.invalidcastexception: «Невозможно разыграть объект com типа 'System .__ Comobject' to Type type 'windows.graphics.directx.direct3d11.iderect3dsurface. Эта операция не удалась, потому что QueryInterface вызовите на componer in the component in the component in the componer in the componered in the componerfface. '{0bf4a146-13c1-4694-bee3-7abf15886}' не удалось из-за следующей ошибки: не поддерживается такая интерфейс (0x80004002 (e_nointerface)). '"


Подробнее здесь: https://stackoverflow.com/questions/797 ... nd-then-re
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»