You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FFmpeg与ytdl-core混流最高音视频生成MP4时长异常问题

问题描述

我用ytdl-core获取分离的视频和音频文件,想把它们合并成MP4并流式传输到响应里。用highestvideo和highestaudio质量参数获取文件,修改了ytdl-core-muxer模块把输出改成MP4,加了-movflags frag_keyframe+empty_moov让MP4支持拖拽。操作没报错,生成了MP4文件,但用Windows Photos打开时,视频播放正常、画质没问题,时长显示完全错误——实际时长1分32秒,但剩余时长显示约5300万小时。

我试过加固定帧率参数-r 60、生成时间戳参数-fflags +genpts,没用;也试过把视频转成h264(用libx264)、音频转成aac,问题还是没解决。

我的FFmpeg调用代码

// create the ffmpeg process for muxing
const ffmpegProcess = cp.spawn(
  ffmpeg,
  [
    // input audio by pipe
    "-thread_queue_size", "4096",
    "-i", "pipe:3",

    // input video by pipe
    "-thread_queue_size", "4096",
    "-r", "60",
    "-i", "pipe:4",

    // map audio and video correspondingly
    "-map", "0:a",
    "-map", "1:v",

    // change the codec
    "-c:v", "libx264", 
    "-c:a", "aac",
        
    "-preset", "ultrafast",

    // Allow output to be seekable, which is needed for mp4 output
    "-movflags", "frag_keyframe+empty_moov",

    // output mp4 and pipe
    "-r", "60",
    "-fflags", "+genpts",
    "-f", "mp4", "pipe:5",
  ],
  {
    // no popup window for Windows users
    windowsHide: true,
    stdio: [
      // silence stdin/out, forward stderr,
      "inherit", "inherit", "inherit",
      // and pipe audio, video, output
      "pipe", "pipe", "pipe",
    ],
  }
);
audioStream.pipe(ffmpegProcess.stdio[3]);
videoStream.pipe(ffmpegProcess.stdio[4]);
ffmpegProcess.stdio[5].pipe(result);

FFmpeg完整控制台输出

ffmpeg version 5.0.1-essentials_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers        
  built with gcc 11.2.0 (Rev7, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp 
--enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx 
--enable-libass --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'pipe:3':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2022-08-21T19:56:49.000000Z
  Duration: 00:01:32.11, start: 0.000000, bitrate: N/A
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], 1892 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
    Metadata:
      creation_time   : 2022-08-21T19:56:49.000000Z
      handler_name    : ISO Media file produced by Google Inc. Created on: 08/21/2022.
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)    
  Metadata:
      creation_time   : 2022-08-21T19:56:49.000000Z
      handler_name    : ISO Media file produced by Google Inc. Created on: 08/21/2022.
      vendor_id       : [0][0][0][0]
Input #1, matroska,webm, from 'pipe:4':
  Metadata:
    encoder         : google/video-file
  Duration: 00:01:32.12, start: 0.000000, bitrate: N/A
  Stream #1:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 3840x2160, SAR 1:1 DAR 16:9, 60 fps, 60 
tbr, 1k tbn (default)
Stream mapping:
  Stream #0:1 -> #0:0 (aac (native) -> aac (native))
  Stream #1:0 -> #0:1 (vp9 (native) -> h264 (libx264))
[libx264 @ 0000022aa059be80] using SAR=1/1
[libx264 @ 0000022aa059be80] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2      
[libx264 @ 0000022aa059be80] profile Constrained Baseline, level 5.2, 4:2:0, 8-bit
[libx264 @ 0000022aa059be80] 264 - core 164 r3094 bfc87b7 - H.264/MPEG-4 AVC codec - Copyleft 2003-2022 
- http://www.videolan.org/x264.html - options: cabac=0 ref=1 deblock=0:0:0 analyse=0:0 me=dia subme=0 psy=1 psy_rd=1.00:0.00 mixed_ref=0 me_range=16 chroma_me=1 trellis=0 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=0 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=0 weightp=0 keyint=250 keyint_min=25 scenecut=0 intra_refresh=0 rc=crf mbtree=0 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=0
Output #0, mp4, to 'pipe:5':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    encoder         : Lavf59.16.100
  Stream #0:0(eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)     
    Metadata:
      creation_time   : 2022-08-21T19:56:49.000000Z
      handler_name    : ISO Media file produced by Google Inc. Created on: 08/21/2022.
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.18.100 aac
  Stream #0:1(eng): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 3840x2160 [SAR 1:1 DAR 16:9], q=2-31, 60 fps, 15360 tbn (default)
    Metadata:
      encoder         : Lavc59.18.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
[matroska,webm @ 0000022aa056cd00] Thread message queue blocking; consider raising the thread_queue_size option (current value: 4096)
frame= 5527 fps= 77 q=-1.0 Lsize=  424599kB time=00:01:32.11 bitrate=37761.2kbits/s speed=1.29x    
video:423226kB audio:1329kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.010570%
[aac @ 0000022aa05ca240] Qavg: 17828.035
[libx264 @ 0000022aa059be80] frame I:23    Avg QP:19.83  size:292044
[libx264 @ 0000022aa059be80] frame P:5504  Avg QP:22.92  size: 77519
[libx264 @ 0000022aa059be80] mb I  I16..4: 100.0%  0.0%  0.0%
[libx264 @ 0000022aa059be80] mb P  I16..4: 26.5%  0.0%  0.0%  P16..4: 14.1%  0.0%  0.0%  0.0%  0.0%    skip:59.3%
[libx264 @ 0000022aa059be80] coded y,uvDC,uvAC intra: 10.6% 27.6% 7.0% inter: 6.5% 12.8% 1.4%
[libx264 @ 0000022aa059be80] i16 v,h,dc,p: 57% 26%  8%  9%
[libx264 @ 0000022aa059be80] i8c dc,h,v,p: 43% 24% 25%  7%
[libx264 @ 0000022aa059be80] kb/s:37637.70
解决方案

问题出在empty_moov标记上:它会让FFmpeg不写入包含时长等核心元数据的完整moov原子,Windows Photos这类播放器依赖这个原子读取正确时长。要同时支持流式拖拽和正确显示时长,调整参数即可:

  1. 替换movflags参数:把-movflags frag_keyframe+empty_moov改成-movflags frag_keyframe+faststart。faststart会把moov原子移到文件开头,既支持流式拖拽,又保留了完整的时长元数据。
  2. 移除重复参数:删除输出部分的-r 60,输入里指定一次帧率就足够。
  3. 可选优化:在音频输入参数里加-vn,明确忽略音频流里附带的视频轨道,避免潜在干扰。

修改后的FFmpeg参数数组:

[
  // input audio by pipe,明确忽略视频轨道
  "-thread_queue_size", "4096",
  "-vn", "-i", "pipe:3",

  // input video by pipe
  "-thread_queue_size", "4096",
  "-i", "pipe:4",

  // map audio and video correspondingly
  "-map", "0:a",
  "-map", "1:v",

  // change the codec
  "-c:v", "libx264", 
  "-c:a", "aac",
      
  "-preset", "ultrafast",

  // 支持流式拖拽且保留完整元数据
  "-movflags", "frag_keyframe+faststart",

  // 确保时间戳正确
  "-fflags", "+genpts",
  "-f", "mp4", "pipe:5",
]

内容的提问来源于stack exchange,提问作者Niek Peters

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 01:20:37