Производительность IDirectXVideoDecoder

Я пытаюсь понять некоторые нюансы IDirectXVideoDecoder. ПРЕДУПРЕЖДЕНИЕ. Выводы, изложенные ниже, не основаны на документах DirectX или каком-либо другом официальном источнике, а являются моими собственными наблюдениями и пониманиями. Это сказал …

При обычном использовании IDirectXVideoDecoder достаточно быстро обрабатывает кадры с любой разумной частотой кадров. Однако, если вы не визуализируете кадры на основе временных кодов и вместо этого идете «как можно быстрее», то в конечном итоге вы сталкиваетесь с узким местом в декодере, и IDirectXVideoDecoder :: BeginFrame начинает возвращать E_PENDING.

По-видимому, в любой момент времени система может иметь только активные X-кадры в декодере. Попытка отправить X + 1 дает вам эту ошибку, пока один из предыдущих кадров не завершится. На моей (несколько более старой) коробке X == 4. На моей новой коробке X == 8.

Что подводит нас к моему первому вопросу:

Q1: Как узнать, сколько одновременных операций декодирования поддерживает система? Какое свойство / атрибут описывает это?

Тогда возникает вопрос, что делать, когда вы нажмете эту ошибку. Я могу придумать 3 разных подхода, но все они имеют недостатки:

1) Просто сделайте цикл в ожидании освобождения декодера:

do {
hr = m_pVideoDecoder->BeginFrame(pSurface9Video[y], NULL);
} while(hr == E_PENDING);

С другой стороны, этот подход обеспечивает максимальную пропускную способность. С другой стороны, это приводит к сожжению огромного количества процессорного времени в ожидании освобождения декодера (здесь тратится> 93% моего времени выполнения).

2) Сделайте цикл и добавьте Sleep:

do {
hr = m_pVideoDecoder->BeginFrame(pSurface9Video[y], NULL);
if (hr == E_PENDING)
Sleep(1);
} while(hr == E_PENDING);

С другой стороны, это значительно снижает нагрузку на процессор. Но со стороны минус, это в конечном итоге замедляет общую пропускную способность.

Пытаясь выяснить, почему это тормозит, я сделал несколько замечаний:

  • Обычное время обработки кадра в моей системе составляет ~ 4 миллисекунды.
  • Sleep (1) может спать в течение целых 8 миллисекунд, даже когда есть доступные для работы процессоры.
  • Кадры, отправленные декодерам, не добавляются в очередь и не декодируются по одному. Он фактически выполняет X-декодирование одновременно.

Результатом всего этого является то, что если вы пытаетесь заснуть, один из декодеров часто оказывается бездействующим.

3) Перед отправкой следующего кадра для декодирования дождитесь завершения одного из предыдущих кадров:

// LockRect doesn't return until the surface is ready.
D3DLOCKED_RECT lr;

// I don't think this matters.  It may always return the whole frame.
RECT r = {0, 0, 2, 2};
hr = pSurface9Video[old]->LockRect(&lr, &r, D3DLOCK_READONLY);
if (SUCCEEDED(hr))
pSurface9Video[old]->UnlockRect();

Это также снижает нагрузку на процессор, но также снижает производительность. Возможно, из-за того, что «поверхность» используется дольше, чем «декодер», но более вероятно, потому что время, которое требуется (бессмысленно) для передачи кадра обратно в память.

Что подводит нас ко второму вопросу:

Q2: Есть ли здесь какой-нибудь способ увеличить пропускную способность без бессмысленной нагрузки на процессор?

Последние мысли:

  • Похоже, что LockRect должен делать WaitForSingleObject. Если бы у меня был доступ к этому дескриптору, ожидание (без копирования кадра) кажется лучшим решением. Но я не могу понять, где его взять. Я пробовал GetDC, GetPrivateData, даже глядя на отладочные данные членов для IDirect3DSurface9. Я не нахожу это.
  • IDirectXVideoDecoder :: EndFrame выводит дескриптор в параметре с именем pHandleComplete, Это звучит как то, что мне нужно. К сожалению, он помечен как «зарезервированный» и, похоже, не работает. Разве есть хитрость?
  • Я довольно новичок в DirectX, так что, может быть, я все неправильно понял?

Обновление 1:

По поводу Q1: Оказывается, обе мои машины поддерживают только 4 декодера (упс). Это затруднит определение того, какое свойство я ищу. В то время как очень немногие свойства (на самом деле ни одно) не возвращают 8 на одной машине и 4 на другой, есть несколько, которые возвращают 4.

По вопросу 2: Поскольку (4) декодеры (предположительно) совместно используются приложениями, идея выяснить, завершено ли декодирование путем (каким-либо образом) запроса о том, не занят ли декодер, не является началом.

Вызов для создания поверхностей не создает дескрипторы (количество дескрипторов остается неизменным во время вызова). Так что идея ожидания на «ручке поверхности» тоже не выглядит удачной.

Единственная идея, которую я оставил, состоит в том, чтобы увидеть, доступна ли поверхность, сделав какой-то другой вызов (кроме LockRect), используя ее. До сих пор я пытался вызывать StretchRect и ColorFill на поверхности, которую декодер «все еще использует», но они завершаются без ошибок, а не блокируются, как LockRect.

Здесь не может быть лучшего ответа здесь. Пока что кажется, что для лучшей производительности я должен использовать # 1. Если загрузка ЦП является проблемой, № 2 лучше, чем # 1. Если я все равно буду читать поверхности обратно в память, тогда # 3 имеет смысл, иначе придерживайтесь 1 или 2.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector