jim-easterbrook / python-gphoto2

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

"gphoto2.GPhoto2Error: [-2] Bad parameters" being thrown when setting config for "eosremoterelease" #56

Closed awtesta closed 5 years ago

awtesta commented 6 years ago

I have a Canon EOS 70D that I am using with the library. Overall things work great and I am really appreciative of the hard work you put into this. I have an error that I'm encountering that I'm hoping you might be able to help with.

My use case is that I have a "controller" application that takes a tcp notification running on a raspberry pi. When a notification is received, I create a new camera context, initialize it, then i want to set a set of photos in rapid succession so I am using the camera objects "set_config" and the canon specific command "eosremoterelease" to issue the down and up buttons. This lets me take 5-10 photos bursts. I am then able to successfully iterate over the camera files and grab them off the camera. All of the above works great with the exception of some rare/infrequent cases.

The issue I'm having is that in some cases (have yet to really get to the bottom of it) the button down/up commands seem to lock up. Based on the examples i've seen in your library, adding "gp.check_result(gp.use_python_logging())" seemed like a logical option so that I could log the errors out and handle them,etc. However, it seems that if I call "gp.check_result(gp.use_python_logging())" then I get error messages like the one below

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.4/threading.py", line 868, in run
    self._target(*self._args, **self._kwargs)
  File "newCameraController.py", line 241, in captureImages
    shutterspeed = camera_config.get_child_by_name('eosremoterelease')
gphoto2.GPhoto2Error: [-2] Bad parameters

and then photos are not captured at all. However if I remove "gp.check_result(gp.use_python_logging())" the code works perfectly. Is there something I am missing or perhaps not calling properly with the library so that errors get logged?

I've also tried the callback option but get the same result. Not sure if this matters (or factors in) at all either but I am spinning up a new thread to take/download the photos on every signal i get.

jim-easterbrook commented 6 years ago

This looks difficult. The use_python_logging function is a bit of a mess, but the best way I've found to call a Python function from a C callback function. A reference to the Python function needs to be stored somewhere, so I use a static variable in the C code. I haven't given a lot of thought to thread safety in all of this.

I would be very wary of sharing a gphoto2 object (e.g. the camera) between threads. I don't know how thread safe libgphoto2 is. I usually use one thread for the camera - it initialises it, interacts with it, and closes it down cleanly, using other mechanisms (Python queues, Qt signals, whatever) to communicate with the rest of the program as appropriate.

I'm off on holiday soon so won't be able to help much for a few weeks. I apologise for the lack of support.

jim-easterbrook commented 6 years ago

I think your problem may be caused by the way I call Python a function from a C callback function. If you have a look at the source you can see I call Py_IsInitialized() before doing anything. This is to prevent the Python callback being called if the Python interpreter is being shut down. After re-reading the Python documentation I'm not sure this is the right approach. https://github.com/jim-easterbrook/python-gphoto2/blob/master/src/gphoto2/port_log.i#L43 https://docs.python.org/2/c-api/init.html

jim-easterbrook commented 6 years ago

I'm now completely stumped. I can't see anything wrong with the callback code installed by use_python_logging and I'm mystified as to how it could cause camera_config.get_child_by_name to fail. I assume you're calling use_python_logging at the start of your program, before creating any threads. It might help to see your complete program, if it's not too large.