Предотвращение крашей в медиаконтейнерах

Данная статья предназначена для тех, кто заинтересован в сохранении воспроизводимости своих записей на случай внезапного системного сбоя. Далее будут описаны харатктерные особенности целых и поврежденных файлов, записанных в нескольких наиболее известных форматах как MP4, MOV, MKV, FLV, рассмотрены особенности изменений в структуре файлов при различных условиях записи.

Целые

MP4

Данная группа файлов была записана в штатных условиях без угрозы внезапной остановки записи.

Можно заметить, что файл состоит из четырех атомов корневого уровня ftyp, free, mdat, moov, в соответствии со структурой описанной в официальной спецификации формата медиаконтейнера MP4.

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

Рис. 1 Структура стандартного MP4 файлаРис. 1 Структура стандартного MP4 файла

Содержимое moov атома имеет особо важное значение для воспроизведения видеоматериала, так как именно в этом месте находится описание информации о том как файл должен быть расшифрован. Для расшифровки файла, чтобы его воспроизвести необходимо установить однозначное соответствие между данными и способами их чтения. Поэтому необходимо знать количество потоков, какой формат данных содержат потоки, какие кодеки совместимы для декодирования. Следует обратить внимание на расположение moov атома в памяти файла. Обычно он расположен в конце файла, что не всегда полезно и безопасно при записи. По этой причине не рекомендуется вести запись в MP4 из-за угрозы получения невоспроизводимого файла в результате внезапного прекращения записи. Такая ситуация возможна при системных сбоях, потере питания и в случае непредвиденного завершения процесса записывающего ПО.

Метаданные извлекаются с помощью ffprobe следующим образом.

ffprobe -hide_banner video.mp4 2> mp4.txt

Рис. 2 Метаданные стандартного MP4 файлаРис. 2 Метаданные стандартного MP4 файла

MOV

В структуре MOV нет особых различий со структурой MP4, файл все также состоит из четырех атомов корневого уровня, но вместе атома free используется атом wide равный ему по размеру. В таких атомах содержится информация о неиспользуемом пространстве памяти. Узнать подробнее про формат медиаконтейнера MOV можно в официальной спецификации формата медиаконтейнера MOV.

Рис. 3 Структура стандартного MOV файлаРис. 3 Структура стандартного MOV файла

В MOV по аналогии с MP4 все метаданные находятся в moov атоме в конце файла.

Метаданные извлекаются с помощью ffprobe следующим образом.

ffprobe -hide_banner video.mov 2> mov.txt

Рис. 4 Метаданные стандартного MOV файлаРис. 4 Метаданные стандартного MOV файла

MKV

Структура MKV уже была описана ранее в официальной спецификации формата медиаконтейнера MKV. Основное отличие от прошлых двух контейнерных форматов в том, что данные по умолчанию записываются небольшими фрагментами, вместо одного общего блока информации в случае с mdat для MP4 и MOV. Такая особенность позволяет избавиться от проблемы критического повреждения файлов в случае внезапного прекращения записи, так как метаданные содержатся в каждом отдельном фрагменте.

Метаданные извлекаются с помощью ffprobe следующим образом.

ffprobe -hide_banner video.mkv 2> mkv.txt

Рис. 5 Метаданные MKV файлаРис. 5 Метаданные MKV файла

FLV

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

Метаданные извлекаются с помощью ffprobe следующим образом.

ffprobe -hide_banner video.flv 2> flv.txt

Рис. 6 Метаданные FLV файлаРис. 6 Метаданные FLV файла

Поврежденные

MP4

Если запись была внезапно прервана есть довольно большая вероятность получить невоспроизводимый файл на выходе.

Рис. 7 Ошибка воспроизведения MP4 файлаРис. 7 Ошибка воспроизведения MP4 файла

Подробнее узнать причину ошибки можно узнать посмотрев логи через ffprobe в консоли

ffprobe -v error video.mp4 2> mp4_error.txt

Лог ошибки выглядит следующим образом для файла 

Рис. 8 Лог ошибки для video.mp4Рис. 8 Лог ошибки для video.mp4

По ошибке «moov atom not found» можно понять, что метаинформацию извлечь не получится, так как не найден moov атом. Дело в том, что запись закончилась раньше, чем планировалось и moov атом физически не был записан в память. Последний доступный атом в данном случае будет mdat. 

Рис. 9 Структура поврежденного MP4 файлаРис. 9 Структура поврежденного MP4 файла

Соответственно, если попробовать достать любую метаинформацию файла, то вывод будет пустой

Например,  

ffprobe -hide_banner video.mp4 2> mp4.txt

Рис. 10 Метаданные поврежденного MP4 файлаРис. 10 Метаданные поврежденного MP4 файла

MOV

В MOV файлах будет наблюдаться похожая ситуация, но как и в прошлый раз разница будет только в названии и размере некоторых корневых атомов структуры. Сам файл воспроизводиться не будет.

ffprobe -v error video.mov 2> mov_error.txt

Рис. 11 Лог ошибки для video.movРис. 11 Лог ошибки для video.mov

Moov атом здесь не наблюдается, как и в MP4, что не позволяет извлечь метаинформацию 

Рис. 12 Структура поврежденного MOV файлаРис. 12 Структура поврежденного MOV файла

ffprobe -hide_banner video.mov 2> mov.txt

Рис. 13 Метаданные поврежденного MOV файлаРис. 13 Метаданные поврежденного MOV файла

MKV

Записанный в условиях внезапной остановки записи MKV файл пострадает меньше по сравнению с MP4 или MOV. Его можно будет воспроизвести, но нельзя перемотать и узнать продолжительность в некоторых плеерах. В этом можно убедиться после извлечения метаданных. Значению поля Duaration соответствует N/A, это значит, что оно не было определено. Также отсутствуют значения длительности для видео и аудио потоков и битрейт.

Рис. 14 Метаданные поврежденного MKV файлаРис. 14 Метаданные поврежденного MKV файла

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

Рис. 15 Лог ошибки для video.mkvРис. 15 Лог ошибки для video.mkv

FLV

Поврежденный FLV файл воспроизводится, но так же не имеет определенного значения длины, записанного в поле Duration, как и поврежденный MKV файл, тем не менее информация о начальной отметке времени осталась. Что касается битрейта, то его все также нет. Дело в том, что значения полей Duration и Bitrate вычисляются в самом конце, а не пересчитываются каждый раз после окончания записи каждого отдельного фрагмента, так как это спровоцировало бы дополнительную нагрузку на систему.

Рис. 16 Метаданные поврежденного FLV файлаРис. 16 Метаданные поврежденного FLV файла

Вывод поломанного FLV файла содержит несколько больше информации о повреждениях. Видно на каком именно пакете прервалась запись и к какому потоку он относился. В данном случае проблема была обнаружена в момент декодирования пакета в потоке видео с dts = 9734. Более вероятно возникновение ошибки именно в видео потоке, так как обычно объем видеоданных занимает в разы больше места, чем аудио, соответственно и времени на его расшифровку тратится пропорционально больше.

DTS (decoding time stamp) — время декодирования опорного кадра, который требуется для отображения текущего в базовых единицах. Может совпадать с PTS (presentation time stamp) если текущий кадр опорный. Как правило базовая единица задается в виде дроби с числом тактов в числителе и частотой тактового генератора в знаменателе. В итоге в процессе расшифровки декодировщик не может получить доступ к объекту в памяти, потому что его не существует и выполнение чтения заканчивается ошибкой.

Рис. 17 Лог ошибки для video.flvРис. 17 Лог ошибки для video.flv

Записанные с предварительными настройками

Предварительно настроенная запись отличается от обычной, тем что в качестве дополнительной настройки используется параметр faststart, который помогает предотвратить проблему критического повреждения MP4 и MOV файлов путем перемещения moov атома в начало файла. Для MKV и FLV данный параметр не имеет большого смысла, так как в их структуре отсутствует отдельный атом с общими метаданными, как moov.

Рис. 18 Настройки записи в OBSРис. 18 Настройки записи в OBS

MP4

Теперь подверженный повреждению файл в условиях внезапной остановки записи удалось оставить воспроизводимым и читаемым. На изображении снизу можно изучить структуру полученного после записи файла. На этот раз moov атом был записан в начале файла после ftyp. Раньше он располагался в самом конце после атома mdat.

Рис. 19 Структура записанного MP4 файлаРис. 19 Структура записанного MP4 файла

Метаданные вновь читаются, причем значения для полей duration и bitrate определены, несмотря на то, что запись была прервана внезапно.  

Рис. 20 Метаданные записанного MP4 файлаРис. 20 Метаданные записанного MP4 файла

MOV

В структуре MOV файла произошли изменения в порядке записи корневых атомов, как и в MP4. Moov атом остался неповрежденным и расположен в начале файла. Воспроизведение файла не нарушено.

Рис. 21 Структура записанного MOV файлаРис. 21 Структура записанного MOV файла

Дополнительно убедиться в целостности файла можно после извлечения метаданных

Рис. 22 Метаданные записанного MOV файлаРис. 22 Метаданные записанного MOV файла

MKV

Для MKV файлов особого эффекта параметр «faststart» не имеет, файл имеет повреждения, полученные в результате внезапной остановки записи.

Рис. 23 Метаданные записанного MKV файлаРис. 23 Метаданные записанного MKV файла

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

Рис. 24 Лог ошибки для video.mkvРис. 24 Лог ошибки для video.mkv

FLV

Никаких особых изменений в лучшую сторону для flv файла использованный параметр не дал. Все старые проблемы остались.

Рис. 25 Метаданные записанного FLV файлаРис. 25 Метаданные записанного FLV файла

Длительность в результате записи осталась нулевой, битрейт неизвестен, тем не менее файл воспроизводится.

Рис. 26 Лог ошибки для video.flvРис. 26 Лог ошибки для video.flv

Фрагментированные

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

  • empty_moov приведет к фрагментации вывода на 100%; без этого первый фрагмент будет мультиплексирован, как короткий фильм (с использованием moov), за которым следуют остальные медиафайлы во фрагментах

  • frag_keyframe вызывает фрагментированный вывод

Рис. 27 Настройки записи OBSРис. 27 Настройки записи OBS

MP4

Использовав дополнительные параметры, удалось сохранить воспроизводимость файла в условиях внезапной остановки записи. В структуре файла наблюдаются заметные изменения. Moov атом расположен в начале файла, далее следует последовательность из двух повторяющихся практически до конца атомов moof и mdat. В этих двух атомах содержится вся необходимая информация о каждом отдельном фрагменте видео. Moof атом — аналог moov для фрагмента записи, mdat — атом содержащий потоки. Завершается файл атомом mfra.

Рис. 28 Структура фрагментированного MP4 файлаРис. 28 Структура фрагментированного MP4 файла

C извлечением метаданных нет особых в данном случае. В метаданных присутствует длительность, тем не менее в некоторых плеерах отсутствует возможность перемотки и не отображается длительность.

Рис. 29 Метаданные фрагментированного MP4 файлаРис. 29 Метаданные фрагментированного MP4 файла

MOV

Что касается структуры MOV файла, то она так же сильно изменена и больше напоминает структуру MKV или FLV файлов из-за последовательности фрагментов, записанных в атомы moof и mdat.

Рис. 29 Структура фрагментированного MOV файлаРис. 29 Структура фрагментированного MOV файла

Повреждений метаданных в данном случае не наблюдается.

Рис. 30 Метаданные фрагментированного MOV файлаРис. 30 Метаданные фрагментированного MOV файла

MKV

Особого эффекта или изменений в худшую или лучшую сторону не наблюдается.

FLV

Особого эффекта или изменений в худшую или лучшую сторону не наблюдается.

Дополнительная информация

Мультиплексирование в obs осуществляется при помощи ffmpeg, соответственно все указанные в данном примере настройки имели бы следующий вид:

ffmpeg -i input -movflags +frag_keyframe+empty_moov out.[mp4/mov]

Пример создания фрагментированного MP4 файла (fMP4) из стандартного MP4 файла

ffmpeg -i video.mp4 -g 52 -c:a aac -c:v libx264 -f mp4 -movflags frag_keyframe+empty_moov fragmented_video.mp4

Альтернативный вариант предварительной настройки записи, который позволяет добиться фрагментированной записи в файл вместо хранения всей информации в едином атоме.

  • empty_moov приведет к фрагментации вывода на 100%; без этого первый фрагмент будет мультиплексирован, как короткий фильм (с использованием moov), за которым следуют остальные медиафайлы во фрагментах

  • separate_moof инициирует создание отдельного атома moof (фрагмента видео) для каждого потока. Обычно пакеты для всех потоков записываются в moof atom (что немного эффективнее), но с этой установленной опцией мультиплексор записывает одну пару moof/mdat для каждой потоков, что упрощает разделение дорожек.

  • frag_keyframe вызывает фрагментированный вывод

  • omit_tfhd_offset отменяет запись абсолютного значения base_data_offset в атомах tfhd. Это позволяет избежать привязки фрагментов к абсолютным позициям байтов в файле/потоках.

Рис. 31 Настройки записи OBS Рис. 31 Настройки записи OBS 

MP4

Следующие настройки позволяют создавать фрагментированный MP4 (fMP4), который вы сможете просмотреть во время преобразования. Однако для просмотра будут доступны только фрагменты, полностью закодированные на момент запуска файла. Чтобы просмотреть фрагменты, закодированные после этой точки, вам придется перезагрузить источник просмотра.

Рис. 32 Структура фрагментированного MP4 файлаРис. 32 Структура фрагментированного MP4 файла

Аналогично прошлому примеру с фрагментацией файл состоит из последовательности атомов корневого уровня mdat и moof и имеет moov атом вначале.

Рис. 33 Метаданные полученного MP4 файлаРис. 33 Метаданные полученного MP4 файла

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

MOV

Эти настройки также применимы в случае с MOV файлами и на выходе дают сравнимый результат

Рис. 34 Структура фрагментированного MOV файлаРис. 34 Структура фрагментированного MOV файла

Как результат здесь так же сохраненные метаданные и нормальная воспроизводимость файла

Рис. 35 Метаданные полученного MOV файлаРис. 35 Метаданные полученного MOV файла

MKV

Особого эффекта или изменений в худшую или лучшую сторону не наблюдается.

FLV

Особого эффекта или изменений в худшую или лучшую сторону не наблюдается.

Дополнительная информация

Мультиплексирование в obs осуществляется при помощи ffmpeg, соответственно все указанные в данном примере настройки имели бы следующий вид:

ffmpeg -i input -movflags +frag_keyframe+separate_moof+omit_tfhd_offset+empty_moov out.[mp4/mov]

Вывод

Чтобы уменьшить вероятность утраты доступа к записанным видеофайлам лучше задуматься сразу над тем, как избежать негативных последствий при возникновении аппаратных или системных проблем на записывающем устройстве. Сделать это можно, выбрав один из более отказоустойчивых форматов записи, как MKV/FLV или, если выходной формат принципиально важен, то воспользоваться одним из методов предотвращения крашей в MP4/MOV из статьи. Восстанавливать убитый файл, гораздо труднее и не всегда возможно. Для тех, кто уже столкнулся с этой проблемой и еще ищет решения возможно будет полезна следующая статья, посвященная теме восстановления MP4/MOV файлов.

Полезные источники

© Habrahabr.ru