要旨
HEVC(H.265)4K動画からIフレームだけを抽出し、滑らかなMP4として再構成するFFmpeg処理を実行したところ、処理自体は完走し再生も可能だが、ログにHEVCデコード系のエラーが大量に出力された。
ログを一次情報として分解すると、エラーは主に「参照フレーム欠落」「フレーム先頭スライス欠落」「デコード不能NALU」に起因し、入力ストリーム側の欠落・破損の存在が強く示唆された。
対策として、Iフレーム抽出をフィルタ段ではなくデコーダ段へ寄せ(-skip_frame nokey)、破損サンプルを捨てつつ進むフラグ(-fflags +discardcorrupt 等)を導入、さらに出力を全I化しレンジを明示した。
その結果、元のコマンドに比べて約6倍高速化し、出力品質も良好だった。
結論として、今回の「大量エラー」はコマンド設計ミスよりも入力HEVCの欠損/破損に由来する可能性が高く、Iフレーム抽出をデコーダ段へ寄せる設計が速度・安定性の両面で有効。
問題設定
何が期待値で、何が現実か
- 期待値:
- HEVC入力からIフレームのみを抽出し、等間隔に並べ直して滑らかなMP4を生成したい。
- ログに致命的エラーが出ず、再現可能で運用に耐える処理にしたい。
- 現実:
- 処理は完了し、出力MP4は再生できた。
- しかしログにHEVCデコード関連のエラーが大量に出力された。
影響(品質/速度/コスト/運用)
- 品質:
- デコード不能区間がある場合、抽出されるフレーム欠落や画の破綻が混入するリスク。
- ピクセルレンジ(full/tv)の曖昧さは、コントラスト変化→OCR閾値の不安定化につながり得る。
- 速度:
- Iフレームだけが欲しいのに全フレームをデコードしに行く設計だと極端に遅くなり得る。
- コスト:
- 4K・veryslowエンコードはCPU/時間コストが大きい。
- 運用:
- ログが赤くなると監視・障害判定が困難。原因切り分けが必須。
状況前提(環境・制約・入力データ特性)
OS/ハード/ライブラリ/バージョン(観測)
- OS/環境:macOS(コンパイラ
Apple clang) - FFmpeg:8.0.1(
ffmpeg version 8.0.1) - ビルド:Homebrew由来(
/usr/local/Cellar/ffmpeg/8.0.1_4) - エンコーダ:libx264有効(
--enable-libx264) - 入力動画生成:VLC stream output(
encoder : vlc 3.0.23 stream output)
対象データ(観測)
- コンテナ:mov,mp4(
Input #0, mov,mp4...) - コーデック:HEVC Main(
Video: hevc (Main)) - 解像度:3840x2160
- フレームレート:14.92 fps(表示としては 15 tbr)
- ピクセルフォーマット:
yuvj420p(pc, bt709)(full range / bt709)
制約
- OCRや解析用途を意識しており、画質優先(unsharp / CRF低め)で処理したい。
- 学習コストより既存ツールの組合せ(FFmpeg)で即時に成果を出したい。
- 処理速度も重要。
ログ(一次情報)
事前情報
- 「出力をMP4にする場合、動画の圧縮設定とタイムスタンプ再計算が重要」
- 「Iフレームのみ抽出はフレーム数が激減するため、setptsで再配置が必要」
- 「高品質Iフレーム凝縮MP4コマンド(カラー版)」として以下が提示されていた(実行コマンド↓)
実行コマンド
ffmpeg -i "data/input.mp4" \
-sws_flags lanczos+accurate_rnd \
-vf "select='eq(pict_type\,I)',unsharp=5:5:1.0:5:5:0.0,setpts=N/FRAME_RATE/TB" \
-c:v libx264 \
-crf 17 \
-pix_fmt yuv420p \
-preset veryslow \
"output/output_i_frames.mp4"
実行結果
入力情報(抜粋):
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'data/input.mp4':
Duration: 00:01:58.81, start: 0.000000, bitrate: 8065 kb/s
Stream #0:0[0x1](eng): Video: hevc (Main) (hev1 / 0x31766568), yuvj420p(pc, bt709), 3840x2160, 8063 kb/s, 14.92 fps, 15 tbr, 1000k tbn (default)
Metadata:
encoder : vlc 3.0.23 stream output
変換の方向:
Stream mapping:
Stream #0:0 -> #0:0 (hevc (native) -> h264 (libx264))
swscale警告:
[swscaler @ ...] deprecated pixel format used, make sure you did set range correctly
HEVCデコード系エラー(大量、抜粋):
[hevc @ ...] Could not find ref with POC 11
[hevc @ ...] Error constructing the frame RPS.
[hevc @ ...] Skipping invalid undecodable NALU: 1
[hevc @ ...] First slice in a frame missing.
[hevc @ ...] Ignoring POC change between slices: 11 -> 10
処理完走(末尾):
frame= 119 fps=0.5 q=-1.0 Lsize= 110815KiB time=00:00:07.80 bitrate=116384.1kbits/s speed=0.0305x elapsed=0:04:16.00
出力内訳(x264統計、抜粋):
[libx264 @ ...] frame I:1
[libx264 @ ...] frame P:47
[libx264 @ ...] frame B:71
解決したいイシュー
- 処理は完了し、ファイルも再生できるが、ログにエラーが出ている。
- ログの各部を丁寧に解説し、特にエラーについて説明したい。
- エラー原因と対策を深く検討し、対策を盛り込んだコマンドを提示したい。
問題分析
直接原因(最小因果)
事実:
- HEVCデコーダが「参照フレームが見つからない(Could not find ref with POC)」を繰り返し報告している。
- 「First slice in a frame missing」「invalid undecodable NALU」など、フレーム構成要素の欠落/破損を示すログが出ている。
推測(ログからの合理的推論):
- 入力HEVCビットストリームに、参照関係を破壊する欠落・破損が含まれている可能性が高い。
- Iフレームだけを抽出したくても、
select='eq(pict_type,I)'判定にはフレーム復元が関与し得るため、破損区間のデコードでエラーを踏みやすい。
根本原因(構造・設計・前提のズレ)
事実:
- 入力は VLC stream output 由来。
- 入力ピクセルフォーマットが
yuvj420p(pc)(full range)で、swscaleがレンジ明示を促している。 - 出力側 x264 統計では P/B フレームが生成されており、「Iフレーム抽出」=「出力も全I」にはなっていない。
推測:
- ストリーミング録画/出力由来で欠落が混入した場合、HEVC参照構造(RPS)が崩れ、復元不能ログが増える。
- 「Iだけ欲しいのに全フレームをデコードしてしまう」設計が速度劣化を招いていた可能性がある。
典型的に見落とす罠(今回ログから言える範囲)
- 罠1(所与):
pict_typeベースの選択は「見た目は抽出」でも、内部ではデコード負荷を避けられない場合がある。 - 罠2(今回示唆):入力が
yuvj420p(pc)のとき、レンジを明示しないとswscale警告が出る。OCR用途では輝度階調が結果に響き得る。 - 罠3(所与):抽出後に
setptsを適切にしないと動画が一瞬で終わる/カクつく(今回は対処済み)。 - 罠4(今回示唆):抽出出力がP/Bを含むと「Iフレーム凝縮」の意図(編集・解析の単純性)とズレる可能性がある。
検討すべき技術論点(MECE)
以下、3階層(大分類→中分類→具体論点)で列挙する。各論点に「重要性」「観測方法」「判断基準」を付す。
ラベル:[Known] 所与の一般論 / [Learned] 今回ログから得た示唆
入力の健全性(コンテナ/ビットストリーム)
-
入力破損の有無
-
[Learned] HEVC参照欠落(POC/RPSエラー)があるか
- 重要性:参照欠落は復元不能→抽出フレーム欠落・画崩れを誘発。
- 観測方法:ffmpegログの
Could not find ref with POC/Error constructing the frame RPS/First slice missingの頻度。 - 判断基準:繰り返し出るなら入力側欠落/破損の疑いが強い。
-
[Learned] NALU単位の破損があるか
- 重要性:
invalid undecodable NALUはデコーダが救済不能なデータを示す。 - 観測方法:ログの
Skipping invalid undecodable NALU。 - 判断基準:継続的に出るなら入力不良の可能性が高い。
- 重要性:
-
-
キーフレームフラグの信頼性
-
[Known] コンテナ上のkeyframeフラグに依存する抽出の取りこぼしリスク
- 重要性:
-skip_frame nokeyは「keyframe判定」を信頼するため。 - 観測方法:抽出フレーム数の比較(
select pict_typevsskip_frame)。 - 判断基準:取りこぼしが顕著なら
select方式に戻す。
- 重要性:
-
抽出戦略(どこでIを選別するか)
-
デコーダ段でのスキップ
-
[Learned]
-skip_frame nokeyの効果- 重要性:I以外をデコードしない→速度改善、破損参照区間を踏みにくい。
- 観測方法:処理時間・ログエラー量・抽出フレーム数。
- 判断基準:速度↑、エラー↓、フレーム数が妥当なら採用。
-
-
フィルタ段での選別
-
[Known]
select='eq(pict_type\,I)'の負荷/エラー踏み- 重要性:復元が必要になりやすく、破損区間でエラーが出やすい。
- 観測方法:同一入力での速度差、エラー差。
- 判断基準:遅い/エラー多いなら段階を前に寄せる。
-
タイムベース/フレーム再配置
-
PTSの再構成
-
[Known]
setptsの妥当性- 重要性:I抽出でフレーム間隔が崩れると再生が破綻。
- 観測方法:出力再生時間、フレームレート、体感の滑らかさ。
- 判断基準:意図したfpsで等間隔・時間が自然。
-
-
FPSの決め方
-
[Learned] 入力が 14.92fps で
FRAME_RATEが期待通り動くとは限らない- 重要性:式の評価対象(フィルタグラフ内変数)が期待とズレるとPTSが狂う。
- 観測方法:出力のfps表示、duration。
- 判断基準:ズレるなら固定fps指定や
N/(fps*TB)へ。
-
色空間/レンジ/ピクセルフォーマット
-
フルレンジ vs TVレンジ
-
[Learned]
yuvj420p(pc)と swscale警告- 重要性:レンジ不一致は見た目/OCRの閾値に影響。
- 観測方法:ログの swscale警告、出力の黒レベル/白レベル。
- 判断基準:警告が出る・画が変ならレンジ明示。
-
-
出力互換ピクセルフォーマット
-
[Known]
-pix_fmt yuv420pの必要性- 重要性:プレイヤ互換を確保。
- 観測方法:再生互換性。
- 判断基準:広い互換が必要ならyuv420p。
-
エンコード設計(目的に応じた最適化)
-
「I抽出」=「出力も全I」か
-
[Learned] 出力がP/Bを生成している事実(統計ログ)
- 重要性:解析/フレームアクセスの単純性が落ちる。
- 観測方法:x264統計の I/P/B 数。
- 判断基準:全Iが要件なら
-g 1 -bf 0等で強制。
-
-
速度と品質のトレード
-
[Known]
preset veryslowの重さ- 重要性:運用コストに直結。
- 観測方法:speed=0.03x 等の速度ログ。
- 判断基準:必要十分なpresetに落とす/前段最適化で救う。
-
対策案
以下、「即時に試せる順」「副作用が少ない順」で並べる。
各案に「狙い」「手順」「期待結果」「失敗時の分岐」を付す。
すぐ試せる暫定対処(Quick fixes)
QF-1:破損サンプルを捨てつつ進む(ログの赤と破綻を減らす)
- 狙い:入力に欠落/破損があっても完走率を上げ、エラーの連鎖を軽減する。
- 手順:
ffmpeg -hide_banner -y \
-fflags +discardcorrupt \
-err_detect ignore_err \
-i "data/input.mp4" \
-sws_flags lanczos+accurate_rnd \
-vf "select='eq(pict_type\,I)',unsharp=5:5:1.0:5:5:0.0,setpts=N/FRAME_RATE/TB" \
-c:v libx264 -crf 17 -pix_fmt yuv420p -preset veryslow \
"output/output_i_frames.mp4"
- 期待結果:
invalid NALUなどの影響箇所を捨て、致命的停止や破綻を減らす。ログも一部抑制。 - 失敗時の分岐:依然として大量エラー→「I以外のデコードを避ける(QF-2)」へ。
QF-2:Iフレーム選別をデコーダ段へ寄せる(速度と安定性を同時に取る)
- 狙い:I以外をデコードしないことで速度を上げ、破損参照区間を踏みにくくする。
- 手順(対策盛り込み版の中核):
ffmpeg -hide_banner -y \
-fflags +discardcorrupt \
-err_detect ignore_err \
-skip_frame nokey \
-i "data/input.mp4" \
-vf "unsharp=5:5:1.0:5:5:0.0,setpts=N/(15*TB)" \
-an \
-c:v libx264 -crf 17 -pix_fmt yuv420p -preset veryslow \
"output/output_i_frames.mp4"
-
期待結果:処理時間の大幅短縮、HEVCデコード系エラーの減少、出力品質の安定。
-
失敗時の分岐:
- 取りこぼしが疑われる(フレーム数が不自然に少ない)→
select='eq(pict_type\,I)'方式に戻すか、入力のkeyframeフラグを検証。 - 依然エラーが出る→入力破損が強く疑われるため、根治策(8.2)へ。
- 取りこぼしが疑われる(フレーム数が不自然に少ない)→
QF-3:レンジを明示してswscale警告を抑制(OCR/視覚安定)
- 狙い:
yuvj420p(pc)のレンジ曖昧さを排除し、コントラストの不確実性を下げる。 - 手順(フィルタにレンジ明示を追加):
ffmpeg -hide_banner -y \
-skip_frame nokey \
-i "data/input.mp4" \
-vf "unsharp=5:5:1.0:5:5:0.0,scale=in_range=full:out_range=tv,format=yuv420p,setpts=N/(15*TB)" \
-an \
-c:v libx264 -crf 17 -preset veryslow \
"output/output_i_frames.mp4"
- 期待結果:swscale警告の減少、画のレンジ一貫性向上。
- 失敗時の分岐:画が意図より眠い/潰れる→
out_range=full等のレンジ方針を再検討(要件依存)。
根治策(Design fixes)
DF-1:出力を「全I(All-Intra)」に強制して“凝縮IフレームMP4”を厳密化
- 狙い:出力にP/Bを作らせず、フレームアクセスの単純性と解析の安定性を上げる。
- 手順(x264をall-intra寄せ):
ffmpeg -hide_banner -y \
-fflags +discardcorrupt \
-err_detect ignore_err \
-skip_frame nokey \
-i "data/input.mp4" \
-vf "unsharp=5:5:1.0:5:5:0.0,scale=in_range=full:out_range=tv,format=yuv420p,setpts=N/(15*TB)" \
-an \
-c:v libx264 -crf 17 -preset veryslow \
-g 1 -bf 0 \
-x264-params "scenecut=0" \
"output/output_i_frames.mp4"
-
期待結果:x264統計でP/Bが0に近づく(全I)。デコードやフレームサンプリングが容易。
-
失敗時の分岐:
- ファイルサイズ増大→CRFやpresetを調整(品質要件と相談)。
- 互換性問題→pix_fmt/level等を見直す。
DF-2:入力生成(録画/エクスポート)の改善(欠落混入を作らない)
-
狙い:
First slice missingやinvalid NALUの根を断つ。 -
手順(一般方針:推測として明示)
-
推測:VLC stream output由来の欠落が疑われるため、可能なら
- 別手段で録画する(カメラ/RTSP録画の信頼できるレコーダ、ffmpeg直録り等)
- 生成時にエラー耐性のあるコンテナ/設定を選ぶ
-
-
期待結果:HEVCデコードエラーがそもそも出ない入力が得られ、処理が安定。
-
失敗時の分岐:生成側が変えられない→QF/DF-1の救済運用を前提化し、欠落許容の検査工程を追加。
検証手順(再現→比較→合否判定)
目的:改善が「速度」「ログ健全性」「出力品質」の3軸で成立しているか、再現可能に判定する。
- 再現(現行コマンド)
-
5.2のコマンドで実行し、以下を記録:
- elapsed、speed、frame数
- HEVCエラー行数の概算(目視でも可)
- swscale警告の有無
- 出力再生時間と体感の滑らかさ
- 比較(対策コマンド)
- QF-2 → QF-3 → DF-1 の順に適用し、同項目を記録。
- 合否判定(例)
- 速度:elapsedが大幅短縮(ユーザー観測では約6倍)
- ログ:
Could not find ref等が減少/許容範囲、swscale警告が抑制 - 品質:出力が再生可能、必要ならOCR前処理で文字輪郭が安定
- 形式:全Iが要件なら、x264統計でP/Bがゼロ(または極小)
対応結果(今回やったこと・得られた結果・残課題)
-
やったこと:
- HEVCデコードエラーの意味をログから分解し、入力欠落/破損の可能性を中心に原因仮説を立てた。
- Iフレーム抽出をデコーダ段へ寄せ、破損を捨てつつ進む方針、レンジ明示、出力全I化などの対策を提示した。
- 対策コマンドを実行(ユーザー側実施)。
-
得た結果(ユーザー観測):
- 元のコマンドに比べて約6倍高速。
- 出力品質が良好。
-
残った不確実性(推測):
- 入力がどの程度破損しているかの定量評価(どの時刻に欠落があるか等)は未実施。
-
-skip_frame nokeyが依存するkeyframeフラグの信頼性(取りこぼし有無)は未検証。
サマリー
結論
ログに出たHEVCデコード系エラー(POC参照欠落/RPS構築失敗/デコード不能NALU/フレーム先頭スライス欠落)は、入力HEVCに欠落・破損が含まれることを強く示唆する。
Iフレーム抽出をデコーダ段へ寄せる(-skip_frame nokey)設計と、破損を捨てながら進む設定を組み合わせることで、速度と安定性を同時に改善でき、ユーザー観測では約6倍高速化し出力も良好だった。
学び(汎化できる教訓)
- 「Iフレームだけ欲しい」なら、可能な限り“早い段(デコーダ/デマクサ側)”でI以外を捨てると効く。
- HEVCの
Could not find ref with POC連発は、コマンド以前に入力の欠落/破損を疑うべき強いサイン。 -
yuvj420p(pc)(full range)を扱う場合はレンジを明示しないと画の一貫性が崩れやすい。
次アクション(優先度順)
- 現行運用:対策コマンド(DF-1相当)を標準化し、速度/ログ/品質の最小セットを検査項目にする。
- 入力健全性:欠落がどの時間帯にあるか(サンプリング再生・フレーム欠落チェック)を定量化する。
- 生成側改善:可能なら録画/出力系(VLC stream output依存)を見直し、欠落混入を抑える。
付録
用語ミニ辞典
- POC(Picture Order Count):表示/参照順を管理するカウンタ。参照すべきPOCが無いと復元不能になる。
- RPS(Reference Picture Set):そのフレームを復元するために必要な参照フレーム集合。
- NALU(Network Abstraction Layer Unit):HEVC/H.264のビットストリーム構成単位。破損するとデコード不能になり得る。
- yuvj420p(pc):フルレンジ(0-255)YUV 4:2:0。レンジ扱いを明示しないと変換時に警告や画のズレを招き得る。
参考:ログ引用(抜粋)
入力情報
Stream #0:0: Video: hevc (Main) ..., yuvj420p(pc, bt709), 3840x2160, 14.92 fps, 15 tbr ...
encoder : vlc 3.0.23 stream output
代表的エラー
Could not find ref with POC ...
Error constructing the frame RPS.
Skipping invalid undecodable NALU: 1
First slice in a frame missing.
swscale警告
deprecated pixel format used, make sure you did set range correctly