jim-easterbrook / python-gphoto2

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

Camera blocks after using the download script #49

Closed dmitryelj closed 6 years ago

dmitryelj commented 6 years ago

Hi,

Thanks for the cool product. After running images download script, the camera (Canon 750D) locks and show "busy" when trying to make a new photo.

The script has "gp.gp_camera_exit(camera)" at the end.

Trying to use "gp.gp_camera_free(camera)" at the end of the script, causing error, is it implemented? Can it help?

The second weird thing is, sometimes it works and the camera is not locked, sometime it does not.

Thanks.

jim-easterbrook commented 6 years ago

gp_camera_free deletes the C camera object (frees its memory) and should never be used according to the libgphoto2 documentation. gp_camera_unref decrements the object's reference count, freeing it when the count reaches zero. This is not user-callable from Python as it would leave a Python object pointing to an invalid C object and cause segmentation faults. Instead it is called automatically when the Python object is destroyed.

gp_camera_exit makes the camera available to other programs. It probably isn't needed as the example script quits anyway. It's good practice to include it though.

Your problem sounds like a bug in libgphoto2 or the camera. What happens if you use the gphoto2 command to download photos? A google search suggests that "busy" problems are quite common, but I didn't see any obvious fix.

bitcraft commented 6 years ago

@dmitryelj are you shooting with a SD card installed?

dmitryelj commented 6 years ago

Thanks for the answer. Sure, the SD card is installed.

I'll try to download and build the last libgphoto2 version, maybe it will help.

bitcraft commented 6 years ago

I had an issue where the camera would get stuck at busy if I was shooting without a SD card. I have a reliable one installed now and haven't run into any issues despite working it extremely hard using a photo booth. I'll link my code, maybe you can find somthing we are doing differently?

https://github.com/bitcraft/tailor/blob/master/tailor/plugins/gphoto2_camera.py#L90-L112

If you ignore the asyncio bits, its a pretty straightforward function. Works like a charm with my Canon 6D.

jim-easterbrook commented 6 years ago

Another user has had problems (unspecified) when using a USB3 port. Using a USB2 port might work better, assuming a USB2 camera.

dmitryelj commented 6 years ago

Thanks for the answer.

Its weird in general. I'm running this script to download photos on the Raspberry Pi:

    camera = gp.check_result(gp.gp_camera_new()) 
    error = gp.check_result(gp.gp_camera_init(camera))
    if error != gp.GP_OK:
        print "Cannot connect camera, error", error
        sys.exit(0)

    camera_files = list_camera_files(camera)
    print camera_files

    out_path = "/home/pi/Documents/photos"
    for path in camera_files:
        folder, name = os.path.split(path)
        info = gp.check_result(gp.gp_camera_file_get_info(camera, folder, name))
        camera_file = gp.check_result(gp.gp_camera_file_get(camera, folder, name, gp.GP_FILE_TYPE_NORMAL))

        dest = out_path + '/' + name
        gp.check_result(gp.gp_file_save(camera_file, dest))

    gp.check_result(gp.gp_camera_exit(camera))

It works like a charm, but - sometimes with about 25% probability camera cannot make pictures more after running the script, indicating "busy" when pressing shutter. Then I cannot access the camera through python-gphoto, but cannot take more pictures. But then, if I run ./sample-autodetect from libgphoto2 sources, the camera became magically unlocked. Thats why I was asking if all resources in the python lib are released correctly.

I builded the last version of libgphoto2 from source, but it didn't help, the symptoms are the same.

jim-easterbrook commented 6 years ago

That really is very strange. It appears the Python script is not always leaving the camera in the correct state, but I have no idea why. There's nothing asynchronous or threaded in your program so it should be deterministic. I wonder if adding a second or two delay between calling gp_camera_exit and quitting the program would help.

It might be worth delving into the source of ./sample-autodetect to see what libgphoto2 calls it's making. In theory you should be able to make the same calls from Python to unlock your camera.

dmitryelj commented 6 years ago

This code is doing nothing special: https://github.com/gphoto/libgphoto2/blob/master/examples/sample-autodetect.c

I tried to make a call of gp.get_config_value_string from python but this method is missing.

jim-easterbrook commented 6 years ago

get_config_value_string isn't a libgphoto2 function, it's defined in config.c https://github.com/gphoto/libgphoto2/blob/master/examples/config.c#L23

dmitryelj commented 6 years ago

Thanks.

dmitryelj commented 6 years ago

Another small update. I reduced the code to only init and exit, and the camera is still "busy" sometimes. Have no idea. Looks like its not a "python-gphoto" issue anyway. But freeing resources issue in Python still exist. When I run C-app at the second time, it finally works and the camera became unlocked, and with the Python app is not.

    camera = gp.check_result(gp.gp_camera_new()) 
    error = gp.check_result(gp.gp_camera_init(camera))
    print "gp_camera_init:", error
    if error != gp.GP_OK:
        print "Cannot connect camera, error", error
        sys.exit(0)

    # This time I'm trying to shoot with the camera
    time.sleep(60)

    gp.check_result(gp.gp_camera_exit(camera))
jim-easterbrook commented 6 years ago

Did you reinstall python-gphoto2 after building and installing the latest libgphoto2? The Python interface might still be using the old version. Use ldd on one of the compiled Python modules (e.g. /usr/lib64/python3.4/site-packages/gphoto2/_camera.cpython-34m.so - the name will be system dependent) to check.

dmitryelj commented 6 years ago

The error gone when I switched to "OOP" interface:

        context = gp.Context()
        camera = gp.Camera()
        camera.init(context)
        ...
        camera.exit(context)

I don't know what it was, it looks, the ticket can be closed.

Thanks again for help.

jim-easterbrook commented 6 years ago

One difference is using a context. I thought the context was optional (whether OOP or not) but you may have found a case where it isn't.