Как прочесть mp4 но в 100 раз быстрее

Jan 09, 2013 18:23

Я как-то писал про то, как читать mp4 контейнер. Структура сложная, поэтому когда я реализовывал этот код пару лет назад, я решил сделать такую архитектуру:
  • читаем заголовок каждого трека
  • строим для каждого трека один большой бинарник в котором закодированы данные по кадрам:

    <>
  • строим общий список всех фреймов, сортированных по DTS:

    <>
  • когда нужно извлечь кадры, перебираем по второму индексу пока не найдем нужный номер с нужным треком
  • потом вытаскиваем все кадры из нужных треков

Это работало с RTMP, который покадрово вычитывает файл и шлет в сеть.
Однако прошло время и стало ясно, что это абсолютно нерабочая ситуация:
  • Во-первых нельзя слать файл покадрово. Нужно только блоками, лучше всего сразу целый GOP
  • во-вторых на 12-гигабайтных файлах открытие занимает по 20 секунд, т.е. пользователь 20 секунд ждет начала просмотра
  • в-третьих считывание gop по такому алгоритму занимает до 3 секунд. При том, что сегмент сам длится 2 секунды, просмотр становится невозможным

Решить проблему получилось крайне быстро и без извратов и без переписывания кусков кода на C

Получилось снизить время открытия файла с 20 секунд до 40 мс, расход памяти с 250 мегабайт до 5 мегабайт, чтение сегмента с 3 секунд до 20 мс.



  • Во-первых пришлось отказался от парсинга всех таблиц в moov атоме. Я решил оставить данные сжатыми, а учитывая что доступ к файлам через mmap, эффект от этого был крайне положительный.
  • Во-вторых пришлось перейти сразу на блочное считывание сегментов. Больше никакого покадрового доступа. Вся компрессия в moov атоме - это дельта-компрессия, т.е. зная таймстемп одного кадра, следующий вычисляется простым паттерн-матчингом бинарника.


Запрогать получилось за один день на январских праздниках, а мораль такова, что высокоуровневая оптимизация позволяет ускориться в 100 раз в то время, как низкоуровневый дроч с NIF-ами зачастую только в 1,5-2 раза.

fp, erlang, оптимизация, mp4

Previous post Next post
Up