Самый быстрый способ декодировать и отображать много видео H264 одновременно C # - PullRequest
4 голосов
/ 14 мая 2011

Как вы можете догадаться из названия вопроса, мы должны декодировать и отображать несколько (например, восемь) видео в формате H.264 одновременно (и синхронизировать их все время, но это уже другой вопрос в другой раз),Видео, как правило, со скоростью 25 кадров в секунду с разрешением 640x480.

Я собираюсь предоставить немного фона, прежде чем я пойму суть проблемы.

Функция должназапекаться в довольно большое приложение C # 3.5 (WinForms).Видео будут занимать прямоугольники в приложении - управляемый код должен быть в состоянии указать, где каждое видео рисуется, а также его размер.

Мы получаем пакеты H264 в C # и запускаем их в собственный декодер H264чтобы получить данные изображения YUV12.

Ранняя попытка состояла в том, чтобы преобразовать изображения YUV12 в RGB24 и передать их BitBlt в HWND, переданный в собственный код из C #.Несмотря на то, что все функции BitBlt'а работали, они должны были происходить в потоке пользовательского интерфейса, что приводило к его замедлению при отображении более пары видео (на 2.6 GHZ core 2 duo).

Текущая попытка ускоряется на однуthread-per-cpu-core при запуске и загрузке балансирует декодирование / отображение видео между этими потоками.Производительность этого потрясающая (мне кажется, что просмотр диспетчера задач гораздо интереснее, чем показ видео).В пользовательском интерфейсе это оставляет желать лучшего.

За миллисекунду, которую мы начали рисовать в HWND, созданном в потоке пользовательского интерфейса (например, панели, закрепленной в элементе управления WinForms) из потока, не являющегося пользовательским интерфейсом, мыиз-за неконтролируемости потоков WinForms начал получать всевозможные забавные действия.Это привело к тому, что мы создали HWND в нативном коде и обратились к ним, причем C # предоставляет прямоугольники, к которым они должны быть обращены в экранных координатах.

Гах!CanOfWorms.Open ().

Проблема: Когда приложение C # получает фокус, оно переходит в начало Z-порядка и скрывает окна видео.Решение. Поместите окна видео всегда сверху.

Проблема: Когда пользователь переключается на другое приложение, окна видео все еще находятся сверху.Решение: Определите активацию и деактивацию приложения C # и соответственно отобразите / скрыте окна видео.

Проблема: пользователь говорит: «Я хочу, чтобы мои видео воспроизводились на одном мониторе, а я редактировал документ Word на другом!»Решение: Скажите пользователю, чтобы он заткнулся, и Word все равно отстой.

Проблема: меня уволили.

и т. Д.и т.д.

Полагаю, суть проблемы в том, что у нас есть HWND, созданные в потоке, не являющемся пользовательским интерфейсом, и мы хотим «смоделировать» те, которые встроены в приложение C #./ предложения?Полностью ли я здесь пообедаю?

Я более чем готов принять совершенно другой подход, если таковой существует (Этот проект потребовал много обучения - выигрыш в лотерею имел бы большую вероятность, чем я выбраллучший подход на каждом шагу вдоль дороги).

Ответы [ 3 ]

3 голосов
/ 14 мая 2011

Забудьте о BitBlt-ing и сделайте это:

  • для каждого окна, в котором вы хотите, чтобы ваше видео воспроизводилось, создайте один график DirectShow и прикрепите средство визуализации графика к этому окну
  • перед рендерингом на графике установите фильтр samplegrabber. Это позволит вам иметь обратный вызов, в котором вы сможете заполнить буфер
  • вместо блиттинга декодировать в буфер, предоставленный в samplegrabber.

Кроме того, я предполагаю, что вы сможете поместить необработанный YUV12 в буфер, поскольку VMRenderer может отображать их напрямую.

Использование DirectShowNet библиотека.

EDIT:

И да, кстати, если видео находится на одном и том же «холсте», вы можете использовать ту же технику с рендерером и создать только одно большое окно, затем сдвинуть декодированные прямоугольники видео «вручную» и поместить их в буфер кадрового буфера.

ЕЩЕ ДРУГОЕ РЕДАКТИРОВАНИЕ:

Бит-биты ВСЕГДА сериализуются, т.е. они не могут работать параллельно.

2 голосов
/ 14 мая 2011

За миллисекунду, которую мы начали рисовать в HWND, созданном в потоке пользовательского интерфейса (например, на панели, закрепленной в элементе управления WinForms) из потока, не являющегося пользовательским интерфейсом, мы начали получать все виды прикольного поведения из-за отсутствия безопасности потока WinForms. Это привело к тому, что мы создали HWND в нативном коде и обратились к ним, причем C # предоставляет прямоугольники, к которым они должны быть нарисованы в экранных координатах.

Что за прикольное поведение? Если вы имеете в виду мерцание или задержку рисования, пытались ли вы заблокировать () панель или любой другой класс для синхронизации потоков / рисования? Опять же: какая именно проблема, когда вы отправляете данные в декодер, получаете изображение, конвертируете его и затем рисуете его с помощью обработчика OnPaint. (Установите другой поток, который зацикливается на 25fps, вызовите panel1.Invalidate () затем)

Полагаю, суть проблемы в том, что у нас есть HWND, созданные в потоке, не являющемся пользовательским интерфейсом, и мы хотим "смоделировать" те, которые встроены в приложение C #.

Не делай этого. Попробуйте нарисовать полученные данные в вашем приложении c #. В общем, я бы не рекомендовал смешивать нативный код и c #. Единственным исключением здесь является наличие декодера h264 в нативном коде.

Используйте ваши потоки для декодирования видеопакетов (как вы уже это делаете), затем создайте один поток, который зацикливается и вызывает Invalidate (как сказано выше). Затем создайте обработчик OnPaint для каждой панели, на которой отображается видео. В этом обработчике получите самое последнее видеоизображение и нарисуйте его (e.Graphics).

Надеюсь, это поможет, но также нужно больше информации о проблеме ...

0 голосов
/ 14 мая 2011

Мне нравится ответ DirectShow, опубликованный ранее, но я хотел включить дополнительную опцию, которую вам было бы проще реализовать, основываясь на этом отрывке из вашего вопроса:

Будучи функциональным, все BitBlt'ing должен был происходить в потоке пользовательского интерфейса, что приводило к его замедлению при отображении более пары видео

Моя идея состоит в том, чтобы начать с этого кода и использовать Async CTP для Visual Studio 2010, который в настоящее время доступен и включает в себя действующую лицензию. Оттуда должно быть относительно просто изменить существующий код, чтобы он был более отзывчивым: просто добавьте ключевые слова await и async в нескольких местах, а остальная часть кода должна быть в основном неизменной.

...