FFmpeg フィルタグラフ設計術:複雑合成を filtergraph ファイルで可読・再利用化

FFmpeg で動画編集を行う際、複数の映像や音声を合成したり、エフェクトを重ねたりする処理が複雑になることはありませんか。
コマンドラインに長大な -filter_complex
を直接記述すると、可読性が低下し、メンテナンスも困難になります。
そんな課題を解決するのが filtergraph ファイル です。 この記事では、フィルタグラフをファイル化することで、複雑な合成処理を可読的に設計し、再利用可能にする方法を詳しく解説します。
背景
FFmpeg におけるフィルタグラフとは
FFmpeg のフィルタグラフは、映像・音声データの処理フローを記述する仕組みです。 入力ストリームに対して、フィルタを連結・分岐・合成することで、多様な映像編集が実現できます。
以下の図は、基本的なフィルタグラフの構造を示しています。
mermaidflowchart LR
input1["入力映像 1"] --> filter1["フィルタA<br/>(例: scale)"]
input2["入力映像 2"] --> filter2["フィルタB<br/>(例: overlay)"]
filter1 --> merge["合成<br/>(overlay)"]
filter2 --> merge
merge --> output["出力映像"]
図で理解できる要点:
- 複数の入力ストリームが個別にフィルタ処理される
- フィルタ結果が合成ポイントで統合される
- 最終的に 1 つの出力ストリームとして書き出される
コマンドライン記述の限界
シンプルな処理であれば、コマンドラインに直接フィルタを記述しても問題ありません。 しかし、以下のような複雑なケースでは、可読性とメンテナンス性が大きく低下します。
# | 状況 | 課題 |
---|---|---|
1 | 複数入力の合成 | フィルタチェーンが長くなり、全体像が把握しにくい |
2 | エフェクトの多段適用 | 各処理の境界が不明瞭になる |
3 | チーム共有・再利用 | コマンド全体をコピー&ペーストする運用は非効率 |
4 | デバッグ作業 | エラー箇所の特定に時間がかかる |
実際の例として、3 つの動画を重ね合わせてピクチャーインピクチャーを作る場合を考えてみましょう。
bashffmpeg -i main.mp4 -i sub1.mp4 -i sub2.mp4 \
-filter_complex "[1:v]scale=320:180[v1];[2:v]scale=320:180[v2];[0:v][v1]overlay=10:10[tmp];[tmp][v2]overlay=10:200" \
-c:v libx264 output.mp4
この 1 行だけでも、処理の流れを追うのは容易ではありません。 さらに、音声合成やフェード効果などを追加すると、コマンドが数百文字に膨れ上がることもあります。
課題
長大なコマンドラインがもたらす問題
複雑なフィルタグラフをコマンドラインに直接記述すると、以下のような問題が発生します。
mermaidflowchart TD
longCmd["長大な<br/>-filter_complex"] --> read["可読性の低下"]
longCmd --> maintain["メンテナンス困難"]
longCmd --> reuse["再利用性の欠如"]
read --> debug["デバッグに時間"]
maintain --> bug["バグの混入"]
reuse --> copy["コピペ運用"]
図で理解できる要点:
- 長大なコマンドは可読性・メンテナンス性・再利用性のすべてに悪影響を及ぼす
- 結果としてデバッグコストが増大し、バグが混入しやすくなる
- コピー&ペースト運用では変更の追跡が困難になる
具体的な課題例
実際のプロジェクトで遭遇する課題を整理します。
# | 課題 | 影響 |
---|---|---|
1 | フィルタの順序が不明瞭 | 意図しない処理結果が発生 |
2 | パラメータの調整が困難 | トライ&エラーのたびにコマンド全体を修正 |
3 | チーム内での共有が非効率 | Slack や Wiki に長大なコマンドを貼り付ける運用 |
4 | バージョン管理ができない | Git で差分を追いにくい |
たとえば、以下のようなコマンドを考えてみましょう。
bashffmpeg -i video1.mp4 -i video2.mp4 -i audio.mp3 -filter_complex \
"[0:v]scale=1920:1080,setsar=1[v0];[1:v]scale=640:360[v1];[v0][v1]overlay=x=1270:y=710:enable='between(t,5,15)'[vout];[0:a][2:a]amix=inputs=2:duration=first[aout]" \
-map "[vout]" -map "[aout]" -c:v libx264 -c:a aac output.mp4
このコマンドを見ただけで、以下の処理内容を即座に理解できるでしょうか。
- メイン映像のスケーリングとアスペクト比調整
- サブ映像のスケーリング
- 5 秒から 15 秒の間だけサブ映像をオーバーレイ
- 元の音声と追加音声をミックス
処理内容を理解するだけでも時間がかかり、パラメータを変更するとなるとさらに手間が増えます。
解決策
filtergraph ファイルによる外部化
FFmpeg では、-filter_complex
の内容を外部ファイルに記述し、それを読み込むことができます。
この方法により、フィルタグラフの可読性が飛躍的に向上します。
bashffmpeg -i input1.mp4 -i input2.mp4 \
-filter_complex_script filtergraph.txt \
-c:v libx264 output.mp4
filtergraph.txt の例:
text# メイン映像のスケーリング
[0:v]scale=1920:1080,setsar=1[v0];
# サブ映像のスケーリング
[1:v]scale=640:360[v1];
# オーバーレイ合成(5-15秒の間のみ表示)
[v0][v1]overlay=x=1270:y=710:enable='between(t,5,15)'[vout]
このように、フィルタグラフをファイルに分離することで、以下のメリットが得られます。
# | メリット | 具体的な効果 |
---|---|---|
1 | 可読性の向上 | コメントや改行を自由に追加できる |
2 | メンテナンス性の向上 | 各フィルタの役割が明確になり、修正が容易 |
3 | 再利用性の向上 | 同じフィルタグラフを複数のプロジェクトで使い回せる |
4 | バージョン管理 | Git で変更履歴を追跡できる |
filtergraph ファイルの基本構文
filtergraph ファイルは、テキストファイルとして作成します。 基本的な記述ルールを理解しましょう。
コメントの挿入
#
で始まる行はコメントとして扱われます。
処理の意図を明記することで、後から見返したときの理解が容易になります。
text# これはコメントです
# 複数行にわたってコメントを記述できます
[0:v]scale=1280:720[scaled]
改行とセミコロン
フィルタの区切りには ;(セミコロン)
を使用します。
改行は自由に入れられるため、処理単位で分割すると見やすくなります。
text# 処理1: スケーリング
[0:v]scale=1280:720[scaled];
# 処理2: テキストオーバーレイ
[scaled]drawtext=text='Hello':fontsize=48:x=10:y=10[texted];
# 処理3: フェード効果
[texted]fade=in:0:30[vout]
ストリーム指定子とラベル
入力ストリームは [番号:タイプ]
の形式で指定します。
[0:v]
: 1 番目の入力ファイルの映像ストリーム[1:a]
: 2 番目の入力ファイルの音声ストリーム
フィルタの出力には、任意のラベルを付けることができます。 このラベルを使って、後続のフィルタで参照します。
text[0:v]scale=1920:1080[v_main];
[1:v]scale=640:360[v_sub];
[v_main][v_sub]overlay=10:10[v_final]
上記の例では、v_main
と v_sub
というラベルを使って、2 つの映像を合成しています。
以下の図は、ストリームとラベルの関係を示しています。
mermaidflowchart LR
in0["入力 0:v"] -->|scale| label1["[v_main]"]
in1["入力 1:v"] -->|scale| label2["[v_sub]"]
label1 --> overlay["overlay"]
label2 --> overlay
overlay --> final["[v_final]"]
図で理解できる要点:
- 各入力ストリームは独立して処理される
- フィルタの出力にラベルを付けることで、後続処理で参照可能になる
- 最終的なラベルが出力ストリームとして使われる
実践的な設計パターン
複雑なフィルタグラフを設計する際は、以下のパターンを活用すると効果的です。
パターン 1: 処理単位でセクション分割
関連する処理をセクションとしてまとめ、コメントで区切ります。
text# ============================================
# セクション1: 入力映像の前処理
# ============================================
# メイン映像のスケーリングとクロップ
[0:v]scale=1920:1080,crop=1920:800:0:140[v_main];
# サブ映像のスケーリング
[1:v]scale=480:270[v_sub];
text# ============================================
# セクション2: 映像合成
# ============================================
# ピクチャーインピクチャー配置
[v_main][v_sub]overlay=x=1420:y=790[v_pip];
text# ============================================
# セクション3: エフェクト適用
# ============================================
# フェードイン・フェードアウト
[v_pip]fade=in:0:30,fade=out:st=570:d=30[vout]
このように、処理の段階ごとにセクションを分けることで、全体の構造が把握しやすくなります。
パターン 2: 変数的なラベル命名
ラベル名に処理内容や状態を反映させると、フロー追跡が容易になります。
text# スケーリング後のラベルに _scaled を付ける
[0:v]scale=1920:1080[v0_scaled];
[1:v]scale=640:360[v1_scaled];
# オーバーレイ後のラベルに _overlayed を付ける
[v0_scaled][v1_scaled]overlay=10:10[v_overlayed];
# フィルタ適用後のラベルに _filtered を付ける
[v_overlayed]eq=brightness=0.1[v_filtered]
以下の命名規則を参考にしてください。
# | ラベル例 | 用途 |
---|---|---|
1 | v0_scaled | 映像 0 をスケーリングした結果 |
2 | v_main | メイン映像として扱うストリーム |
3 | v_pip | ピクチャーインピクチャー合成後 |
4 | a_mixed | 音声ミックス後 |
5 | vout | 最終出力映像 |
パターン 3: 条件分岐の明示
時間帯や条件によって処理を変える場合は、コメントで明記します。
text# 0-5秒: フェードイン
# 5-60秒: 通常表示
# 60-65秒: フェードアウト
[0:v]fade=in:0:150,fade=out:st=1800:d=150[vout]
text# 10秒から20秒の間だけサブ映像を表示
[v_main][v_sub]overlay=x=10:y=10:enable='between(t,10,20)'[vout]
テンプレート化とパラメータ管理
同じ構造のフィルタグラフを繰り返し使う場合は、テンプレート化が有効です。 ただし、FFmpeg の filtergraph ファイルには変数機能がないため、シェルスクリプトや Python スクリプトで生成する方法を取ります。
シェルスクリプトによる生成
bash#!/bin/bash
# パラメータ定義
MAIN_WIDTH=1920
MAIN_HEIGHT=1080
SUB_WIDTH=640
SUB_HEIGHT=360
OVERLAY_X=1270
OVERLAY_Y=710
# filtergraph ファイル生成
cat > filtergraph.txt <<EOF
# メイン映像のスケーリング
[0:v]scale=${MAIN_WIDTH}:${MAIN_HEIGHT}[v_main];
# サブ映像のスケーリング
[1:v]scale=${SUB_WIDTH}:${SUB_HEIGHT}[v_sub];
# オーバーレイ合成
[v_main][v_sub]overlay=x=${OVERLAY_X}:y=${OVERLAY_Y}[vout]
EOF
このスクリプトを実行すると、パラメータに基づいた filtergraph.txt が生成されます。
bash# filtergraph 生成
bash generate_filtergraph.sh
# FFmpeg 実行
ffmpeg -i main.mp4 -i sub.mp4 \
-filter_complex_script filtergraph.txt \
-c:v libx264 output.mp4
Python による高度な生成
より複雑なロジックが必要な場合は、Python を使うと柔軟に対応できます。
python#!/usr/bin/env python3
# パラメータクラス定義
class FilterGraphConfig:
def __init__(self, main_size, sub_size, overlay_pos):
self.main_width, self.main_height = main_size
self.sub_width, self.sub_height = sub_size
self.overlay_x, self.overlay_y = overlay_pos
python# filtergraph 生成関数
def generate_filtergraph(config):
return f"""
# メイン映像のスケーリング
[0:v]scale={config.main_width}:{config.main_height}[v_main];
# サブ映像のスケーリング
[1:v]scale={config.sub_width}:{config.sub_height}[v_sub];
# オーバーレイ合成
[v_main][v_sub]overlay=x={config.overlay_x}:y={config.overlay_y}[vout]
"""
python# 使用例
if __name__ == "__main__":
config = FilterGraphConfig(
main_size=(1920, 1080),
sub_size=(640, 360),
overlay_pos=(1270, 710)
)
filtergraph = generate_filtergraph(config)
with open("filtergraph.txt", "w") as f:
f.write(filtergraph)
print("filtergraph.txt を生成しました")
この方法を使えば、設定ファイルから読み込んだパラメータで、動的に filtergraph を生成することも可能です。
具体例
ここでは、実際のユースケースに基づいた filtergraph 設計例を紹介します。
ケース 1: ピクチャーインピクチャー合成
メイン映像の右下に、サブ映像を小さく表示するピクチャーインピクチャーを作成します。
要件:
- メイン映像: 1920x1080
- サブ映像: 640x360(右下に配置)
- 5 秒から 15 秒の間だけサブ映像を表示
以下の図は、処理フローを示しています。
mermaidflowchart TD
main["メイン映像<br/>1920x1080"] --> scale1["スケーリング<br/>維持"]
sub["サブ映像<br/>元サイズ"] --> scale2["スケーリング<br/>640x360"]
scale1 --> overlay["overlay<br/>x=1270 y=710<br/>5-15秒のみ"]
scale2 --> overlay
overlay --> output["出力映像<br/>1920x1080"]
図で理解できる要点:
- メイン映像はサイズを維持しつつ処理される
- サブ映像は指定サイズにスケーリングされる
- オーバーレイは条件付きで時間制御される
filtergraph_pip.txt:
text# ============================================
# ピクチャーインピクチャー合成
# ============================================
# メイン映像のスケーリング(アスペクト比補正)
[0:v]scale=1920:1080,setsar=1[v_main];
text# サブ映像のスケーリング
[1:v]scale=640:360[v_sub];
text# オーバーレイ合成(5-15秒の間だけ表示)
# x=1270: 右下配置(1920 - 640 - 10px マージン)
# y=710: 右下配置(1080 - 360 - 10px マージン)
[v_main][v_sub]overlay=x=1270:y=710:enable='between(t,5,15)'[vout]
実行コマンド:
bashffmpeg -i main.mp4 -i sub.mp4 \
-filter_complex_script filtergraph_pip.txt \
-map "[vout]" \
-c:v libx264 -preset medium -crf 23 \
output_pip.mp4
ケース 2: 3 分割画面レイアウト
3 つの映像を横並びに配置する分割画面を作成します。
要件:
- 出力解像度: 1920x1080
- 各映像: 640x1080(横幅を 3 分割)
以下の図は、レイアウト構造を示しています。
mermaidflowchart LR
in1["映像 1"] --> pos1["左<br/>x=0"]
in2["映像 2"] --> pos2["中央<br/>x=640"]
in3["映像 3"] --> pos3["右<br/>x=1280"]
pos1 --> canvas["黒背景<br/>1920x1080"]
pos2 --> canvas
pos3 --> canvas
canvas --> out["出力"]
図で理解できる要点:
- ベースとなる黒背景キャンバスを用意
- 各映像をスケーリングして指定位置に配置
- overlay を連続適用して合成
filtergraph_split3.txt:
text# ============================================
# 3分割画面レイアウト
# ============================================
# ベースとなる黒背景キャンバス作成
color=c=black:s=1920x1080:d=10[bg];
text# 各映像のスケーリング(横幅640に統一)
[0:v]scale=640:1080,setsar=1[v0];
[1:v]scale=640:1080,setsar=1[v1];
[2:v]scale=640:1080,setsar=1[v2];
text# 1つ目の映像を左端に配置
[bg][v0]overlay=x=0:y=0[tmp1];
text# 2つ目の映像を中央に配置
[tmp1][v1]overlay=x=640:y=0[tmp2];
text# 3つ目の映像を右端に配置
[tmp2][v2]overlay=x=1280:y=0[vout]
実行コマンド:
bashffmpeg -i video1.mp4 -i video2.mp4 -i video3.mp4 \
-filter_complex_script filtergraph_split3.txt \
-map "[vout]" \
-c:v libx264 -preset medium -crf 23 \
output_split3.mp4
ケース 3: 音声ミックスとフェード
複数の音声を合成し、映像にフェードエフェクトを適用します。
要件:
- メイン音声と BGM をミックス(音量比 7:3)
- 映像の最初と最後にフェード効果を適用
- フェードイン: 0-1 秒
- フェードアウト: 最後の 1 秒
以下の図は、音声処理のフローを示しています。
mermaidflowchart LR
audio1["メイン音声<br/>音量 0.7"] --> mix["amix"]
audio2["BGM<br/>音量 0.3"] --> mix
mix --> aout["[aout]<br/>ミックス済み音声"]
filtergraph_fade_audio.txt:
text# ============================================
# 映像処理: フェードイン・フェードアウト
# ============================================
# フェードイン(0-1秒、30フレーム)
# フェードアウト(最後の1秒、30フレーム)
# ※ st=570 は 19分30秒の位置を想定(実際の長さに応じて調整)
[0:v]fade=in:0:30,fade=out:st=570:d=30[vout];
text# ============================================
# 音声処理: ミックス
# ============================================
# メイン音声の音量を70%に調整
[0:a]volume=0.7[a0];
text# BGMの音量を30%に調整
[1:a]volume=0.3[a1];
text# 2つの音声をミックス
# duration=first: メイン音声の長さに合わせる
[a0][a1]amix=inputs=2:duration=first[aout]
実行コマンド:
bashffmpeg -i main.mp4 -i bgm.mp3 \
-filter_complex_script filtergraph_fade_audio.txt \
-map "[vout]" -map "[aout]" \
-c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 192k \
output_fade_audio.mp4
ケース 4: 動的テキストオーバーレイ
時間経過に応じて表示内容が変わるテキストを映像に重ねます。
要件:
- 0-5 秒: "Introduction" を表示
- 5-10 秒: "Main Content" を表示
- 10 秒以降: "Conclusion" を表示
filtergraph_text_dynamic.txt:
text# ============================================
# 動的テキストオーバーレイ
# ============================================
# フォント設定の共通定義
# fontfile: フォントファイルのパス(環境に応じて変更)
# fontsize: 48px
# fontcolor: 白
# x, y: 画面中央
text# 0-5秒: "Introduction" を表示
[0:v]drawtext=fontfile=/System/Library/Fonts/Hiragino\ Sans\ W6.ttc:text='Introduction':fontsize=48:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:enable='between(t,0,5)'[txt1];
text# 5-10秒: "Main Content" を表示
[txt1]drawtext=fontfile=/System/Library/Fonts/Hiragino\ Sans\ W6.ttc:text='Main Content':fontsize=48:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:enable='between(t,5,10)'[txt2];
text# 10秒以降: "Conclusion" を表示
[txt2]drawtext=fontfile=/System/Library/Fonts/Hiragino\ Sans\ W6.ttc:text='Conclusion':fontsize=48:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:enable='gte(t,10)'[vout]
実行コマンド:
bashffmpeg -i input.mp4 \
-filter_complex_script filtergraph_text_dynamic.txt \
-map "[vout]" \
-c:v libx264 -preset medium -crf 23 \
output_text_dynamic.mp4
ケース 5: 複数エフェクトの段階的適用
スケーリング、クロップ、色調補正、シャープネス適用を順次実行します。
要件:
- 4K 映像を Full HD にスケーリング
- 上下の黒帯をクロップ(2.35:1 シネスコ風)
- 明度とコントラストを調整
- 軽いシャープネスを適用
filtergraph_multi_effects.txt:
text# ============================================
# 複数エフェクトの段階的適用
# ============================================
# ステップ1: 4K → Full HD スケーリング
[0:v]scale=1920:1080[v_scaled];
text# ステップ2: シネスコサイズにクロップ
# 1920x817(アスペクト比 2.35:1)
# y=131.5: 上下均等に切り取り((1080-817)/2)
[v_scaled]crop=1920:817:0:131.5[v_cropped];
text# ステップ3: 色調補正
# brightness: 明度を10%アップ
# contrast: コントラストを5%アップ
# saturation: 彩度を5%アップ
[v_cropped]eq=brightness=0.1:contrast=1.05:saturation=1.05[v_color];
text# ステップ4: シャープネス適用
# luma_msize_x, luma_msize_y: マトリックスサイズ 5x5
# luma_amount: 強度 0.5(軽め)
[v_color]unsharp=luma_msize_x=5:luma_msize_y=5:luma_amount=0.5[vout]
実行コマンド:
bashffmpeg -i input_4k.mp4 \
-filter_complex_script filtergraph_multi_effects.txt \
-map "[vout]" \
-c:v libx264 -preset slow -crf 18 \
output_cinema.mp4
以下の図は、エフェクト適用の流れを示しています。
mermaidflowchart TD
input["入力<br/>3840x2160"] --> step1["スケーリング<br/>1920x1080"]
step1 --> step2["クロップ<br/>1920x817"]
step2 --> step3["色調補正<br/>brightness/contrast"]
step3 --> step4["シャープネス<br/>unsharp"]
step4 --> output["出力<br/>1920x817"]
図で理解できる要点:
- 各処理が独立したステップとして定義されている
- 処理順序が明確で、デバッグや調整が容易
- 不要なステップをコメントアウトすることで、部分的なテストが可能
まとめ
FFmpeg のフィルタグラフをファイル化することで、複雑な映像処理が格段に扱いやすくなります。 この記事では、以下のポイントを解説しました。
# | ポイント | 効果 |
---|---|---|
1 | filtergraph ファイルの基本構文 | コメントや改行で可読性が向上 |
2 | セクション分割とラベル命名 | 処理の流れが追いやすくなる |
3 | テンプレート化とパラメータ管理 | 再利用性が高まり、チーム共有が容易に |
4 | 実践的な具体例 | 実際のユースケースに即座に応用可能 |
長大なコマンドラインに悩んでいた方は、ぜひ filtergraph ファイルを活用してみてください。 可読性・メンテナンス性・再利用性のすべてが改善され、FFmpeg での映像編集がより快適になるはずです。
Git でバージョン管理すれば、変更履歴の追跡や複数人での共同編集もスムーズに行えます。 チーム開発においても、filtergraph ファイルは強力な武器となるでしょう。
関連リンク
- article
FFmpeg フィルタグラフ設計術:複雑合成を filtergraph ファイルで可読・再利用化
- article
FFmpeg コマンド 100 連発:入力・出力・フィルタ・ストリーム指定の定番集
- article
FFmpeg を macOS で最適導入:Homebrew +オプション選定で機能漏れゼロ
- article
FFmpeg デインターレース比較:yadif vs bwdif vs nnedi3 の画質と速度検証
- article
FFmpeg 音ズレを根治:VFR→CFR 変換と PTS 補正の実践ガイド
- article
FFmpeg アーキテクチャ超図解:demuxer→decoder→filter→encoder→muxer の流れを一望
- article
Vue.js コンポーネント API 設計:props/emit/slot を最小 API でまとめる
- article
GitHub Copilot 前提のコーディング設計:コメント駆動 → テスト → 実装の最短ループ
- article
Tailwind CSS マルチブランド設計:CSS 変数と data-theme で横断対応
- article
Svelte フォーム体験設計:Optimistic UI/エラー復旧/再送戦略の型
- article
GitHub Actions でゼロダウンタイムリリース:canary/blue-green をパイプライン実装
- article
Git エイリアス 50 連発:長コマンドを一行にする仕事術まとめ
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来