Using python ctypes to get buffer of floats from shared library into python string
-
22-08-2019 - |
Question
I'm trying to use python ctypes to use these two C functions from a shared library:
bool decompress_rgb(unsigned char *data, long dataLen, int scale)
float* getRgbBuffer()
The first function is working fine. I can tell by putting some debug code in the shared library and checking the input.
The problem is getting the data out. The RGB buffer is a pointer to a float (obviously) and this pointer stays constant during the life of the application. Therefore whenever I want to decompress an image, I call decompress_rgb
and then need to see what's at the location pointed to by getRgbBuffer
. I know that the buffer size is (720 * 288 * sizeof(float)) so I guess this has to come into play somewhere.
There's no c_float_p
type so I thought I'd try this:
getRgbBuffer.restype = c_char_p
Then I do:
ptr = getRgbBuffer()
print "ptr is ", ptr
which just outputs:
ptr = 3078746120
I'm guessing that's the actual address rather than the content, but even if I was successfully dereferencing the pointer and getting the contents, it would only be the first char.
How can I get the contents of the entire buffer into a python string?
Edit: Had to change:
getRgbBuffer.restype = c_char_p
to
getRgbBuffer.restype = c_void_p
but then BastardSaint's answer worked.
Solution
Not fully tested, but I think it's something along this line:
buffer_size = 720 * 288 * ctypes.sizeof(ctypes.c_float)
rgb_buffer = ctypes.create_string_buffer(buffer_size)
ctypes.memmove(rgb_buffer, getRgbBuffer(), buffer_size)
Key is the ctypes.memmove()
function. From the ctypes documentation:
memmove(dst, src, count)
Same as the standard C memmove library function: copiescount
bytes fromsrc
todst
.dst
andsrc
must be integers or ctypes instances that can be converted to pointers.
After the above snippet is run, rgb_buffer.value
will return the content up until the first '\0'
. To get all bytes as a python string, you can slice the whole thing: buffer_contents = rgb_buffer[:]
.
OTHER TIPS
It's been a while since I used ctypes and I don't have something which returns a "double *" handy enough to test this out, but if you want a c_float_p:
c_float_p = ctypes.POINTER(ctypes.c_float)
Reading BastardSaint's answer, you just want the raw data, but I wasn't sure if you're doing that as a workaround to not having a c_float_p.