2017-01-17 7 views
0

Я разрабатываю специальный видеоплеер, который применяет «фильтры» для каждого декодированного кадра. Моя текущая цель - масштабировать декодированный кадр (без ограничений, за исключением предела памяти).Масштабирование IDirect3DSurface9

Часть декодирования выполняется с использованием ffmpeg (av_read_frame, avcodec_send_packet, avcodec_receive_frame). EVR из Media Foundation используется в качестве рендеринга видео. Точнее, я извлекаю «образец» (который является всего лишь оберткой вокруг обычной экранной поверхности d3d), ffmpeg использует этот буфер для хранения декодированного фрейма, и я даю этот «образец» визуализатору, который кэширует его, а затем представляет его на экране при необходимости (время представления из временной метки образца, скорости воспроизведения и системных часов).

я получить поверхности (формат = X8R8G8B8, тип = D3DRTYPE_SURFACE, использование = 0, бассейн = D3DPOOL_DEFAULT, Мультисэмпл = DDMULTISAMPLE_NONE) из пула доступных поверхностей (через IMFVideoSampleAllocator). Работа с данными RGB32 является требованием, и декодированные кадры преобразуются при необходимости.

Что касается функции масштабирования/масштабирования, я сначала использовал функцию libswscale (функция sws_scale) с SWS_FAST_BILINEAR, но для изменения размера моего кадра с 1920x800 до 1920x400 требуется ~ 80 мс (фиксированные значения для целей тестирования). Затем я попытался сделать масштабирование себя, используя наивный билинейный алгоритм, но это было хуже и уходило на пол.

Я выполнил минимальный тестовый пример, который загружает BMP-файл, масштабирует его и записывает масштабированные данные в другой BMP. Удивительно, что тот же код занимает ~ 15 мс (libswcale) или ~ 30 мс (наивный билинейный).

Затем я модифицировал свой видеоплеер, используя av_image_alloc и av_image_copy_to_buffer. Выделение не требует времени, копирование занимает целую секунду, а масштабирование занимает 5 мс. Вся часть слишком медленная, чтобы делать масштабирование в реальном времени, но это показывает, что существует большая разница между «происхождением» памяти (поверхность malloc'ed или d3d).

Выравнивание данных может быть причиной медленности, но мой тестовый пример использует тот же шаблон в памяти (шаг = ширина * 4, снизу вверх), и это намного быстрее. Я печатал входной и выходной буфер% 16, и это 0, поэтому мне кажется безопасным.

Я также пробовал использовать метод StretchRect, но он не работает между внешними поверхностями.

Есть идеи? NB: Я планирую создавать поверхности и представлять их самостоятельно, поэтому часть рендеринга является слабой зависимостью для меня. Итак, если у вас есть простой образец D3D в качестве ссылки, я возьму его.

+0

Я думаю, вы можете использовать DXVA2/DXVA-HD для масштабирования. – VuVirt

ответ

0

Я изучил «EVRPresenter sample» код и масштабирование выполняются с помощью исходных/удаленных RECT при вызове метода IDirect3DSwapChain9 :: Present, поэтому я догадался IDirect3DDevice9 :: StretchRect был правильным подходом.

Поскольку он не поддерживает растягивание между экранными поверхностями, я создал целевую поверхность визуализации с помощью IDirect3DDevice9 :: CreateRenderTarget, и теперь работает вызов StretchRect. Масштабирование даже достаточно быстро, чтобы отображать видео 4K без какого-либо дрожания! Я использую libswscale как откат.

@VuVirt В настоящее время я использую EVR, который поддерживает DXVA, поэтому я предполагаю, что он используется внутренне. Я буду внимательно читать API, я, вероятно, буду использовать его, когда напишу свой собственный ведущий.

Я понял, что это действительно задача рендеринга для смешивания/масштабирования/представления кадров. Мой текущий код работает, но я полагаюсь на внутренности визуализации. В некоторых случаях рендеринг может использовать интерфейсы Direct3D10 и StrectRect is not available in Direct3D10.

В любом случае, спасибо за чтение!

Смежные вопросы