Должна ли дорожка в фрагментированном MP4 начинаться с ключевого кадра?

Я принимаю поток RTMP и преобразовываю его в фрагментированный файл MP4 в JavaScript. Это заняло неделю работы, но я почти закончил эту задачу. Я создаю действительный атом ftyp, атом moov и атом moof, и первый кадр видео фактически воспроизводится (со звуком), прежде чем он перейдет в бесконечную буферизацию без ошибок, перечисленных в chrome://media-internals

Подключив видео к ffprobe, я получаю сообщение об ошибке, похожее на:

[mov,mp4,m4a,3gp,3g2,mj2 @ 0x558559198080] Failed to add index entry
    Last message repeated 368 times
[h264 @ 0x55855919b300] Invalid NAL unit size (-619501801 > 966).
[h264 @ 0x55855919b300] Error splitting the input into NAL units.

Это привело меня к масштабному поиску проблем с выравниванием данных или недопустимых смещений байтов в моих атомах tfhd и trun, однако независимо от того, где я искал или как я разрезал данные, я не мог найти никаких проблем в атоме moof.

Затем я взял исходный файл FLV и преобразовал его в MP4 в формате ffmpeg с помощью следующей команды:

ffmpeg -i ~/Videos/rtmp/big_buck_bunny.flv -c copy -ss 5 -t 10 -movflags frag_keyframe+empty_moov+faststart test.mp4

Я открыл как созданный мной MP4, так и вывод MP4 с помощью ffmpeg в файле синтаксического анализа атома и сравнил их:

Сравнение файлов MP4 с файлами MP4A

Первое, что бросилось мне в глаза, это то, что файл, сгенерированный ffmpeg, содержит несколько видеосэмплов на moof. В частности, каждый moof начинался с 1 ключевого кадра, затем содержал все разностные кадры до следующего ключевого кадра (который использовался как начало следующего атома moof).

Сравните это с тем, как я создаю свой MP4. Я создаю атом moof каждый раз, когда приходит пакет FLV VIDEODATA. Это означает, что мой moof может не содержать ключевого кадра (и обычно его нет)

Может из-за этого у меня проблемы? Или есть что-то еще, что мне не хватает?

Видеофайлы, о которых идет речь, можно скачать здесь:

Другой проблемой, которую я заметил, было плодотворное использование ffmpeg base_data_offset в атоме tfhd. Однако, когда я попытался отследить общее количество добавленных байтов и самостоятельно установить base_data_offset, я получил сообщение об ошибке в Chrome в следующем виде: «MSE не поддерживает base_data_offset». Согласно спецификации ISO/IEC 14996-10:

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

Эта формулировка приводит меня к мысли, что data_offset в первом атоме trun должно быть равно размеру атома moof, а data_offset во втором атоме trun должно быть 0 (0 байт с конца данных, определенных предыдущим фрагментом). . Однако, когда я попробовал это, я получил ошибку, что видеоданные не могут быть проанализированы. Что действительно привело к данным, которые можно было проанализировать, так это длина атома moof плюс общая длина первой дорожки (как если бы базовое смещение было первым байтом закрывающая коробку moof, такая же, как и первая дорожка)


person stevendesu    schedule 14.12.2018    source источник


Ответы (1)


Нет, moof не нужно начинать с ключевого кадра. Создаваемый вами файл выдает недопустимые ошибки размера NALU, поскольку он имеет недопустимые окончательные размеры. Перед каждым nal (в mdat) должен быть указан размер. Глядя на ваш файл, первые 4 байта после mdat равны 0x21180C68, что НАМНОГО слишком велико, чтобы быть допустимым размером.

person szatmary    schedule 15.12.2018
comment
У меня первая аудио дорожка, а вторая видео дорожка. 0x21180C68 — это данные AAC, а не данные H.264. - person stevendesu; 15.12.2018
comment
Собираюсь отметить это как правильное, поскольку нет, moof не нужно начинать с ключевого кадра. точно отвечает на вопрос. Но следующие предложения неверны (мои размеры NAL были действительными, 0x21180C68 не был размером NAL, поскольку это были аудиоданные, а не видеоданные). Причина, по которой мое видео не воспроизводилось, заключалась в том, что мой traf имел продолжительность 0. Вводящее в заблуждение сообщение об ошибке было связано с ошибкой в ​​FFMPEG. В итоге я прочитал весь исходный код FFMPEG, чтобы понять это. - person stevendesu; 22.01.2019