标准Python中如何对memoryview对象使用ctypes.memmove
解决PySide6中处理后numpy数组转回QVideoFrame的内存复制问题
问题背景
使用PySide6捕获屏幕并拦截视频流,通过OpenCV处理帧后,需要将处理后的numpy数组转回QVideoFrame以输出视频流。目前已完成numpy转QImage的步骤,但在将QImage字节复制到QVideoFrame内存时遇到问题:QImage.bits()和QVideoFrame.bits()返回memoryview对象,无法通过bits()[0]获取内存指针,导致ctypes.memmove调用出错。
解决方案
无需依赖内存指针操作,直接利用Python标准的memoryview切片赋值即可完成字节复制,完全兼容标准Python环境(无需CPython特定API)。具体实现步骤如下:
- 确保QVideoFrame已通过
map(QVideoFrame.ReadWrite)完成内存映射 - 获取QVideoFrame和QImage对应的memoryview对象
- 通过切片赋值将QImage的字节数据直接复制到QVideoFrame的内存区域
- 完成复制后必须调用
unmap()解除内存映射,避免资源泄漏
完整代码示例
import cv2 import numpy as np from PySide6.QtMultimedia import QVideoFrame, QVideoFrameFormat from PySide6.QtGui import QImage # 假设arr是OpenCV处理后的numpy数组 arr = cv2.cvtColor(arr, cv2.COLOR_BGR2RGBA) # 从numpy数组创建QImage image = QImage(arr.data, arr.shape[1], arr.shape[0], QImage.Format.Format_RGBA8888) # 创建与QImage匹配的QVideoFrame格式 format_ = QVideoFrameFormat( image.size(), QVideoFrameFormat.pixelFormatFromImageFormat(image.format()) ) frame2 = QVideoFrame(format_) # 映射QVideoFrame到可读写内存 if frame2.map(QVideoFrame.ReadWrite): try: # 获取两个对象的memoryview frame_memory = frame2.bits() image_memory = image.bits() # 直接复制字节数据 frame_memory[:image.sizeInBytes()] = image_memory[:image.sizeInBytes()] finally: # 务必解除映射,释放资源 frame2.unmap() # 处理后的frame2可用于视频流输出
注意事项
- 确保QVideoFrame的像素格式与QImage完全一致,否则会导致画面显示异常
- 必须在
try...finally块中执行unmap(),即使复制过程中出现异常也能正确释放内存 - memoryview的切片赋值是Python标准操作,无需依赖任何第三方库或CPython私有API
内容的提问来源于stack exchange,提问作者Edward Spencer
相关产品推荐
相关产品推荐

