Заметки · 01.06.2022

Вырезаем фрагмент из видео

Продолжение весёлых видеоприключений в мире PowerShell и FFMPEG. Все посты на эту тему можно найти по этому тегу.

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

Действуем так: размещаем в папке с целевым видеофайлом утилиту ffmpeg.exe (скачиваем здесь) и PowerShell скрипт следующего содержания:

### Создать папку ###
New-Item -Path cut -ItemType Directory -ErrorAction Ignore | Out-Null

### Убрать пробелы из имени файла ###
dir *.mp4 | ren -NewName { $_.Name -replace ' ','_' }

### Вырезать и сохранить фрагмент из файла MP4 ###
  Get-ChildItem -Filter *.mp4 | ForEach-Object {
  $timebegin = "00:00:05" # <-- Время начала фрагмента
  $timeend = "00:00:10"   # <-- Время окончания фрагмента
  $cmd = "-i $_ -ss $timebegin -to $timeend -c copy cut\fragment.mp4"   
  Start-Process -FilePath ffmpeg.exe -ArgumentList $cmd -Wait -NoNewWindow }

В переменной $timebegin задаем время начало фрагмента, который нам нужен, а в $timeend задаем время окончания фрагмента. Важно соблюсти синтаксис оформления переменных: hh:mm:ss.

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

Итоговый файл попадёт в папку cut и будет называться fragment.mp4.

Отдельная команда для утилиты ffmpeg выглядит так:

ffmpeg.exe -i video.mp4 -ss 00:00:05 -to 00:00:10 -c copy fragment.mp4

В данной команде параметры -ss и -to как раз и отвечают за фрагментирование видео, а параметр -с copy задаёт прямое копирование потока из исходного файла без конвертации.

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

Set-ExecutionPolicy Unrestricted -Force.

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

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

После пары минут созидания получается вот такой скрипт:

### Создать папку ###
New-Item -Path cut -ItemType Directory -ErrorAction Ignore | Out-Null

### Убрать пробелы из имени файла ###
dir *.mp4 | ren -NewName { $_.Name -replace ' ','_' }

### Создать промежуточный файл ###
Get-ChildItem -Filter *mp4 | ForEach-Object { 
      $cmd = "-i "+ "$_" + " -c copy " + "$($_.Name).mts"   
      Start-Process -FilePath ffmpeg.exe -ArgumentList $cmd -Wait -NoNewWindow }

### Вырезать фрагмент из файла MP4 ###
Get-ChildItem -Filter *mts | ForEach-Object {
      $timebegin = "00:00:05" # <-- Время начала
      $timeend = "00:00:10"   # <-- Время окончания
      $bitrate = "1500k"      # <-- Битрейт видеопотока
      $cmd = "-i $_ -ss $timebegin -to $timeend -c:v libx264 -b:v $bitrate -crf 23 -c:a aac -b:a 256k cut\fragment.mp4"
      Start-Process -FilePath ffmpeg.exe -ArgumentList $cmd -Wait -NoNewWindow }

### Удалить временный файл ###
    Get-ChildItem -Filter *mts | ForEach-Object { Remove-Item -Path $_ }

Обращаю Ваше пристальное внимание, что в код добавилась переменная $bitrate, с помощью которой задаётся скорость потока.