AVFrame с форматом NV12 прерывается с использованием аппаратного ускорения D3D11

У меня есть видеодекодер 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; и теперь все работает как надо, у меня ушел целый день на написание двух строчек кода :)

Что вы подразумеваете под «разрывами формата NV12 при использовании D3D11», D3D11 не поддерживает формат NV12, вы должны преобразовать его в RGBA. Где ваш код D3D11?

Simon Mourier 12.06.2024 12:03

извини, я имею в виду ускорение D3D11, а из av_hwframe_transfer_data я получаю кадр от графического процессора, он имеет формат nv12

faith0058 12.06.2024 12:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема заключалась в том, что размер линии кадра на самом деле был больше, чем ширина. Уравнивание решило проблему.

ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0);
_receivedFrame->linesize[0] = _receivedFrame->width;
_receivedFrame->linesize[1] = _receivedFrame->width;

Другие вопросы по теме