0
1

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 で普通にメディアファイルを扱うと副音声などの stream が欠落

Last updated at Posted at 2024-09-02

要約

  • 手軽に対策するには -map 0 を指定して全ての stream を出力
  • 動画ファイルは program と stream で構成される構造
  • 現時点 (2024-09-02) では、FFmpeg は入力ファイルの program 構造を完全に複製不能
  • stream に含まれる次についてはこの記事では扱わないので、またの機会に解説:
    • metadata
    • packet, frame の PTS time

手軽な対策のコマンド

ffmpeg \
  -i <入力ファイル名> \
  -map 0 \
  -c copy \
  <出力ファイル名>

前提知識: 動画ファイルの構造

  • 1 つの動画ファイルは複数の program を含むことが可能
  • 1 つの program は複数の stream を含むことが可能
  • program は stream を含まないことが可能
  • 1 つの動画ファイルは program に含まれない stream を含むことが可能
  • 1 つの動画ファイル内の stream はファイル内の全ての stream 間で順番を保持

確認方法

次のコマンドで出力される JSON データを解析することで確認可能:

ffprobe \
  -show_entries program=program_num:stream=index \
  -output_format json \
  -loglevel repeat+fatal \
  <動画ファイル名>
出力される JSON の例
{
    "programs": [
        {
            "program_num": 23656,
            "streams": [
                {
                    "index": 1,
                    "side_data_list": [
                        {

                        }
                    ]
                },
                {
                    "index": 2
                },
                {
                    "index": 3
                },
                {
                    "index": 4
                },
                {
                    "index": 5
                },
                {
                    "index": 6
                }
            ]
        },
        {
            "program_num": 0,
            "streams": [

            ]
        }
    ],
    "stream_groups": [

    ],
    "streams": [
        {
            "index": 0
        },
        {
            "index": 1,
            "side_data_list": [
                {

                }
            ]
        },
        {
            "index": 2
        },
        {
            "index": 3
        },
        {
            "index": 4
        },
        {
            "index": 5
        },
        {
            "index": 6
        }
    ]
}

JSON の root キーの streams には、
program に含まれる stream と program に含まれない stream の両方が含まれることに注意

上記の JSON の場合、ファイル内の program と stream の構造は次の通り:

動画ファイル
  ├─ stream 0
  ├─ program 23656
  │    ├─ stream 1
  │    ├─ stream 2
  │    ├─ stream 3
  │    ├─ stream 4
  │    ├─ stream 5
  │    └─ stream 6
  └─ program 0

FFmpeg はデフォルトでは入力ファイルの一部の stream のみ出力

FFmpeg はデフォルトでは:

  • video, audio, 字幕の stream は入力ファイルから 1 つの stream のみ出力
  • データや添付ファイルの stream は出力せず

4.1.1 Automatic stream selection | ffmpeg Documentation

ビデオ: 最高解像度の stream
オーディオ: 最も多くのチャンネルを持つ stream
字幕: 最初に見つかった字幕 stream ですが、注意点があります
出力形式のデフォルトの字幕エンコーダは
テキ​​ストベースまたは画像ベースのいずれかであり、
同じタイプの字幕ストリームのみが選択されます
同じタイプの複数のストリームが均等にレートする場合、
インデックスが最も低いストリームが選択されます
データまたは添付ファイルのストリームは自動的に選択されず、
-map を使用してのみ含めることができます

手軽な対策: -map オプションの使用

入力ファイルが 1 つの場合は -map 0 で全ての stream を出力

Simple examples | Map – FFmpeg

-map 0 From input index #0 (the 1st input) select all streams.

FFmpeg は program と stream の構造を完全に複製不能

単純に -map 0 を指定すると、FFmpeg は入力ファイルの program 構造を維持せず、
新たに program_num: 1 で program を作成し、
すべての stream をその program に含めるように動作する模様:

#4525 (Multi-program structure of input is not preserved in MPEG-TS output) – FFmpeg

先ほどの JSON の例で説明すると、
-map 0 を指定した場合の出力ファイルの program と stream の構造は次の通り:

入力ファイル            出力ファイル
    ├─ stream 0            └─ program 1
    ├─ program 23656            ├─ 入力ファイルの stream 0
    │    ├─ stream 1            ├─ 入力ファイルの stream 1
    │    ├─ stream 2            ├─ 入力ファイルの stream 2
    │    ├─ stream 3            ├─ 入力ファイルの stream 3
    │    ├─ stream 4            ├─ 入力ファイルの stream 4
    │    ├─ stream 5            ├─ 入力ファイルの stream 5
    │    └─ stream 6            └─ 入力ファイルの stream 6
    └─ program 0

program の構造を維持するためには -program オプションを使い、
program_num と、その program に含める stream の index を指定する必要あり

参考:
FFMPEG - build transport stream with multiple programs - Video Production Stack Exchange

コマンドの例:

ffmpeg \
  -i <入力ファイル名> \
  -map 0:0 \
  -map p:23656 \
  -program program_num=23656:st=1:st=2:st=3:st=4:st=5:st=6 \
  -c copy \
  <出力ファイル名>

上記のコマンドを実行した場合の出力ファイルの program と stream の構造は次の通り:

入力ファイル            出力ファイル
    ├─ stream 0            ├─ program 23656
    ├─ program 23656       │    ├─ 入力ファイルの stream 1
    │    ├─ stream 1       │    ├─ 入力ファイルの stream 2
    │    ├─ stream 2       │    ├─ 入力ファイルの stream 3
    │    ├─ stream 3       │    ├─ 入力ファイルの stream 4
    │    ├─ stream 4       │    ├─ 入力ファイルの stream 5
    │    ├─ stream 5       │    └─ 入力ファイルの stream 6
    │    └─ stream 6       └─ 入力ファイルの stream 0
    └─ program 0

上記の対応を行っても、次の内容は維持することは不可能:

  • stream を含まない program
  • stream の順序

なお、この他に metadata という情報や、
stream 内の各 packet, frame の PTS time に関しても見ておく必要があるが、
この記事では扱わないので、またの機会に解説

stream を含まない program

FFmpeg の -program オプションで作成不能であるため

stream の順序

FFmpeg の -program オプションを使用した場合、
stream の順序はコマンドのオプションで指定した順にならないため

-program オプションを使用しなければ stream の順序は -map で指定した順

Order | Map – FFmpeg

Order
The order of -map options is important:

  • -map order determines the stream order in the output(s).
  • Mapping is applied in order. This is useful when using negative mapping.

Examples

Tip:
You can add -c copy to many of these examples to enable stream copy mode.
This is useful if you want to mux only and avoid encoding.

-map 0 を設定した場合 -copy_unknown は不要

検証したところ、-map 0 を設定した場合、
-copy_unknown を設定しなくても
FFMpeg がサポートしていない codec の stream を含む全ての stream が出力されることを確認済

念のため、-map 0 -copy_unknown を設定しても動作に問題なし

5.11 Advanced options | ffmpeg Documentation

-copy_unknown
Allow input streams with unknown type to be copied instead of failing
if copying such streams is attempted.

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?