【问题标题】:Streaming video in memory with OpenCV VideoWriter and Python BytesIO使用 OpenCV VideoWriter 和 Python BytesIO 在内存中流式传输视频
【发布时间】:2018-12-05 17:29:35
【问题描述】:

我想知道是否可以在 Python 中使用 OpenCV VideoWriter 类“流式传输”数据?

通常为了处理内存中的数据,否则我会使用 BytesIO(或 StringIO)。

我尝试使用 BytesIO 失败了:

import cv2
from io import BytesIO

stream = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc('x264')

data = BytesIO()

# added these to try to make data appear more like a string
data.name = 'stream.{}'.format('av1')
data.__str__ = lambda x: x.name

try:
    video = cv2.VideoWriter(data, fourcc=fourcc, fps=30., frameSize=(640, 480))
    start = data.tell()

        # Check if camera opened successfully
        if (stream.isOpened() == False): 
            print("Unable to read camera feed", file=sys.stderr)
            exit(1)

        # record loop
        while True:
            _, frame = stream.read()
            video.write(frame)
            data.seek(start)
            # do stuff with frame bytes
            # ...

            data.seek(start)

    finally:
        try:
            video.release()
        except:
            pass
finally:
    stream.release()

但是,我没有编写 BytesIO 对象,而是得到以下消息:

Traceback (most recent call last):
  File "video_server.py", line 54, in talk_to_client
    video = cv2.VideoWriter(data, fourcc=fourcc, fps=fps, frameSize=(width, height))
TypeError: Required argument 'apiPreference' (pos 2) not found

...所以当我将 VideoWriter 调用修改为 cv2.VideoWriter(data, apiPreference=0, fourcc=fourcc, fps=30., frameSize=(640, 480))(我读到 0 表示自动,但我也尝试过 cv2.CAP_FFMPEG)时,我得到以下错误:

Traceback (most recent call last):
  File "video_server.py", line 54, in talk_to_client
    video = cv2.VideoWriter(data, apiPreference=0, fourcc=fourcc, fps=fps, frameSize=(width, height))
TypeError: bad argument type for built-in operation

所以我的问题是,是否可以在内存中使用cv2.VideoWriter 类编写编码视频,如果可以,它是如何完成的?

在这一点上,我的想法很新鲜,所以欢迎任何帮助:-)

【问题讨论】:

  • 您是否尝试在不写入磁盘的情况下对视频进行编码?这在 OpenCV 中是不可能的。

标签: python opencv video-streaming cv2 in-memory


【解决方案1】:

不幸的是,OpenCV 不支持对内存进行编码(或解码)。您必须写入(或读取)磁盘才能使 VideoWriter(或 VideoCapture)工作。

【讨论】:

  • 我担心是这样的。我想在通过网络传输之前对视频进行编码以减少发送的数据量,但是我试图避免将数据写入磁盘......我想我会回退到通过网络发送单个图像。
  • 是的,很遗憾 OpenCV 不支持这个功能,因为我确信它会被大量使用。
【解决方案2】:

如果您想方便地加载已在内存中的视频,请使用临时文件:https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile

import tempfile
import cv2

my_video_bytes = download_video_in_memory()

with tempfile.NamedTemporaryFile() as temp:
   temp.write(my_video_bytes)

   video_stream = cv2.VideoCapture(temp.name)

   # do your stuff.

不幸的是,这仍然会在磁盘上创建一个文件。但是,嘿,至少您不必自己管理。有一个 SpooledTemporaryFile() 实现将保留在内存中,但不幸的是,它不会创建 OpenCV 可以引用的文件系统名称。

编辑更新:

进一步探索 Linux 界面,看起来您可以通过使用 tmpfs 实用程序来充分利用临时文件并将其仅存在于内存中。

在 Ubuntu 机器上测试,未指定 dir 的 NamedTemporaryFile() 对象将遵循 TMPDIR(它恰好指向我机器上的 /tmp。现在,不确定其他操作系统,但我的机器确实没有使用tmpfs 挂载/tmp。它已挂载在主分区上。

但是,像这样创建自己的“内存文件系统”非常容易:sudo mount -t tmpfs -o size=1G tmpfs my_folder

如果我们检查df my_folder -h 的输出,我会看到:

Filesystem      Size  Used Avail Use% Mounted on
tmpfs           1.0G     0  1.0G   0% my_folder

太邪恶了!!

所以现在如果我在 Python 中这样做:

with tempfile.NamedTemporaryFile(dir="my_folder") as temp:

我刚刚在 linux 中使用mkstemp 在完全内存文件系统中创建了一个临时文件。当然,我确实承担了将数据从我的 python 内存复制到另一个内存位置的成本。但是,嘿,在大文件上,这可能比写入磁盘便宜。

确保您的内存文件系统有足够的内存来保存视频文件,否则tmpfs 将利用交换空间将文件放在磁盘上。

【讨论】:

    【解决方案3】:

    如果你使用 Linux,你可以创建一个 ramdisk 并写入它。

    mount -t tmpfs -o size=512m tmpfs /mnt/ramdisk
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-21
      • 2019-08-04
      • 2019-10-16
      • 2021-01-02
      • 2023-01-16
      • 2017-06-07
      • 2016-11-01
      相关资源
      最近更新 更多