1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FFmpegでHEVC入力からIフレーム抽出MP4を生成する際にHEVCデコードエラーが大量発生する原因と、6倍高速化した対策コマンド

1
Posted at

要旨

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_type vs skip_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 missinginvalid NALU の根を断つ。

  • 手順(一般方針:推測として明示)

    • 推測:VLC stream output由来の欠落が疑われるため、可能なら

      • 別手段で録画する(カメラ/RTSP録画の信頼できるレコーダ、ffmpeg直録り等)
      • 生成時にエラー耐性のあるコンテナ/設定を選ぶ
  • 期待結果:HEVCデコードエラーがそもそも出ない入力が得られ、処理が安定。

  • 失敗時の分岐:生成側が変えられない→QF/DF-1の救済運用を前提化し、欠落許容の検査工程を追加。

検証手順(再現→比較→合否判定)

目的:改善が「速度」「ログ健全性」「出力品質」の3軸で成立しているか、再現可能に判定する。

  1. 再現(現行コマンド)
  • 5.2のコマンドで実行し、以下を記録:

    • elapsed、speed、frame数
    • HEVCエラー行数の概算(目視でも可)
    • swscale警告の有無
    • 出力再生時間と体感の滑らかさ
  1. 比較(対策コマンド)
  • QF-2 → QF-3 → DF-1 の順に適用し、同項目を記録。
  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)を扱う場合はレンジを明示しないと画の一貫性が崩れやすい。

次アクション(優先度順)

  1. 現行運用:対策コマンド(DF-1相当)を標準化し、速度/ログ/品質の最小セットを検査項目にする。
  2. 入力健全性:欠落がどの時間帯にあるか(サンプリング再生・フレーム欠落チェック)を定量化する。
  3. 生成側改善:可能なら録画/出力系(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
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?