Reputation: 338
I want to fill the pixel data of an empty QVideoFrame
instance. In PySide6, the bits(0)
method returns a memory view and I can directly modify it by slicing and assigning. But in PyQt6, sip.voidptr
is returned instead and I can't figure out how should I deal with it!
I am not really familiar with Python C bindings. Is there any way to easily access the memory using voidptr
? Thanks in advance!
Here is a sample code.
from PyQt6 import QtCore, QtMultimedia
pfmt = QtMultimedia.QVideoFrameFormat.PixelFormat.Format_Y8
ffmt = QtMultimedia.QVideoFrameFormat(QtCore.QSize(1280, 1024), pfmt)
vf = QtMultimedia.QVideoFrame(ffmt)
vf.map(QtMultimedia.QVideoFrame.MapMode.ReadWrite)
# Data manipulation should come here.
vf.unmap()
Ok, I found out that voidptr
can be converted to an array by passing the size of the video frame.
In the comment location of the code above,
>>> size = vf.bytesPerLine(0)*vf.height()
>>> vf.bits(0).asarray(size)
PyQt6.sip.array(unsigned char, 1310720)
Modifying a single pixel works fine.
>>> arr = vf.bits(0).asarray(vf.bytesPerLine(0)*vf.height())
>>> arr[0]
0
>>> arr[0] = 255
>>> arr[0]
255
But assigning the bytes to sip.array
raised error.
>>> data = bytes(255 for _ in range(size))
>>> arr[:] = data
TypeError: can only assign another array of unsigned char to the slice
Answers in another question raised same error.
Upvotes: 1
Views: 445
Reputation: 338
Thanks to @musicamante I managed to find the solution. It seems that voidptr
can be directly accessed to write the bytes, provided that its size is known. QVideoFrame.bits()
returns voidptr
with unknown size (perhaps it is a bug of PyQt) so I had to manually set the size from QVideoFrame.mappedBytes
.
Here is the full code:
from PyQt6 import QtCore, QtMultimedia
pfmt = QtMultimedia.QVideoFrameFormat.PixelFormat.Format_Y8
ffmt = QtMultimedia.QVideoFrameFormat(QtCore.QSize(1280, 1024), pfmt)
vf = QtMultimedia.QVideoFrame(ffmt)
vf.map(QtMultimedia.QVideoFrame.MapMode.ReadWrite)
ptr = frame.bits(0)
ptr.setsize(frame.mappedBytes(0))
ptr[:] = bytes(255 for _ in range(size))
vf.unmap()
Upvotes: 1