简体   繁体   English

为什么 OpenCV 读取视频比 FFMPEG 快?

[英]Why does OpenCV read video faster than FFMPEG?

I noticed that OpenCV reads video frames almost 2x faster than FFMPEG.我注意到 OpenCV 读取视频帧的速度几乎比 FFMPEG 快 2 倍。

Why is that?这是为什么? I thought all OpenCV does is call FFMPEG under the hood, possibly adding its own overhead.我认为所有 OpenCV 所做的都是在引擎盖下调用 FFMPEG,可能会增加它自己的开销。

Here's the code I use to obtain these results这是我用来获得这些结果的代码

import cv2
import time
import numpy as np

cap = cv2.VideoCapture("BigBuckBunny.mp4", apiPreference=cv2.CAP_FFMPEG)
frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

start = time.perf_counter()
while True:
    ret, frame = cap.read()
    if ret is False:
        break
    assert frame.shape == (720, 1280, 3)
    assert frame.dtype == np.uint8
end = time.perf_counter()

print(f"{frames/(end-start):.1f} frames per second")
# Output: 692.3 frames per second

cap.release()

For FFMPEG (using the python-ffmpeg library:对于 FFMPEG(使用python-ffmpeg库:

import ffmpeg
import numpy as np
import time

vid_info = ffmpeg.probe("BigBuckBunny.mp4")['streams'][1]
frames = int(vid_info['nb_frames'])

process1 = (
    ffmpeg
    .input("BigBuckBunny.mp4")
    .output('pipe:', format='rawvideo', pix_fmt='bgr24')
)
print(process1.compile())
# Output: ['ffmpeg', '-i', 'BigBuckBunny.mp4', '-f', 'rawvideo', '-pix_fmt', 'bgr24', 'pipe:']


process1 = process1.run_async(pipe_stdout=True)

start = time.perf_counter()
while True:
    in_bytes = process1.stdout.read(1280 * 720 * 3)
    if not in_bytes:
        break
    frame = np.frombuffer(in_bytes, np.uint8).reshape([720, 1280, 3])
end = time.perf_counter()
print(f"{frames/(end-start):.1f} frames per second")
# Output: 373.6 frames per second
process1.wait()

Here's information about the video (~10 minutes length)这是有关视频的信息(约 10 分钟长度)

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'BigBuckBunny.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isomavc1mp42
    creation_time   : 2010-01-10T08:29:06.000000Z
  Duration: 00:09:56.47, start: 0.000000, bitrate: 2119 kb/s
  Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
    Metadata:
      creation_time   : 2010-01-10T08:29:06.000000Z
      handler_name    : (C) 2007 Google Inc. v08.13.2007.
      vendor_id       : [0][0][0][0]
  Stream #0:1(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1991 kb/s, 24 fps, 24 tbr, 24k tbn, 48 tbc (default)
    Metadata:
      creation_time   : 2010-01-10T08:29:06.000000Z
      handler_name    : (C) 2007 Google Inc. v08.13.2007.
      vendor_id       : [0][0][0][0]

And FFMPEG and OpenCV versions:以及 FFMPEG 和 OpenCV 版本:

ffmpeg version 4.4.2-0ubuntu0.22.04.1 Copyright (c) 2000-2021 the FFmpeg developers
opencv-python-headless        4.6.0.66

It may be due to the fact how the libraries are implemented and the overhead of pipes.这可能是由于库的实现方式和管道的开销。

  1. cv2简历2

cv2 implemented in c++ and uses libavcodec library (part of ffmpeg) for decoding frames: cv2 在 c++ 中实现,并使用libavcodec库(ffmpeg 的一部分)来解码帧:

https://github.com/opencv/opencv/blob/97c6ec6d49cb78321eafe6fa220ff80ebdc5e2f4/modules/videoio/src/cap_ffmpeg_impl.hpp#L1299 https://github.com/opencv/opencv/blob/97c6ec6d49cb78321eafe6fa220ff80ebdc5e2f4/modules/videoio/src/cap_ffmpeg_impl.hpp#L1299

cv2 does not use ffmpeg as binary executable and uses the part of ffmpeg specifically designed for reading/decoding frames. cv2 不使用ffmpeg作为二进制可执行文件,而是使用专为读取/解码帧而设计的 ffmpeg 的一部分。

  1. ffmpeg-python is a wrapper around ffmpeg executable (which in turn uses libavcodec under the hood too) that calls ffmpeg with subprocess and returns results through the pipes. ffmpeg-python是 ffmpeg 可执行文件的包装器(它又在后台使用libavcodec ),它使用subprocess进程调用ffmpeg并通过管道返回结果。

Good stuff.好东西。 Interestingly, under Windows 10 & FFmpeg 5.0.1, my results are the reverse of yours (but much closer):有趣的是,在 Windows 10 & FFmpeg 5.0.1 下,我的结果与你的相反(但更接近):

  • OpenCV: 491.9 frames per second OpenCV: 491.9 frames per second
  • FFmpeg-Python: 519.4 frames per second FFmpeg-Python: 519.4 frames per second

And out of curiosity, I tried my ffmpegio package to see how much overhead it incurs, it came out: 507.5 frames per second (code below) Both FFmpeg-Python and FFmpegIO scoring in the same ballpark indicates these numbers aren't fluke.出于好奇,我尝试了我的ffmpegio package 来查看它会产生多少开销,结果是: 507.5 frames per second (代码如下) FFmpeg-Python 和 FFmpegIO 在同一个球场上的得分表明这些数字并非侥幸。

So, it's likely Win/Linux or 4.4/5.0 differences or both.因此,很可能是 Win/Linux 或 4.4/5.0 差异或两者兼而有之。 I retested FFmpeg-Python with FFmpeg 4.4.1 and got: 428.1 frames per second (log reporting speed=17.9x down from x21.7 . I'd say FFmpeg devs optimized the color conversion codebase in v5 releases to match or surpass OpenCV. (Or the tested OpenCV version uses the libav libraries associated with FFmpeg v5) I retested FFmpeg-Python with FFmpeg 4.4.1 and got: 428.1 frames per second (log reporting speed=17.9x down from x21.7 . I'd say FFmpeg devs optimized the color conversion codebase in v5 releases to match or surpass OpenCV. (或者测试的 OpenCV 版本使用与libav v5 关联的 libav 库)

test_ffmpegio.py

import ffmpegio
import time

frames = ffmpegio.probe.video_streams_basic("BigBuckBunny.mp4")[0]['nb_frames']

print(frames)

with ffmpegio.open("BigBuckBunny.mp4",'rv') as f:
    start = time.perf_counter()
    for frame in f:
        pass # frame is 1x1280x720x3 rgb np array
    end = time.perf_counter()

print(f"{frames/(end-start):.1f} frames per second")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM