mp4v2 muxer что это
Гайд по конвертации / исправлению / пред-обработке видео
Этот пост — для «своих».
Так что никакие претензии к оформлению или структуре — не принимаются.
Гайд по конвертации / исправлению / пред-обработке видео
(включая записи стримов, скачанное с твича и ютуба, ваши приватные хоум-видео, и т.д., и т.п.)
1. Перегонка видео из одного формата в другой
2. Меняем содержимое файла
3. Меняем/исправляем само изображение/звук
0. Софт, который должен быть всегда
Половина проблем с обработкой видео решается после выполнения лишь этого пункта.
Вкратце — суть такова:
1. Установи K-Lite Codec Pack в самом полном его виде: в издании Mega и с пресетом Lots of stuff.
2. Перед установкой убедись, что никакие из тех кодеков, что включены в K-Lite, у тебя не дублируются в системе ни сами по себе, ни в других паках. Проще говоря — удали любые другие кодеки, которые у тебя установлены, если только они не супер-специализированные (вроде DNxHD).
3. Поставь Avidemux и любые конвертации/преобразования/подрезки видео делай в нём, если он справляется.
Да, он бесплатный, легковесный и опенсорсный.
Нет, Adobe Media Encoder, конвертилка от Xilisoft или любые другие платные софтины — не лучше.
Сильно не лучше.
Потому что.
Подробно — вот пошаговые инструкции:
0. Если уже установлен K-Lite старой версии, лезь в папку с ним и забэкапь куда-нибудь файлы с расширением ini из папок MPC-HC и MPC-HC64.
Если их нет — поздравляю! Настройки плеера в реестре, хрен ты их оттуда выковыришь.
Удаляй K-Lite через «установку и удаление».
1. Если в системе есть любые другие кодеки или пакеты кодеков, кроме K-Lite и официального QuickTime — удаляй и их тоже.
2. Ставь QuickTime, если не стоит.
3. Ставь K-Lite свежей версии.
4. Ставь Avidemux, соответствующий разрядности твоей операционки (64 либо 32 бит). Если не знаешь разрядность — жми на клаве Win+Pause и смотри там.
Всё, на что я не обратил внимание — оставляй по дефолту.
Вуаля! Самый полный комплект кодеков установлен.
1. Перегонка видео из одного формата в другой
Сперва — давай кое-что проясним.
Для того, чтобы преобразовать, допустим, FLV в MP4, далеко не всегда надо конвертировать сам видеопоток, который находится внутри этих контейнеров. Довольно часто (а на деле — почти всегда) можно сохранить видеофайл в другой формат, скопировав видеопоток без изменений.
Что это нам даёт?
• Во-первых, такая конвертация — значительно быстрее. По сути, она происходит с той же скоростью, что и просто копирование файла.
• Во-вторых, раз видео не пережимается — то и качество не теряется, и конвертированный файл не весит больше.
Один нюанс: целевой контейнер должен поддерживать тот формат, которым сжат видеопоток. Но, к счастью, в эпоху HD почти всегда у нас видео сжато кодеком h264 — а значит, его можно спокойно перегонять в FLV, MP4, MKV и даже QuickTime’овский MOV.
Зная это, теперь мы понимаем, что на самом деле тебе почти наверняка не нужно именно конвертировать видео. Достаточно лишь сменить контейнер.
И вот именно из-за такой возможности Avidemux нагибает любые другие платные софты для конвертации.
Как обычно:
• Drag-n-drop в окошко Avidemux
• Ctrl+O
• Кнопка вверху на панельке
• Пункт в меню «File»
• Оставляешь дефолтный режим кодирования аудио и видео — Copy.
• Выбираешь нужный контейнер. В случае с mp4 — лучше сперва пробовать MP4v2 Muxer. И если с ним не заработает — тогда просто MP4.
• Просто сохраняешь файл под новым именем.
1.2. Как узнать, получится ли просто скопировать видеопоток из имеющегося контейнера в нужный мне?
Самое простое — попробовать пересохранить через Avidemux в нужный формат. Ваш Кэп 🙂
Если же что-то не выходит, • Открываешь своё видео в Media Player Classic Home Cinema (MPC, он поставился вместе с K-Lite).
• Shift + F10
Здесь указан кодек, которым закодирован видеопоток.
• А дальше гуглишь, поддерживается ли этот кодек в том контейнере, в который ты пытаешься сохранить. В данном случае — исходное видео скачано с ютуба в flv (самое низкое качество), в котором оно сжато кодеком Flash Video 1 (также известным как Sorenson Spark). И, увы, в mp4 этот кодек не поддерживается.
1.3. Что делать, если целевой контейнер не поддерживает этот кодек?
Увы, всё-таки придётся перекодировать. По идее, в 90% случаев тебе не придётся сталкиваться с этой проблемой.
Но если всё же столкнёшься, • Вместо «Copy» выбираешь для видео подходящий кодек.
• Настраиваешь ему параметры качества.
• Опять же, выбираешь нужный контейнер.
• Если аудиокодек тоже не поддерживается — делаешь с ним то же самое.
• Сохраняешь.
1.4. Так в какой формат, каким кодеком, и с какими настройками мне надо кодировать?
Сейчас самый ходовой формат видео — это h264 (он же — AVC — Advanced Video Coding). А самый «кошерный» контейнер для него — это MP4. Но он держит не все форматы аудио.
Самый же универсальный контейнер — это MKV. Он держит вообще все форматы — как аудио, так и видео. Но, увы, не все программы для монтажа могут с ним нормально работать.
Так что ориентируйся на связку mp4/h264, а аудио — mp3. К счастью, на ютубе аудио всегда в mp3 — так что его перекодировать не требуется, даже если придётся пережимать видео (хотя и это актуально только для очень низких разрешений).
Как ты мог заметить, если нужно перекодировать, то в Avidemux’е есть 2 кодера в AVC: H264 (ff/nvidia) и Mpeg4 AVC (x264).
Жми на Configure — и поймёшь, зачем он нужен.
Он тупо более простой в настройке — и всё. Два этих поля означают то же самое, что и в OBS. 3000 / 9000 — это абсолютный минимум для стрима в 720p. Качественный битрейт надо подбирать.
И именно поэтому я рекомендую использовать не данный кодек, а следующий.
Нажимаешь Configure — и…
БЕЗ ПАНИКИ!
Спокойно!
Да, настроек овер дофига. Но на самом деле, они все — для «адвансед юзеров». А всё, что от нас требуется — это выбрать пресет и покрутить один-единственный ползунок.
• В самом верху выбираешь пресет — fast, veryFast, ultraFast — в зависимости от того, насколько много времени есть на кодирование файла. Чем быстрее — тем хуже качество.
• Убеждаешься, что Encoding Mode стоит в Constant Rate Factor.
• Если надо — можешь точно подкрутить ползунок качества. Точное понимание того, какое значение к какому качеству приводит — приходит с опытом.
Возьми за отправную точку дефолтные 12. Чем больше цифра — тем быстрее жмётся и меньше размер файла, но хуже качество (да, больше = хуже).
2. Меняем содержимое файла
2.0. Как перемещаться по шкале времени в Avidemux?
2.1. Как собрать несколько фрагментов записи (стрима) в один файл?
При чём, если все фрагменты — одного и того же формата (одинаковые размеры кадра, кодек, частота кадров, и желательно — чтоб были сжаты вообще одним и тем же софтом, с одинаковыми параметрами), то Avidemux, опять же, объединит видео- и аудиопотоки без конвертации.
Другими словами, запись стрима можно без потерь собрать в один непрерывный файл.
2.2. Как обрезать запись, оставив лишь нужную часть?
Тут есть один нюанс. Когда оставляешь лишь часть записи — конец можешь подрезать, как угодно. А вот начинаться она должна с ключевого кадра.
• Перемещаешься на первый кадр, который надо оставить.
• Обозначаешь его началом нужной части (также называемым как «Маркер А»). Делаешь это либо кнопкой внизу, либо клавишей «[«.
Внизу, под всеми кнопками, следи, чтоб тип кадра был — I-FRM. Это и есть ключевой кадр.
• Аналогичным образом устанавливаешь конец выделения (клавиша «]«).
• Можно подрезать только конец или только начало.
• Сохраняешь файл под новым именем.
2.3. Как заменить аудиодорожку?
Тут же — можешь явно указать язык аудио (второй столбец), а также вместо копирования потока настроить его перекодирование (остальные столбцы).
2.4. У меня упал OBS, файл записи не проигрывается. Можно его починить?
Есть шанс. Небольшой, но всё же есть. • Находишь файл. Смотришь его размер. Если он весит не ноль (или какие-то смешные килобайты) — значит, видеопоток там внутри сохранился. Но оборвался «без предупреждения». Попробуй его просто открыть Avidemux’ом и пересохранить. В такой же контейнер, потоки — копируем.
• Если не поможет — попробуй его перед сохранением подрезать в конце на пару кадров / секунд. • Если и это не поможет — попробуй подрезать в конце до ближайшего ключевого кадра.
• Если шла трансяляция на твич — можно оттуда забрать запись, и начало использовать из того файла, который писался локально, а конец — скачанный.
Почему бы не использовать всю запись с твича? Можно и так. Но в локальном файле нет дропов.
3. Меняем/исправляем само изображение/звук
Если файл перекодируется — то можно произвести манипуляции с самим видеопотоком. Его можно:
• подрезать (убираем чёрные полосы — YouTube это любит);
• устранить интерлейсинг (такой отголосок прошлого, при котором наблюдается горизонтальная «расчёска» на движущихся объектах);
•… аналогично устранить «квадраты сжатия» (сделать деблокинг);
• вшить «хардкорные» субтитры прямо в видео;
•… и наложить ещё кучу подобных «исправлялок» видеопотока.
Аналогично — фильтры можно наложить на аудио. Например, смещение звука делается через фильтры (да, требуется перекодирование).
Аудиофильтры можно наложить как на всё вместе, так и на отдельные потоки (см. 2.3).
По идее, тут должны быть типа какие-то выводы. Но их не будет, потому что это тупо инструкция к действию.
Отмечу лишь, что возможности Avidemux расширяются ещё сильнее, если его использовать в паре с AviSynth. Что лично мне несколько раз конкретно так спасало жизнь. Но это уже совсеем другая история, попахивающая лютым хардкором.
В качестве бонуса — для скачивания видосов с ютуба рекомендую плагин к ФаерФоксу, YouTube Video and Audio Downloader. Он работает только с YT, но является самым крутым расширением для этих целей. И — да — он может скачивать видео в HD, при котором, как известно, видео и аудио представлено отдельными файлами. И он их автоматически объединяет после скачивания. Без перекодирования, как Avidemux.
А, ну и ещё кое-что. Я сторонник универсальных безотказных решений.
Поэтому задача этого гайда — рассказать о минимальном количестве наиболее простых, но при этом надёжных, функциональных и производительных утилит для решения максимально широкого спектра задач, связанных с обработкой видеофайлов.
Методом проб и ошибок я остановился на одной утилитке, которая делает всё вышеперечисленное, и почти всегда делает это лучше, чем более узкоспециализированные аналоги.
Скорее всего, где-то там могут быть какие-то ещё софтины для решения обозначенных проблем, но… Хотя нет. Я почти уверен, что более подходящих программ под всё то, что выделено жирным выше — нет. Да, включая монструозные платные пакеты от именитых производителей.
Поэтому любые претензии в духе: «Чё-то мне этот твой Avidemux как-то ниочинь, то ли дело мой любимый (платный, крякнутый) %ИМЯ_СОФТИНЫ%», — засуньте себе сами знаете куда.
Хотите воевать со своей любимой «самой лучшей» программой для конвертации — воюйте дальше, но зачем тогда вы заглянули сюда?
Хотите решить проблемы с преобразованием видео — делайте, как я говорю, либо же…
Хотите предложить более удобный/простой способ решения — я только за: вперёд, в комментарии. Лучшее — враг хорошего. Я буду только рад, если кто-то подскажет ещё более крутые программки для монтажа/мукса/демукса без рекодирования.
Но сразу замечу: помимо перечисленных в этом гайде утилит — я также активно использую следующие, однако для «широких масс» считаю их неприменимыми:
• MeGUI
• FFMPEG
• YAMB
• MKV merge/extract
Avidemux MP4v2 Muxer outputting variable frame rate (audio sync issues)
Thread Tools
Display
Source is from a Digital8 tape that I captured in WinDV to a DV-AVI Type 1 file, then ran through VirtualDub with direct stream copy saved as AVI, this is to convert it to DV-AVI Type 2 so that I can open it in Avidemux (DV-AVI Type 1 won’t open in Avidemux). Here I’m using a few filters to de-interlace, resize to 640×480 etc. and output to MP4 (h264 and AAC resampled to 48000khz), but the audio in the output file is gradually losing sync. I have had success with these settings before but this video gets really bad towards the end.
In my quest to figure out the cause of this, I just noticed that when using the MP4v2 Muxer in Avidemux, MediaInfo shows this:
Frame rate mode : Variable
Frame rate : 59.940 (59940/1000) FPS
Minimum frame rate : 19.982 FPS
Maximum frame rate : 59.960 FPS
However, the AVI files are constant frame rate, and when I set Avidemux Output Format to MP4 Muxer instead of MP4v2 Muxer, the output file is constant frame rate. I suspect this is why the audio is coming out of sync. Can MP4v2 Muxer not output constant frame rate?
MediaInfo reports variable frame rate when the container is at all able to support it. That doesn’t always mean that it is actually used; MediaInfo does not scan the whole file, creating statistics about the duration of every frame. It relies more on values stored in headers.
But in your case, the slight difference between the general (NTSC conformant) and the max-vfr rate (slightly off NTSC) is suspicious, as well as a weird min-vfr rate. A miscalculation seems probable.
DV codec does not support vfr. Neither does avi container. Mp4v2 muxer may have some problems, but it sounds like something else (or in addition) is being done wrong here.
There are better options for converting type1 to type2, just look in the tools section. No need for all the vdub business.
DV codec does not support vfr. Neither does avi container. Mp4v2 muxer may have some problems, but it sounds like something else (or in addition) is being done wrong here.
There are better options for converting type1 to type2, just look in the tools section. No need for all the vdub business.
Right, the source files were constant frame rate, that’s why I’m confused why conversion to MP4 would introduce VFR. If use the same H264 and AAC settings but use the MKV Muxer in Avidemux I get constant frame rate MKV file. It makes no sense why outputting MP4 would do this. Also, I should mention that part of the reason I was using VirtualDub was to append multiple files that were recorded close together into one AVI file. It shouldn’t be altering the video or audio at all, just remuxing. If there is a better way please let me know. You didn’t give any recommendations for alternatives so I tried out DVdate to convert to DV-AVI Type 2, but still Avidemux was outputting VFR with audio losing sync.
I tried My MP4Box GUI and it seems after demuxing the video and audio from the problem MP4 files and then remuxing a new MP4 file from the H264 and AAC files, I have a constant frame rate 59.94 and audio is back to being in sync! At least it worked on this video. I will have to see if it fixes the others too. Should I go ahead with this workflow or is this likely to introduce more issues? Still frustrated that Avidemux doesn’t have a setting to turn VFR off, wish I didn’t have to go through this extra step.
Руководство по FFmpeg libav
Долго искал книгу, в которой было бы разжёвано, как использовать FFmpeg-подобную библиотеку, известную как libav (название расшифровывается как library audio video). Обнаружил учебник «Как написать видеоплеер и уложиться в менее чем тысячу строк». К сожалению, информация там устаревшая, так что пришлось создавать мануал своими силами.
Большая часть кода будет на C, однако не волнуйтесь: Вы легко всё поймёте и сможете применить на любимом языке. У FFmpeg libav уйма привязок ко многим языкам (в том числе и к Python и к Go). Но даже если Ваш язык прямой совместимости не имеет, всё равно можно привязаться через ffi (вот пример с Lua).
Начнём с краткого экскурса о том, что такое видео, аудио, кодеки и контейнеры. Затем перейдем к ускоренному курсу, посвященному использованию командной строки FFmpeg, и, наконец, напишем код. Не стесняйтесь переходить сразу в раздел «Тернистый путь изучения FFmpeg libav».
Есть мнение (и не только моё), что потоковое интернет-видео уже приняло эстафету от традиционного телевидения. Как бы то ни было, FFmpeg libav точно достоин изучения.
Оглавление
![]()
Статья переведена при поддержке компании EDISON.
Мы очень любим работать с видео! 😉
Вступление ↑
Видео — это то, что ты видишь! ↑
Если последовательность изображений менять с заданной частотой (скажем, 24 изображения в секунду), то создаётся иллюзия движения. Это и есть основная идея видео: серия изображений (кадров), движущихся с заданной скоростью.
Иллюстрация 1886 года.
Аудио — это то, что ты слышишь! ↑
Хотя немое видео может вызывать самые разные чувства, добавление звука резко повышает степень удовольствия.
Звук — это колебательные волны, распространяемые в воздухе или в любой других средах передачи (таких как газ, жидкость или твердое вещество).
В цифровой аудиосистеме микрофон преобразует звук в аналоговый электрический сигнал. Затем аналого-цифровой преобразователь (АЦП) — обычно с использованием импульсной кодовой модуляции (ИКМ) — преобразует аналоговый сигнал в цифровой.
Кодек — сжатие данных ↑
Кодек — это электронная схема или программное обеспечение, сжимающее или распаковывающее цифровое аудио/видео. Он преобразует необработанное (несжатое) цифровое аудио/видео в сжатый формат (или наоборот).
Но если мы решим упаковать миллионы изображений в один файл и назовем его фильмом, у нас может получиться огромный файл. Давайте посчитаем:
Допустим, создаём видео с разрешением 1080×1920 (высота × ширина). Тратим 3 байта на пиксель (минимальную точку на экране) для цветового кодирования (24-битного цвета, что дает нам разных цветов). Это видео работает со скоростью 24 кадра в секунду, общая продолжительность 30 минут.
Для этого видео потребуется приблизительно 250,28 Гб памяти или 1,11 Гбит/с! Вот поэтому и придётся использовать кодек.
Контейнер — удобный способ хранения аудио/видео ↑
Формат контейнера (оболочки) — это формат метафайла, спецификация которого описывает, как различные элементы данных и метаданных сосуществуют в компьютерном файле.
Это единый файл, содержащий все потоки (в основном, аудио и видео), обеспечивающий синхронизацию, содержащий общие метаданные (такие как заголовок, разрешение) и т.п.
Обычно формат файла определяется по его расширению: например, video.webm — это, скорее всего, видео с использованием контейнера webm.
Командная строка FFmpeg↑
Самодостаточное кроссплатформенное решение для записи, конвертации и потоковой передачи аудио/видео.
Для работы с мультимедиа у нас есть восхитительный инструмент — библиотека под названием FFmpeg. Даже если Вы не используете её в своём программном коде, то всё равно используете её (Вы ведь используете Chrome?).
В библиотеке есть консольная программка для ввода командной строки под названием ffmpeg (маленькими буквами, в отличие от названия самой библиотеки). Это простой и мощный бинарник. Например, можно конвертировать из mp4 в avi, просто набрав такую команду:
Мы только что сделали ремиксинг — сконвертировали из одного контейнера в другой. Технически FFmpeg также может выполнять транскодирование, но об этом позже.
Инструмент командной строки FFmpeg 101 ↑
У FFmpeg есть документация, где всё отлично объяснено, как что работает.
Схематично, программа командной строки FFmpeg ожидает, что следующий формат аргументов выполнит свои действия — ffmpeg <1> <2>-i <3> <4>, где:
— глобальные параметры
— параметры входного файла
— входящий URL
— параметры выходного файла
— исходящий URL
В частях <2>, <3>, <4>, <5>указывается столько аргументов, сколько нужно. Проще понять формат передачи аргументов на примере:
# ПРЕДУПРЕЖДЕНИЕ: файл по ссылке весит 300 МБ
Эта команда берет входящий mp4-файл, содержащий два потока (аудио, закодированный с помощью кодека aac, и видео, закодированный с использованием кодека h264), и преобразует его в webm, изменяя также кодеки аудио и видео.
Если упростить приведенную выше команду, то следует учесть, что FFmpeg примет значения по умолчанию вместо Вас. Например, если просто набрать
то, какой аудио/видео кодек он использует для создания output.mp4?
Вернер Робица написал руководство по чтению/исполнению, посвященное кодированию и редактированию с помощью FFmpeg.
Основные операции над видео↑
При работе с аудио/видео мы обычно выполняем ряд задач связанных с мультимедиа.
Транскодирование (перекодирование)↑
Что это? Процесс преобразования потокового или аудио или видео (или и то и другое одновременно) из одного кодека в другой. Формат файла (контейнер) при этом не меняется.
Для чего? Бывает, что некоторые устройства (телевизоры, смартфоны, консоли и т. д.) не поддерживают формат аудио/видео X, но поддерживают формат аудио/видео Y. Или же более новые кодеки предпочтительнее, поскольку обеспечивают лучшую степень сжатия.
Как? Преобразуем, к примеру, видео H264 (AVC) в H265 (HEVC):
Трансмультиплексирование↑
Что это? Преобразование из одного формата (контейнера) в другой.
Для чего? Бывает, что некоторые устройства (телевизоры, смартфоны, консоли и т. д.) не поддерживают формат файла X, но поддерживают формат файла Y. Или же более новые контейнеры, в отличие от устаревших, предоставляют современные требуемые функции.
Как? Конвертируем mp4 в webm:
Трансрейтинг↑
Что это? Изменение скорости передачи данных или создание другого представления.
Для чего? Пользователь может смотреть Ваше видео как в сети 2G на маломощном смартфоне, так и через оптоволоконную интернет-связь на 4K-телевизоре. Поэтому следует предлагать более одного варианта воспроизведения одного и того же видео с разными скоростями передачи данных.
Как? производит воспроизведение с битрейтом между 3856K и 2000K.
Обычно трансрейтинг осуществляется в связке с перекалибровкой. Вернер Робица написал еще одну обязательную для ознакомления статью о контроле скорости FFmpeg.
Трансайзинг (перекалибровка)↑
Что это? Изменение разрешающей способности. Как сказано выше, транссайзинг часто проводится одновременно с трансрейтингом.
Для чего? По тем же причинам, что и с трансрейтингом.
Как? Уменьшим разрешение 1080 до 480:
Бонус: адаптивный стриминг↑
Что это? Создание множества разрешений (битрейтов) и разбиение медиа на части и их передача по протоколу http.
Для чего? Ради обеспечения гибкого мультимедиа, которое можно просматривать хоть на бюджетном смартфоне хоть на 4K-плазме, чтобы можно было легко масштабировать и развертывать (но это может добавить задержку).
Как? Создадим адаптивный WebM с использованием DASH:
Выходя за рамки↑
Несть числа другим применениям FFmpeg. Я использую его вместе с iMovie для создания/правки некоторых видео для YouTube. И Вам, безусловно, использовать его профессионально тоже ничего не препятствует.
Тернистый путь изучения FFmpeg libav↑
Разве время от времени не поразительно то, что воспринимается через слух и зрение?
Биолог Дэвид Роберт Джонс
FFmpeg крайне полезен как инструмент в виде командной строки для выполнения важных операций с мультимедийными файлами. Может и в программах его тоже получится использовать?
FFmpeg состоит из нескольких библиотек, которые можно интегрировать в наши собственные программы. Обычно, при установке FFmpeg, автоматически устанавливаются все эти библиотеки. Я буду ссылаться на набор этих библиотек как FFmpeg libav.
Название раздела является данью уважения серии Зеда Шоу «Тернистый путь обучения [. ]», в частности его книге «Тернистый путь обучения языку C».
Глава 0 — простенький «Hello World»↑
В нашем Hello World на самом деле не будет приветствовать мир на языке консоли. Вместо этого распечатаем следующую информацию о видео: формат (контейнер), продолжительность, разрешение, аудиоканалы и, напоследок, расшифруем некоторые кадры и сохраним их как файлы изображений.
Архитектура FFmpeg libav↑
Но прежде чем начнём писать код, давайте посмотрим, как вообще работает архитектура FFmpeg libav и как ее компоненты взаимодействуют с другими.
Вот схема процесса декодирования видео:
Сначала медиафайл загружается в компонент по имени AVFormatContext (контейнер видео также является форматом). На самом деле он не полностью загружает весь файл: часто читается только заголовок.
Как только загрузили минимальный заголовок нашего контейнера, можно получить доступ к его потокам (их можно представить как элементарные аудио- и видео-данные). Каждый поток будет доступен в компоненте AVStream.
Предположим, наше видео имеет два потока: аудио, закодированное с помощью кодека AAC, и видео, закодированное с помощью кодека H264 (AVC). Из каждого потока можем извлечь фрагменты данных, называемые пакетами, которые загружаются в компоненты, называемые AVPacket.
Данные внутри пакетов по-прежнему кодируются (сжимаются), и для декодирования пакетов нам необходимо передать их конкретному AVCodec.
AVCodec декодирует их в AVFrame, в результате чего этот компонент выдает нам несжатый кадр. Отметим, что терминология и процесс одинаковы как для аудио- так и видео-потока.
Требования↑
Так как иногда возникают проблемы при компиляции или запуске примеров, мы будем использовать Docker в качестве среды разработки/выполнения. Также будем использовать видео с большим кроликом, поэтому, если у вас его нет на локальном компьютере, просто проведите в консоли команду make fetch_small_bunny_video.
Собственно, код↑
TLDR; покажи мне пример выполянемого кода, бро:
Мы опустим некоторые детали, но не волнуйтесь: исходный код доступен на github.
Мы собираемся выделить память для компонента AVFormatContext, который будет содержать информацию о формате (контейнере).
Теперь мы собираемся открыть файл, прочитать его заголовок и заполнить AVFormatContext минимальной информацией о формате (обратите внимание, что обычно кодеки не открываются). Для этого используется функция avformat_open_input. Он ожидает AVFormatContext, имя файла и два необязательных аргумента: AVInputFormat (если вы передадите NULL, FFmpeg определит формат) и AVDictionary (которые являются опциями демультиплексора).
Также можно напечатать название формата и длительность медиа:
Чтобы получить доступ к потокам, нам нужно прочитать данные с носителя. Это делает функция avformat_find_stream_info. Теперь pFormatContext-> nb_streams будет содержать количество потоков, а pFormatContext-> streams[i] даст нам i-й по счёту поток (AVStream).
Пройдемся в цикле по всем потокам:
Для каждого потока мы собираемся сохранить AVCodecParameters, описывающий свойства кодека, используемого i-м потоком:
Используя свойства кодеков можем найти соответствующий, запрашивая функцию avcodec_find_decoder, также можем найти зарегистрированный декодер для идентификатора кодека и вернуть AVCodec — компонент, который знает, как кодировать и декодировать поток:
Теперь мы можем распечатать информацию о кодеках:
С помощью кодека выделяем память для AVCodecContext, который будет содержать контекст для нашего процесса декодирования/кодирования. Но затем нужно заполнить этот контекст кодека параметрами CODEC — мы делаем это с помощью avcodec_parameters_to_context.
После того, как мы заполнили контекст кодека, необходимо открыть кодек. Вызываем функцию avcodec_open2 и затем можем ее использовать:
Теперь мы собираемся прочитать пакеты из потока и декодировать их в кадры, но сначала нам нужно выделить память для обоих компонентов (AVPacket и AVFrame).
Давайте скормим наши пакеты из потоков функции av_read_frame, пока у нее есть пакеты:
Теперь отправим пакет необработанных данных (сжатый кадр) в декодер через контекст кодека, используя функцию avcodec_send_packet:
И давайте получим кадр необработанных данных (несжатый кадр) от декодера через тот же контекст кодека, используя функцию avcodec_receive_frame:
Мы можем напечатать номер кадра, PTS, DTS, тип кадра и т.д.:
И напоследок, можем сохранить наш декодированный кадр в простое серое изображение. Процесс очень прост: мы будем использовать pFrame->data, где индекс связан с цветовыми пространствами Y, Cb и Cr. Просто выбираем 0 (Y), чтобы сохранить наше серое изображени:
И вуаля! Теперь у нас есть полутоновое изображение размером 2Мб:
Глава 1 — синхронизация аудио и видео↑
Быть в игре — это когда юный JS-разработчик пишет новый MSE-видеоплеер.
Прежде чем перейдем написанию кода транскодирования, давайте поговорим о синхронизации или о том, как видеоплеер узнаёт правильное время для воспроизведения кадра.
В предыдущем примере мы сохранили несколько кадров:
Когда мы проектируем видеоплеер, нам нужно воспроизводить каждый кадр в определенном темпе, иначе трудно получить удовольствие от видео либо из-за того, что оно воспроизводится слишком быстро, либо слишком медленно.
Поэтому нам нужно определить некую логику для плавного воспроизведения каждого кадра. В этом отношении каждый кадр имеет временнýю метку представления (PTS — от presentation timestamp), которая представляет собой увеличивающееся число, учитываемое в переменной timebase, которая представляет собой рациональное число (где знаменатель известен как временно́й масштаб — timescale), делимое на частоту кадров (fps).
Проще понять на примерах. Давайте смоделируем некоторые сценарии.
Для fps = 60/1 и timebase = 1/60000 каждый PTS будет увеличивать timescale / fps = 1000, поэтому реальное время PTS для каждого кадра может быть (при условии, что оно начинается с 0):
Почти по тому же сценарию, но с timescale, равной 1/60:
Для fps = 25/1 и timebase = 1/75 каждая PTS будет увеличивать timescale / fps = 3, и время PTS может быть:
Теперь с pts_time мы можем найти способ визуализировать это синхронизированным со звуком pts_time или с системными часами. FFmpeg libav предоставляет эту информацию через свой API:
Просто из любопытства, сохраненные нами кадры были отправлены в порядке DTS (кадры: 1, 6, 4, 2, 3, 5), но воспроизведены в порядке PTS (кадры: 1, 2, 3, 4, 5). Также обратите внимание, насколько дешевле обходятся B-кадры по сравнению с P или I-кадрами:
Глава 2 — ремультиплексирование↑
Ремультиплексирование (перекомпоновка, remuxing) — переход от одного формата (контейнера) к другому. Например, мы можем без особого труда заменить видео MPEG-4 на MPEG-TS с помощью FFmpeg:
MP4-файл будет демультиплексирован, при этом файл не будет декодирован или кодирован (-c copy), и, в конце концов, на выходет получим mpegts-файл. Если не указывать формат -f, ffmpeg попытается угадать его на основании расширения файла.
Общее использование FFmpeg или libav следует такому шаблону/архитектуре или рабочему процессу:
Теперь давайте создадим пример с использованием libav, чтобы обеспечить тот же эффект, что и при выполнении такой команды:
Мы собираемся читать из ввода (input_format_context) и изменять его на другой вывод (output_format_context):
Обычно начинаем с того, что выделяем память и открываем формат ввода. Для этого конкретного случая мы собираемся открыть входной файл и выделить память для выходного файла:
Будем ремультиплексировать только потоки видео, аудио и субтитров. Поэтому фиксируем, какие потоки будем использовать, в массив индексов:
Сразу после того, как выделим необходимую память, нужно выполнить цикл по всем потокам, и для каждого из которых надо создать новый выходной поток в нашем контексте выходного формата, используя функцию avformat_new_stream. Обратите внимание, что мы помечаем все потоки, которые не являются видео, аудио или субтитрами, чтобы была возможность пропустить их.
Теперь создаём выходной файл:
После этого можно копировать потоки, пакет за пакетом, из нашего ввода в наши выходные потоки. Это происходит в цикле, пока есть пакеты (av_read_frame), для каждого пакета нужно пересчитать PTS и DTS, чтобы наконец записать его (av_interleaved_write_frame) в наш контекст выходного формата.
Для завершения нам нужно записать трейлер потока в выходной медиафайл с помощью функции av_write_trailer:
Это работает! Не верите?! Проверьте с помощью ffprobe:
Подводя итог тому, что мы сделали, теперь можем вернуться к нашей первоначальной идее о том, как работает libav. Но мы пропустили часть кодека, что отображено на схеме.
Прежде чем закончим эту главу, хотелось бы показать такую важную часть процесса ремультиплексрования, где можно передавать параметры мультиплексору. Допустим, надо предоставить формат MPEG-DASH, поэтому нужно использовать фрагментированный mp4 (иногда называемый fmp4) вместо MPEG-TS или обычного MPEG-4.
С помощью командной строки это легко:
Почти так же просто это и в libav-версии, просто передаём опции при записи выходного заголовка, непосредственно перед копированием пакетов:
Теперь можем сгенерировать этот фрагментированный mp4-файл:
Чтобы убедиться, что тут всё по-честному, Вы можете использовать удивительный сайт-инструмент gpac/mp4box.js или сайт http://mp4parser.com/, дабы увидеть различия — сначала загрузите mp4.
Как видно, он имеет один неделимый блок mdat — это место, где находятся видео и аудио кадры. Теперь загрузите фрагментированный mp4, чтобы увидеть, как он расширяет блоки mdat:
Глава 3 — транскодирование↑
TLDR; покажи мне код и исполнение:
Мы пропустим некоторые детали, но не волнуйтесь: исходный код доступен на github.
В этой главе создадим минималистичннй транскодер, написанный на C, который может конвертировать видео из H264 в H265 с использованием библиотек FFmpeg libav, в частности libavcodec, libavformat и libavutil.
AVFormatContext — это абстракция для формата медиа-файла, т.е. для контейнера (MKV, MP4, Webm, TS)
AVStream представляет каждый тип данных для данного формата (например: аудио, видео, субтитры, метаданные)
AVPacket — это фрагмент сжатых данных, полученных из AVStream, которые могут быть декодированы с помощью AVCodec (например: av1, h264, vp9, hevc), генерирующих необработанные данные, называемые AVFrame.
Трансмультиплексирование↑
Начнем с простого преобразования, затем загрузим входной файл.
Теперь настроим декодер. AVFormatContext предоставит нам доступ ко всем компонентам AVStream, и для каждого из которых можем получить их AVCodec и создать конкретный AVCodecContext. И, наконец, можем открыть данный кодек, чтобы перейти к процессу декодирования.
AVCodecContext содержит данные о конфигурации мультимедиа, такие как скорость передачи данных, частота кадров, частота дискретизации, каналы, высота и многие другие.
Также нужно подготовить выходной медиа-файл для преобразования. Сначала выделим память для выходного AVFormatContext. Создадим каждый поток в выходном формате. Чтобы правильно упаковать поток, копируем параметры кодека из декодера.
Устанавливаем флаг AV_CODEC_FLAG_GLOBAL_HEADER, который сообщает кодировщику, что он может использовать глобальные заголовки, и, наконец, открываем выходной файл для записи и сохраняем заголовки:
Получаем AVPacket от декодера, корректируем метки времени и записываем пакет правильно в выходной файл. Несмотря на то, что функция av_interleaved_write_frame сообщает «write frame», сохраняем пакет. Заканчиваем процесс перестановки, записывая трейлер потока в файл.
Транскодирование↑
В предыдущем разделе была простая программа для преобразования, теперь добавим возможность кодировать файлы, в частности, перекодирование видео с h264 на h265.
После того, как подготовлен декодер, но перед тем, как организовать выходной медиафайл, настроим кодировщик.
Необходимо расширить цикл декодирования для транскодирования видеопотока:
Мы преобразовали поток мультимедиа из h264 в h265. Как и ожидалось, версия медиа-файла h265 меньше, чем h264, при этом у программы широкие возможности:
Положа руку на сердце, признаюсь, что было несколько посложнее, чем представлялось в начале. Пришлось ковыряться в исходном коде командной строки FFmpeg и много тестировать. Наверное, что-то где-то упустил, потому что пришлось применять force-cfr для h264, и всё ещё выскакивают некоторые предупреждающие сообщения, например о том, что тип кадра (5) принудительно был изменен на тип кадра (3).