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
Мобильная версия