Go言語とFFmpegで動画を連結する:完全ガイド

バックエンド

1. 導入:なぜGoとFFmpegなのか?

Go言語(Golang)は、その高い並行処理能力とシンプルな構文から広く採用されています。そのため、動画処理やストリーミングサービスなど、処理速度が求められるバックエンドシステムに最適です。

そして、動画処理のデファクトスタンダードである FFmpegをGoから呼び出します。これにより、堅牢かつ高速な動画連結システムを構築できます。

この記事では、Goの os/exec パッケージを用いてFFmpegコマンドを実行します。具体的な手順として、複数の動画ファイルを結合する具体的な手順を解説します。


2. FFmpegによる動画連結の原理

FFmpegで複数の動画(例:input1.mp4, input2.mp4)を結合する最も確実な方法は、**デムクサー(Demuxer)を利用した連結ファイル(Concat List)**方式です。

2.1 連結ファイル(Concat List)の作成

FFmpegに直接動画ファイルを渡すのではありません。代わりに、結合したい動画のパスをリスト化したテキストファイル(例: mylist.txt)を事前に作成します。

注意: 動画のエンコード方式や解像度が異なる場合、連結前にエンコードを統一する必要があります。さもないと、エラーが発生したり、予期せぬ結果になることがあります。

mylist.txt の内容例:

Plaintext

file 'input1.mp4'
file 'input2.mp4'
file 'input3.mp4'

2.2 Go言語での連結ファイル作成

Go言語のコードで、動的にこのテキストファイルを生成します。

Go

package main

import (
	"os"
	"path/filepath"
)

// 結合したい動画ファイル名のリスト
var inputFiles = []string{"input1.mp4", "input2.mp4", "input3.mp4"}
const concatListFile = "mylist.txt"

func createConcatList() error {
	// ファイルを作成します
	f, err := os.Create(concatListFile)
	if err != nil {
		return err
	}
	defer f.Close()

	// ファイルリストを書き込みます
	for _, file := range inputFiles {
		line := "file '" + filepath.Base(file) + "'\n"
		if _, err := f.WriteString(line); err != nil {
			return err
		}
	}
	return nil
}

3. GoからFFmpegを実行し動画を結合する

連結ファイル (mylist.txt) が用意できたら、次に Goの os/exec パッケージを使用してFFmpegコマンドを実行します。

3.1 FFmpegコマンドの構造

動画を再エンコードせずに高速に結合する場合、以下のコマンド形式を使用します。

Bash

ffmpeg -f concat -i mylist.txt -c copy output.mp4
オプション意味
-f concat入力形式として連結デムクサーを使用することを指定します。
-i mylist.txt連結リストファイルをインプットとして指定します。
-c copyコーデックをコピーします(つまり、再エンコードしないため高速です)。
output.mp4出力ファイル名です。

3.2 Go言語での実行コード

os/exec を使用してFFmpegコマンドを実行し、エラー処理を行います。

Go

package main

import (
	"log"
	"os/exec"
)

func runFFmpegConcat() error {
	// 実行するFFmpegコマンドと引数を定義します
	cmd := exec.Command("ffmpeg",
		"-f", "concat",
		"-i", concatListFile, // 作成した連結リストファイル
		"-c", "copy",
		"output_final.mp4",
	)

	log.Printf("FFmpegコマンドを実行中: %s\n", cmd.String())

	// 標準出力と標準エラー出力を取得(デバッグ用)
	output, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("FFmpeg実行エラー: %s\n", string(output))
		return err
	}

	log.Println("動画の連結が完了しました: output_final.mp4")
	return nil
}

func main() {
	if err := createConcatList(); err != nil {
		log.Fatalf("連結リスト作成エラー: %v", err)
	}
	
	// リスト作成に成功したら、FFmpegを実行します
	if err := runFFmpegConcat(); err != nil {
		log.Fatalf("FFmpeg実行に失敗しました: %v", err)
	}
}

4. まとめと発展的な応用

Go言語とFFmpegの組み合わせは、動画処理バックエンドを構築する上で強力な選択肢です。

応用例:

  • 再エンコードを伴う連結: 入力動画の解像度やビットレートを統一したい場合は、-c copy の代わりに -c:v libx264 -preset fast などのエンコード設定を指定します。
  • エラー処理の強化: 大規模なシステムでは、Goルーチンを利用してFFmpegの実行ログをパースし、進捗を監視する機能を実装することで、さらに堅牢な動画処理パイプラインを構築できます。

この方法を応用すれば、Go言語でユーザーがアップロードした動画の処理を効率的に行うことが可能です。

コメント

タイトルとURLをコピーしました