シネマティックリールエディター
生のクリップが入ったフォルダと音楽トラックを使って、15〜45秒、9:16、ビート同期のシネマティックリールを作成します。すべての編集はコマンドラインからFFmpegで行います。計画は編集可能な編集リスト(edl.json)に保存されるため、最初からやり直すことなく変更を再レンダリングできます。
0. 絶対ルール
raw/内のファイルは絶対に変更または削除しないでください。すべての出力はwork/とout/に書き込みます。- 音楽はユーザーが提供する必要があります(ライセンス済み/ロイヤリティフリー)。
music/が空の場合はトラックをリクエストし、著作権のある音楽をダウンロードしないでください。 - 最終レンダリングの前に、ショットプラン(ステップ4)をユーザーに表示し、承認を得てください。
- ビート上でのハードカットを優先します。トランジションは控えめに(リールあたり最大2〜3つ)使用してください。
1. 前提条件の確認
ffmpeg -version && ffprobe -version
python3 -c "import librosa, numpy" || pip install librosa numpy soundfile
FFmpegが見つからない場合は、ユーザーにインストールを指示し(Windows: winget install ffmpeg、Mac: brew install ffmpeg、Linux: sudo apt install ffmpeg)、処理を停止します。
2. フォルダ構成
project/
raw/ # カメラクリップ(読み取り専用)
music/ # 音楽トラック1つ
luts/ # オプションの .cube カラーグレーディング用LUT
work/ # サムネイル、セグメント、edl.json、beats.json
out/ # 最終レンダリング(reel_v1.mp4、reel_v2.mp4 ...)
3. 映像のインベントリと確認
すべてのクリップについて、長さ、解像度、fps、向きを記録します:
ffprobe -v error -show_entries format=duration:stream=width,height,r_frame_rate,codec_type -of json raw/CLIP.mp4
クリップごとにコンタクトシートを作成し(2秒ごとに1フレーム)、Readツールで表示して各ショットに何が写っているかを確認します:
ffmpeg -y -i raw/CLIP.mp4 -vf "fps=1/2,scale=320:-1,tile=4x3" -frames:v 1 work/thumbs/CLIP.jpg
各使用可能な瞬間にタグを付けます:ショットタイプ(ワイド/ミディアム/クローズアップ/ディテール)、被写体、動き、品質(シャープ、安定、照明良好)、スローモーション対応可能か(ソースが50fps以上)。
4. ストーリーの構築(ショットプラン)
すべてのリールを次のように構成します:
- フック(0〜2秒) — 最も印象的なショット。ロゴやテキストのイントロは不要。
- ビルドアップ — 詳細と期待感(クローズアップ、スローモーション)。
- ヒーローモーメント — 最大のビート/音楽のドロップに合わせて。
- エモーション/ペイオフ — 反応、人々、祝福。
- アウトロ(最後の2〜3秒) — クリーンなワイドショット、オプションのテキストまたはロゴ、音楽のフェード。
車の納車テンプレート(映像に合わせて調整):エクステリアワイド → ロゴクローズアップ → ホイール/ヘッドライトの詳細 → 家族が歩いてくる(スローモーション) → カバーを外す(ドロップに合わせて) → キーの受け渡し → 反応/笑顔 → インテリア+ステアリング → ケーキ/ガーランド/プージャ → 最初のドライブアウェイ(ワイド、アウトロ)。
ルール:ショットサイズを変化させる(ワイドを2回連続で使わない)、各ショットは0.5〜2.5秒に収める、感情的なショットやリビールショットにのみスローモーションを使用する、可能な限り動きに合わせてカットする。
5. ビート検出
# work/beats.py
import librosa, json, sys
y, sr = librosa.load(sys.argv[1])
tempo, frames = librosa.beat.beat_track(y=y, sr=sr)
beats = librosa.frames_to_time(frames, sr=sr).tolist()
onset = librosa.onset.onset_strength(y=y, sr=sr)
json.dump({"tempo": float(tempo), "beats": beats}, open("work/beats.json", "w"), indent=1)
print(f"tempo {float(tempo):.1f} BPM, {len(beats)} beats")
ビートに合わせてカットします(速いセクションではすべてのビート、遅いセクションでは2ビートまたは4ビートごと)。ドロップ(最大のエネルギージャンプ)を見つけ、そこにヒーローショットを配置します。
6. 編集リスト work/edl.json の作成
{
"output": {"w": 1080, "h": 1920, "fps": 30},
"music": {"file": "music/track.mp3", "start": 12.0, "fade_out": 1.5},
"grade": {"lut": "luts/teal_orange.cube", "vignette": true},
"shots": [
{"id": 1, "src": "raw/C0001.mp4", "in": 4.20, "dur": 1.40, "speed": 1.0, "crop_x": "center", "note": "フック – 車のワイド"},
{"id": 2, "src": "raw/C0007.mp4", "in": 10.0, "dur": 1.00, "speed": 0.5, "crop_x": "center", "note": "ホイール スローモーション"}
],
"transitions": [{"after_shot": 4, "type": "fade", "dur": 0.3}],
"text": [{"text": "Welcome Home", "start": 18.0, "end": 21.0}]
}
durはタイムライン上の長さです。speedが0.5の場合、使用されるソース範囲はdur × speed秒になります。レンダリング前にこの計画をシンプルなテーブル(ショット、時間、説明)としてユーザーに表示します。
7. 各ショットを均一なセグメントとしてレンダリング
すべてのセグメントは、同一の解像度、fps、ピクセルフォーマット、オーディオなしでなければなりません。これにより、きれいに結合できます。
# ランドスケープソース → 9:16クロップ、スピード、グレーディング
ffmpeg -y -ss IN -t SRC_DUR -i raw/CLIP.mp4 -an -vf "\
setpts=PTS/SPEED,\
scale=-2:1920,crop=1080:1920,\
fps=30,\
lut3d=luts/teal_orange.cube,\
eq=contrast=1.06:saturation=1.10,\
vignette=PI/5,\
format=yuv420p" \
-c:v libx264 -crf 16 -preset medium work/seg_01.mp4
SRC_DUR = dur × speed。スローモーションには高fpsのソースを使用します。minterpolateは(遅く、アーティファクトが発生するため)要求がない限り避けてください。- 縦型ソース:
scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920を使用します。 - LUTがない場合:シネマティックなルックにするために、
eq=contrast=1.08:saturation=1.15:gamma=0.98に加えてcurves=preset=increase_contrastを使用します。 - 9:16リールではシネマティックバーは使用しません。
8. セグメントの結合
トランジションなし — concat demuxerを使用:
printf "file 'seg_%02d.mp4'\n" 1 2 3 ... > work/list.txt
ffmpeg -y -f concat -safe 0 -i work/list.txt -c copy work/video.mp4
2つのセグメント間にトランジションを入れる場合はxfadeを使用します(オフセット = 最初のクリップの長さ − トランジションの長さ):
ffmpeg -y -i work/seg_04.mp4 -i work/seg_05.mp4 -filter_complex \
"[0][1]xfade=transition=fade:duration=0.3:offset=1.2,format=yuv420p" work/seg_04_05.mp4
各トランジションはタイムラインをその長さだけ短くします — ビートの同期を再確認してください。
9. 音楽、テキスト、最終エクスポート
ffmpeg -y -i work/video.mp4 -ss MUSIC_START -i music/track.mp3 -filter_complex "\
[1:a]afade=t=in:d=0.3,afade=t=out:st=FADE_START:d=1.5,loudnorm=I=-14:TP=-1:LRA=11[a];\
[0:v]drawtext=fontfile=FONT.ttf:text='Welcome Home':fontsize=72:fontcolor=white:\
x=(w-text_w)/2:y=h*0.72:enable='between(t,18,21)':alpha='if(lt(t,18.4),(t-18)/0.4,1)'[v]" \
-map "[v]" -map "[a]" -shortest \
-c:v libx264 -crf 18 -preset slow -profile:v high -pix_fmt yuv420p -r 30 \
-c:a aac -b:a 192k -movflags +faststart out/reel_v1.mp4
マシン上でdrawtext用のフォントファイルを見つけます(またはユーザーに尋ねます)。テキストは最小限に、安全領域内に配置します(上部15%と下部25%は避ける。InstagramのUIがあるため)。
10. 品質チェック(常に実施)
ffprobe out/reel_vN.mp4→ 1080×1920、30 fps、H.264、AAC、計画通りの長さ。- 最終リールのコンタクトシート(
fps=2,scale=270:-1,tile=6x5)を表示して確認:黒フレームがない、トリミングミスがない(頭が切れていない)、色味が一貫している。 - ラウドネスを確認し、ヒーローショットがドロップに合っていることを確認します。
- ユーザーに報告:長さ、ショット数、ファイルパス、および不明な点があれば何でも。
11. 修正
決して最初からやり直さないでください。work/edl.jsonを編集し(ショットの入れ替え、in/dur、スピード、テキスト、グレーディングの変更)、変更されたセグメントのみを再レンダリングし、再結合して次のバージョン(reel_v2.mp4)としてエクスポートします。ユーザーが比較できるように古いバージョンは保持します。