使用OpenCV VideoWriter和Python BytesIO在内存中流式传输视频

scyqe7ek  于 2023-06-24  发布在  Python
关注(0)|答案(3)|浏览(177)

我想知道是否可以在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类来编写编码的视频,如果有,是如何完成的?
在这一点上我是新鲜的想法,所以任何帮助将是最受欢迎的:-)

7ajki6be

7ajki6be1#

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

zf9nrax1

zf9nrax12#

如果您想方便地加载已在内存中的视频,请使用临时文件:www.example.com 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将利用交换空间将文件放在磁盘上。
编辑更新
Kubernetes还允许您直接在Pod或Deployment上执行此操作。因此,您可以直接在容器的文件系统上创建一个TMPFS目录!

volumes:
- name: data
  emptyDir:
    medium: Memory
    sizeLimit: 64Mi
volumeMounts:
- mountPath: /tmp/data
  name: data
vmdwslir

vmdwslir3#

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

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

相关问题