Перейти к основному содержимому

MKV

MKV (Matroska Video, читается "матрёшка", а не "матроска") – это открытый контейнерный формат мультимедиа, разработанный в 2002 году. Он предназначен для хранения видео, аудио, субтитров и метаданных в одном файле. Формат является гибким и расширяемым, что позволяет использовать его для различных целей, включая потоковую передачу данных, создание Blu-ray дисков и многое другое. Основная цель разработки MKV заключалась в создании универсального контейнера, который мог бы поддерживать множество форматов видео и аудио без привязки к конкретным кодекам.

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

Основные характеристики MKV:

  • Открытый стандарт: проект Matroska поддерживается сообществом разработчиков и доступен под лицензией LGPL.
  • Поддержка множества потоков: может содержать несколько видеопотоков, аудиодорожек и субтитров одновременно.
  • Расширяемость: благодаря модульному подходу, формат легко адаптируется под новые технологии и стандарты.
  • Совместимость: поддерживает широкий спектр видео- и аудиоформатов, таких как H.264/AVC, HEVC/H.265, AAC, MP3 и многие другие.

Структура файла MKV

Файл MKV состоит из блоков EBML (Extensible Binary Meta Language), которые определяют структуру контейнера. Вот основные элементы структуры:

  • EBML Header: Заголовок, содержащий информацию о версии формата и глобальные настройки.
  • Segment: Основной блок, включающий все остальные элементы.
  • Cluster: Блок, содержащий фрагменты видео и аудио данных.
  • Tracks: Описывают потоки видео, аудио и субтитры.
  • Attachments: Дополнительная информация, такая как обложки альбомов, шрифты для субтитров и т.п.
  • Chapters: Разделы внутри видео, позволяющие переходить между ними.
  • Tags: Метаданные, такие как название фильма, автор, жанр и др.

Пример структуры файла MKV:

EBML Header
Segment
SeekHead (информация для быстрого поиска)
Info (общая информация о сегменте)
Tracks (описание видеопотока, аудиопоотов и субтитров)
Chapters (разделы видео)
Attachments (вложенные файлы)
Tags (метаданные)
Cluster (видео и аудиофрагменты)

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

:::

Преобразование видео в MKV c перекодированием в FFMPEG

Для преобразования видео из одного формата в другой с сохранением в контейнере MKV можно использовать следующую команду:

ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -b:a 128k output.mkv

Где:

  • input.mp4 – исходный файл,
  • libx264 – кодек для сжатия видео (H.264),
  • crf 23 – параметр качества видео (чем меньше значение, тем выше качество),
  • aac – кодек для сжатия аудио (Advanced Audio Coding),
  • 128k – битрейт аудио,
  • output.mkv – выходной файл в формате MKV.

Добавление нескольких аудиодорожек

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

ffmpeg -i video.mp4 -i audio1.wav -i audio2.wav \
-map 0:v -map 1:a -map 2:a \
-c copy output.mkv

Здесь:

  • video.mp4, audio1.wav, audio2.wav – исходные файлы,
  • -map 0:v – копирование видеопотока из первого файла,
  • -map 1:a и -map 2:a – добавление двух аудиодорожек из второго и третьего файлов,
  • -c copy – копирование потоков без перекодирования,
  • output.mkv – результирующий файл.

Извлечение отдельных дорожек

Для извлечения отдельной дорожки (например, субтитров) из файла MKV можно использовать такую команду:

ffmpeg -i input.mkv -map 0:s:0 subtitles.srt

Где:

  • input.mkv – входной файл,
  • -map 0:s:0 – выбор первой субтитровой дорожки,
  • subtitles.srt – выходной файл с субтитрами в формате SRT.

Перенос потоков из MKV в MP4 без перекодирования

::: success При записи внешних потоков лучше использовать контейнер MKV на случай аварийного прерывания записи (отключение питания, программный сбой) -- уже записанная до сбоя часть файла будет читаться. Но для большей совместимости удобнее хранить файлы в контейнере MP4. Следующая команда поможет переложить запись между контейнерами быстро и без потери качества, здесь не используется пережатие содержимого, только меняется контейнер.

:::

ffmpeg -i input.mkv -c copy output.mp4

Где:

  • -i input.mkv: указывает путь к входному файлу в формате MKV.
  • -c copy: сообщает ffmpeg о необходимости копирования всех потоков без их перекодирования.
  • output.mp4: имя выходного файла в формате MP4.

Работа с MKV через GStreamer

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

Простое воспроизведение видео

Для воспроизведения видео в формате MKV можно использовать следующий код на Python:

import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst

Gst.init(None)

pipeline = Gst.Pipeline()
source = Gst.ElementFactory.make("filesrc", None)
source.set_property("location", "video.mkv")
demuxer = Gst.ElementFactory.make("matroskamux", None)
decoder = Gst.ElementFactory.make("decodebin", None)
sink = Gst.ElementFactory.make("autovideosink", None)

pipeline.add(source, demuxer, decoder, sink)
Gst.element_link_many(source, demuxer, decoder, sink)

loop = GObject.MainLoop()
pipeline.set_state(Gst.State.PLAYING)
try:
loop.run()
except KeyboardInterrupt:
pass
finally:
pipeline.set_state(Gst.State.NULL)

Этот скрипт создает простой граф потока, состоящий из источника (filesrc), демультиплексора (matroskamux), декодера (decodebin) и вывода (autovideosink). При запуске он воспроизводит видео из файла video.mkv.

Демонстрация поддержки метаданных

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

import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst

def on_tag(bus, msg):
taglist = msg.parse_tag()
if taglist is not None:
for key in ["title", "genre"]:
value = taglist.get_string(key)[1]
print(f"{key}: {value}")

Gst.init(None)

pipeline = Gst.Pipeline()
source = Gst.ElementFactory.make("filesrc", None)
source.set_property("location", "video.mkv")
demuxer = Gst.ElementFactory.make("matroskamux", None)
decoder = Gst.ElementFactory.make("decodebin", None)
sink = Gst.ElementFactory.make("autovideosink", None)

bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect("message::tag", on_tag)

pipeline.add(source, demuxer, decoder, sink)
Gst.element_link_many(source, demuxer, decoder, sink)

loop = GObject.MainLoop()
pipeline.set_state(Gst.State.PLAYING)
try:
loop.run()
except KeyboardInterrupt:
pass
finally:
pipeline.set_state(Gst.State.NULL)

Этот скрипт выводит метаданные, такие как название и жанр, при воспроизведении файла video.mkv. Для этого используется сигнал message::tag шины сообщений GStreamer.