Пытаюсь разобраться, как происходит преобразование YV12 фрейма. Для простоты создаю вот такой DS граф
С камеры снимаю фреймы размером 640x480, после ЛАВ декодер преобразовывает его в YV12 и передает его на DS рендер.
С Выхода декодера вижу следующее:
Ширина фрейма преобразовалась с 640 на 1024, соответственно, вместо ожидаемого размера 1.5*640*480=460800 вижу 737280,
т.е пересчитанный для ширины 1024. По теории страйд может отличаться от ширины кадра на рендере. Но почему на столько и почему 1024?
И еще, почему в VIDEOINFOHEADER2 установлен флаг деинтерлейсинга — dwInterlaceFlags, хотя в ЛАВ декодере он отключен? Т.е. выходит
, что простым преобразованием RGB24 в YV12 не обойтись, и в мой фильтр нужно добавлять деинтерлейсинг, чтобы нормально заработал DS рендер?
Здравствуйте, Vicul, Вы писали:
V>Ширина фрейма преобразовалась с 640 на 1024, соответственно, вместо ожидаемого размера 1.5*640*480=460800 вижу 737280, V>т.е пересчитанный для ширины 1024. По теории страйд может отличаться от ширины кадра на рендере. Но почему на столько и почему 1024?
Сначала фильтры договариваются на 640х480. Как только Renderer аллоцирует Direct3D surface в видеопамяти, при старте, он берет его реальные размеры и реальный страйд. Это происходит c использованием механизма Dynamic Reconnect from Downstream. У себя в фильтре ты это ловишь как установленное поле media type у output семпла. Для YV12 страйд у тебя будет: для Y плоскости 1024 * 12 / 8 = 1536 байт, для CyCb плоскостей: 512 * 12 / 8 = 768 байт. Плоскости копируешь построчно сразу в память Direct3D surface сначала Y, затем сразу CbCy.
V>Когда я вместо ЛАВ декодера ставлю свой фильтр с преобразованием RGB24 в YV12 (https://gist.github.com/thedeemon/8052fb98f8ba154510d7), V>у меня выходит искаженное изображение, хотя параметры такие же:
V> Image: fail.jpg
V> И еще, почему в VIDEOINFOHEADER2 установлен флаг деинтерлейсинга — dwInterlaceFlags, хотя в ЛАВ декодере он отключен? Т.е. выходит V>, что простым преобразованием RGB24 в YV12 не обойтись, и в мой фильтр нужно добавлять деинтерлейсинг, чтобы нормально заработал DS рендер?
Нет, это флаг для Renderera. Для его использования, если поддерживается, нужно установить соответствующее свойство в его настройках. На копирование буфера это никак не влияет.
V>Где я тупо копирую преобразованный буфер в YV12 c pIn на pOut не подходит?
Как раз подходит. Но нужно копировать все плоскости по строкам с учетом страйда. pOut->GetBuffer() сразу даст указатель на кусок в видео-памяти. Только вот копировать из pOut не желательно, можно сильно просадить производительность на некоторых системах. На всякий случай псевдокод для Y:
for (y = 0; y < 480; ++y) {
copy(src, dst, 640);
src += 640;
dst += stride;
}
V>Как раз подходит. Но нужно копировать все плоскости по строкам с учетом страйда. pOut->GetBuffer() сразу даст указатель на кусок в видео-памяти. Только вот копировать из pOut не желательно, можно сильно просадить производительность на некоторых системах. На всякий случай псевдокод для Y: V>
V>>Как раз подходит. Но нужно копировать все плоскости по строкам с учетом страйда. pOut->GetBuffer() сразу даст указатель на кусок в видео-памяти. Только вот копировать из pOut не желательно, можно сильно просадить производительность на некоторых системах. На всякий случай псевдокод для Y: V>>
Здравствуйте, Vicul, Вы писали:
V>Спасибо заработало. Правильный код здесь, может кому время сэкономит...
Код у вас правильный только для вашего конкретного случая. Лучше не прибивать константы гвоздями, а точно брать из текущего контекста. Страйд задается конкретной реализацией Direct3D и драйвером оборудования. Он не обязан быть 1024 байта и это все определяется аллокацией видеопамяти. По-этому лучше делать так:
Если (SUCCEED(pOut->GetMediaType()), то значит рендерер хочет динамический сменить тип, и это ваш случай. Дальше из этого медиа-типа вы берете VIDEOINFOHEADER и от туда width. Он всегда должен быть больше либо равен вашему size.cx. Дальше страйд вы считаете как vi.vihWidth * 12 /8 — в байтах. Не забудьте после всего вызвать SetMediaType() у фильтра с новым медиа-типом и освободить ресурсы AM_MEDIA_TYPE.
V>Код у вас правильный только для вашего конкретного случая. Лучше не прибивать константы гвоздями, а точно брать из текущего контекста. Страйд задается конкретной реализацией Direct3D и драйвером оборудования. Он не обязан быть 1024
Правильно, константы там не должно быть. Это только код "напопроб", проверить идею. Ну, а в приложении, в первом вызове Transform(), я вызываю GetMediaType(), где я по ширине кадра определяю уже устаканившийся страйд без умножения на 12/8. Умножение мне пока не нужно, потому что граф всегда настраивается на одно только разрешение камеры. А если надо установить новое разрешение, я создаю новый граф. Пока так проще.