jim-easterbrook / python-gphoto2

Python interface to libgphoto2
GNU Lesser General Public License v3.0
362 stars 59 forks source link

gp_camera_wait_for_event ignores timeout, blocks for a long time #29

Closed Ruuttu closed 6 years ago

Ruuttu commented 7 years ago

With the Canon EOS 600D, I'm polling gp_camera_wait_for_event in an endless loop with a timeout of 1 (ms). After physically triggering a shot on the camera, the function produces a GP_EVENT_FILE_ADDED event, but not before blocking for about 1.2 seconds. The duration is reduced when taking smaller pictures, so this might be the time it takes to download the image.

My goal is to download images in small chunks while keeping the loop interactive. Seems like this should be doable.

jim-easterbrook commented 7 years ago

Do you get the same behaviour with a C program? I'm not aware of anything in the Python interface that would add a delay, so your problem may be with libgphoto2 itself.

I don't think the image is being downloaded during your 1.2 second delay, I think the camera is busy saving it to its SD card (and so not responding to USB). If you don't need to store the image on the SD card you could try capturing to memory instead. (It might also be worth trying a faster SD card.)

PS. Rather than using a loop with a short timeout I'd prefer to use a separate thread to wait for the camera to have an image. I do this with any sort of blocking operation in an interactive program.

mangodan2003 commented 7 years ago

I'm also using a Canon EOS 600D and seeing unexpected behaviour trying to use gp_camera_wait_for_event.

It seems to just return right away. i.e. it never waits!

Python 3.4.5 (default, Feb 21 2017, 16:14:02) 
[GCC 4.9.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import gphoto2 as gp
>>> context = gp.Context()
>>> camera = gp.Camera()
>>> camera.wait_for_event(1000,context)
[0, None]
>>> gp.gp_camera_wait_for_event(camera,1000,context)
[0, 0, None]
>>> gp.version.gp_library_version(1)
['2.5.14', 'all camlibs', 'gcc (C compiler used)', 'ltdl (for portable loading of camlibs)', 'EXIF (for special handling of EXIF files)']

Any pointers?

jim-easterbrook commented 7 years ago

How soon is "right away"? You're specifying a timeout of only 1 second.

mangodan2003 commented 7 years ago

much less than 1sec. fwiw specifying much longer makes no difference.

Python 3.4.2 (default, Oct 19 2014, 13:31:11) 
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import gphoto2 as gp, time
>>> context = gp.Context()
>>> camera = gp.Camera()
>>> start = time.time()
>>> camera.wait_for_event(10000,context)
[0, None]
>>> time.time()  - start
0.2146010398864746

subsequent calls return much quicker - assume the first call has to do a bit more work initiinlaising the "connection"

>>> start = time.time()
>>> camera.wait_for_event(10000,context)
[0, None]
>>> time.time()  - start
0.014323234558105469
jim-easterbrook commented 7 years ago

I don't know then. The return value of 0 is GP_EVENT_UNKNOWN - the documentation says "unknown and unhandled event. argument is a char* or NULL" so maybe there's a string there that the Python interface is currently ignoring. It would appear that you need to poll camera.wait_for_event in a loop until you get an event of interest. It might be worth asking for clarification on the libgphoto mailing list though.

mangodan2003 commented 7 years ago

ok thanks, I remember finding that 0 meant gp.GP_EVENT_UNKNOWN come to think of it and wondered similar..

mangodan2003 commented 7 years ago
>>> while True:
...  foo = camera.wait_for_event(10000,context)
...  if foo[0] != 0:
...    print(foo)
...    break
... 
[2, <Swig Object of type 'CameraFilePath *' at 0x767ac7c0>]

:)

jim-easterbrook commented 7 years ago

I've just added code to handle any string when GP_EVENT_UNKNOWN is returned. Trying it on my EOS 100D I get the following

Type "help", "copyright", "credits" or "license" for more information.
>>> import gphoto2 as gp
>>> ctx = gp.Context()
>>> cam = gp.Camera()
>>> cam.init(ctx)
>>> cam.wait_for_event(1000, ctx)
[0, 'PTP Property d105 changed']
>>> cam.wait_for_event(1000, ctx)
[0, 'PTP Property d108 changed']
>>> cam.wait_for_event(1000, ctx)
[0, 'PTP Property d106 changed']
>>> cam.wait_for_event(1000, ctx)
[0, 'PTP Property d107 changed']
>>> cam.wait_for_event(1000, ctx)
[0, 'PTP Property d109 changed']
>>> cam.wait_for_event(1000, ctx)
[0, 'PTP Property d10a changed']
>>> cam.wait_for_event(1000, ctx)
[0, 'PTP Property d10b changed']
>>> cam.wait_for_event(1000, ctx)
[0, 'PTP Property d10c changed']
>>>

I suspect I might run out of such events eventually. [Edit - yes, I did. After which it was blocking as it should.]