首页 > 解决方案 > How to use stdout.write in python3 when piping to ffmpeg?

问题描述

My main goal for this project I'm working on is to use a python script to get any webcam footage, edit it with opencv, and then pipe the edited video frames with ffmpeg to a dummy webcam from v4l2loopback. Here's the sample code I made that runs exactly as I want to on 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()

and then run it with

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

However, I want it to work with python3 instead of 2.7, and I found a way to make it work where I replace the "sys.stdout..." line with

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

This works well, except that it only runs at 14 fps while the 2.7 code could run at 30. I'm kind of at a loss as to how to fix this issue/ what this issue exactly is. I'm running this on a raspberry pi if that helps. Thanks so much!

标签: python-3.xopencvffmpegstdoutv4l2loopback

解决方案


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

因为您的问题的标题是“如何在 python3 中使用 stdout.write 在管道到 ffmpeg 时?”,我将首先回答这个问题:

sys.stdout.buffer.write(data)

这就是你的做法。

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

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

如何快速写入标准输出?

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

让我们检查一下(使用分析器),您的 python 脚本在哪里花时间做事:

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 个函数。对我来说,这返回:

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 加快视频抓取速度。

不幸的是,我不能回答那个;-)


推荐阅读