[libcamera-devel,v3,12/17] py: cam.py: Use new events support
diff mbox series

Message ID 20220701084521.31831-13-tomi.valkeinen@ideasonboard.com
State Superseded
Headers show
Series
  • Python bindings event handling
Related show

Commit Message

Tomi Valkeinen July 1, 2022, 8:45 a.m. UTC
Convert cam.py to use the new event dispatching. In addition to handling
the request-completed event, handle also disconnect, camera-added and
camera-removed events (which only do a simple print).

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
 src/py/cam/cam.py | 31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)

Comments

Jacopo Mondi Aug. 18, 2022, 3:49 p.m. UTC | #1
Hi Tomi

On Fri, Jul 01, 2022 at 11:45:16AM +0300, Tomi Valkeinen wrote:
> Convert cam.py to use the new event dispatching. In addition to handling
> the request-completed event, handle also disconnect, camera-added and
> camera-removed events (which only do a simple print).
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> ---
>  src/py/cam/cam.py | 31 +++++++++++++++++++++++++------
>  1 file changed, 25 insertions(+), 6 deletions(-)
>
> diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py
> index 6b6b678b..f19bad57 100755
> --- a/src/py/cam/cam.py
> +++ b/src/py/cam/cam.py
> @@ -230,11 +230,20 @@ class CaptureState:
>      # Called from renderer when there is a libcamera event
>      def event_handler(self):
>          try:
> -            reqs = self.cm.get_ready_requests()
> -
> -            for req in reqs:
> -                ctx = next(ctx for ctx in self.contexts if ctx.idx == req.cookie)
> -                self.__request_handler(ctx, req)
> +            evs = self.cm.get_events()
> +            for ev in evs:
> +                type = ev.type
> +
> +                if type == libcam.Event.Type.Undefined:
> +                    raise RuntimeError("Bad event type")
> +                elif type == libcam.Event.Type.CameraAdded:
> +                    print('Camera added:', ev.camera)
> +                elif type == libcam.Event.Type.CameraRemoved:
> +                    print('Camera added:', ev.camera)

s/added/removed/

> +                elif type == libcam.Event.Type.Disconnect:
> +                    self.__disconnect_handler(ev.camera)
> +                elif type == libcam.Event.Type.RequestCompleted:
> +                    self.__request_handler(ev.camera, ev.request)
>
>              running = any(ctx.reqs_completed < ctx.opt_capture for ctx in self.contexts)
>              return running
> @@ -242,7 +251,9 @@ class CaptureState:
>              traceback.print_exc()
>              return False
>
> -    def __request_handler(self, ctx, req):
> +    def __request_handler(self, cam, req):
> +        ctx = next(ctx for ctx in self.contexts if ctx.camera == cam)
> +
>          if req.status != libcam.Request.Status.Complete:
>              raise Exception('{}: Request failed: {}'.format(ctx.id, req.status))
>
> @@ -297,6 +308,9 @@ class CaptureState:
>              ctx.camera.queue_request(req)
>              ctx.reqs_queued += 1
>
> +    def __disconnect_handler(self, cam):
> +        print(f'Camera {cam} disconnected')
> +

Why this has a separate handler while the other ones that simply print
a message do not ?

Nit apart:
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>

Thanks
  j

>      def __capture_init(self):
>          for ctx in self.contexts:
>              ctx.acquire()
> @@ -447,6 +461,11 @@ def main():
>
>          state.do_cmd_capture()
>
> +        # This is not strictly needed, but it helps to do a proper cleanup as we
> +        # drop any unhandled events, and so makes it easier to use memory leak
> +        # detectors.
> +        cm.get_events()
> +
>      return 0
>
>
> --
> 2.34.1
>
Laurent Pinchart Aug. 18, 2022, 8:59 p.m. UTC | #2
On Thu, Aug 18, 2022 at 05:49:22PM +0200, Jacopo Mondi wrote:
> On Fri, Jul 01, 2022 at 11:45:16AM +0300, Tomi Valkeinen wrote:
> > Convert cam.py to use the new event dispatching. In addition to handling
> > the request-completed event, handle also disconnect, camera-added and
> > camera-removed events (which only do a simple print).
> >
> > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> > ---
> >  src/py/cam/cam.py | 31 +++++++++++++++++++++++++------
> >  1 file changed, 25 insertions(+), 6 deletions(-)
> >
> > diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py
> > index 6b6b678b..f19bad57 100755
> > --- a/src/py/cam/cam.py
> > +++ b/src/py/cam/cam.py
> > @@ -230,11 +230,20 @@ class CaptureState:
> >      # Called from renderer when there is a libcamera event
> >      def event_handler(self):
> >          try:
> > -            reqs = self.cm.get_ready_requests()
> > -
> > -            for req in reqs:
> > -                ctx = next(ctx for ctx in self.contexts if ctx.idx == req.cookie)
> > -                self.__request_handler(ctx, req)
> > +            evs = self.cm.get_events()
> > +            for ev in evs:
> > +                type = ev.type
> > +
> > +                if type == libcam.Event.Type.Undefined:
> > +                    raise RuntimeError("Bad event type")
> > +                elif type == libcam.Event.Type.CameraAdded:
> > +                    print('Camera added:', ev.camera)
> > +                elif type == libcam.Event.Type.CameraRemoved:
> > +                    print('Camera added:', ev.camera)
> 
> s/added/removed/
> 
> > +                elif type == libcam.Event.Type.Disconnect:
> > +                    self.__disconnect_handler(ev.camera)
> > +                elif type == libcam.Event.Type.RequestCompleted:
> > +                    self.__request_handler(ev.camera, ev.request)
> >
> >              running = any(ctx.reqs_completed < ctx.opt_capture for ctx in self.contexts)
> >              return running
> > @@ -242,7 +251,9 @@ class CaptureState:
> >              traceback.print_exc()
> >              return False
> >
> > -    def __request_handler(self, ctx, req):
> > +    def __request_handler(self, cam, req):
> > +        ctx = next(ctx for ctx in self.contexts if ctx.camera == cam)

Could the contexts list become a dictionary indexed by camera ?

> > +
> >          if req.status != libcam.Request.Status.Complete:
> >              raise Exception('{}: Request failed: {}'.format(ctx.id, req.status))
> >
> > @@ -297,6 +308,9 @@ class CaptureState:
> >              ctx.camera.queue_request(req)
> >              ctx.reqs_queued += 1
> >
> > +    def __disconnect_handler(self, cam):
> > +        print(f'Camera {cam} disconnected')
> > +
> 
> Why this has a separate handler while the other ones that simply print
> a message do not ?
> 
> Nit apart:
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> 
> >      def __capture_init(self):
> >          for ctx in self.contexts:
> >              ctx.acquire()
> > @@ -447,6 +461,11 @@ def main():
> >
> >          state.do_cmd_capture()
> >
> > +        # This is not strictly needed, but it helps to do a proper cleanup as we
> > +        # drop any unhandled events, and so makes it easier to use memory leak
> > +        # detectors.
> > +        cm.get_events()
> > +
> >      return 0
> >
> >
Tomi Valkeinen Aug. 19, 2022, 6:56 a.m. UTC | #3
On 18/08/2022 18:49, Jacopo Mondi wrote:
> Hi Tomi
> 
> On Fri, Jul 01, 2022 at 11:45:16AM +0300, Tomi Valkeinen wrote:
>> Convert cam.py to use the new event dispatching. In addition to handling
>> the request-completed event, handle also disconnect, camera-added and
>> camera-removed events (which only do a simple print).
>>
>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
>> ---
>>   src/py/cam/cam.py | 31 +++++++++++++++++++++++++------
>>   1 file changed, 25 insertions(+), 6 deletions(-)
>>
>> diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py
>> index 6b6b678b..f19bad57 100755
>> --- a/src/py/cam/cam.py
>> +++ b/src/py/cam/cam.py
>> @@ -230,11 +230,20 @@ class CaptureState:
>>       # Called from renderer when there is a libcamera event
>>       def event_handler(self):
>>           try:
>> -            reqs = self.cm.get_ready_requests()
>> -
>> -            for req in reqs:
>> -                ctx = next(ctx for ctx in self.contexts if ctx.idx == req.cookie)
>> -                self.__request_handler(ctx, req)
>> +            evs = self.cm.get_events()
>> +            for ev in evs:
>> +                type = ev.type
>> +
>> +                if type == libcam.Event.Type.Undefined:
>> +                    raise RuntimeError("Bad event type")
>> +                elif type == libcam.Event.Type.CameraAdded:
>> +                    print('Camera added:', ev.camera)
>> +                elif type == libcam.Event.Type.CameraRemoved:
>> +                    print('Camera added:', ev.camera)
> 
> s/added/removed/

Right... Copy-pasting... =)

>> +                elif type == libcam.Event.Type.Disconnect:
>> +                    self.__disconnect_handler(ev.camera)
>> +                elif type == libcam.Event.Type.RequestCompleted:
>> +                    self.__request_handler(ev.camera, ev.request)
>>
>>               running = any(ctx.reqs_completed < ctx.opt_capture for ctx in self.contexts)
>>               return running
>> @@ -242,7 +251,9 @@ class CaptureState:
>>               traceback.print_exc()
>>               return False
>>
>> -    def __request_handler(self, ctx, req):
>> +    def __request_handler(self, cam, req):
>> +        ctx = next(ctx for ctx in self.contexts if ctx.camera == cam)
>> +
>>           if req.status != libcam.Request.Status.Complete:
>>               raise Exception('{}: Request failed: {}'.format(ctx.id, req.status))
>>
>> @@ -297,6 +308,9 @@ class CaptureState:
>>               ctx.camera.queue_request(req)
>>               ctx.reqs_queued += 1
>>
>> +    def __disconnect_handler(self, cam):
>> +        print(f'Camera {cam} disconnected')
>> +
> 
> Why this has a separate handler while the other ones that simply print
> a message do not ?

You know, I have no idea... I'll just move the print along with the others.

> Nit apart:
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>

Thanks!

  Tomi
Tomi Valkeinen Aug. 19, 2022, 7:03 a.m. UTC | #4
On 18/08/2022 23:59, Laurent Pinchart wrote:
> On Thu, Aug 18, 2022 at 05:49:22PM +0200, Jacopo Mondi wrote:
>> On Fri, Jul 01, 2022 at 11:45:16AM +0300, Tomi Valkeinen wrote:
>>> Convert cam.py to use the new event dispatching. In addition to handling
>>> the request-completed event, handle also disconnect, camera-added and
>>> camera-removed events (which only do a simple print).
>>>
>>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
>>> ---
>>>   src/py/cam/cam.py | 31 +++++++++++++++++++++++++------
>>>   1 file changed, 25 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py
>>> index 6b6b678b..f19bad57 100755
>>> --- a/src/py/cam/cam.py
>>> +++ b/src/py/cam/cam.py
>>> @@ -230,11 +230,20 @@ class CaptureState:
>>>       # Called from renderer when there is a libcamera event
>>>       def event_handler(self):
>>>           try:
>>> -            reqs = self.cm.get_ready_requests()
>>> -
>>> -            for req in reqs:
>>> -                ctx = next(ctx for ctx in self.contexts if ctx.idx == req.cookie)
>>> -                self.__request_handler(ctx, req)
>>> +            evs = self.cm.get_events()
>>> +            for ev in evs:
>>> +                type = ev.type
>>> +
>>> +                if type == libcam.Event.Type.Undefined:
>>> +                    raise RuntimeError("Bad event type")
>>> +                elif type == libcam.Event.Type.CameraAdded:
>>> +                    print('Camera added:', ev.camera)
>>> +                elif type == libcam.Event.Type.CameraRemoved:
>>> +                    print('Camera added:', ev.camera)
>>
>> s/added/removed/
>>
>>> +                elif type == libcam.Event.Type.Disconnect:
>>> +                    self.__disconnect_handler(ev.camera)
>>> +                elif type == libcam.Event.Type.RequestCompleted:
>>> +                    self.__request_handler(ev.camera, ev.request)
>>>
>>>               running = any(ctx.reqs_completed < ctx.opt_capture for ctx in self.contexts)
>>>               return running
>>> @@ -242,7 +251,9 @@ class CaptureState:
>>>               traceback.print_exc()
>>>               return False
>>>
>>> -    def __request_handler(self, ctx, req):
>>> +    def __request_handler(self, cam, req):
>>> +        ctx = next(ctx for ctx in self.contexts if ctx.camera == cam)
> 
> Could the contexts list become a dictionary indexed by camera ?

It could, but I think it would result in more code and a "random" order 
for code execution (e.g. in which order do we start the cameras).

  Tomi

Patch
diff mbox series

diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py
index 6b6b678b..f19bad57 100755
--- a/src/py/cam/cam.py
+++ b/src/py/cam/cam.py
@@ -230,11 +230,20 @@  class CaptureState:
     # Called from renderer when there is a libcamera event
     def event_handler(self):
         try:
-            reqs = self.cm.get_ready_requests()
-
-            for req in reqs:
-                ctx = next(ctx for ctx in self.contexts if ctx.idx == req.cookie)
-                self.__request_handler(ctx, req)
+            evs = self.cm.get_events()
+            for ev in evs:
+                type = ev.type
+
+                if type == libcam.Event.Type.Undefined:
+                    raise RuntimeError("Bad event type")
+                elif type == libcam.Event.Type.CameraAdded:
+                    print('Camera added:', ev.camera)
+                elif type == libcam.Event.Type.CameraRemoved:
+                    print('Camera added:', ev.camera)
+                elif type == libcam.Event.Type.Disconnect:
+                    self.__disconnect_handler(ev.camera)
+                elif type == libcam.Event.Type.RequestCompleted:
+                    self.__request_handler(ev.camera, ev.request)
 
             running = any(ctx.reqs_completed < ctx.opt_capture for ctx in self.contexts)
             return running
@@ -242,7 +251,9 @@  class CaptureState:
             traceback.print_exc()
             return False
 
-    def __request_handler(self, ctx, req):
+    def __request_handler(self, cam, req):
+        ctx = next(ctx for ctx in self.contexts if ctx.camera == cam)
+
         if req.status != libcam.Request.Status.Complete:
             raise Exception('{}: Request failed: {}'.format(ctx.id, req.status))
 
@@ -297,6 +308,9 @@  class CaptureState:
             ctx.camera.queue_request(req)
             ctx.reqs_queued += 1
 
+    def __disconnect_handler(self, cam):
+        print(f'Camera {cam} disconnected')
+
     def __capture_init(self):
         for ctx in self.contexts:
             ctx.acquire()
@@ -447,6 +461,11 @@  def main():
 
         state.do_cmd_capture()
 
+        # This is not strictly needed, but it helps to do a proper cleanup as we
+        # drop any unhandled events, and so makes it easier to use memory leak
+        # detectors.
+        cm.get_events()
+
     return 0