views:

824

answers:

2

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.

+1  A: 

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: copies count bytes from src to dst. dst and src 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[:].

Steef
Thanks for the advice. I'm definitely getting closer. At the moment the getRgbBuffer() pointer doesn't seem to match the one that is being returned by the C function. I'll keep battling on and come back to mark you correct when (or if!) I get it working.
If I change "getRgbBuffer.restype = c_char_p" to "getRgbBuffer.restype = c_void_p" then I get the correct address back from getRgbBuffer(). Unfortunately "print rgb_buffer.value" outputs nothing. :(
It's working now. Two things, first I needed the restype to be c_void_p and also to see the data I had to do "for a in rgb_buffer: print a". As I said, "print rgb_buffer.value" outputs nothing for some reason. If you could tweak your answer for those two points I'll mark it correct. Thanks again.
`print rgb_buffer.value` prints the contents up until the first null character: >>> import ctypes >>> b = ctypes.create_string_buffer(10) >>> b.value = 'a\0b' >>> b.value 'a' >>> b[:] 'a\x00b\x00\x00\x00\x00\x00\x00\x00'Maybe that's why?Anyway, glad it works now :)
Steef
Oh blast, no formatting in comments
Steef
Ah, my buffer may well have started with null values as it's RGB data. I've got pictures out of my C image decoder now. Very satisfying, thanks.
+1  A: 

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.

Andrew Dalke