FFmpegで動画を連結するPowerShellスクリプト

WindowsPowerShell,Windows,プログラミング

動画エンコーダーのFFmpegを使うと、分割された動画ファイルを一つの動画に連結することができます。コマンドラインで入力ファイルを指定すれば連結できるのですが、手動で実行するのも大変なのでPowerShellスクリプトをつくってみました。

これを使えば、ドラレコなどで撮影した分割動画ファイルを簡単に連結できます。

やりたいこと

クルマにパイオニアのサイバーナビをつけていて、「MAユニット」とフロントカメラもつけるとAR的な感じの運転支援機能も利用することができます。このMAユニットにはドラレコ機能もあって、衝撃検知で録画してくれたり、常時録画してくれたりします。

ドラレコの常時録画で撮影した映像は、5分ごとに分割されており、長時間運転していると大量のファイルが保存されます。この5分ごとに分割されたファイルを連結して一つのファイルにしたい、というのが今回やりたいことです。

今回使用するFFmpegは、いろんな動画コーデックに対応していますので、「ドラレコ動画の連結」以外の用途でも使えるだろうと思います。

また、再エンコードせずに連結できるため、画質はそのままで、超高速で実行できます。

(同様のことはmp4boxでもできるのですが、対応している入力ファイルの形式や、スクリプトの作りやすさからFFmpegを使っています)

FFmpegのダウンロード

動画の連結には「FFmpeg」というソフトを使います。FFmpeg公式サイトダウンロードページではソースコードしか配布されてませんので、自分でFFmpegをビルドするか、どなたかがビルドしたものをダウンロードしてくる必要があります。

今回は、公式サイトからリンクされているBtbNさんがビルドしたものを使おうと思います。BtbNさんビルドのFFmpeg配布ページはこちらです。

記事執筆時点では2021-02-05版が最新のようで、その中でもビルドオプションごとにたくさんバイナリが用意されています。ビルドオプションによっては対応していない動画ファイルなどもあると思いますので、全部入りっぽいもの(安直にファイルサイズが大きいもの)をダウンロードすることにします。

BtbNさんのビルド済みFFmpegバイナリをダウンロードします

ダウンロードしたら解凍します。実際に使用するのは、binフォルダにあるffmpeg.exeのみです。

FFmpegで動画を連結する

動画が数個くらいなら、コマンドプロンプト等でコマンドを手打ちして実行しても良いかもしれません。ということで、まずはコマンドプロンプトでFFmpegを使って動画を連結する方法を紹介します。公式サイトの解説はこちらです。

大きく分けると「ファイルリストを作成して入力する方法」と、「入力ファイルの引数として指定する方法」の2種類あります。

事前にファイルリストを作成して、FFmpegで動画を連結する

まず、メモ帳などで動画ファイルのリストを作成します。中身はこんな感じです。#から始まる行はコメント行で、動画のパスはfile 'パス'の形式で書いていきます。これを任意の名前(今回はmylist.txt)で保存します。

#コメント
file 'D:\rec\2020_0621_1242_45_00_RM.avi'
file 'D:\rec\2020_0621_1247_45_00_RM.avi'
file 'D:\rec\2020_0621_1252_45_00_RM.avi'

このファイルリストをFFmpegに入力してやると、動画を連結してくれます。連結するコマンドはこちらです。必要であれば、フルパスで指定してください。

ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4
  • -f concatは、複数のファイルを連結して入力ファイルとみなす指示です。
  • -safe 0は、ファイルリストに記載している動画のパスが絶対パス表記の場合は必要です。
  • -i mylist.txtは、ファイルリストのパスです。要すればフルパスで指定してください。
  • -c copyは、再エンコードせずに出力するための指示です。
  • output.mp4は、出力ファイルパスで、自由に決めて構いません。拡張子も、FFmpegが対応している動画コンテナであれば何でもOKです(mp4、avi、mkv、・・・)。

上記を実行すると、mylist.txtに書いた動画を連結できます。

ファイルパスを引数として指定して、FFmpegで動画を連結する

もう一つ、次の形式でFFmpegを実行すると、ファイルリストをつくらずに引数として入力ファイルを指定して動画を連結できます。

ffmpeg -i "concat:input1.avi|input2.avi|input3.avi" -c copy output.mp4
  • -i "concat:動画パス1|動画パス2|動画パス3"というように、連結したい動画のファイルパスをパイプ記号で区切って指定します。要すればフルパスで指定してください。
  • -c copyは、再エンコードせずに出力するための指示です。
  • output.mp4は、出力ファイルパスで、自由に決めて構いません。拡張子も、FFmpegが対応している動画コンテナであれば何でもOKです(mp4、avi、mkv、・・・)。

PowerShellスクリプトを使って簡単に動画を連結する

前項のやり方は動画が数個くらいなら実行できますが、連結したいファイルが大量にある場合はコマンドの入力がとても大変です。

そこで、フォルダ内の動画ファイルをFFmpegで連結するPowerShellスクリプトをつくってみました。下記のファイルをconcatMovie.ps1などのファイル名で保存してください。また、11行目のffmpeg.exeのファイルパスは、ご自身の環境に合わせて書き換えてください(Shift+右クリック をして、「パスのコピー」をすると便利です)。

# ffmpegで動画を連結するPowerShellスクリプト concatMovie.ps1
# https://astherier.com/blog/2021/02/concat-movie-ffmpeg-powershell/

# Copyright (c) 2021 astherier
# This software is released under the MIT License.
# http://opensource.org/licenses/mit-license.php

param($srcDir="",$srcExt="avi",$destPath)

# ダウンロードしたffmpeg.exeのファイルパスに変更してください:
$ffmpeg="C:\ProgramFiles\encoder\ffmpeg-BtbN\bin\ffmpeg.exe"

if($srcDir -eq ""){
	$srcDir=".\"
}
$srcDir=(Get-Item $srcDir).fullname
if($destPath -eq $null){
	$destPath=join-path $srcDir "!concat.$srcExt"
}
echo "Input Folder     : $srcDir"
echo "Input Extension  : $srcExt"
echo "Output File Path : $destPath"
echo ""

$movieList=(ls (join-path $srcDir "*$srcExt"))

if($movieList.length -eq 0){
	echo "入力動画が見つかりませんでした"
	exit
}

$catList=""
foreach($movie in $movieList){
	if($movie.fullname -ne $destPath){
		$catList+=$movie.fullname+"|"
	}
}
$catList=$catList.substring(0,$catList.length-1)

& $ffmpeg -i "concat:$catList" -c copy $destPath

使い方(PowerShellをご存じの方向け)

基本的な使い方は次の通りです。必要であれば、concatMovie.ps1もフルパスで指定してください。

powershell concatMovie.ps1 入力フォルダ 入力ファイルの拡張子 出力ファイルパス

オプション名を省略せずに書くとこんな感じです。

powershell concatMovie.ps1 -srcDir 入力フォルダ -srcExt 入力ファイルの拡張子 -destPath 出力ファイルパス
  • -srcDirには、連結したい動画が入っているフォルダを指定します。初期値は「.\」、つまり実行中のコマンドプロンプトのカレントディレクトリです。
  • -srcExtには、連結したい動画の拡張子を指定します。srcDirにある、srcExtで終わるファイルを連結します。初期値は「avi」です。
  • -destPathには、出力先のファイルパスを指定します。初期値は「(入力フォルダ)\!concat.(入力ファイルの拡張子)」です。出力先のフォルダが存在しない場合、エラーで止まります。また、出力パスが既に存在する場合は、FFmpegから上書きして良いか聞かれます。上書きして良ければ「y」と入力します。

何も引数を指定せずに実行すると、「カレントディレクトリにあるaviファイルを連結して、!concat.aviという名前で出力する」という動作をします。

「D:\recにあるaviファイルを連結して、D:\output.mp4に出力する」という場合は、次のように実行します。

powershell concatMovie.ps1 "D:\rec" avi "D:\output.mp4"

使い方(ショートカット経由)

上記の使い方は、コマンドプロンプト等の利用に慣れた方向けの説明でしたが、もっと手軽にドラッグ&ドロップで実行できるよう、ショートカットを作成してみましょう。

保存したconcatMovie.ps1を右クリックして「コピー」し、ショートカットを置きたいフォルダで右クリックして「ショートカットの貼り付け」をして、ショートカットを作成します。

このショートカットにaviファイルが入っているフォルダをドラッグ&ドロップすると、そのフォルダの中に!concat.aviという名前で連結したファイルが出力されます。

(ショートカットのリンク先に引数を指定してもうまく動かないようです。入力拡張子や出力パスを指定したい場合は、ps1ファイルをいじるか、コマンドプロンプトから実行するか、バッチファイルを作る必要があります)