Разделить MKV по главам

Вопрос или проблема

У меня есть длинный файл MKV, который я хочу разделить на отдельные главы.

Запуск ffmpeg -i long.mkv дает мне всю информацию о главах, встроенных в файл:

 Duration: 01:23:45.80, start: 0.000000, bitrate: 8116 kb/s
    Chapter #0.0: start 0.000000, end 235.000000
    Metadata:
      title           : Chapter 01
    Chapter #0.1: start 235.000000, end 450.160000
    Metadata:
      title           : Chapter 02
    Chapter #0.2: start 450.160000, end 789.400000
    ...

В файле 10 глав – я хочу в итоге получить 10 отдельных файлов.

Похоже, что -map_chapters может сделать что-то похожее, но я не могу найти документацию по этому поводу.

разделение MKV видео на главы с использованием mkvmerge

mkvmerge -o output.mkv --split chapters:all input.mkv

https://www.bunkus.org/videotools/mkvtoolnix/doc/mkvmerge.html

Я не могу найти надежный способ сделать это с помощью ffmpeg / avconv, но я могу найти способ сделать это с помощью HandBrakeCLI.

 HandBrakeCLI -c 3 -i whatever.mkv -o 3.mkv

Этот код извлечет 3-ю главу из mkv.

решение в лоб, хехе:

ffmpeg -i long.mkv | grep 'start.*end.*[0-9]*' | sed -r 's/.*#[0-9]\.([0-9]*).* ([0-9]*\.[0-9]*).*( [0-9]*\.[0-9]*)/ ffmpeg -i long.mkv -ss \2 -to\3 -acodec copy -vcodec copy chapter\1.mkv/g;'

Вы можете добавить xargs для выполнения вывода в ковбойском стиле:
| xargs -I cmd bash -c 'cmd'

Это мое решение, оно хорошо работает на ubuntu-16.04.02-LTS. Оно основано на другом решении, но улучшено в части обработки глав и созданных файлов для каждой главы.

Вот пример выполнения:

$ mkv-split-chapters some-mkv-file.mkv
Filename: some-mkv-file
Extension: mkv
Filedir: .
ffmpeg -i some-mkv-file.mkv -ss 0.000000 -to 394.800000 -acodec copy -vcodec copy ./some-mkv-file-#00.mkv
[...]
ffmpeg -i some-mkv-file.mkv -ss 394.800000 -to 767.160000 -acodec copy -vcodec copy ./some-mkv-file-#01.mkv
[...]
ffmpeg -i some-mkv-file.mkv -ss 757.160000 -to 1216.720000 -acodec copy -vcodec copy ./some-mkv-file-#02.mkv
[...]

Вот скрипт:

$ cat /usr/local/bin/mkv-split-chapters
#!/bin/bash
file="$1"
if [ -z "$file" ]; then
        echo "Missing file argument!"
        exit 1
fi

filename=$(basename "$file")
fileextension="${filename##*.}"
filename="${filename%.*}"
filedir=$(dirname "$file")
echo "Filename: $filename"
echo "Extension: $fileextension"
echo "Filedir: $filedir"
ffmpeg -i $file 2>&1 | grep 'Chapter' | grep 'start' | grep ', end' | awk "{
        chapter=\$2
        # replace : with nil
        gsub(/:/, \"\", chapter)
        start=\$4
        # remove everything but 0-9.
        gsub(/[^0123456789\.]/, \"\", start)
        end=\$6
        command=sprintf(\"ffmpeg -i $file -ss %s -to %s -acodec copy -vcodec copy $filedir/$filename-%s.$fileextension\n\", start, end, chapter)
        print(command)
        system(command)
}"

Скрипт также доступен здесь:

https://github.com/dpsenner/mkv-split-chapters

Вы можете использовать программу с графическим интерфейсом с открытым исходным кодом под названием LosslessCut. Она позволяет без потерь разделять популярные форматы, такие как mp4 и mkv, мгновенно, без перекодирования видео. Работает очень хорошо.

Улучшая ответ @gabriel_agm, вот моя вспомогательная функция. Моя версия ffmpeg использует двоеточие вместо точки для разделения title:chapter, и выводит полезную информацию на stderr. Я также добавляю извлечение субтитров.

split_by_chapter() {
   for word in "${@}" ;
   do
      ffmpeg -i "${word}" 2>&1 | sed -n -r -e "/start.*end.*[0-9]*/{s/.*#[0-9]*:([0-9]*).* ([0-9]*\.[0-9]*).*( [0-9]*\.[0-9]*)/ffmpeg -i ${word} -ss \2 -to\3 -acodec copy -vcodec copy -scodec copy ${word}-chapter\1.mkv \;/g;p;}"
   done
}

Чтобы выполнить вывод, вам нужно сделать следующее:

$( split_by_chapter file1.mkv file2.mkv file3.mkv )

Что, естественно, создаст файлы вида:

$ ls file*mkv
file1-chapter0.mkv file1-chapter1.mkv file1-chapter2.mkv
file2-chapter0.mkv file2-chapter1.mkv file3-chapter0.mkv

Ограничения из других комментариев о ограничениях ключевых кадров все еще применимы, но это допустимо.

FFmpeg не может напрямую разделить файлы по главам, так что вам придется либо использовать другой инструмент (например, mkvmerge, если это mkv, см. ответ Endoro), либо использовать скрипт для выполнения этого в два этапа: сначала извлечь временные метки глав с помощью ffprobe, затем передать временные метки в ffmpeg, чтобы разделить файл.

Учтите, что другие ответы полагаются на разбор читаемого человеком вывода ffmpeg, что менее надежно.

Вы можете получить информацию о главах в формате json с помощью ffprobe -hide_banner -v warning -output_format json -show_chapters $video_with_chapters

  • -hide_banner скрывает информацию о версии/сборке, которую ffmpeg/ffprobe обычно печатает при каждом вызове
  • -v warning показывает только предупреждения или более серьезные сообщения в stderr
  • -output_format json выводит данные в формате json
  • -show_chapters показывает информацию о главах в stdout в соответствии с output_format

stdout будет выглядеть примерно так:

{
  "chapters": [
    {
      "id": 3673034544977082062,
      "time_base": "1/1000000000",
      "start": 0,
      "start_time": "0.000000",
      "end": 270000000000,
      "end_time": "270.000000",
      "tags": {
        "title": "Chapter 01"
      }
    },
    {
      "id": -8793060959530591199,
      "time_base": "1/1000000000",
      "start": 270000000000,
      "start_time": "270.000000",
      "end": 300000000000,
      "end_time": "300.000000",
      "tags": {
        "title": "Chapter 02"
      }
    }
  ]
}

Затем, чтобы вырезать одну главу, передайте start_time в -ss (перейти к этой позиции) и end_time в -to (декодировать до этой позиции) как входные параметры (до -i):

ffmpeg -ss 270.000000 -to 300.000000 -i long.mkv -c copy output-chapter-2.mkv


Вот полный скрипт:

#!/usr/bin/env bash
set -e
video_with_chapters="$1"
video_basename="$(basename -- "$video_with_chapters")"
output_prefix="chapter-"
output_extension=".${video_basename##*.}"
chapters_json="$(ffprobe -hide_banner -v warning -output_format json -show_chapters "$video_with_chapters")"
chapter_count="$(echo "$chapters_json" | jq ".chapters|length")"
if (( "$chapter_count" == 0 )); then
  echo "$0: no chapters in $video_with_chapters" >&2
  exit 1
fi
for ((i=0; i < "$chapter_count"; i++ )); do
  chapter_start="$(echo "$chapters_json" | jq ".chapters[$i].start_time" -r)"
  chapter_end="$(echo "$chapters_json" | jq ".chapters[$i].end_time" -r)"
  if [[ "$chapter_start" == "$chapter_end" ]]; then
    // Некоторые файлы имеют главы в виде диапазонов временных меток, в то время как другие файлы имеют пустые диапазоны, и главы отмечают точку во времени.
    if (( "$i" + 1 == "$chapter_count" )); then
      chapter_end=
    else
      chapter_end="$(echo "$chapters_json" | jq ".chapters[$((i+1))].end_time" -r)"
    fi
  fi
  input_args=(-ss "$chapter_start")
  if [[ -n "$chapter_end" ]]; then
    input_args+=(-to "$chapter_end")
  fi
  output_fn="${output_prefix}$(printf "%03d" "$i")${output_extension}"
  ffmpeg \
    -hide_banner -v warning \
    "${input_args[@]}" -i "$video_with_chapters" \
    -c copy "$output_fn"
done
echo "Разделение на главы завершено" >&2

Более подробная версия доступна на https://github.com/shelvacu/ffmpeg-chapter-split

Ответ или решение

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

Теоретическая часть

Формат MKV (Matroska Video) известен своей мощностью и гибкостью, включая возможность хранения нескольких видео- и аудиопотоков, субтитров и метаданных в одном файле. Потому, разделение файла на основании его встроенных глав может быть весьма полезным, особенно для управления и воспроизведения видеоконтента.

Программа FFmpeg широко известна в сообществе за ее способность обрабатывать файлы различных форматов, включая MKV. В то время как FFmpeg предоставляет всеобъемлющие возможности по манипуляции медиафайлами, ее инструменты напрямую не предназначены для разделения MKV-файлов по главам. Однако с помощью правильного подхода, как используется в некоторых скриптах и методах, описанных ниже, можно все же осуществить желаемую задачу.

Примеры

  1. С помощью mkvmerge:
    Использование mkvmerge — это наиболее прямой и надежный способ разделения файла MKV на отдельные главы. Команда следующего вида:

    mkvmerge -o output.mkv --split chapters:all input.mkv

    Данная команда автоматически разделяет входной файл input.mkv по всем главам, создавая отдельные файлы для каждой главы.

  2. С помощью FFmpeg:
    Еще один способ решения задачи заключается в использовании FFmpeg для извлечения временных меток глав и последующего разделения:

    • Получение информации с помощью ffprobe:

      ffprobe -hide_banner -v warning -print_format json -show_chapters long.mkv

      Это выводит информацию о главах в формате JSON, затем с помощью скрипта можно извлечь временные коды начала и конца каждой главы.

    • Разделение файлов:

      ffmpeg -ss <начало> -to <конец> -i long.mkv -c copy output-chapter-n.mkv

      Этот метод требует создания отдельного скрипта для автоматизации процесса извлечения временных меток и вызова FFmpeg для каждого диапазона времени.

  3. С использованием скриптов:
    Для Unix-подобных систем можно использовать shell-скрипты, которые автоматически извлекают все главы и создают отдельные файлы:

    split_by_chapter() {
      for file in "${@}" ; do
         ffmpeg -i "${file}" 2>&1 | sed -n -r -e "/start.*end.*[0-9]*/{...}"
      done
    }

    Этот метод требует базового понимания работы sed и bash, но предоставляет мощный инструмент для автоматизации процесса.

Применение

Разделение MKV на главы полезно в различных сценариях:

  • Создание обучающих материалов: Лекции или презентации могут быть представлены в более управляемом формате, что облегчает использование и просмотр материала.

  • Проект постпроцесса: Видео могут быть разделены на более мелкие части, чтобы их было проще редактировать или использовать для отдельных проектов.

  • Архивация и организация: Организация мультимедийных библиотек может быть более эффективной, если использовать структуры, основанные на главах.

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

Оцените материал
Добавить комментарий

Капча загружается...