Search code examples
androidpython-3.xcamerakivy

How to release camera in kivy zbarcam


i'm working on a qr code scanner using kivy zbarcam, I managed to make it work but the problem is the camera initializes right away and does not release the camera after leaving the screen. I tried zbarcam.stop() and root.ids.zbarcam_id.ids.xcamera.play=False but what it does is just unscheduling and doesn't really release the use of camera. I tried to build this in buildozer but it's so slow since the camera is using a lot of memory even when not in use.

Can somebody know what is the workaround on this?

This is my code:

from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen
from kivy.clock import Clock
from kivymd.app import MDApp

class QRScreen(Screen):
    pass

class LoginScreen(Screen):
    pass

class ScannerScreen(Screen):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Clock.schedule_once(self._after_init)
        # self.ids.zbarcam_id.ids.xcamera.play=True
    
    def _after_init(self, dt):
        """
        Binds `ZBarCam.on_symbols()` event.
        """
        zbarcam = self.ids.zbarcam_id
        zbarcam.bind(symbols=self.on_symbols)

    def on_symbols(self, zbarcam, symbols):
        """
        Loads the first symbol data to the `QRFoundScreen.data_property`.
        """
        # going from symbols found to no symbols found state would also
        # trigger `on_symbols`
        if not symbols:
            return

        symbol = symbols[0]
        data = symbol.data.decode('utf8')
        print(data)
        self.manager.get_screen('qr').ids.data.text= data
        self.manager.transition.direction = 'left'
        self.manager.current = 'qr'

    def on_leave(self):
        zbarcam = self.ids.zbarcam_id
        zbarcam.stop()



class DemoApp(MDApp):
    def build(self):
    # screen =Screen()
    
        self.title='Demeter'
        self.theme_cls.theme_style = "Dark"
        self.theme_cls.primary_palette = "DeepPurple"   

        self.help = Builder.load_file('main.kv')
        return self.help

DemoApp().run()

kv file:

#:import ZBarCam kivy_garden.zbarcam.ZBarCam

ScreenManager:
    LoginScreen:
    ScannerScreen:
    QRScreen:

<LoginScreen>:
    name: "login"
    MDFlatButton:
        text:'release'
        on_press:
            root.manager.current = 'scanner'
            root.manager.transition.direction = "right"

<ScannerScreen>:
    name: 'scanner'
    ZBarCam:
        id: zbarcam_id
        play: False
    MDFlatButton:
        id: iyu
        text:'release'
        on_press:
            root.ids.zbarcam_id.ids.xcamera.play=False
    MDFlatButton:
        id: ads
        text:'replay'
        pos_hint: {"center_x": 0.5, "center_y": 0.95}
        on_press:
            root.ids.zbarcam_id.ids.xcamera.play=True

<QRScreen>:
    name: 'qr'
    MDIconButton:
        icon:'arrow-left'
        pos_hint: {'center_x':0.1,'center_y':0.95}
        on_press: 
            root.manager.current = 'scanner'
            root.manager.transition.direction = "right"

    MDLabel:
        id:data
        text: "asdgasda"
        pos_hint: {'center_y':0.5}
        theme_text_color: "Custom"
        text_color: 0, 1, 0, 1  

Solution

  • I was having the same problem and finally found the solution (based on this)

    In my case I initate ZBarCam in the .py file instead of .kv (see example).

    To actually close the camera, you can call the following:zbarcam.ids['xcamera']._camera._device.release() in your on_leave() function.

    If you initiate/manage ZBarCam in the .kv, I think that the equivalent would be something like: root.ids.zbarcam.ids.xcamera._camera._device.release()

    If compiled with buildzoner for Android, I have to use self.zbarcam.ids['xcamera']._camera = None instead