У меня есть видеодекодер ffmpeg-autogen, я пытаюсь использовать D3D11 в качестве аппаратного ускорителя, но кадр, который я получаю в результате (в формате NV12), неверный. Если я делаю то же самое с Vulkan в качестве ускорителя, все работает нормально, но vulkan использует больше ресурсов видеокарты..
Для рендеринга использую OpenTK, полученные кадры конвертирую в RGB с текстурами и шейдерами.
Ниже инициализация моего декодера.
public VideoStreamDecoder(AVCodecParameters* parameters, AVCodec* codec)
{
AVCodec* _codec = codec;
_pCodecContext = ffmpeg.avcodec_alloc_context3(_codec);
ffmpeg.av_hwdevice_ctx_create(&_pCodecContext->hw_device_ctx, AVHWDeviceType.AV_HWDEVICE_TYPE_D3D11VA, null, null, 0).ThrowExceptionIfError();
ffmpeg.avcodec_parameters_to_context(_pCodecContext, parameters).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;
_pFrame = ffmpeg.av_frame_alloc();
_receivedFrame = ffmpeg.av_frame_alloc();
}
И функция чтения кадров
public bool TryReadNextFrame(out AVFrame frame, AVPacket packet)
{
int error;
do
{
ffmpeg.avcodec_send_packet(_pCodecContext, &packet).ThrowExceptionIfError();
error = ffmpeg.avcodec_receive_frame(_pCodecContext, _pFrame);
} while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));
error.ThrowExceptionIfError();
ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0);
//here i get NV12 frame
var clonedFrame = ffmpeg.av_frame_clone(_receivedFrame);
frame = *clonedFrame;
return true;
}
И вот результат, который я получаю с обоими ускорителями:
Vulkanнормально работает
Та же камера, но D3D11сломан
Еще один интересный момент, это то, что камеры, которые не работают, имеют формат yuv420p, а единственная работающая с D3D11 имеет yuvj420.
Я попробовал изменить формат с помощью sws_scale с NV12 на NV12, и это сработало, но оно использует слишком много ресурсов процессора.
Также попробовал изменить формат на rgb перед функцией av_hwframe_transfer_data и отобразить его с помощью рендеринга Vulkan, с Vulkan вроде как работает, а с D3D11 — нет.
ОБНОВЛЯТЬ
Я заметил, что размер рамки больше ширины, и попробовал
_receivedFrame->linesize[0] = _receivedFrame->width;
И это помогло, теперь изображение выглядит лучше, но всё равно не идеально.
ОБНОВЛЕНИЕ 2
я тоже пробую
_receivedFrame->linesize[1] = _receivedFrame->width; и теперь все работает как надо, у меня ушел целый день на написание двух строчек кода :)
извини, я имею в виду ускорение D3D11, а из av_hwframe_transfer_data я получаю кадр от графического процессора, он имеет формат nv12





Проблема заключалась в том, что размер линии кадра на самом деле был больше, чем ширина. Уравнивание решило проблему.
ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0);
_receivedFrame->linesize[0] = _receivedFrame->width;
_receivedFrame->linesize[1] = _receivedFrame->width;
Что вы подразумеваете под «разрывами формата NV12 при использовании D3D11», D3D11 не поддерживает формат NV12, вы должны преобразовать его в RGBA. Где ваш код D3D11?