Vas*_*dis 2 python video opencv ffmpeg
跑步:
ffmpeg -i test.ts -fflags +genpts -c copy -y test.mp4
Run Code Online (Sandbox Code Playgroud)
对于这个test.ts,它有 30 个帧,可以由 opencv 读取,我最终得到 28 个帧,其中 27 个帧可以由 opencv 读取。进一步来说:
ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 tmp.ts
Run Code Online (Sandbox Code Playgroud)
返回 30。
ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 tmp.mp4
Run Code Online (Sandbox Code Playgroud)
返回 28。
以这种方式使用 OpenCV
cap = cv2.VideoCapture(tmp_path)
readMat = []
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
readMat.append(frame)
Run Code Online (Sandbox Code Playgroud)
我得到 ts 文件 30 帧,而 mp4 得到 27 帧。
有人可以解释为什么存在差异吗?从 ts 转换为 mp4 期间没有出现错误:
ffmpeg version N-111746-gd53acf452f Copyright (c) 2000-2023 the FFmpeg developers
built with gcc 11.3.0 (GCC)
configuration: --ld=g++ --bindir=/bin --extra-libs='-lpthread -lm' --pkg-config-flags=--static --enable-static --enable-gpl --enable-libaom --enable-libass --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libsvtav1 --enable-libdav1d --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-nonfree --enable-cuda-nvcc --enable-cuvid --enable-nvenc --enable-libnpp
libavutil 58. 16.101 / 58. 16.101
libavcodec 60. 23.100 / 60. 23.100
libavformat 60. 10.100 / 60. 10.100
libavdevice 60. 2.101 / 60. 2.101
libavfilter 9. 10.100 / 9. 10.100
libswscale 7. 3.100 / 7. 3.100
libswresample 4. 11.100 / 4. 11.100
libpostproc 57. 2.100 / 57. 2.100
[mpegts @ 0x4237240] DTS discontinuity in stream 0: packet 5 with DTS 306003, packet 6 with DTS 396001
Input #0, mpegts, from 'tmp.ts':
Duration: 00:00:21.33, start: 3.400000, bitrate: 15 kb/s
Program 1
Metadata:
service_name : Service01
service_provider: FFmpeg
Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(progressive), 300x300, 1 fps, 3 tbr, 90k tbn
Output #0, mp4, to 'test.mp4':
Metadata:
encoder : Lavf60.10.100
Stream #0:0: Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 300x300, q=2-31, 1 fps, 3 tbr, 90k tbn
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
[out#0/mp4 @ 0x423e280] video:25kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 4.192123%
frame= 30 fps=0.0 q=-1.0 Lsize= 26kB time=00:00:21.00 bitrate= 10.3kbits/s speed=1e+04x
Run Code Online (Sandbox Code Playgroud)
我正在处理的视频的起源来自于静态图像ts视频的连续拼接操作,由此类update方法产生:
ffmpeg -i test.ts -fflags +genpts -c copy -y test.mp4
Run Code Online (Sandbox Code Playgroud)
这是因为 DTS 时间存在不连续性:
你说:
有人可以解释为什么存在差异吗?从 ts 转换为 mp4 期间没有出现错误:
但错误就在这里:
[mpegts @ 0x4237240] 流 0 中的 DTS 不连续:数据包 5 具有 DTS 306003,数据包 6 具有 DTS 396001
持续时间:00:00:21.33,开始时间:3.400000
使用ffprobe -show_frames
分/分_时间
306000 3.4
306001 3.400011
306000 3.4
306001 3.400011
396000 4.4
306003 3.400033
396001 4.400011
396002 4.400022
396003 4.400033
396004 4.400044
486004 5.400044
576004 6.400044
666004 7.400044
756004 8.400044
846004 9.400044
936004 10.400044
1026004 11.400044
1116004 12.400044
1206004 13.400044
1296004 14.400044
1386004 15.400044
1476004 16.400044
1566004 17.400044
1656004 18.400044
1746004 19.400044
1836004 20.400044
1926004 21.400044
2016004 22.400044
2106004 23.400044
2196004 24.400044
Run Code Online (Sandbox Code Playgroud)
不过,即使你使用-fflags +igndts,我也只能得到 29 帧。问题本身出在 .TS 文件中,并且您可以在第一帧中看到时间戳存在 DTS 不连续性。
在尝试让它忽略时间戳后,一切仍然为我产生 29 帧,而不是 FFMPEG 的 30 帧。可能我还缺少其他东西,但我不大量使用 FFMPEG。
我尝试了可以在以下位置找到的内容:
https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts
https://ffmpeg.org/ffmpeg.html#toc-Advanced-options
我尝试过:
-fps_mode passthrough
Run Code Online (Sandbox Code Playgroud)
29帧
-vf "setpts='(RTCTIME - RTCSTART) / (TB * 1000000)'"
Run Code Online (Sandbox Code Playgroud)
29帧
-vf "asetpts=N/SR/TB"
Run Code Online (Sandbox Code Playgroud)
29帧
-copytb -1 -copyts -start_at_zero -fps_mode passthrough -dts_delta_threshold 1000000 -dts_error_threshold 1440000
Run Code Online (Sandbox Code Playgroud)
29帧
另请注意,如果您尝试使用:
306000 3.4
306001 3.400011
306000 3.4
306001 3.400011
396000 4.4
306003 3.400033
396001 4.400011
396002 4.400022
396003 4.400033
396004 4.400044
486004 5.400044
576004 6.400044
666004 7.400044
756004 8.400044
846004 9.400044
936004 10.400044
1026004 11.400044
1116004 12.400044
1206004 13.400044
1296004 14.400044
1386004 15.400044
1476004 16.400044
1566004 17.400044
1656004 18.400044
1746004 19.400044
1836004 20.400044
1926004 21.400044
2016004 22.400044
2106004 23.400044
2196004 24.400044
Run Code Online (Sandbox Code Playgroud)
OpenCV 从视频中读取的帧总数仅为 21 帧,因为 OpenCV 只读取文件所说的内容。因此,如果您使用上面的方法,它只会产生 21 帧。.TS 文件本身的 pts 时间戳存在问题,因此TimeLength * FramesPerSecond = TotalFramesOpenCV 查询以推断总帧数的计算结果出现偏差。
正如您所指出的,使用普遍存在的“成功时”方法确实会产生完整的 30 帧。
我不会使用 FFMPEG 本身来提取帧,而只是依赖 OpenCV 方法,因为这似乎不是 FFMPEG 中的错误,而是编码库的一个功能,用于丢弃具有错误时间戳的帧。
-fps_mode passthrough
Run Code Online (Sandbox Code Playgroud)
帧数:30