Код avformat выдает немного другой результат, чем ffmpeg с теми же параметрами - почему?

Я хотел бы добиться того же результата, что и этот вызов командной строки ffmpeg из кода:

ffmpeg -i CAMERARTSPLINK -c:v copy -an -movflags +frag_keyframe+empty_moov -f mp4

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

got 36 bytes:  0, 0, 0, 36, 102, 116, 121, 112, ..., 111, 54, 109, 112, 52, 49, 
got 512 bytes: 0, 0, 3, 76, 109, 111, 111, 118, 0, 0, 0, ..., 132, 0, 0, 3, 0, 4, 0, 0, 3, 0, 202,

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

Я создал небольшой демонстрационный пример кода с avformat для ремуксирования RTSP H264 в MP4. В коде широко используется хорошая библиотека videostreamer от Horgh.

Я разместил пример кода на pastebin.com (400 loc). Он успешно строится, но вам нужно связать его с avformat, avdevice, avcodec и avutil.

Я старался изо всех сил, чтобы добиться того же результата, однако, когда я запускаю этот код, первые несколько байтов после байта #38 отличаются (может быть, не только они, я ничего не сравнивал после байта #548):

writeOutput: writing 36 bytes: 0, 0, 0, 36, 102, 116, 121, 112, ..., 111, 54, 109, 112, 52, 49, 
writeOutput: writing 512 bytes: 0, 0, 0, 0, 109, 111, 111, 118, 0, 0, 0, ..., 132, 0, 0, 3, 0, 4, 0, 0, 3, 0, 202, 

Вы можете видеть, что вторая строка вывода моего кода начинается с 0 0 0 0 109,

тогда как ffmpeg дал 0 0 3 76 109.

Все остальные (даже байты здесь не вставлены) полностью совпадают (по крайней мере, для первых 548 байт).

Что не так с моим кодом? Эти 2 байта кажутся очень важными для декодирования этого потока.


person Daniel    schedule 14.02.2020    source источник


Ответы (2)


102, 116, 121, 112 в ascii равно ftyp Это поле типа формата mp4. 0, 0, 0, 36 - размер коробки

109, 111, 111, 118 в ascii равно mdat Это поле данных. 0, 0, 0, 0 - размер коробки.

В этом случае размер блока mdat неизвестен, потому что мы еще не знаем размер всех видео- и аудиокадров. Поэтому используется заполнитель нуля. Когда файл будет завершен, значение размера должно быть перезаписано правильным размером.

person szatmary    schedule 14.02.2020
comment
Спасибо. имеет смысл. однако команда ffmpeg не выводится в файл, она переходит непосредственно в стандартный вывод. так что он не может изменить размер поля после того, как он был напечатан на стандартный вывод. Как я могу добиться того же с помощью avformat? - person Daniel; 15.02.2020
comment
что мне нужно: avformat не должен печатать поле mdat, пока его размер не известен - person Daniel; 15.02.2020
comment
то есть в моем пользовательском обратном вызове ввода-вывода не определена функция поиска. - person Daniel; 15.02.2020
comment
или, чтобы изменить вопрос: как ffmpeg знает размер mdat (во время печати на стандартный вывод), а мой код - нет? - person Daniel; 15.02.2020
comment
Ffmpeg не может знать размер блока mdat до того, как он будет записан. Запись mp4 на стандартный вывод не является допустимой операцией. Вы должны либо использовать фрагментированный mp4, либо другой потоковый контейнер, такой как mkv. - person szatmary; 15.02.2020
comment
моя команда ffmpeg создает фрагментированный mp4, потому что использует «frag_keyframe». Эта опция также добавлена ​​в мой код. Итак, ffmpeg при создании fmp4 знает размер mdat, а мой код — нет. - person Daniel; 16.02.2020
comment
Ты уверен? Можете ли вы проверить остальную часть файла на наличие moof? - person szatmary; 16.02.2020
comment
Не знаю что проверять, но вот анализ thumb.co.il: imgur.com/a /ScPiOai (это стандартный вывод из командной строки ffmpeg выше, записанный в файл) - person Daniel; 16.02.2020
comment
О, и я думаю, что вы не правы: 109, 111, 111, 118 в ascii это moov. - person Daniel; 16.02.2020
comment
Я знаю, что 109, 111, 111, 118 — это moov. Вот поэтому я и спрашиваю про моф. - person szatmary; 17.02.2020
comment
Вы написали 109, 111, 111, 118 в ascii, это mdat Это поле данных. 0, 0, 0, 0 - это размер коробки. Moof: я связал изображение, которое содержит moof, но не знаю, что там увидеть :( - person Daniel; 17.02.2020

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

Проблема заключалась в том, что ffmpeg (с вводом h264) при записи атома в выходной буфер:

Это все хорошо, но при заполнении остальной части буфера он использует avio_w8 и avio_w8 очищают буфер, если он достигает его конца.

Если вы используете пользовательский ввод-вывод с avio_alloc_context И вы не определяете достаточно большой буфер, И вы также не определяете операцию поиска, И записываемый атом больше, чем размер вашего буфера, он будет сброшен, а ffmpeg будет не сможет вернуться назад, чтобы обновить размер атома.

И это, вероятно, приведет к повреждению (и невозможности воспроизведения) выходного видеофайла или потока.

Таким образом, решением было увеличить размер буфера с 512 до 4096, в этом случае атом moov может поместиться даже без операции поиска.

Это довольно просто, если вы знаете, что длина атома moov превышает 512 байт, и посмотрите мой пример кода.

person Daniel    schedule 20.02.2020