JS S
JS S

Reputation: 338

(PyQt6) How can I write bytes to memory using sip.voidptr?

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!

Edit 1

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()

Edit 2

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

Answers (1)

JS S
JS S

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

Related Questions