gpt4 book ai didi

video - 与ffmpeg帧数不一致

转载 作者:行者123 更新时间:2023-12-04 22:46:23 37 4
gpt4 key购买 nike

我经常遇到 hvc1 视频在 ffprobe 信息和 FFmpeg 信息之间获取帧数不一致的问题,我想知道此问题的原因是什么,以及如何无需重新解决即可解决该问题对视频进行编码。

我用我拥有的测试视频编写了以下示例脚本

我将视频分成 5 秒的片段,我得到 ffprobe 给出的预期视频长度,但 FFmpeg 在除第一个片段之外的每个片段上给出的帧数比预期少 3 帧。

如果我按 10 秒分割或任何分割,问题完全相同,我总是会丢失 3 帧。

我注意到第一个片段总是比其他片段小 3 帧(在 ffprobe 上),并且它是唯一一致的片段。

这是我为测试此问题而编写的示例脚本:

# get total video frame number using ffprobe or ffmpeg
total_num_frames=$(ffprobe -v quiet -show_entries stream=nb_read_packets -count_packets -select_streams v:0 -print_format json test_video.mp4 | jq '.streams[0].nb_read_packets' | tr -d '"')
echo $total_num_frames
ffmpeg -hwaccel cuda -i test_video.mp4 -vsync 2 -f null -

# Check ffprobe of each segment is consistent
rm -rf clips && mkdir clips && \
ffmpeg -i test_video.mp4 -acodec copy -f segment -vcodec copy -reset_timestamps 1 -segment_time 5 -map 0 clips/part_%d.mp4
count_frames=0
for i in {0..5}
do
num_packets=$(ffprobe -v quiet -show_entries stream=nb_read_packets -count_packets -select_streams v:0 -print_format json clips/part_$i.mp4 | jq '.streams[0].nb_read_packets' | tr -d '"')
count_frames=$(($count_frames+$num_packets))
echo $num_packets $count_frames $total_num_frames
done

输出如下

3597
ffmpeg version 4.2.4-1ubuntu0.1 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 9 (Ubuntu 9.3.0-10ubuntu2)
configuration: --prefix=/usr --extra-version=1ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
libavutil 56. 31.100 / 56. 31.100
libavcodec 58. 54.100 / 58. 54.100
libavformat 58. 29.100 / 58. 29.100
libavdevice 58. 8.100 / 58. 8.100
libavfilter 7. 57.100 / 7. 57.100
libavresample 4. 0. 0 / 4. 0. 0
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test_video.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2mp41
encoder : Lavf58.29.100
Duration: 00:00:59.95, start: 0.035000, bitrate: 11797 kb/s
Stream #0:0(und): Video: hevc (Main) (hvc1 / 0x31637668), yuv420p(tv, bt709), 1920x1080, 11692 kb/s, 60.01 fps, 60 tbr, 19200 tbn, 19200 tbc (default)
Metadata:
handler_name : Core Media Video
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 91 kb/s (default)
Metadata:
handler_name : Core Media Audio
Stream mapping:
Stream #0:0 -> #0:0 (hevc (native) -> wrapped_avframe (native))
Stream #0:1 -> #0:1 (aac (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, null, to 'pipe:':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2mp41
encoder : Lavf58.29.100
Stream #0:0(und): Video: wrapped_avframe, nv12, 1920x1080, q=2-31, 200 kb/s, 60 fps, 60 tbn, 60 tbc (default)
Metadata:
handler_name : Core Media Video
encoder : Lavc58.54.100 wrapped_avframe
Stream #0:1(und): Audio: pcm_s16le, 44100 Hz, mono, s16, 705 kb/s (default)
Metadata:
handler_name : Core Media Audio
encoder : Lavc58.54.100 pcm_s16le
frame= 3597 fps=788 q=-0.0 Lsize=N/A time=00:00:59.95 bitrate=N/A speed=13.1x
video:1883kB audio:5162kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

然后

297 297 3597
300 597 3597
300 897 3597
300 1197 3597
300 1497 3597
300 1797 3597 <--- output are consistent based on ffprobe

但是如果我使用以下命令使用 ffmpeg 检查段大小

ffmpeg -hwaccel cuda -i clips/part_$i.mp4 -vsync 2 -f null - 

第 0 部分没问题

frame=  297 fps=0.0 q=-0.0 Lsize=N/A time=00:00:04.95 bitrate=N/A speed=12.5x    
video:155kB audio:424kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

对于所有其他部分,它不一致,应该是 300

frame=  297 fps=0.0 q=-0.0 Lsize=N/A time=00:00:04.95 bitrate=N/A speed=12.3x    
video:155kB audio:423kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

这个问题与任何其他间隔大小完全相同,例如 10 秒我会得到以下视频大小:

ffprobe 597 - 600 ...
ffmpeg 597 597 ...

我认为这可能与源 vfr 或 cfr 有关,但我尝试将输入转换为 cfr,但没有任何变化。

此外,我尝试每秒强制关键帧检查是否是关键帧问题,参数如下:-force_key_frames "expr:gte(t,n_forced*1)",但问题是完全相同的。

我做错了什么? hvc1 中的文件经常发生这种情况,我真的不知道如何处理。

最佳答案

差异的根源在于 FFprobe 会计算丢弃的数据包,而 FFmpeg 不会将丢弃的数据包计为帧。


您的结果与使用 3 个 B 帧(每个 P 帧或 I 帧有 3 个连续 B 帧)创建的视频流一致。

根据Wikipedia :

I‑frames are the least compressible but don't require other video frames to decode.
P‑frames can use data from previous frames to decompress and are more compressible than I‑frames.
B‑frames can use both previous and forward frames for data reference to get the highest amount of data compression.

将包含 P 帧和 B 帧的视频分割成多个片段而不重新编码时,依赖链会中断。

  • (几乎)总是有一些帧依赖于上一个片段或下一个片段中的帧。
  • 保留上述帧,但匹配的数据包被标记为“丢弃”(用 AV_PKT_FLAG_DISCARD 标志标记)。

为了处理同一数据集,我们构建了合成视频(用作输入)。

使用以下命令构建合成视频:

ffmpeg -y -r 60 -f lavfi -i testsrc=size=384x256:rate=1 -vf "setpts=N/60/TB" -g 60 -vcodec libx265 -x265-params crf=28:bframes=3:b-adapt=0 -tag:v hvc1 -pix_fmt yuv420p -t 20 test_video.mp4
  • -g 60 将 GOP 大小设置为 60 帧(每 60 帧插入一个关键帧)。
  • bframes=3:b-adapt=0 强制使用 3 个连续的 B 帧。

为了验证 I/P/B 帧的数量,我们可以使用 FFprobe:

ffprobe -i test_video.mp4 -show_frames -show_entries frame=pict_type

输出如下:

pict_type=I
pict_type=B
pict_type=B
pict_type=B
pict_type=P
pict_type=B
pict_type=B
pict_type=B
...


按时间分段视频(每段 5 秒):

ffmpeg -i test_video.mp4 -f segment -vcodec copy -reset_timestamps 1 -segment_time 5 clips/part_%d.mp4

FFprobe 计数:
297 1497 1200
300 1797 1200
300 2097 1200
303 2400 1200

FFmpeg 计数:
帧= 297
帧= 297
帧= 297
帧= 300

如您所见,结果与您的输出一致。


我们可以使用 FFprobe 识别“丢弃”的数据包:

ffprobe -i part_1.mp4 -show_packets

查找flags=_D
带有 flags=_D 的数据包被标记为“已丢弃”
注意:在视频流中,每个数据包都匹配一个帧。

FFprobe 输出开头为:
flags=K_
flags=_D
flags=_D
flags=_D
flags=__
flags=__
flags=__
...

对于每个中间段,有 3 个数据包被标记为“丢弃”,这就是 FFmpeg 与 FFprobe 相比丢失 3 个帧的原因。

关于video - 与ffmpeg帧数不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70578206/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com