添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
不拘小节的牛排  ·  C# WPF ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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]
>>> arr[0] = 255
>>> arr[0]

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.

You could try to follow a procedure similar to this one. I suppose that the size has to be set using QVideoFrame.mappedBytes(). – musicamante Feb 2 at 1:12 I don't have lot of experience with SIP and memory access, but I believe it's possible that SIP arrays don't properly implement the slice argument of __getitem__(), and revert to the default behavior that just maps values as integers. I'd suggest you to write to the PyQt mailing list, providing a valid minimal reproducible example. – musicamante Feb 2 at 2:20

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

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.