Реализация потоковой передачи аудио/видео 2 из исходного кода Chrome

внешний интерфейс алгоритм Chrome FFmpeg

первый разВ основном он знакомит с механизмом управления буфером и кодеком для загрузки аудио и видео в Chrome, а в этой статье подробно рассказывается о процессе декодирования и воспроизведения. Проведите исследование с выпуском Chromium 69.

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

1. Составьте хром, который может играть в MP4

Самособранный Chromium не может воспроизводить видео в формате mp4 и не может быть загружен с официального сайта, терминал выдает такую ​​ошибку:

[69542:775:0714/132557.522659:ERROR:render_media_log.cc(30)] MediaEvent: PIPELINE_ERROR DEMUXER_ERROR_NO_SUPPORTED_STREAMS

Говорят, что произошла ошибка, когда демультиплексирование, то есть мультиплексирование, не поддерживает текущий формат потока, то есть Chromium не поддерживает парсинг формата mp4, почему так? После некоторых поисков и нащупывания я обнаружил, что просто измените режим компиляции ffmpeg с Chromium на Chrome. Отредактируйте файл Third_Party/ffmpeg/ffmpeg_options.gni и измените первые несколько строк кода — установите для _default_ffmpeg_branding значение Chrome, а затем перекомпилируйте, как показано в следующем коде:

# if (is_chrome_branded) {
  _default_ffmpeg_branding = "Chrome"
# } else {
#  _default_ffmpeg_branding = "Chromium"
# }

Скомпилированный Chromium может воспроизводить видео. Для компиляции целевого брендинга проекта Chromium можно установить три режима: Chrome (официальная версия)/Chromium/Chrome OS. Настройка компиляции ffmpeg автоматически выберет собственный брендинг в соответствии с типом брендинга, судя по приведенному выше коду, если брендинг Chrome, он добавит несколько дополнительных декодеров для воспроизведения mp4.

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

Кроме того, у него есть настройка own_codecs:

proprietary_codecs = is_chrome_branded || is_chromecast

Составленная официальная версия Chrome будет открыта по умолчанию, и ее роль - добавить некоторые дополнительные декодеры, такие как поддержка EME (зашифрованные носители расширений) зашифрованных носителей.

В конце концов, сравнение влияния не может открыться и возможность открывать и воспроизводить в начале показано на следующем рисунке:

Так почему же Chromium напрямую не открывает поддержку mp4, это может быть ограничено некоторыми протоколами с открытым исходным кодом и патентами mp4 или ffmpeg.

2. Формат mp4 и демультиплексирование

У видео может быть 3 дорожки (Track): видео, аудио и текст, но хранение данных одномерное, от 1 байта до n-го байта, поэтому куда ставить видео, куда ставить аудио, mp4 Здесь оговариваются форматы /avi и др. Процесс синтеза видео- и аудиодорожек в mp4-файл называется мультиплексированием (mux), а разделение аудио- и видеодорожек в mp4-файле называется демультиплексированием (demux). слова приходят из сферы общения.

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

мы используем этоmountain.mp4Видео mp4 продолжительностью 1 с и размером 487 КБ используется в качестве объекта исследования и открывается с помощью редактора, такого как возвышенное, для отображения исходного двоичного содержимого, как показано на следующем рисунке:

Изображение выше представляет собой исходное двоичное содержимое, выраженное в шестнадцатеричном формате. Два шестнадцатеричных числа (0000) представляют 1 байт. Как показано на рисунке выше, четвертый байт равен 0x18.

mp4 использует блоки для хранения данных. Стандарт определяет несколько типов блоков. Типы данных, хранящиеся в каждом блоке, разные. Блоки могут быть вложенными блоками. Первые 4 байта каждого блока указывают размер занимаемого им пространства.Например, первое поле выше имеет размер 0x18 = 24 байта, что означает, что следующие 24 байта являются содержимым этого блока, поэтому на рисунке выше показано 3431 в строка 2 - это содержимое первого блока. 4 байта сразу после первых 4 байтов, представляющих размер, являются типом блока, значение закодировано в ASCII, а первый блок имеет тип:

6674 7970 => ftyp

Функция поля ftyp состоит в том, чтобы отметить текущий тип файла, а следующие 4 байта указывают, что это формат Microsoft MPEG-4, который обычно называется mp4:

6d70 3432 => mp42

Таким образом, общий анализ первого блока показан на следующем рисунке:

Второй блок также анализируется, как показано на следующем рисунке:

Это блок moov, и moov хранит метаданные блока, в том числе количество аудио- и видеодорожек, ширину и высоту видео, количество сэмплов (кадров), где находятся данные кадров. местонахождение и другую ключевую информацию. Учтите, что хранение мультимедийных данных в формате mp4 может быть прерывистым, а воспроизведение может располагаться впереди, но это не беда. Потому что эту информацию о местоположении можно найти в окне moov. Несколько сэмплов образуют чанк, то есть чанк может содержать один или несколько сэмплов, и расположение чанка также находится в поле moov.

В конце находится блок mdat, представляющий собой блок для мультимедийных данных, размером 492242 байт, который занимает большую часть пространства файла mp4. Смещение чанка в moov относительно mdat.

В приведенном выше мы устали от разбора байт за байтом, и мы можем использовать некоторые готовые инструменты, такие как этот онлайнMP4Box.jsили этоMP4Parser, как показано на рисунке ниже, в moov всего два трекбокса:

Разверните подокно видеодорожки, найдите поле stsz, вы увидите, что всего 24 кадра, а также можно увидеть размер каждого кадра, как показано на следующем рисунке:

Здесь мы обнаруживаем, что самый большой кадр весит 98 КБ, а самый маленький - всего 3 КБ. Один кадр представляет собой изображение. Почему такая большая разница между разными кадрами?

Поскольку некоторые кадры являются ключевыми (I-кадр, Intra-кадр), они содержат полную информацию об изображении кадра, поэтому они относительно велики, и I-кадр можно использовать в качестве эталонного кадра. Другие кадры представляют собой только разницу между записью и эталонным кадром, который называется промежуточным кадром, поэтому он относительно мал.Кадр предсказания включает в себя кадр прямого предсказания P-кадр и кадр B двунаправленного предсказания, а P-кадр относится к ранее декодированное изображение. , в то время как ссылка на B-кадр является двунаправленной. Таким образом, нет смысла просто получать предсказанный кадр, вам нужен опорный кадр перед ним для декодирования. Коэффициент сжатия опорного кадра (h264) аналогичен jpg, обычно до 7 к 1, в то время как коэффициент сжатия прогнозируемого кадра может достигать нескольких десятков к 1.

Тогда как хранятся эти кадры, в какие фрагменты они помещаются и где находится каждый фрагмент? Как показано в поле stco ниже:

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

От [1, 3), т.е. с 1-го по 2-й фрагмент, каждый фрагмент имеет 10 сэмплов, а с [3, конец), т.е. 3-й фрагмент, составляет 4 сэмпла. Таким образом, если я хочу найти смещение 13-го кадра в поле mdat, я могу знать, что это 3-й образец во 2-м фрагменте, поэтому обратитесь к приведенным выше данным, чтобы вычислить начальную позицию:

Конечная позиция 236645 + 6274 = 242919, поэтому 13-й кадр хранится в интервале [236645, 242919) mdat. Вот статьястатьяПредставлен алгоритм получения данных кадра mp4, который аналогичен процессу, который мы проанализировали выше.

Этот кадр (13 кадров) настолько мал, что, скорее всего, это не ключевой кадр. В частности, как судить о том, является ли кадр ключевым, главным образом, по последнему типу в информации заголовка кадра, а значение 5 является ключевым кадром, что включает в себя определенный процесс декодирования.

Есть еще вопрос, как узнать, что этот mp4 закодирован в h264, а не в h265 или подобное, это можно узнать через бокс avc1, как показано на следующем рисунке:

avc1 является псевдонимом h.264.В этом поле есть много параметров, необходимых для декодирования, таких как уровень, SPS, PPS и т. д., например, максимальное количество опорных кадров и т. д., см. аннотации выше. Если максимальный опорный кадр шире, степень сжатия может быть улучшена, когда можно использовать больше опорных кадров, но эффективность декодирования будет снижена, и это неудобно при поиске адресации, и многие кадры необходимо считывать позже. , или удерживайте много кадров вперед, особенно когда для потоковой передачи может потребоваться загрузка большого количества контента заранее. Максимальное количество опорных кадров, полученных в результате приведенного выше анализа SPS, равно 3 (max_num_ref_frames).

Далее, как декодировать кадр изображения и восстановить его в rgb-изображение?

3. Декодирование видеокадра

Для декодирования кадра I опорный кадр не требуется. Процесс декодирования подобен процессу декодирования JPG. Кадр P и кадр B должны опираться на предыдущий и предыдущий кадры для восстановления полного содержимого. Поэтому порядок декодирования кадров обычно не в порядке воспроизведения. С тем же успехом мы могли бы изучить типы всех кадров приведенного выше примера видео с помощью онлайн-сайта.Online Video GOP Analyzer, результаты анализа представлены на следующем рисунке:

Ось x представляет в общей сложности 24 кадра от 0 до 23, ось y представляет размер каждого кадра, зеленая - это ключевой кадр I кадра, красная - кадр P прямого предсказания, а синяя - кадр Кадр двунаправленного предсказания B-кадр, это хорошо видно См., на объеме I-кадр > P-кадр > B-кадр. Порядок расположения этих 24 кадров:

I B B B P B B B P ... B P I

Первый и последний два кадра – это кадры I, которые просто формируют последовательность изображений GOP (группу изображений). В последовательности GOP кадр I является начальным кадром, за ним следуют кадр B и кадр P (может не кадр Б).

Последовательность кадров на приведенном выше рисунке увеличивается в соответствии с отметкой времени представления (PTS) каждого кадра.PTS момента времени воспроизведения, полученного из 12-го кадра (средний красный столбец), составляет 0,54 с.

Однако порядок хранения и порядок декодирования не соответствуют порядку воспроизведения.Вы можете сравнить таблицу размеров кадра на шаге 2:

Среди них sample_sizes — это порядок хранения, а порядок гистограммы соответствует PST. Сравнивая их, вы можете видеть, что метка времени декодирования DTS (метка времени декодирования) каждого кадра находится в следующем порядке:

I P B B B P B B B ...

В последовательности GOP кадр I является начальным кадром, который анализируется первым, затем кадр P и, наконец, кадр B. Можно предположить, что, поскольку кадр P зависит от кадра I, кадр P должен быть первым. перед B-кадром, а B-кадры могут зависеть от I-кадров и P-кадров, поэтому их можно анализировать последними. Итак, как мы можем узнать конкретные зависимости, то есть список систем отсчета для каждого кадра?

Прежде всего, порядок воспроизведения POC (число порядков изображения) каждого кадра может быть рассчитан из информации заголовка каждого кадра.С помощью некоторого программного обеспечения, такого как JW Reference, POC от первого кадра до пятого кадра Порядок хранения можно найти следующим образом:

0 8 2 4 6 ...

Здесь он увеличивается на 2, а если преобразовать в 1, то это:

0 4 1 2 3 ...

согласуется с приведенным выше анализом.

Тогда как узнать, кто является опорным кадром кадра межкадрового предсказания B-кадра и P-кадра? Прежде чем ответить на этот вопрос, необходимо знать, что относится к опорному кадру.В jpg/h264 картинка делится на макроблоки, один макроблок 16*16px, который хранится в единицах макроблоков и записывается.Информация о цвете находится в Формат YCbCr, Y относится к яркости или оттенкам серого, Cb относится к синему компоненту, а Cr относится к красному компоненту. Как показано ниже:

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

Список опорных кадров динамически поддерживается в процессе декодирования и помещается в структуру данных DPB (буфер декодированных изображений).В нем есть два списка.Список 0 — прямой и список 1 — обратный.Согласно максимальному количеству опорных кадров DPB имеет ограниченное пространство. После его заполнения некоторые политики будут очищены или сброшены.

Поиск соответствующего макроблока в опорном кадре называется оценкой движения, а восстановление полного макроблока с помощью соответствующего блока — компенсацией движения. Как показано ниже:

В блоке кадра B третьего кадра на приведенном выше рисунке найдено 3 совпадающих блока, которые являются соседними I, P, B, и эти три кадра являются его опорными кадрами. Направление стрелки — это вектор движения.Из приведенной выше диаграммы видно, что объект перемещается сверху вниз (обратите внимание, что приведенный выше порядок — это порядок хранения IPBB, а порядок воспроизведения — IBBP).

Существует множество алгоритмов для оценки движения и компенсации движения, и у h264 есть рекомендуемый алгоритм.

Пока мы знаем основной принцип декодирования, как декодировать изображение этого кадра в картинку rgb, я в "wasm + ffmpeg реализует функцию фронтального перехвата видеокадров«Скомпилируйте ffmpeg в wasm, а затем реализуйте эту функцию на странице интерфейса. Он в основном использует декодирование ffmpeg, а Chrome также использует ffmpeg в качестве механизма декодирования. Ключевой функцией вызова является avcodec_decode_video2 (это устарело и будет упомянуто ниже).

С помощью ffmpeg мы можем разобрать все кадры на rgb-изображения.Как эти изображения образуют видео?

4. Воспроизведение видео

Самый интуитивно понятный способ основан на частоте кадров, например, частота кадров видео в приведенном выше примере составляет 25 кадров в секунду, в 1 с 25 кадров, а интервал воспроизведения каждого кадра составляет 1 с / 25 = 0,04 с, то есть каждые 40 мс воспроизводится кадр, который формирует видео. Используя функцию av_frame_get_best_effort_timestamp ffmpeg, можно получить время воспроизведения PST каждого кадра Теоретически время начала воспроизведения можно использовать в качестве отправной точки, и соответствующий кадр PST можно воспроизвести с соответствующей разницей во времени. С точки зрения реализации, поток, воспроизводящий видео, может заснуть из-за разницы во времени pst между двумя соседними кадрами.Когда время истекло, поток просыпается и затем отображает новый кадр.

На самом деле, чтобы лучше обеспечить синхронизацию аудио и видео, необходимо сделать поправку на основе текущего времени воспроизведения аудио. Например, если поток, декодирующий видео, зависает и не может идти в ногу со временем, а звуковые часы слишком отличаются от времени звука и превышают пороговое значение, такое как 0,1 с, то кадр будет потерян, не показывать наоборот, если поток декодирования видео быстрый, то задержите его, пусть поток, воспроизводящий видео, заснет на более длительное время, и сохраните текущий кадр без изменений. Более научный метод заключается в одновременном изменении аудио и видео с текущим временем воспроизведения, то есть записи системного времени при запуске воспроизведения и вычитании времени начала из текущего системного времени, чтобы получить время воспроизведения. Это то, что делает Chrome, и когда мы смотрим на исходный код Chrome, мы обнаруживаем, что этот процесс сложнее, чем описано выше.

5. Процесс воспроизведения видео в Chrome

Начнем с мультиплексирования. Мультиплексирование Chrome находится вsrc/media/filters/ffmpeg_demuxer.ccВнутри сначала инициализируйте format_context с данными буфера, запишите информацию о формате видео, а затем вызовите avformat_find_stream_info, чтобы получить все потоки, поток содержит одну дорожку, циклические потоки, различайте аудио, видео, текст в соответствии с codec_id три дорожки, записывайте каждую дорожку Число of , установите продолжительность воспроизведения и используйте fist_pts для инициализации времени начала воспроизведения start_time. И создайте экземпляр объекта DemuxerStream, который будет записывать ширину и высоту видео, есть ли угол поворота и т. д., инициализировать audio_config и video_config и использовать их при декодировании. Почти каждый шаг в этом осуществляется через PostTask, то есть функция выбрасывается в медиапоток как задача для обработки, и одновременно передается callback-функция, которая обрабатывается. Если один из шагов завершится ошибкой, следующий шаг не будет выполнен, например, если встретится неподдерживаемый формат контейнера, инициализация завершится ошибкой на первом шаге, и функция обратного вызова не будет настроена на отключение.

Декодирование — это декодирование аудио и видео с использованием avcodec_send_packet и avcodec_receive_frame из ffmpeg.Упомянутый выше avcodec_decode_video2 устарел, а начиная с ffmpeg3 была введена новая функция декодирования.

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

После завершения аудиодекодирования он будет помещен в AudioBufferQueue audio_buffer_renderer_algorithm, ожидая чтения потока AudioOutputDevice. Почему он называется алгоритмом, потому что он также имеет функцию реализации алгоритма регулировки длительности голоса WSOLA, так называемую переменную скорость и инвариантную высоту тона, потому что в JS мы можем настроить воспроизведение аудио/видео для регулировки скорости воспроизведения.

После завершения декодирования видео оно будет помещено в очередь буфера video_buffer_renderer_algorithm.cc.Функция этого класса также заключается в обеспечении плавного воспроизведения, включая отношения синхронизации часов, описанные выше.

При подготовке к рендерингу первым будет передан video_frame_compositor.cc.Этот компоновщик в медиа выступает посредником между медиа и Chrome Compositor (финальный композитинг), который синтезирует и рендерит обработанный кадр, как упоминалось в предыдущих статьях.Chrome использует skia как библиотека рендеринга и в основном управляет рисованием через предоставляемый ею класс Cavans.

Формат ffmpeg, используемый Chrome, сокращен, а поддерживаемые форматы ограничены, иначе один ffmpeg будет занимать более 10 МБ.

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

7. Резюме

В этой статье представлено множество концепций декодирования видео, в том числе характеристики формата контейнеров mp4, способы демультиплексирования аудио- и видеоданных и что такое I-кадры, B-кадры и P-кадры. Вводится, что время воспроизведения PST и порядок декодирования DST часто несовместимы в процессе декодирования (если есть B-кадры), а B-кадры и P-кадры декодируются и восстанавливаются посредством оценки движения и компенсации движения. Наконец, в нем рассказывается, как Chrome использует ffmpeg для декодирования, и анализируется общий процесс воспроизведения видео в Chrome.

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

Конференция разработчиков мини-программ Nuggets WeChat