管道传输到 ffmpeg 时如何在 python3 中使用 stdout.write?

How to use stdout.write in python3 when piping to ffmpeg?

我正在从事的这个项目的主要目标是使用 python 脚本获取任何网络摄像头素材,使用 opencv 对其进行编辑,然后使用 ffmpeg 将编辑后的视频帧传输到虚拟网络摄像头来自 v4l2loopback。这是我在 python 2.7:

上完全按照我想要的方式制作的示例代码

import cv2
import subprocess as sp
import sys

cap = cv2.VideoCapture(1)

cv2.namedWindow('result', cv2.WINDOW_AUTOSIZE)

while True:
    ret, frame = cap.read()
    cv2.imshow('result', frame)

    sys.stdout.write(frame.tostring())

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

然后 运行 它与

python pySample.py | ffmpeg -f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 -i - -vf format=yuv420p -f v4l2 /dev/video17

但是,我希望它与 python3 而不是 2.7 一起工作,并且我找到了一种方法来使其工作,我将“sys.stdout...”行替换为

sys.stdout.buffer.write(frame.tobytes())

这很好用,除了它在 14 fps 时只有 运行s 而 2.7 代码可​​以在 30 fps 运行。我有点不知道如何解决这个问题/ 这个问题究竟是什么。如果有帮助,我会 运行 在 raspberry pi 上解决这个问题。非常感谢!

当管道传输到 ffmpeg 时,如何在 python3 中使用 stdout.write?

由于您的问题标题为“当管道传输到 ffmpeg 时如何在 python3 中使用 stdout.write?”,我将首先回答:

sys.stdout.buffer.write(data)

这就是你的做法。

你已经知道了(因为我已经从你的问题中得到了答案),所以我想这不是你真正想问的。

所以你真正的问题似乎是:

如何写入标准输出快速?

然而,这意味着您认为写入 stdout 很慢。为什么? (很可能是因为您更改的唯一一行处理写入标准输出)。

让我们检查一下(使用分析器),您的 python-script 花时间做事的地方:

python3 -m cProfile -o pySample.prof pySample.py | ffmpeg -f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 -i - -vf format=yuv420p -f v4l2 /dev/video17

这将创建一个包含所有呼叫信息的 pySample.prof 文件。我们可以检查它:

import pstats
pstats.Stats("pySample.prof").sort_stats(pstats.SortKey.TIME).print_sorted(5)

这将为我们提供 运行 脚本时消耗最多时间的 5 个函数。 对我来说这个 returns:

Mon Nov 16 14:40:40 2020    pySample.prof

         70698 function calls (68335 primitive calls) in 49.782 seconds

   Ordered by: internal time
   List reduced from 881 to 5 due to restriction <5>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      490   40.614    0.083   40.614    0.083 {method 'read' of 'cv2.VideoCapture' objects}
      490    3.813    0.008    3.813    0.008 {method 'write' of '_io.BufferedWriter' objects}
      490    2.334    0.005    2.334    0.005 {waitKey}
      490    1.238    0.003    1.238    0.003 {method 'tobytes' of 'numpy.ndarray' objects}
        1    0.913    0.913   49.783   49.783 pySample.py:1(<module>)

现在这很有趣。 它基本上告诉我们,python花了很多时间从视频设备读取数据,只有很少时间写入它到输出(并将其转换为字节)。

所以你的问题应该是:我如何使用 OpenCV 加速视频抓取。

很遗憾,我无法回答 那个 ;-)