Извлекаем аудио дорожку из видео файла с помощью ffmpeg

prolinux

Опубликован:  2023-06-19T10:29:23.776194Z
Отредактирован:  2023-06-19T10:29:23.776194Z
Статус:  публичный
40
0
0

Как известно, ffmpeg - достаточно мощное средство для работы с аудио и видео файлами. Начинающие пользователи обычно сталкиваются с трудностями при работе с этой программой. В этом выпуске блога я покажу надёжное решение одной повседневной задачи - будем извлекать аудио дорожку из видео файла в формате MKV при помощи программы ffmpeg и преобразовывать извлечённый поток в формат MP3. Для ffmpeg совершенно не имеет значения, какого формата будет входящий файл. Вместо MKV это может быть AVI или MP4 файл, ffmpeg поддерживает множество форматов. В этой демонстрации я покажу решение задачи на компьютере с операционной системой с ядром Linux на борту. Приступим...

О задаче

Файлы с видео в большинстве своём являются контейнерами и обычно содержат внутри несколько различных параллельных потоков:

  • видео поток;

  • одну или несколько аудио дорожек;

  • один или несколько потоков субтитров.

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

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

Про ffmpeg

Ffmpeg - это аудио-видео фреймворк с интерфейсом командной строки, он поддерживает достаточно большой список аудио и видео форматов, и может кодировать и аудио, и видео, и вместе, и по отдельности. Вся проблема заключается в интерфейсе программы, современный пользователь персонального компьютера как-то не привык выражать свои желания чёткими языковыми командами, а предпочитает нажимать кнопки. У ffmpeg кнопок нет, и поэтому мало кто пользуется её по-истине вездесущими возможностями.

Сейчас я дам простой и действенный рецепт решения одной конкретной задачи с помощью этой великолепной программы, вы увидите, что ларчик просто открывается, и желаемое достигается легко, а командная строка не так уже и страшна, если решать задачу методично и взвешенно, опираясь на мануал, google и прочие StackOverflow.

Подготовка окружения

Для решения поставленной задачи мне понадобится компьютер с установленной операционной системой на базе ядра Linux. В моём случае это будет Debian sid. В систему должен быть установлен ffmpeg, и установить его в deb-совместимых операционных системах можно простой командой.

$ sudo apt install ffmpeg

Если планируется кодировать аудио поток внешним энкодером, вдруг нужно будет, этот энкодер тоже должен быть установлен в системе.

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

$ cd ~/kino

Здесь ~/kino это имя каталога в домашнем каталоге текущего пользователя текущего сеанса. Этот каталог я создал предварительно и положил в него исходный MKV файл.

$ ls
kino.mkv

Вот так это выглядит в терминале на моей операционной системе.

y8L7yGtZ21.png

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

Получаем информацию об исходном файле

Формат исходного файла - MKV, то есть файл в сути своей является коробкой, внутри которой лежат разные интересные штуковины. Чтобы из этой коробки достать что-либо, нужно в неё заглянуть и посмотреть, а что же там лежит, чтобы выбрать нужное. Получить информацию о файле MKV можно различными способами. И поскольку у меня есть ffmpeg, я буду получать эту информацию с его помощью вот такой простой и незамысловатой командой.

$ ffmpeg -i kino.mkv 2>&1 >/dev/null | grep Stream

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

  Stream #0:0(eng): Video: h264 (High), yuv420p(progressive), 1152x484 [SAR 1:1 DAR 288:121], 23.98 fps, 23.98 tbr, 1k tbn (default)
  Stream #0:1(rus): Audio: ac3, 48000 Hz, 5.1(side), fltp, 448 kb/s (default)
  Stream #0:2(rus): Audio: ac3, 48000 Hz, 5.1(side), fltp, 448 kb/s
  Stream #0:3(eng): Audio: ac3, 48000 Hz, 5.1(side), fltp, 448 kb/s
  Stream #0:4(rus): Subtitle: subrip (default)
  Stream #0:5(eng): Subtitle: subrip

Как видно, исходный файл содержит шесть различных потоков, каждый поток обозначен цифрами, и у каждого потока обозначен его исходный формат и некоторые параметры. В данном случае меня интересует поток 0:3 - это оригинальная англоязычная звуковая дорожка фильма, она многоканальная, её я и буду извлекать с одновременным преобразованием в другой формат. Цифры из обозначения потока (0:3) мне потребуются далее для формирования команды ffmpeg, их я буду передавать ключом -map.

Извлекаем аудио дорожку в формат MP3

Ffmpeg умеет кодировать множество аудио форматов, в его недрах есть и декодеры, и энкодеры для аудио. В этой демонстрации я покажу одновременное извлечение и перекодирование аудио в самый распространённый и широко поддерживаемый производителями гаджетов формат - MP3.

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

ffmpeg -i kino.mkv -v quiet -stats -vn -map 0:3 -codec:a mp3 -b:a 128k -map_metadata -1 eng.mp3

В этой команде я задал номер извлекаемой дорожки ключом -map, формат файла на выходе ключом -codec:a, и битрейт получаемого файла ключом -b:a. В конце команды я вписал имя получаемого файла. Жму Enter, в терминале появляется выхлоп ffmpeg, который показывает прогресс текущего процесса. Набираюсь терпения и дожидаюсь завершения этого процесса, пока в терминале вновь не появится приглашение командной строки. Поскольку исходный файл имеет достаточно значительную длительность, процесс займёт некоторое количество времени.

6RIlD43rb2.png

После завершения процесса в моём текущем каталоге появляется файл с заданным именем - eng.mp3, и его уже можно воспроизвести каким-нибудь модным плеером. Вот что об этом файле говорит программа mediainfo.

$ mediainfo eng.mp3 
General
Complete name                            : eng.mp3
Format                                   : MPEG Audio
File size                                : 98.4 MiB
Duration                                 : 1 h 47 min
Overall bit rate mode                    : Constant
Overall bit rate                         : 128 kb/s
Writing library                          : LAME3.100

Audio
Format                                   : MPEG Audio
Format version                           : Version 1
Format profile                           : Layer 3
Format settings                          : Joint stereo / MS Stereo
Duration                                 : 1 h 47 min
Bit rate mode                            : Constant
Bit rate                                 : 128 kb/s
Channel(s)                               : 2 channels
Sampling rate                            : 48.0 kHz
Frame rate                               : 41.667 FPS (1152 SPF)
Compression mode                         : Lossy
Stream size                              : 98.4 MiB (100%)
Writing library                          : LAME3.100

Великолепно, задачу можно считать решенной, аудио дорожка из фильма извлечена.

Извлекаем аудио дорожку в формат PCM Wav

Иногда хочется извлечь аудио дорожку, но перекодировать её в другой формат внешним энкодером, а не встроенным в ffmpeg. Насколько веские причины мотивируют такое желание, не суть важно, если желание возникло, от него нельзя отказываться, дабы не испытать впоследствии чувства вины. Давайте посмотрим, что мы можем сделать в этом случае.

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

$ ffmpeg -i kino.mkv -v quiet -stats -vn -map 0:3 -codec:a pcm_s16le -ac 2 -map_metadata -1 eng.wav

В этой команде я задал номер извлекаемой дорожки ключом -map, формат на выходе ключом -codec:a, в данном случае это pcm_s16le, а, поскольку, и входящий, и исходящий потоки многоканальные, я ограничил количество каналов на выходе ключом -ac, имя получаемого файла - eng.wav. Жму Enter и опять получаю возможность наблюдать выхлоп ffmpeg. Остаётся дождаться завершения процесса.

zVPixOZ2Kt.png

И вот что говорит программа mediainfo о полученном в результате выполнения этой команды файле.

$ mediainfo eng.wav
General
Complete name                            : eng.wav
Format                                   : Wave
Format settings                          : PcmWaveformat
File size                                : 1.15 GiB
Duration                                 : 1 h 47 min
Overall bit rate mode                    : Constant
Overall bit rate                         : 1 536 kb/s
Writing application                      : Lavf59.27.100

Audio
Format                                   : PCM
Format settings                          : Little / Signed
Codec ID                                 : 1
Duration                                 : 1 h 47 min
Bit rate mode                            : Constant
Bit rate                                 : 1 536 kb/s
Channel(s)                               : 2 channels
Sampling rate                            : 48.0 kHz
Bit depth                                : 16 bits
Stream size                              : 1.15 GiB (100%)

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

Отдаём поток PCM Wav в программный канал

Файлы PCM Wav занимают достаточно много дискового пространства, полученный в предыдущем примере файл весит 1.15 GiB, о чём нам рассказала программа mediainfo, и возникает вполне разумное желание, обойтись без файла PCM Wav, но получить при этом файл нужного формата внешним энкодером. Задача тоже очень просто решается использованием программного канала.

Получить, например, формат MP3 можно внешним энкодером lame, если он установлен в систему. В этом случае можно задать любые поддерживаемые энкодером опции кодирования. Для такого варианта команда будет чуть чуть сложней, выглядит так.

$ ffmpeg -i kino.mkv -v quiet -stats -vn -map 0:3 -codec:a pcm_s16le -ac 2 -map_metadata -1 -f wav - | lame --silent -V 0 - eng1.mp3

В этом случае в процессе кодирования участвуют две программы, ffmpeg извлекает выбранную дорожку в формат PCM Wav и отдаёт полученные данные по программному каналу программе lame, которая преобразует этот поток в файл с именем eng1.mp3. И в этом варианте для lame можно задать абсолютно любые поддерживаемые программой ключи. Жму Enter и вновь наблюдаю выхлоп ffmpeg до полного завершения процесса.

dj916BzUZA.png

Полученный файл можно сравнить с полученным в первом примере файлом с помощью выхлопа mediainfo, вот как он выглядит в моём терминале.

$ mediainfo eng1.mp3 
General
Complete name                            : eng1.mp3
Format                                   : MPEG Audio
File size                                : 174 MiB
Duration                                 : 1 h 47 min
Overall bit rate mode                    : Variable
Overall bit rate                         : 226 kb/s
Writing library                          : LAME3.100

Audio
Format                                   : MPEG Audio
Format version                           : Version 1
Format profile                           : Layer 3
Format settings                          : Joint stereo / MS Stereo
Duration                                 : 1 h 47 min
Bit rate mode                            : Variable
Bit rate                                 : 226 kb/s
Minimum bit rate                         : 32.0 kb/s
Channel(s)                               : 2 channels
Sampling rate                            : 48.0 kHz
Frame rate                               : 41.667 FPS (1152 SPF)
Compression mode                         : Lossy
Stream size                              : 174 MiB (100%)
Writing library                          : LAME3.100
Encoding settings                        : -m j -V 0 -q 0 -lowpass 24 --vbr-new -b 32

Не сложно заметить, что этот файл отличается от файла в первом примере битрейтом и размером. У последнего файла битрейт имеет другой характер и варьируется по значению от 32k до 226k, в результате чего размер файла тоже сильно отличается от размера файла из первого примера.

Расшифровка некоторых использованных ключей ffmpeg

У каждого использованного в представленных командах ключа ffmpeg своё значение, давайте расшифруем некоторые из использованных ключей.

  • -i filename - ключ задаёт имя входящего файла, этот файл должен существовать и располагаться в текущем рабочем каталоге;

  • -v quiet - ключ делает программу ffmpeg молчаливой и предотвращает вывод на терминал дополнительной вспомогательной информации;

  • -stats - с этим ключом ffmpeg выводит в терминал строчку отображающую прогресс текущего процесса и некоторые параметры процесса;

  • -vn - ключ указывает программе ffmpeg, что видео поток кодировать не нужно, с ним ffmpeg будет обрабатывать только указанный аудио поток;

  • -map 0:3 - ключ указывает программе ffmpeg, какой именно поток исходного файла обрабатывать, заданные цифры можно определить из выхлопа первой в этой демонстрации команды ffmpeg;

  • -codec:a mp3 - ключ указывает формат получаемого на выходе файла;

  • -ac 2 - ключ указывает количество каналов получаемого файла, если поток на входе содержит большее количество каналов, на выходе поток будет смикширован в заданное этим ключом количество каналов;

  • -map_metadata -1 - ключ предотвращает запись метаданных исходного файла в полученный файл;

  • -f wav - ключ указывает формат выходного файла, необходим, если выходной поток отдаётся в программный канал, или если у получаемого файла не указано расширение.

Выводы и умозаключения

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

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

Метки:  linux, cli, ffmpeg, mkv, avi, mp4, pcm, wav, mp3