V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
henix
V2EX  ›  FFmpeg

ffmpeg 处理后视频时长问题

  •  
  •   henix · 31 天前 · 1886 次点击

    用 ffmpeg -t 将一个 10s 的视频剪裁到 3s 后,播放时长没问题,但是放进 concat 过滤器,这个视频片段占用的长度仍为原长度 10s ,后面 7s 表现为最后一帧静止画面。尝试了各种方法都不行,还望大神赐教。

    问题详细描述:

    1. 用完全重编码的方法将一个 10s 的视频转换为 3.971s 并去掉音频:

    ffmpeg -t 3.971 -i "加载.mp4" -c:v libx264 -tune animation -crf 1 -an loading.mp4

    ffprobe 结果文件 loading.mp4 如下:

    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'loading.mp4':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf61.7.100
      Duration: 00:00:03.98, start: 0.000000, bitrate: 49072 kb/s
      Stream #0:0[0x1](eng): Video: h264 (High 4:4:4 Predictive) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080, 49068 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
          Metadata:
            handler_name    : ?Mainconcept Video Media Handler
            vendor_id       : [0][0][0][0]
            encoder         : Lavc61.19.100 libx264
    

    疑点:时长为 3.98 ,已经不精确?

    原始视频的 ffprobe ,是不是原始视频有什么不正常:

    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '加载.mp4':
      Metadata:
        major_brand     : mp42
        minor_version   : 0
        compatible_brands: mp42mp41
        creation_time   : 2022-03-26T12:31:39.000000Z
      Duration: 00:00:10.00, start: 0.000000, bitrate: 9763 kb/s
      Stream #0:0[0x1](eng): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080, 9395 kb/s, 60 fps, 60 tbr, 60k tbn (default)
          Metadata:
            creation_time   : 2022-03-26T12:31:39.000000Z
            handler_name    : ?Mainconcept Video Media Handler
            vendor_id       : [0][0][0][0]
            encoder         : AVC Coding
      Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 317 kb/s (default)
          Metadata:
            creation_time   : 2022-03-26T12:31:40.000000Z
            handler_name    : #Mainconcept MP4 Sound Media Handler
            vendor_id       : [0][0][0][0]
    

    2. 将一个 webm 视频 overlay 到上述视频上,并加入音频,且音视频都重编码:

    疑点:webm 视频的时长显示为 N/A ,但实际为 3.5s 左右

    用了 -filter_complex chromakey,scale;overlay

    结果的 ffprobe 如下:

    Input #0, matroska,webm, from 'opening.mkv':
      Metadata:
        COMPATIBLE_BRANDS: isomiso2avc1mp41
        MAJOR_BRAND     : isom
        MINOR_VERSION   : 512
        ENCODER         : Lavf61.7.100
      Duration: 00:00:03.98, start: 0.000000, bitrate: 70572 kb/s
      Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv420p(tv, bt709, progressive), 1920x1080, 60 fps, 60 tbr, 1k tbn
          Metadata:
            ENCODER         : Lavc61.19.100 libx264
            DURATION        : 00:00:03.984000000
      Stream #0:1: Audio: flac, 44100 Hz, stereo, s16
          Metadata:
            ENCODER         : Lavc61.19.100 flac
            DURATION        : 00:00:03.970000000
    

    这一步结果视频长度 3.984s

    3. 将上一步的结果用 concat 加到另外两个视频流的中间:

    -filter_complex
        "[10:v]trim=0:3.97[t10v]",
        "[10:a]atrim=0:3.97[t10a]",
        "[fv1t][fa1t][t10v][t10a][fv2t][fa2t]concat=3:1:1",
    

    其中 "[10]" 代表上一步结果的视频流和音频流,已经用 trim 处理

    结果:在生成的文件中,这一段的实际占用时间为 10s ,而不是我需要的 3.971s ,后面 7s 是最后一帧静止画面和静音。

    24 条回复    2024-11-21 17:51:28 +08:00
    lovelylain
        1
    lovelylain  
       31 天前 via Android
    ffprobe -loglevel trace "加载.mp4"
    msg7086
        2
    msg7086  
       31 天前
    238 帧是 3.967s
    239 帧是 3.983s
    怎么可能出现 3.971s ?

    至于把一个不兼容的段塞到原来的流里,炸锅概率本来就非常大,能正常播放才是奇迹。VPS/SPS/PPS 都不一样的,timecode 也没处理吧大概。
    henix
        3
    henix  
    OP
       31 天前
    @lovelylain ffprobe -loglevel trace "加载.mp4" 贴到这里了: https://gist.github.com/henix/0ae8a97aeb78fc60206e4b75464fcfbd
    这个原始视频是别人给我的,估计应该是用 Adobe 的软件做出来的
    shintendo
        4
    shintendo  
       31 天前
    我🌿,看到这贴猛然想起一个困扰我多年的问题:
    我用剪映剪视频的时候,会用小丸工具箱( ffmpeg 封装的工具)从原始视频素材(多为 mkv 的影视剧)里剪出几十秒的片段,这些片段文件大小没问题,直接用播放器播放也没问题,但是一旦拖进剪映里面,那个素材的长度就变成了原始 mkv 的几小时长度,其中前几十秒是我要的,后面都是最后一帧的静止。
    我一直不知道是什么原因!
    henix
        5
    henix  
    OP
       31 天前
    @msg7086 初学视频编辑,还不知道你说的这些名词啥意思...但最后 concat 那一步我对齐了分辨率都是 1920x1080 ,帧率都是 60 fps ,还有啥需要注意的吗
    confi
        6
    confi  
       31 天前 via iPhone
    之前用 ffmpeg 或其他套壳软件,用关键帧方式裁剪视频,也出现这个问题,未解决
    lslqtz
        7
    lslqtz  
       31 天前
    @msg7086 238/59.94=3.9706=3.971

    另外部分设备拍摄的视频很小的概率会丢帧.
    tool2dx
        8
    tool2dx  
       31 天前 via Android
    @confi “用关键帧方式裁剪视频”,把关键字三个字去掉,就解决了。
    lslqtz
        9
    lslqtz  
       31 天前
    但就我印象中, 59.94fps 应该是单独一档, 不会按 60fps 来显示. 也许, 这只是一个巧合.

    一个最简单的 workaround 是, 你描述到最后是静帧持续, 那么可以在处理完成后再次尝试进行一次裁切.
    lslqtz
        10
    lslqtz  
       31 天前
    @confi 关键帧通常几秒甚至几十秒一次, 因此不能用关键帧来精确裁剪和定位视频.
    lslqtz
        11
    lslqtz  
       31 天前
    另外, 引用这个答案: https://stackoverflow.com/a/63357242
    ```
    ffmpeg -i vid1.mp4 -i vid2.mp4 -filter_complex "[0:v]trim=0:2,setpts=PTS-STARTPTS[v1];[1:v]trim=3:6,setpts=PTS-STARTPTS[v2];[0:a]atrim=0:2,asetpts=PTS-STARTPTS[a1];[1:a]atrim=3:6,asetpts=PTS-STARTPTS[a2];[v1][a1][v2][a2]concat=n=2:v=1:a=1" out.mp4
    ```
    msg7086
        12
    msg7086  
       31 天前
    @lslqtz
    59.94 fps, 59.94 tbr, 59.94 tbn
    我这边 60/1.001 的都是这么显示的,不会显示 60 。
    msg7086
        13
    msg7086  
       31 天前
    @henix #5 压制参数有很多,然后其中很多是互相不兼容的,也就是一个视频里不能同时出现一段用这个参数另一段用那个参数。比如说 ref ,假如你前面片段用 ref3 ,然后解码器为 ref3 开了对应大小的帧缓冲区,然后你后面的片段用了 ref4 ,那跑的时候就会出现缓冲区读不到帧的情况,因为解码器是按照前面的设置 3 来初始化的。
    lslqtz
        14
    lslqtz  
       31 天前
    @msg7086 那我只能推测是丢帧, 因为最后生成的 ffprobe 有一个 metadata DURATION: 00:00:03.984000000, 它既不符合 59.94 也不符合 60fps.
    msg7086
        15
    msg7086  
       31 天前   ❤️ 1
    @lslqtz 239 帧 60fps 是 3.983333 ,考虑到 timebase 精度,3.984 算是正常范围。
    henix
        16
    henix  
    OP
       31 天前
    感谢各位回复!
    我刚才发现在完全不使用原始的 加载.mp4 的情况下依然会出现这个问题,可能是我的思考方向错了,今天被这个问题心态搞得有点绷不住。。。
    目前初步怀疑是最后一步 concat 之前会把一个大视频拆分成前后两段,后面那段 trim 之后没加 setpts 导致的(因为前面一段正好是 7s ,让我误以为是原始视频的 7s )
    有后续进展再更新
    yinmin
        17
    yinmin  
       31 天前
    试试下面这条切视频的指令:
    ffmpeg -ss 00:01:00 -to 00:10:00 -i in.mp4 -c copy out.mp4
    234ygg
        18
    234ygg  
       31 天前 via iPhone
    ffmpeg 有时候改变一下 option 的前后顺序,都能剪出来点略微不一样的东西😂 很烦
    emonber
        19
    emonber  
       30 天前
    -ss -to 放在 -i <input> 后面,这样时间似乎会精确一些。
    另外,可以查看下转码后的视频时间戳:ffmpeg -i <input> -vf showinfo -f null -
    512357301
        20
    512357301  
       30 天前 via Android
    遇事不决用 PR ,真的省心,个人无所谓正版盗版,先解决问题
    mumbler
        21
    mumbler  
       30 天前   ❤️ 1
    要精确剪辑,首先要增加视频关键帧密度
    ffmpeg -i input.mp4 -forced-idr 0.1 -c:v libx264 -keyint_min 10 -g 10 output.mp4
    这个命令会将输入视频重新编码,在每 0.1 秒插入一个关键帧,提高视频的关键帧密度。然后你再剪辑就可以精确到 0.1 秒了,这样视频体积会显著增大,当然你也可以每 1 秒增加关键帧
    chocotan
        22
    chocotan  
       30 天前
    -i 放前面去试试
    wnpllrzodiac
        23
    wnpllrzodiac  
       30 天前 via Android
    全部解码成帧,再编码一定没问题。想用 concat 就是会有奇怪问题的概率。非线编全是在操作帧,而不是视频片断,所以很吃资源。
    henix
        24
    henix  
    OP
       30 天前
    今天研究了一下,确实是最后一步的 concat 用的片段是 trim 之后没加 setpts ,之前有个回复提醒了我。

    最后一步修正之后的 filter_complex:

    ```
    "[fv]split[fv1][fv2]",
    "[fv1]trim=0:7[fv1t]",
    "[fv2]trim=7,setpts=PTS-STARTPTS[fv2t]",
    "[fa]asplit[fa1][fa2]",
    "[fa1]atrim=0:7[fa1t]",
    "[fa2]atrim=7,asetpts=PTS-STARTPTS[fa2t]",
    "[fv1t][fa1t][10:v][10:a][fv2t][fa2t]concat=3:1:1",
    ```

    现在已经正常了,感谢各位的讨论
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2645 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 15:07 · PVG 23:07 · LAX 07:07 · JFK 10:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.