32blogby Studio Mitsu

FFmpegで動画を無劣化・爆速カット:-c copyによるトリミング術

FFmpegの-c copyオプションで動画を再エンコードなしで瞬時にカットする方法を解説。GOP構造との関係・キーフレームのスナップ挙動・トラブルシューティングまで詳しく解説。

by omitsu15 min read
目次

ffmpeg -ss <開始> -to <終了> -i input.mp4 -c copy output.mp4 — これだけで動画を再エンコードなし・画質劣化ゼロでカットできる。-c copy はエンコード済みデータをそのままコピーするだけなので、10GBの4K動画でも3秒以内に完了する。

動画コンテンツの切り抜き(トリミング)作業において、Adobe Premiere Pro や DaVinci Resolve といった NLE(非線形編集ソフト)を立ち上げるのは、往々にしてオーバーエンジニアリングだ。単純なカット作業にちょっとした起動時間と、実時間以上のエンコード時間を費やす必要はない。カンファレンス録画やロング素材からクリップを抜くだけなら、このコマンド1行で事足りる。

FFmpeg の「ストリームコピー機能」を活用すれば、ギガバイト級の 4K 動画であっても、わずか数秒で、かつ1 ビットの画質劣化もなく 必要なシーンだけを抽出できる。

bash
ffmpeg -y -ss 00:01:30 -to 00:05:30 -i "input.mp4" -c copy "output.mp4"

実戦用スクリプト

再エンコード(画質の変換処理)を行わず、データコピーのみで完了する最速のコマンドだ。

Windows (PowerShell)

powershell
# 変数定義
$InputVideo = "input.mp4"
$OutputVideo = "output_cut.mp4"
$StartTime = "00:01:30" # 開始時刻 (HH:MM:SS)
$EndTime = "00:01:40"   # 終了時刻 (HH:MM:SS)

# コマンド実行
# -ss : 開始時刻へシーク
# -to : 終了時刻を指定(-t なら「長さ」指定)
# -c copy : 再エンコードせずストリームを複製
ffmpeg -y -ss $StartTime -to $EndTime -i "$InputVideo" -c copy "$OutputVideo"

macOS / Linux (Bash)

bash
#!/bin/bash

INPUT="input.mp4"
OUTPUT="output_cut.mp4"
START="00:01:30" # 開始時刻
END="00:01:40"   # 終了時刻

# Input Seeking (-ss を -i の前に配置) により高速シークを実現
ffmpeg -y -ss "$START" -to "$END" -i "$INPUT" -c copy "$OUTPUT"

技術解説:Stream Copy の内部ロジックとトレードオフ

提示したコマンドの核となるのは -c copy(または -c:v copy -c:a copy)オプションだ。

1. デコード/エンコードのバイパス

通常の動画編集は「デコード(解凍)→ 画像処理 → エンコード(再圧縮)」というプロセスを経る。これが画質劣化と処理遅延の主原因だ。

-c copy は、コンテナ(MP4 や MKV)から取り出したエンコード済みのパケットを、デコードせずにそのまま新しいコンテナへ格納する(Demux → Mux)。計算負荷はディスク I/O 速度にほぼ依存するため、CPU 使用率は極めて低く、処理は一瞬で完了 する。

入力コンテナMP4 / MKV読取Demuxパケット抽出パススルー-c copyデコード/エンコードなし書込Mux新コンテナ

具体的な速度感:

  • 10GB の 4K 動画(2時間)から 10 秒を切り出す場合、再エンコードなら数分かかる
  • -c copy なら1〜2 秒 で完了する

2. シーク位置と Input Seeking

コマンド内の -ss-i に配置している点に注目してほしい。

  • Input Seeking(-ss-i の前に配置): 入力ファイルを読み込む段階で、指定時刻のパケット位置までファイルポインタを移動させる。デコード処理をスキップするため爆速だが、後述するキーフレームの制約を受ける。詳細は FFmpeg公式のSeekingドキュメント に記載されている。
  • Output Seeking(-ss-i の後に配置): ファイルを先頭からデコードしながら指定位置まで進む。正確だが、-c copy と組み合わせると挙動が不安定になるため、無劣化カットでは使わない。

3. キーフレーム(I-frame)の制約

無劣化カットには技術的に避けられないトレードオフが存在する。 「カット地点がキーフレームにスナップされる」 という点だ。

GOP 構造の仕組み:

現代の動画コーデック(H.264、H.265、AV1)は、GOP(Group of Pictures)という単位で圧縮されている。GOP は完全な画像情報を持つ「I フレーム(キーフレーム)」から始まり、差分情報しか持たない「P/B フレーム」が続く。

スナップ挙動:

-c copy では P/B フレーム単体では映像を復元できないため、指定した時刻(例: 00:01:30)の直前にある最も近い I フレーム まで自動的に開始位置が巻き戻される。

例えば、GOP 長が 5 秒の動画で 00:01:30 からカットしようとした場合:

  • 実際の開始位置: 00:01:27(最寄りの I フレーム)
  • ズレ: 最大で GOP 長分(数秒〜10 秒程度)

結論: 無劣化カットは「秒単位の厳密な編集」には向かない。「大体このあたり」を切り抜く用途に特化しており、開始地点が最大で数秒ズレる可能性があることを許容する必要がある。1 フレーム単位の精度が必要な場合は、-c copy を諦めて再エンコードを選択する。

トラブルシューティング

切り抜いた動画の最初が真っ暗になる、または止まる

プレーヤーの互換性問題だ。無理やり P フレームから開始されたデータになっている可能性がある。Input Seeking(-ss-i の前に配置)を使用していれば FFmpeg が自動的に直前のキーフレームを拾うが、再生ソフトによってはその余分な数秒をうまく処理できない場合がある。

解決策: -avoid_negative_ts make_zero オプションを追加してタイムスタンプをリセットする。

bash
ffmpeg -ss 00:01:30 -to 00:05:30 -i input.mp4 \
    -c copy \
    -avoid_negative_ts make_zero \
    output.mp4

-t-to の違いは?

  • -t 10: 開始地点から「10 秒間」切り抜く(Duration 指定)
  • -to 00:01:40: 動画のタイムスタンプで「1 分 40 秒」の地点まで切り抜く(End Time 指定)

「ここからここまで」を指定したい場合は -to が直感的だ。

注意: -ss-i の前に置いた場合(Input Seeking)、-to は入力ファイルの絶対タイムスタンプを参照する。例えば -ss 00:01:30 -to 00:05:30 と指定した場合、1分30秒から5分30秒までが切り出される(開始地点からの相対時刻ではない)。

音声と映像がずれる

-c copy では音声と映像のタイムスタンプをそのままコピーするため、カット位置によってはわずかなズレが生じることがある。原因は、映像のキーフレームと音声のキーフレームが同じタイムスタンプに存在しないことだ。

解決策1: タイムスタンプをリセットする(多くの場合これで十分):

bash
ffmpeg -ss 00:01:30 -to 00:05:30 -i input.mp4 \
    -c copy \
    -avoid_negative_ts make_zero \
    output.mp4

解決策2: 音声だけ再エンコードする(映像は無劣化のまま、同期を正確に修正):

bash
ffmpeg -ss 00:01:30 -to 00:05:30 -i input.mp4 \
    -c:v copy \
    -c:a aac -b:a 192k \
    output.mp4

音声の再エンコードは映像と比べてデータ量が桁違いに小さいため、数秒で完了する。

バッチ処理への応用

複数の動画を一括でカットしたい場合のスクリプト例だ。

Bash でのバッチカット:

bash
#!/bin/bash

# CSVファイル形式(1行目はヘッダー):
# input,start,end,output
# video1.mp4,00:01:30,00:05:00,clip1.mp4
# video2.mp4,00:00:10,00:02:30,clip2.mp4

tail -n +2 clips.csv | while IFS=',' read -r input start end output; do
    ffmpeg -y -ss "$start" -to "$end" -i "$input" -c copy "$output"
    echo "完了: $output"
done

PowerShell でのバッチカット:

powershell
# clips.csv の各行を処理
Import-Csv -Path "clips.csv" -Header "Input","Start","End","Output" | ForEach-Object {
    ffmpeg -y -ss $_.Start -to $_.End -i $_.Input -c copy $_.Output
    Write-Host "完了: $($_.Output)"
}

GUI で無劣化カットしたいなら: LosslessCut

コマンドラインが苦手なら、LosslessCut というオープンソースのGUIツールがある。内部的にはFFmpegの -c copy と同じストリームコピーを使っていて、キーフレーム位置をタイムライン上で視覚的に確認できる。詳しくは FFmpeg GUI代替ツール比較 を参照。

関連記事

よくある質問

-c copy はどの動画フォーマットでも使える?

FFmpegがデムックス・マックスできるフォーマットならすべて対応する — MP4、MKV、MOV、AVI、WebM、TSなど。内部のコーデックは関係ない(デコードしないから)。唯一の制約は、出力コンテナが入力コーデックをサポートしていること(例: VP9はMKVやWebMには入るがMP4には入らない)。

キーフレームの位置を事前に確認する方法は?

ffprobe -select_streams v -show_frames -show_entries frame=pkt_pts_time,key_frame -of csv input.mp4 | grep ",1$" で全キーフレームのタイムスタンプをリストアップできる。これでカット位置をキーフレームに合わせれば、ズレを最小限にできる。

同じ動画から複数区間を一度にカットできる?

-c copy の1コマンドでは無理だ。区間ごとにFFmpegを実行して、最後に ffmpeg -f concat -safe 0 -i list.txt -c copy merged.mp4 で結合する。スクリプト化するなら Python バッチ自動化ガイド が参考になる。

字幕やメタデータも保持される?

-c copy はデフォルトですべてのストリーム(字幕・メタデータ含む)をコピーする。出力コンテナが字幕をサポートしていれば問題ない。全ストリームを明示的に含めるには -map 0 を追加する。

VFR(可変フレームレート)の動画でも使える?

問題なく動作する。-c copy はタイムスタンプに一切手を加えないため、VFR特有の問題は発生しない。VFRで問題が起きるのは再エンコード時であって、ストリームコピーではない。

ファイルサイズや動画の長さに制限はある?

FFmpeg側の実用的な制限はない。50GB超のProResファイルや数時間の録画でも問題なく処理できる。処理速度はディスクI/Oに依存するので、100GBのファイルも1GBのファイルもカット速度はほぼ同じだ。

カットの終了点はどのくらい正確?

終了点も最寄りのキーフレームにスナップするが、前方にスナップ する — FFmpegは終了タイムスタンプを含むGOPを完全に出力する。実用上、終了点のズレは開始点より小さくなる傾向がある。

カット結果をプレビューする方法は?

ffplay -ss 00:01:30 -t 10 input.mp4 で開始地点から10秒間をサクッとプレビューできる。GUIでプレビューしたいなら LosslessCut がキーフレーム境界を視覚的に表示してくれる。

まとめ

動画の「無劣化カット」は、画質の維持と作業効率の最大化において最強のアプローチだ。

目的推奨手法
大体の位置でカット(数秒のズレ許容)-c copy(本記事の方法)
厳密な時刻でカット(フレーム精度)-c:v libx264 -preset fast などで再エンコード
大量ファイルのバッチカットスクリプト化 + -c copy

カンファレンス録画の切り抜き、ハイライトクリップの作成、SNS向け素材の抽出——こうした作業のたびにNLEを立ち上げていたなら、-c copy で作業時間は桁違いに短縮される。動画データを「映像」ではなく「パケットの塊」として扱えるようになる。その視点の転換こそが、FFmpegを道具として自在に操るための第一歩だ。

FFmpegのシーク動作の詳細は 公式ドキュメントSeeking wiki を参照。