LINUX.ORG.RU

Как вычислить недостающие параметры H.264 потока

 , ,


1

3

Я тут в процессе написания драйвера vdpau застрял. Чтобы заработало ускорение декодирования, надо вызывать vaapi. Проблема состоит в том, что оба интерфейса требуют разные параметры H.264. Часть из них совпадает по имени поля в структурах (имена взяты из стандарта), а часть нет. При этом VAAPI требует намного больше данных, чем VDPAU, то есть мне нужно откуда-то эти данные взять.

К примеру, нужен такой параметр, как first_mb_in_slice. Его можно достать из потока, ffmpeg его достаёт и... выбрасывает. А потом, когда нужно формировать это поле для передачи в vaRenderPicture, высчитывает заново, причём с текстом стандарта это плохо соотносится (там должно быть смещение, либо половина смещения, в зависимости от флага. Код в ffmpeg делит пополам только координату y, а x просто прибавляет). И так далее. Всё осложняется тем, что я не знаком с подробностями технологий сжатия видео.

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

В общем, нужна рука помощи. Я тут ниже буду постить особо непонятные мне моменты. Надеюсь на ваше понимание.

Upd. Все параметры нашлись в самом потоке. Первый байт после заголовка — NAL header, дальше slice_header (7.3.3), в котором и были недостающие данные.

★★★★★

Последнее исправление: i-rinat (всего исправлений: 1)
slice_parameters->slice_type

Судя по всему, тип слайса — то же самое, что тип кадра, I,P,B. Правильно ли я понимаю, что тип кадра можно определить по числу ссылок на другие? То есть ноль ссылок — I, одна ссылка — P, две и больше — B? Число ссылок у меня есть.

pic_param->pic_init_qs_minus26

С этим вообще ступор. SI, SP слайсы — вообще загадка.

slice_parameters->direct_spatial_mv_pred_flag

В ffmpeg хранится какой-то внутренний флаг direct_spatial_mv_pred, берётся, по-видимому, из потока. Как его вычислить из других параметров?

        slice_parameters->cabac_init_idc
        slice_parameters->slice_qp_delta
        slice_parameters->disable_deblocking_filter_idc
        slice_parameters->slice_alpha_c0_offset_div2
        slice_parameters->slice_beta_offset_div2

То же.

За RefPicList ещё не брался, но там похоже просто копия ссылочных кадров.

i-rinat ★★★★★
() автор топика
Ответ на: комментарий от GAMer

Там же ещё вроде направление есть.

Ась? Я понимаю, что большая часть моих вопросов разрешится внимательным чтением стандарта, но там 280 страниц.

i-rinat ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

Ну если б я что-то понимал... =)
B-фрейм же ссылается и вперёд и назад.

GAMer ★★★★★
()
Ответ на: комментарий от i-rinat

То есть ноль ссылок — I, одна ссылка — P, две и больше — B?

Википедия утверждает, что в h.264 как p, так и b слайсы могут иметь по несколько ссылок. Даже b может иметь всего одну.

А так как они всегда в порядке декодирования, разницы между ними и нет (?). Одним вопросом больше.

i-rinat ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

но там 280 страниц.

Я нашёл свежую (актуальную) версию рекомендаций на http://www.itu.int . Теперь там 680 страниц.

i-rinat ★★★★★
() автор топика

Выяснилось, что данные посылаются вместе со nal header + slice_header(), в нём многие параметры есть, надеюсь, что все. Осталось разобрать поток.

i-rinat ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

Все параметры нашлись в самом потоке. Первый байт после заголовка — NAL header, дальше slice_header (7.3.3), в котором и были недостающие данные.

Некоторые параметры так и остались неизвестными, но они, похоже, драйвером не используются.

i-rinat ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

Судя по всему, тип слайса — то же самое, что тип кадра, I,P,B. Правильно ли я понимаю, что тип кадра можно определить по числу ссылок на другие? То есть ноль ссылок — I, одна ссылка — P, две и больше — B? Число ссылок у меня есть.

00 00 00 01 - в битстриме это начало NAL, ты вроде уже нашел все это... если распаковывать контейнер, например mp4 - там начало каждого слайса указано в самом контейнере, поэтому 00 00 00 01 - байты отсутствуют.

Размер NAL его обычно 4 байта (почти всегда), можно их пропустить, дальше следующий байт (точнее 5 его бит) несет в себе информацию о типе юнита: (type & 0x1f), если тип == [1..5] это слайс (5 по-моему это IDR), (слайс = кадр или часть кадра, (обычно кадр)), и если тип юнит - это слайс, то пропускаем байт, пропускаем голомб и читаем следующий голомб, если он = 4, 7, 9 это I фрейм, 3, 5, 8 - P фрейм, 1, 6 - B фрейм.

Число ссылок, да, может варьировать, до 16 для High profile.

Чтобы взять все параметры стрима (а не отдельного слайса), нам нужны два особых юнита, которые предваряют каждый IDR, это SPS (+VUI данные) и PPS, но, полагаю, это ты давно уже нашел. :-)

Вообще будут вопросы по поводу AVC или особенно контейнеров, пиши в личку, мож что подскажу.

elijah_sd
()
Ответ на: комментарий от elijah_sd

Эх, кабы ты раньше сказал, я б столько сил сэкономил. Особенно про заголовок слайса и exp-golomb.

Дополнительной сложностью было то, что у меня нет доступа ко всему потоку. Только слайсы. К тому же некоторых значений из PPS не хватает, а VAAPI требует почти все.

i-rinat ★★★★★
() автор топика
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Ну про вывод изображения и масштабирование я понял.
А вот то, что ты все vaapi скармливашь - вот это я пропустил.

devl547 ★★★★★
()
Ответ на: комментарий от devl547

все vaapi скармливашь

Изначально я этого и хотел. OpenGL это из-за того что у VAAPI с композитингом беда.

i-rinat ★★★★★
() автор топика
2 декабря 2014 г.
Ответ на: комментарий от elijah_sd

...

очень любопытно как вы обрабатываете сырой поток H264? хочу написать свой обработчик, можете немного проконсультировать?буду очень признателен!

Nebesny
()
Ответ на: ... от Nebesny

На самом деле ничего сложного, но много рутины. ITU-T в помощь :-)

Мы с коллегами занимались разбором параметров h264 стрима (SPS/PPS/SEI/VUI). А как работает декодинг я себе представляю (возможно даже детально), но никогда этим не занимался.

В ffmpeg и подобных проектах можно найти пример парсинга SPS/PPS, но все сводится к написанию битридера, из которого последовательно (по спеке) читаются значения полей - эн бит или код голомба; будет много ветвлений, так что в общем случае нельзя все сразу прочитать в структуру и брать поля, приходится именно побитно вычитывать.

Если дадите контакты могу скинуть пару ссылок на простые примеры к которым я имею отношение и могу объяснить как оно работает (т.к. тот же ffmpeg по-моему не лучший проект для разбора).

elijah_sd
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.