问题
*I am trying to display preview from webcam captured using v4l.
Here is an idea of how the code looks like:
from ctypes import *
from v4l2 import *
from Image import fromstring
from Tkinter import Tk, Label
from ImageTk import PhotoImage
from ctypes.util import find_library
libc = CDLL(find_library('c'))
posix_memalign = libc.posix_memalign
getpagesize = libc.getpagesize
device_name = '/dev/video0'
ps = preview_settings = {
'width': 320,
'height': 240,
'pixformat': 'RGB',
}
PIX_FMT = V4L2_PIX_FMT_RGB555
preview = Tk()
image = PhotoImage(ps['pixformat'], (ps['width'], ps['height']))
label = Label(preview, text='Preview', image=image, width=ps['width'], height=ps['height'])
label.pack()
capability = v4l2_capability()
size = v4l2_frmsizeenum()
format = v4l2_format()
request = v4l2_requestbuffers()
buffer = v4l2_buffer()
b_address = c_void_p()
frame_name_count = '0'
type = V4L2_BUF_TYPE_VIDEO_CAPTURE
device = open(device_name, 'rw')
ioctl(device, VIDIOC_QUERYCAP, addr(capability))
size.pixel_format = PIX_FMT
size.index = 0
format.type = type
format.fmt.pix.pixelformat = PIX_FMT
format.fmt.pix.width = size.discrete.width
format.fmt.pix.height = size.discrete.height
format.fmt.pix.field = V4L2_FIELD_NONE
format.fmt.pix.bytesperline = 0
format.fmt.pix.sizeimage = 0
request.type = type
request.memory = V4L2_MEMORY_USERPTR
request.count = 1
ioctl(device, VIDIOC_S_FMT, addr(format))
ioctl(device, VIDIOC_G_FMT, addr(format))
ioctl(device, VIDIOC_REQBUFS, addr(request))
posix_memalign(addressof(b_address), getpagesize(), format.fmt.pix.sizeimage)
buffer.type = request.type
buffer.memory = request.memory
buffer.index = 0
buffer.m.userptr = b_address.value
buffer.length = format.fmt.pix.sizeimage
while True:
ioctl(device, VIDIOC_QBUF, addr(buffer))
ioctl(device, VIDIOC_STREAMON, cast(type, c_void_p))
ioctl(device, VIDIOC_DQBUF, addr(buffer))
preview_data = string_at(buffer.m.userptr, buffer.length)
im = fromstring(ps['pixformat'], (ps['width'], ps['height']), preview_data)
image.paste(im)
preview.update()
and I get ValueError: not enough image data
well, I import
c_lib = CDLL(find_library('c'))
posix_memalign = c_lib.posix_memalign
getpagesize = c_lib.getpagesize
and then after
ioctl(device, VIDIOC_S_FMT, addr(format))
ioctl(device, VIDIOC_G_FMT, addr(format))
and stuff like that, I try to acquire memory
posix_memalign(addressof(b_address), getpagesize(), format.fmt.pix.sizeimage)
now b_address is no longer = None
b_address is something like c_void_p(145014784)
then I start the loop, QBUF, DQBUF, etc..
the thing is, that when I call pygame.image.frombuffer
pg_img = pygame.image.frombuffer(
buffer.m.userptr,
(format.fmt.pix.width, format.fmt.pix.height),
preview_settings['pixformat']
)
I get TypeError: expected a character buffer object
回答1:
Looks like ctypes.string_at(address, size) is what you want. That'll give you a python string buffer with the contents of the memory at your pointer's address. This should be suitable to pass to Image.fromstring
or pygame.image.frombuffer
.
回答2:
I don't know much about ctypes, but I am doing a similar thing (wrapped c++ webcam capture, displayed with DirectPython).
In my case I just made a buffer in python like this:
bufferSize = imageWidth * imageHeight
buf = "\0" * bufferSize
Pass buf to your image capture function for filling?
Maybe post a more complete code sample...
回答3:
Have you tried passing buffer
directly as the first arg? If that doesn't work and you want to make a writeable character buffer with ctypes
, create_string_buffer is the only way I know (I don't understand where you're getting the b_address.value
from).
回答4:
OK, what I did was to leave pygame for Tkinter and PIL
now after the same allocation I pass buffer.m.userptr
*to fromstring method from Image
first I have, of course, the following:
import Image
import Tkinter
tk = Tkinter.Tk()
preview = ImageTk.PhotoImage(ps['pixformat'], (ps['width'], ps['height']))
label = Tkinter.Label(tk, text='Preview', image=preview, width=ps['width'], height=ps['height'])
label.pack()
and now preview:
im = Image.fromstring(ps['pixformat'], (format.fmt.pix.width, format.fmt.pix.height), '\0'*buffer.m.userptr)
preview.paste(im)
tk.update()
I did what @sipickles said, with '\0' to see if the whole thing will work And it did :)
the thing is how to pas that userptr correctly and is the data in it actually what it needs to be passed to the preview
I am really lost here. Someone knows v4l2?
回答5:
Ok. so for now I fixed the sizeimage problem by setting the sizeimage myself:
Now frombuffer displays something that is not the frame from the buffer.
from ctypes import *
from v4l2 import *
from Image import fromstring
from Tkinter import Tk, Label
from ImageTk import PhotoImage
from ctypes.util import find_library
libc = CDLL(find_library('c'))
posix_memalign = libc.posix_memalign
getpagesize = libc.getpagesize
device_name = '/dev/video0'
ps = preview_settings = {
'width': 320,
'height': 240,
'pixformat': 'RGB',
}
PIX_FMT = V4L2_PIX_FMT_RGB555
preview = Tk()
image = PhotoImage(ps['pixformat'], (ps['width'], ps['height']))
label = Label(preview, text='Preview', image=image, width=ps['width'], height=ps['height'])
label.pack()
capability = v4l2_capability()
size = v4l2_frmsizeenum()
format = v4l2_format()
request = v4l2_requestbuffers()
buffer = v4l2_buffer()
b_address = c_void_p()
type = V4L2_BUF_TYPE_VIDEO_CAPTURE
device = open(device_name, 'rw')
ioctl(device, VIDIOC_QUERYCAP, capability)
size.pixel_format = PIX_FMT
size.index = 0
format.type = type
format.fmt.pix.pixelformat = PIX_FMT
format.fmt.pix.width = size.discrete.width
format.fmt.pix.height = size.discrete.height
format.fmt.pix.field = V4L2_FIELD_NONE
request.type = type
request.memory = V4L2_MEMORY_USERPTR
request.count = 1
format.fmt.pix.sizeimage = format.fmt.pix.width * format.fmt.pix.height * 4
buffer.length = format.fmt.pix.sizeimage
ioctl(device, VIDIOC_S_FMT, format)
posix_memalign(byref(b_address), getpagesize(), format.fmt.pix.sizeimage)
buffer.m.userptr = b_address.value
buffer.type = request.type
buffer.memory = request.memory
ioctl(device, VIDIOC_REQBUFS, request)
while True:
ioctl(device, VIDIOC_QBUF, buffer)
ioctl(device, VIDIOC_STREAMON, cast(type, c_void_p))
ioctl(device, VIDIOC_DQBUF, buffer)
**# What happens here? preview_data is wrong?**
preview_data = string_at(buffer.m.userptr, buffer.length)
im = frombuffer(ps['pixformat'], (ps['width'], ps['height']), preview_data)
image.paste(im)
preview.update()
来源:https://stackoverflow.com/questions/2070768/user-pointer-in-python