【问题标题】:Why can't I reorder the streams in my mpg container with ffmpeg?为什么我不能用 ffmpeg 重新排序我的 mpg 容器中的流?
【发布时间】:2021-04-11 23:46:48
【问题描述】:

背景:Could having audio as stream 0 and video as stream 1 explain why my MPG will play on OSX QuickTime Player, but not Win10 Movies & TV?
我有一个 mpg 文件,其中音频作为流 0,视频作为流 1。
它在 OSX QT 播放器下运行良好,但在 Win10 的默认应用程序下运行良好。
由于缺乏更好的想法,我假设异常的流排序是我的问题,我正在尝试使用 ffmpeg 修复它. 多么幸运! https://trac.ffmpeg.org/wiki/Map 准确描述了我的情况!

重新排序流

-map 选项的顺序决定了输出中流的顺序。在此示例中,输入文件将音频作为流#0,将视频作为流#1(这是可能的,但不常见)。重新定位视频的示例,使其首先列出,然后是音频:

ffmpeg -i input.mp4 -map 0:v -map 0:a -c 复制 output.mp4

此示例流复制(重新复用)使用 -c copy 以避免重新编码。

我使用的正是那个命令,但翻转似乎不起作用,如下所示:

ffprobe -hide_banner myfile.trimmed.mpg
[h264 @ 000001b965b569c0] Increasing reorder buffer to 2
Input #0, mpeg, from 'myfile.trimmed.mpg':
  Duration: 00:02:41.09, start: 0.500000, bitrate: 6255 kb/s
    Stream #0:0[0x80]: Audio: ac3, 48000 Hz, 5.1(side), fltp, 384 kb/s
    Stream #0:1[0x1e2]: Video: h264 (High), yuv420p(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], Closed Captions, 59.94 fps, 59.94 tbr, 90k tbn, 119.88 tbc
ffmpeg -hide_banner -i myfile.trimmed.mpg -map 0:v -map 0:a -c copy myfile.trimmed.flipped.mpg
[h264 @ 000001fa0ee94680] Increasing reorder buffer to 2
Input #0, mpeg, from 'myfile.trimmed.mpg':
  Duration: 00:02:41.09, start: 0.500000, bitrate: 6255 kb/s
    Stream #0:0[0x80]: Audio: ac3, 48000 Hz, 5.1(side), fltp, 384 kb/s
    Stream #0:1[0x1e2]: Video: h264 (High), yuv420p(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], Closed Captions, 59.94 fps, 59.94 tbr, 90k tbn, 119.88 tbc
[mpeg @ 000001fa0ee88dc0] VBV buffer size not set, using default size of 230KB
If you want the mpeg file to be compliant to some specification
Like DVD, VCD or others, make sure you set the correct buffer size
[mpeg @ 000001fa0ee88dc0] ac3 in MPEG-1 system streams is not widely supported, consider using the vob or the dvd muxer to force a MPEG-2 program stream.
Output #0, mpeg, to 'myfile.trimmed.flipped.mpg':
  Metadata:
    encoder         : Lavf58.45.100
    Stream #0:0: Video: h264 (High), yuv420p(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 59.94 fps, 59.94 tbr, 90k tbn, 59.94 tbc
    Stream #0:1: Audio: ac3, 48000 Hz, 5.1(side), fltp, 384 kb/s
Stream mapping:
  Stream #0:1 -> #0:0 (copy)
  Stream #0:0 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame= 9570 fps=0.0 q=-1.0 Lsize=  123008kB time=00:02:40.95 bitrate=6260.6kbits/s speed= 518x
video:114772kB audio:7545kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.565047%
ffprobe -hide_banner myfile.trimmed.flipped.mpg
[h264 @ 0000021edcf36ac0] Increasing reorder buffer to 2
Input #0, mpeg, from 'myfile.trimmed.flipped.mpg':
  Duration: 00:02:41.09, start: 0.500000, bitrate: 6255 kb/s
    Stream #0:0[0x80]: Audio: ac3, 48000 Hz, 5.1(side), fltp, 384 kb/s
    Stream #0:1[0x1e2]: Video: h264 (High), yuv420p(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], Closed Captions, 59.94 fps, 59.94 tbr, 90k tbn, 119.88 tbc

什么,什么?! 命令输出看起来完全符合我的要求,但生成的文件与原始文件具有相同的流顺序。我缺少什么?
一个可能的线索:看起来音频流在视频流之前开始。我在音频流中看到的最小 pkt_pts_time 是 00:00:00.500000,而我在视频流中看到的最小是 0:00:01.912967。 这有关系吗?

【问题讨论】:

    标签: audio video ffmpeg


    【解决方案1】:

    起初看起来很棘手。我想知道this old FFmpeg trac ticket 是否可能掌握关键:

    在 mpeg-ps 中没有流顺序。 您从 ffmpeg 输出顺序中看到的可能只是音频或视频数据包先出现

    但这实际上不是问题;但是值得注意的是,当您应该尝试输出 MP4 或 MKV 时,您的文件具有 .mpg 扩展名。 ".mpg" is only valid if it contains legacy MPEG-1 and MPEG-2 formats。 H.264 或 AAC 基本流无效。

    如果您没有自己创建此文件,则它可能是一个标签错误的容器(例如 MKV 或 MP4),或者有人奇怪地将流混合到 .mpg。请注意 FFmpeg 在您的流重新排序尝试期间如何警告您不兼容的编解码器。

    MPEG-PS 是一种分组格式,因此不存在这样的基本流。如果它是真正的 MPEG-PS 文件,则可能首先出现一个音频样本。无论哪种方式,您都应该放弃使用 .mpg 作为您的格式。

    请参阅此答案的结尾,了解如何使用 FFprobe 相当准确地识别实际容器格式。

    我又想了想,最后一个神经元提醒我-map 输出是如何遵循赋值顺序的。

    需要注意的重要一点是,-map 0:v -map 0:a 在包含多个流类型的文件中并不完全符合您的预期,因为该语法匹配该类型的所有适用流。


    Gyan 澄清说,如果您的文件只有一个视频和一个音频流,-map 0:v -map 0:a 的功能将等同于-map 0:1 -map 0:0

    如果您想使用0:a 语法,例如,如果您有多个音频,则必须单独处理它们,否则 FFmpeg 将在重新排序时将它们分组。 -map 0:a 将移动两个音频; -map 0:a:0 只会移动第一个音频。

    另一种方法,记住始终检查您操作的每个文件中的流顺序,是按照您希望它们在输出中的顺序指定绝对流编号。所以,-map 0:1 -map 0:0 如果您的视频是源文件中两个流中的第二个。

    对于一个视频和一个音频流的文件,您可以使用任一方法。


    测试

    我创建了一个 .MP4 文件,其中包含一个 H.264 视频作为流 0:0 和一个 MP3 音频作为流 0:1。

    原始文件:

    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\temp\video-audio.mp4':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf58.78.100
      Duration: 00:05:00.30, start: 0.000000, bitrate: 422 kb/s
      Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 421 kb/s, 23.98 fps, 23.98 tbr, 11988 tbn, 47.95 tbc (default)
        Metadata:
          handler_name    : GPAC ISO Video Handler
          vendor_id       : [0][0][0][0]
      Stream #0:1(und): Audio: mp3 (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 180 kb/s (default)
        Metadata:
          handler_name    : SoundHandler
          vendor_id       : [0][0][0][0]
    

    然后我把它反馈给FFmpeg:

    ffmpeg -i C:\temp\video-audio.mp4 -map 0:1 -map 0:0 -c copy C:\temp\swapped.mp4
    (在这种情况下相当于-map 0:a -map 0:v

    结果:交换流; MP3音频流为0:0,H.264视频流为0:1

    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\temp\swapped.mp4':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf58.78.100
      Duration: 00:05:00.30, start: 0.000000, bitrate: 422 kb/s
      Stream #0:0(und): Audio: mp3 (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 180 kb/s (default)
        Metadata:
          handler_name    : SoundHandler
          vendor_id       : [0][0][0][0]
      Stream #0:1(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 421 kb/s, 23.98 fps, 23.98 tbr, 11988 tbn, 47.95 tbc (default)
        Metadata:
          handler_name    : GPAC ISO Video Handler
          vendor_id       : [0][0][0][0]
    

    这似乎完成了你想要的:-)

    ffmpeg -i INPUTFILE -map 0:1 -map 0:0 -c copy OUTPUTFILE.mp4
    ffmpeg -i INPUTFILE -map 0:v -map 0:a -c copy OUTPUTFILE.mp4

    提醒:

    • 对于一个视频和一个音频流的文件,您可以使用上述任一方法。
    • 对于包含多个音频或视频的文件,确定流索引并使用更精细的0:v:00:a:0 语法进行指定。

    ffmpeg -i INPUTFILE 显示文件的数字流 ID,这对于奇数文件可能更快。但是,数字引用会在重新排序时跳过仅指定音频、视频、字幕等的完整性检查。

    FFmpeg's Stream SpecifiersAdvanced Options 文档值得收藏。

    进一步阅读:

    (非常感谢 Gyan 如此细心!)


    使用FFprobe识别容器

    FFprobe 可以尽最大努力检测真正的容器格式,忽略扩展名。这是我的演示“swapped.mp4”的示例,重命名为 .mpg:

    ffprobe -hide_banner -show_error -show_format -i "C:\temp\swapped.mpg"
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\temp\swapped.mpg':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf58.78.100
      Duration: 00:05:00.30, start: 0.000000, bitrate: 422 kb/s
      Stream #0:0(und): Audio: mp3 (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 180 kb/s (default)
        Metadata:
          handler_name    : SoundHandler
          vendor_id       : [0][0][0][0]
      Stream #0:1(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 421 kb/s, 23.98 fps, 23.98 tbr, 11988 tbn, 47.95 tbc (default)
        Metadata:
          handler_name    : GPAC ISO Video Handler
          vendor_id       : [0][0][0][0]
    [FORMAT]
    filename=C:\temp\swapped.mpg
    nb_streams=2
    nb_programs=0
    format_name=mov,mp4,m4a,3gp,3g2,mj2
    format_long_name=QuickTime / MOV
    start_time=0.000000
    duration=300.301000
    size=15847817
    bit_rate=422184
    probe_score=100
    TAG:major_brand=isom
    TAG:minor_version=512
    TAG:compatible_brands=isomiso2avc1mp41
    TAG:encoder=Lavf58.78.100
    [/FORMAT]
    

    注意major_brand=isom (ISO Base Media file format)、format_nameformat_long_name 等等。

    我上个月制作的 true MPEG-2 视频(DVD 翻录)输出如下:

    ffprobe -hide_banner -show_error -show_format -i "C:\temp\opera.mpg"
    Input #0, mpeg, from 'C:\temp\opera.mpg':
      Duration: 02:15:23.71, start: 66240.530111, bitrate: 4194 kb/s
      Stream #0:0[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, smpte170m, top first), 720x576 [SAR 64:45 DAR 16:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
        Side data:
          cpb: bitrate max/min/avg: 7000000/0/0 buffer size: 1835008 vbv_delay: N/A
      Stream #0:1[0x80]: Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
    [FORMAT]
    filename=C:\temp\opera.mpg
    nb_streams=2
    nb_programs=0
    format_name=mpeg
    format_long_name=MPEG-PS (MPEG-2 Program Stream)
    start_time=66240.530111
    duration=8123.712000
    size=4259503237
    bit_rate=4194637
    probe_score=26
    [/FORMAT]
    

    FFprobe 正确地将format_name 报告为mpegformat_long_name 作为MPEG-PS

    【讨论】:

    • 如果输入先有单音频流,后有单视频流,则-map 0:1 -map 0:0-map 0:v -map 0:a效果相同
    • @Gyan 我在我的机器上进行了测试,但情况似乎并非如此。我再测试一下,看看是不是一次性的。
    • 好吧,我很高兴被证明是错误的@gyan! - ffmpeg -i C:\temp\swapped.mp4 -map 0:v -map 0:a -c copy C:\temp\swapped-corrected.mp4确实工作。多么奇怪,我想知道为什么我的测试不起作用,我什至尝试了几次。我会更正我的答案。谢谢。
    【解决方案2】:

    克里斯所说的一切都是正确的,而且帮助很大。内含 H264 视频的原始 .MPG 来自 TivoDecoder;我从没想过质疑该容器对于该视频格式是否有效,当 QT 愿意播放它时,我认为 ffprobe 警告没什么大不了的。 :)

    Remuxing 到 MP4 容器给了我一些 Windows 可以播放的东西。

    ffmpeg -hide_banner -ss 00:17:24 -i myfile.mpg -t 00:02:40 -c copy myfile.trimmed.mp4
    [h264 @ 000002d5d73f4040] Increasing reorder buffer to 2
    [mpegts @ 000002d5d73edbc0] PES packet size mismatch
    [mpegts @ 000002d5d73edbc0] Packet corrupt (stream = 1, dts = 8467425232).
    [mpegts @ 000002d5d73edbc0] Could not find codec parameters for stream 2 (Unknown: none ([151][0][0][0] / 0x0097)): unknown codec
    Consider increasing the value for the 'analyzeduration' and 'probesize' options
    [mpegts @ 000002d5d73edbc0] PES packet size mismatch
    [mpegts @ 000002d5d73edbc0] Packet corrupt (stream = 1, dts = 8467425232).
    Input #0, mpegts, from 'myfile.mpg':
      Duration: 00:30:00.63, start: 92282.982578, bitrate: 6249 kb/s
      Program 1
        Stream #0:0[0x1aab]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], Closed Captions, 59.94 fps, 59.94 tbr, 90k tbn, 119.88 tbc
        Stream #0:1[0x1abf]: Audio: ac3 ([129][0][0][0] / 0x0081), 48000 Hz, 5.1(side), fltp, 384 kb/s
        Stream #0:2[0x1ac1]: Unknown: none ([151][0][0][0] / 0x0097)
    [mp4 @ 000002d5d7e90540] track 1: codec frame size is not set
    Output #0, mp4, to 'myfile.trimmed.mp4':
      Metadata:
        encoder         : Lavf58.45.100
        Stream #0:0: Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 59.94 fps, 59.94 tbr, 90k tbn, 90k tbc
        Stream #0:1: Audio: ac3 (ac-3 / 0x332D6361), 48000 Hz, 5.1(side), fltp, 384 kb/s
    Stream mapping:
      Stream #0:0 -> #0:0 (copy)
      Stream #0:1 -> #0:1 (copy)
    Press [q] to stop, [?] for help
    frame= 9570 fps=0.0 q=-1.0 Lsize=  122587kB time=00:02:39.99 bitrate=6276.6kbits/s speed= 462x
    video:114772kB audio:7545kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.220873%
    
    ffprobe -hide_banner -show_error -show_format -i myfile.trimmed.mp4
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'myfile.trimmed.mp4':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf58.45.100
      Duration: 00:02:40.96, start: 0.000000, bitrate: 6239 kb/s
        Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv), 1280x720 [SAR 1:1 DAR 16:9], Closed Captions, 5890 kb/s, 59.94 fps, 59.94 tbr, 90k tbn, 119.88 tbc (default)
        Metadata:
          handler_name    : VideoHandler
        Stream #0:1(und): Audio: ac3 (ac-3 / 0x332D6361), 48000 Hz, 5.1(side), fltp, 384 kb/s (default)
        Metadata:
          handler_name    : SoundHandler
        Side data:
          audio service type: main
    [FORMAT]
    filename=myfile.trimmed.mp4
    nb_streams=2
    nb_programs=0
    format_name=mov,mp4,m4a,3gp,3g2,mj2
    format_long_name=QuickTime / MOV
    start_time=0.000000
    duration=160.960000
    size=125529106
    bit_rate=6239021
    probe_score=100
    TAG:major_brand=isom
    TAG:minor_version=512
    TAG:compatible_brands=isomiso2avc1mp41
    TAG:encoder=Lavf58.45.100
    [/FORMAT]
    

    我遇到了一个视频和音频严重不同步的新问题,但我将把它作为一个单独的问题提出。

    【讨论】:

    • 什么不同步,是视频领先的音频还是音频领先的视频?还是会在一小时内缓慢漂移,例如音频采样率问题?如果视频流明显是预期速率的两倍或可变帧速率,您可能必须为视频流重新生成 PTS。不太难。
    【解决方案3】:

    使用 ffmpeg 工具重新排序音频流非常棘手,但可以。 如果您知道源流的编号,或者它们的 ID,只需按照您想要的顺序映射它们: ffmpeg -i "..." -map 0:a:0,0:1 -map 0:a:1,0:1 ... 或使用 -map i:0xbbbb -map i:0xaaaa ... 即-map 命令允许选择音频流的新顺序。

    更棘手的是,如果您想根据它们的语言对其进行重新排序:假设您的源包含英语、法语和西班牙语(以及可能的其他)音轨,并且您希望将它们排序为法语、英语、西班牙语等其他语言如下。因此,基于 -map 命令,您可以执行以下操作: ffmpeg -i "..." -map 0:V,0:0 -map 0:m:language:fre? 0:m:语言:eng? 0:m:语言:spa? -地图0:a? -地图-0:s? ....参数的一点解释:首先将真实视频流(大写V)映射为目标流0(您可以更改它),然后搜索元数据语言法语的流,如果存在(最后的问号)放作为第一个音频流,对其他请求的语言重复相同的操作,但在完成映射任何其他流之前,以防没有任何您请求的语言或不会丢失某些源音频流,最后(在某些情况下非常重要案例)删除字幕映射,因为字幕的元数据与音频流的元数据相同,如果有法语的字幕流但没有法语的音频流,则结果将是字幕流映射并且没有音频流 - 这取决于您的要求当然。

    不要忘记使用 -map 命令会阻止自动将所有流映射到目标,这就是为什么在命令中放置“-map 0:v”的原因,数据流和下载流也是如此。任何音频流选择末尾的问号允许缺少确切的音频流,因此 ffmpeg 命令不会因错误而停止。

    注意:映射命令可能会在输出中复制您的音频流...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-08
      • 2013-01-03
      相关资源
      最近更新 更多