Как правильно обернуть H264 в FLV с помощью FFMPEG?

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

tl; dr: существует разница между кодированием видео и его непосредственным сохранением в FLV и выполнением этого в два отдельных этапа. Мне нужно делать это отдельно, как мне получить тот же результат, что и при прямом выполнении?

Аппаратный кодировщик Nvidia NVENC производит необработанные данные H.264 без контейнера, которые трудно воспроизвести в большинстве видеоплееров. Для приложения Adobe AIR мне нужно обернуть видео в формат FLV, для чего я хотел использовать FFMPEG:

ffmpeg -f h264 -i "input.h264" -c copy -f flv "output.flv"

Это не сработало, как ожидалось, потому что первый кадр каждого видео, обработанного таким образом, просто не отображается. Каждое видео отображается только со второго кадра, что является позором для однокадровых видео (с использованием аппаратного кодировщика графического процессора только для молниеносного сжатия изображения).

Для проверки я теперь дважды перекодирую входное видео: один раз прямо на выход FLV.

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f flv "A.flv"

и один раз в H.264, а потом засунул его в FLV.

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f h264 "reencode.h264"
ffmpeg -f h264 -i "reencode.h264" -c copy -f flv "B.flv"

Первое видео воспроизводится нормально, второе - нет. Результирующий FLV прямого подхода (A.flv, см. Ниже) имеет немного другую файловую структуру, особенно отличается блок NAL, что, как я подозреваю, является причиной различного поведения.

Итак, мой вопрос: если у меня уже есть видео H.264 и я хочу, чтобы оно было скопировано в контейнер FLV без перекодирования, но заголовки файла и кадра должны быть правильно заполнены, как это делается при фактическом перекодировании, как это сделать? Я говорю это FFMPEG? Есть ли для этого команды, такие как «-c copy butGenerateValidHeader»?

Вот соответствующие части файлов:

Прямой подход

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f flv "A.flv"

A.flv

46 4C 56 01 01 00 00 00 09 00 00 00 00 12 00 00 // FLV header + metadata
B8 00 00 00 00 00 00 00 02 00 0A 6F 6E 4D 65 74
61 44 61 74 61 08 00 00 00 08 00 08 64 75 72 61
74 69 6F 6E 00 3F A0 E5 60 41 89 37 4C 00 05 77
69 64 74 68 00 40 93 80 00 00 00 00 00 00 06 68
65 69 67 68 74 00 40 8E F0 00 00 00 00 00 00 0D
76 69 64 65 6F 64 61 74 61 72 61 74 65 00 40 9E
84 80 00 00 00 00 00 09 66 72 61 6D 65 72 61 74
65 00 40 3E 00 00 00 00 00 00 00 0C 76 69 64 65
6F 63 6F 64 65 63 69 64 00 40 1C 00 00 00 00 00
00 00 07 65 6E 63 6F 64 65 72 02 00 0D 4C 61 76
66 35 37 2E 37 31 2E 31 30 30 00 08 66 69 6C 65
73 69 7A 65 00 40 F9 5C B0 00 00 00 00 00 00 09

00 00 00 C3 09 00 00 2B 00 00 00 00 00 00 00 17 // AVC sequence start
00 00 00 00
            01 4D 40 20 FF E1 00 17             // ?
                                    67 4D 40 20 // Sequence parameter set
95 A0 13 81 F7 EB 01 10 00 00 3E 80 00 0E A6 08
F1 C3 2A
         01 00 04                               // ?
                  68 EE 3C 80                   // Picture parameter set
                              00 00 00 36 09 01 // AVC NALU
94 9A 00 00 00 00 00 00 00 17 01 00 00 00
                                          00 01 // ?
94 91
      65                                        // IDR frame
        [B8 04 1D FF ...]
00 01 94 A5 09 00 00 05 00 00 00 00 00 00 00    // ?
                                             17 // AVC sequence end
02 00 00 00 00 00 00 10

Кодирование в первую очередь

ffmpeg -f h264 -i "input.h264" -c:v h264_nvenc -f h264 "reencode.h264"

reencode.h264

00 00 00 01 67 4D 40 20 95 A0 13 81 F7 EB 01 10 // Sequence parameter set
00 00 3E 80 00 0E A6 08 F1 C3 2A
                                 00 00 00 01 68 // Picture parameter set
EE 3C 80
         00 00 00 01 65                         // IDR frame
                       [B8 04 1D FF ...]        // Frame data

Выдавить в контейнер

ffmpeg -f h264 -i "reencode.h264" -c copy -f flv "B.flv"

B.flv

46 4C 56 01 01 00 00 00 09 00 00 00 00 12 00 00 // FLV header + metadata
A4 00 00 00 00 00 00 00 02 00 0A 6F 6E 4D 65 74
61 44 61 74 61 08 00 00 00 07 00 08 64 75 72 61
74 69 6F 6E 00 3F A4 7A E1 47 AE 14 7B 00 05 77
69 64 74 68 00 40 93 80 00 00 00 00 00 00 06 68
65 69 67 68 74 00 40 8E F0 00 00 00 00 00 00 0D
76 69 64 65 6F 64 61 74 61 72 61 74 65 00 00 00
00 00 00 00 00 00 00 0C 76 69 64 65 6F 63 6F 64
65 63 69 64 00 40 1C 00 00 00 00 00 00 00 07 65
6E 63 6F 64 65 72 02 00 0D 4C 61 76 66 35 37 2E
37 31 2E 31 30 30 00 08 66 69 6C 65 73 69 7A 65
00 40 F9 5B 40 00 00 00 00 00 00 09
                                    00 00 00 AF // AVC sequence start
09 00 00 05 00 00 00 00 00 00 00 17 00 00 00 00

00 00 00 10 09 01 94 BD 00 00 00 00 00 00 00 17 // AVC NALU
01 00 00
         00 00 00 00 01 67 4D 40 20 95 A0 13 81 // Sequence parameter set
F7 EB 01 10 00 00 3E 80 00 0E A6 08 F1 C3 2A
                                             00 // Picture parameter set
00 00 01 68 EE 3C 80
                     00 00 00 01 65             // IDR frame
                                   [B8 04 1D FF // Frame data
...]
00 01 94 C8 09 00 00 05 00 00 00 00 00 00 00    // ?
                                             17 // AVC sequence end
02 00 00 00 00 00 00 10

Обновление 08.08.2017: добавлены входные и выходные файлы для проверки.


person mOfl    schedule 03.08.2017    source источник
comment
Вы не возражаете поделиться своими различными видеофайлами?   -  person Markus Schumann    schedule 03.08.2017
comment
Попробуйте ffmpeg -f h264 -i "reencode.h264" -c copy -bsf:v extract_extradata -f flv "B.flv" командную строку, то есть с фильтром битового потока extract_extradata.   -  person nobody555    schedule 03.08.2017
comment
@Markus Schumann: Я добавил файлы в конце вопроса.   -  person mOfl    schedule 08.08.2017
comment
@body555: Спасибо за совет, но он не работает. Мало того, что видео не отображается в Adobe AIR, оно также больше не отображается в MPC-HC.   -  person mOfl    schedule 08.08.2017
comment
Прежде всего, ваше описание файловой структуры противоречит реальной структуре в ваших двоичных файлах A.flv и B.flv (они обратны). Итак, какой результат вам действительно нужен A.flv (со стартовыми кодами: 00 00 00 01 67 .. 00 00 00 01 68 .. 00 00 00 01 65) или B.flv (avcC: 00 17 67 .. 00 04 68. 00 01 94 91 65)? Стандартный формат для FLV подобен B.flv с avcC (без начальных кодов) и по умолчанию создается с помощью: ffmpeg -i "reencode.h264" -c copy "C.flv": C. flv. Если это сработает, попробуйте обновить файл ffmpeg. Что касается формата со стартовыми кодами, то я не знаю, как их создавать.   -  person nobody555    schedule 08.08.2017
comment
@body555 Пожалуйста, любезный сэр, ответьте на этот вопрос и благодарим вас за предоставленный файл. Я понял, что в вашем файле в качестве кодировщика используется Lavf57.76.100, а в моем - Lavf57.71.100. Поэтому я обновил FFMPEG с 3.3.2 до 3.3.3 (ночная сборка 20170807-1bef008), и теперь мультиплексированный FLV воспроизводится в AIR по желанию.   -  person mOfl    schedule 09.08.2017
comment
@mOfl, нужно ли для этого решения сначала перекодировать входной h.264 в новый, второй h.264? Тогда новый h.264 (reencoded.h264) упакован как FLV? Если вы не против вообще пропустить FFmpeg, я покажу вам код AS3, который отображает этот input.h264 непосредственно в приложении AIR. Только для неподвижных изображений h264?   -  person VC.One    schedule 09.08.2017
comment
@ VC.One Нет, input.h264 не нужно перекодировать. Я просто сделал это, чтобы увидеть разницу в файлах, которые создает FFMPEG. Я хотел бы пропустить FFMPEG и FLV, если есть способ напрямую воспроизводить неподвижные изображения h264 (в формате приложения B) в AIR!   -  person mOfl    schedule 10.08.2017


Ответы (2)


Прежде всего, ваше описание файловой структуры противоречит реальной структуре в ваших двоичных файлах A.flv и B.flv (они обратны). Так какого результата вы действительно хотите? Как A.flv с начальными кодами: 00 00 00 01 67 .. 00 00 00 01 68 .. 00 00 00 01 65 или как B.flv с avcC + 00 17 67 .. 00 04 68 .. 00 01 94 91 65?

Стандартный формат для FLV похож на B.flv с avcC (без начальных кодов), и по умолчанию он создается с помощью: ffmpeg -i "reencode.h264" -c copy "C.flv": здесь получается C.flv.

Если этот файл работает для вас, попробуйте обновить свой ffmpeg (я использовал самокомпилированную версию из основной ветки). Что касается формата со стартовыми кодами, то я не знаю, как их создавать.

person nobody555    schedule 09.08.2017

(1)

"Если у меня уже есть видео H.264 и я хочу, чтобы его скопировали в контейнер FLV без перекодирования, но заголовки файла и кадра должны быть заполнены правильно, как это делается при собственно перекодирование, как мне сообщить об этом в FFMPEG? "

Вы хотите мультиплексирование: попробуйте команду ниже (напрямую копирует данные H.264 в контейнер FLV).

ffmpeg -i input.h264 -c:v copy output.flv

(2)

Первый кадр каждого видео, обработанного таким образом, просто не отображается. Каждое видео отображается только со второго кадра, что позор для однокадровых видео ...

Как вы проверяете кадры, чтобы узнать, отображается ли только кадр 2 и далее? Это код AS3 netStream.pause() или медиаплееры, такие как VLC?

В FLV каждый видеокадр переходит в Video Tag. С другими кодеками мы можем сказать поместить кадр № 1 в videoTag № 1 и т. Д. Но с H.264 первый тег всегда содержит данные «Конфигурация декодера AVC», поэтому пиксели входного видеокадра №1 будет существовать в теге FLV videoTag №2.
Также с вашими первыми показанными байтами ... в разделе "AVC NALU", что 17 01 дает вам знать, что это ключевой кадр (первый кадр всегда является ключевым кадром), декодеры MPEG никогда не покажут второй кадр (обычно P-кадр) если он не был декодирован при первом декодировании ключевого кадра (I-кадр). Ваше изображение кадра №1 где-то существует ...

Мне не удалось воссоздать эту проблему с видео H.264 с обратным отсчетом тайм-кода. Первый кадр начинается с 00hh:00mm:00ss:00msec, а мсек перемещается вверх кадр за кадром. После использования команды, показанной в пункте (1), я вижу первый кадр в VLC и MPC-HC, а также в AS3, если я использую appendBytes для подачи в декодер данных только одного кадра (byteArray упакован как 1-кадровый FLV).

person VC.One    schedule 06.08.2017
comment
Предлагаемое ремюксинг, к сожалению, не работает. Посмотрите мой обновленный вопрос на видео с результатами (copy.flv). Хотя он воспроизводится в MPC-HC, он не отображается в AIR (AS3, используя netStream.appendBytes). - person mOfl; 08.08.2017