Exemple #1
0
    def __init__(self, config, camera):
        self.conf = config
        self.camera = camera
        self.printer = PrinterProxy(self.conf)

        # platform and pygame
        logger.info("PLATFORM: %s" % platform_devs.running_platform)
        platform_devs.platform_init()
        pygame.init()
        pygame.mouse.set_visible(False)

        self.clock = pygame.time.Clock()

        # peripherials
        self.button = platform_devs.Button()
        self.lights = platform_devs.Lights(self.conf['devices']['lights_external'])
        self.button.register_callback(self.button_callback)

        # view and model
        self.is_running = False
        self.live_view_running = False
        self.live_view_still_img = None
        self.view = view.PygView(self, self.conf, self.camera)
        self.model = model.PhotoBoothModel(self)
        to_upload_sessions = self.model.load_from_disk()

        # capture thread
        self.capture_names = Queue(maxsize=0)
        self.thread_capture = Thread(target=self.capture_image_worker)
        self.thread_capture.setDaemon(True)

        # upload background process (creating GIF is cpu-intensive, make it happen in other process to bypass GIL)
        self.upload_pipe = None
        if self.conf['upload']['enabled']:
            pipe = multiprocessing.Pipe()
            self.upload_pipe = pipe[0]
            self.process_upload = multiprocessing.Process(target=upload.run, args=(self.conf, pipe))
            self.process_upload.daemon = True

            # try to reupload not yet uploaded sessions
            if self.conf['upload']['retrying']:
                for sess in to_upload_sessions:
                    self.upload_pipe.send((sess.id, sess.get_medium_img_paths(),\
                        sess.get_full_img_paths(), sess.random_tags))


        self.next_fps_update_ticks = 0
Exemple #2
0
    def __init__(self, config):
        self.conf = config
        self.cam = picam.PiCam(config)
        self.printer = PrinterProxy(self.conf)

        # platform and picam
        logger.info("PLATFORM: %s" % platform_devs.running_platform)
        platform_devs.platform_init()
        self.cam.start()

        # peripherials
        self.button = platform_devs.Button()
        self.button_pressed = False
        self.lights = platform_devs.Lights(self.conf['devices']['lights_external'])
        self.button.register_callback(self.button_callback)

        # uploader
        self.upload = UploadProxy(self.conf)

        # model
        self.is_running = False
        self.model = model.VideoBoothModel(self)
Exemple #3
0
class VideoBoothController(object):
    """ controlling the logic flow around the whole application """

    def __init__(self, config):
        self.conf = config
        self.cam = picam.PiCam(config)
        self.printer = PrinterProxy(self.conf)

        # platform and picam
        logger.info("PLATFORM: %s" % platform_devs.running_platform)
        platform_devs.platform_init()
        self.cam.start()

        # peripherials
        self.button = platform_devs.Button()
        self.button_pressed = False
        self.lights = platform_devs.Lights(self.conf['devices']['lights_external'])
        self.button.register_callback(self.button_callback)

        # uploader
        self.upload = UploadProxy(self.conf)

        # model
        self.is_running = False
        self.model = model.VideoBoothModel(self)


    def run(self):
        """Main loop"""

        self.is_running = True
        self.button.start()
        self.upload.start()

        while self.is_running:
            # if camera stopped working, exit
            if not self.cam.update():
                break

            button_pressed = self.process_events()
            # detecting LONG PRESS for poweroff:
            self.button.update_state()

            self.model.update(button_pressed)
            # TODO: polling/fps instead of this?
            time.sleep(0.3)

        self.quit()

    def __del__(self):
        self.cam.stop()
        platform_devs.platform_deinit()

    def quit(self):
        self.is_running = False
        if self.model:
            self.model.quit()
            self.model = None

        self.lights.pause()
        self.cam.stop()

    def button_callback(self):
        self.button_pressed = True

    def process_events(self):
        button_pressed = self.button_pressed
        self.button_pressed = False
        return button_pressed

    def get_external_ip(self):
        return platform_devs.get_ip()

    def set_info_text(self, text_arg, big=False, color="ffffff"):
        text = text_arg.strip().replace("\n", "\\n")
        if big:
            self.cam.set_text(text, pt=140, layout_align="center,center", color=color)
        else:
            self.cam.set_text(text, pt=60, color=color)

    def set_rec_text(self, time):
        text = "\\n".join([u"●REC", time])
        self.cam.set_text(text, layout_align="top,right", horizontal_margin=30, vertical_margin=30, color="ff0000")


    def start_recording(self):
        self.cam.start_recording()

    def stop_recording(self):
        self.cam.stop_recording()

    def check_recording_state(self, post_res):
        if not self.cam.is_recording():
            new_movie_fn = self.cam.last_rec_filename()
            logger.info("NEW MOVIE: %s", new_movie_fn)

            (upload_url, frontend_url) = post_res or ("", "")
            self.upload.async_process(upload_url, new_movie_fn)

            if len(frontend_url) > 0:
                logger.info("frontend URL: %s", frontend_url)
                self.printer.print_video(frontend_url)
            return True

        return False
Exemple #4
0
class PhotoBoothController(object):
    """ controlling the logic flow around the whole application """

    QUIT_KEYS = pygame.K_ESCAPE, pygame.K_q
    BUTTON_KEY= pygame.K_SPACE,

    BUTTONPUSHEVENT = pygame.USEREVENT + 2

    def __init__(self, config, camera):
        self.conf = config
        self.camera = camera
        self.printer = PrinterProxy(self.conf)

        # platform and pygame
        logger.info("PLATFORM: %s" % platform_devs.running_platform)
        platform_devs.platform_init()
        pygame.init()
        pygame.mouse.set_visible(False)

        self.clock = pygame.time.Clock()

        # peripherials
        self.button = platform_devs.Button()
        self.lights = platform_devs.Lights(self.conf['devices']['lights_external'])
        self.button.register_callback(self.button_callback)

        # view and model
        self.is_running = False
        self.live_view_running = False
        self.live_view_still_img = None
        self.view = view.PygView(self, self.conf, self.camera)
        self.model = model.PhotoBoothModel(self)
        to_upload_sessions = self.model.load_from_disk()

        # capture thread
        self.capture_names = Queue(maxsize=0)
        self.thread_capture = Thread(target=self.capture_image_worker)
        self.thread_capture.setDaemon(True)

        # upload background process (creating GIF is cpu-intensive, make it happen in other process to bypass GIL)
        self.upload_pipe = None
        if self.conf['upload']['enabled']:
            pipe = multiprocessing.Pipe()
            self.upload_pipe = pipe[0]
            self.process_upload = multiprocessing.Process(target=upload.run, args=(self.conf, pipe))
            self.process_upload.daemon = True

            # try to reupload not yet uploaded sessions
            if self.conf['upload']['retrying']:
                for sess in to_upload_sessions:
                    self.upload_pipe.send((sess.id, sess.get_medium_img_paths(),\
                        sess.get_full_img_paths(), sess.random_tags))


        self.next_fps_update_ticks = 0

    def __del__(self):
        platform_devs.platform_deinit()

    def run(self):
        """Main loop"""

        self.is_running = True
        self.thread_capture.start()
        self.button.start()

        if self.conf['upload']['enabled']:
            self.process_upload.start()

        # first session is for setting up, fire lights at full brightness, or not
        #self.lights.set_brightness(self.conf["devices"]["lights_full"])

        while self.is_running:
            self.clock.tick(self.view.fps)
            button_pressed = self.process_events()
            self.button.update_state()

            self.view.update()
            self.model.update(button_pressed)

            if self.next_fps_update_ticks < pygame.time.get_ticks():
                fps_str = "[FPS]: %.2f" % (self.clock.get_fps())
                pygame.display.set_caption(fps_str)
                #logger.debug(fps_str)
                self.next_fps_update_ticks = pygame.time.get_ticks() + self.conf['debug']['fps_update_ms']

        self.quit()

    def quit(self):
        self.is_running = False
        if self.model:
            self.model.quit()
            self.model = None
        if self.upload_pipe:
            self.upload_pipe.close()
            self.upload_pipe = None

        self.lights.pause()
        pygame.quit()

    def button_callback(self):
        button_event = pygame.event.Event(self.BUTTONPUSHEVENT)
        pygame.event.post(button_event)

    def process_events(self):
        """ Returns wheter "THE BUTTON" has been pressed """
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.is_running = False
            elif event.type == self.BUTTONPUSHEVENT:
                return True
            elif event.type == pygame.KEYDOWN:
                if event.key in PhotoBoothController.QUIT_KEYS:
                    self.is_running = False
                elif event.key in PhotoBoothController.BUTTON_KEY:
                    return True
                elif event.key == pygame.K_p: # for debugging
                    self.print_camera_preview()
                    return False

        return False

    def start_live_view(self):
        self.live_view_running = True
        self.camera.start_preview()
        self.view.lv.start()

    def resume_live_view(self):
        self.view.lv.start()

    def stop_live_view(self, still_img=None):
        self.live_view_running = False
        self.camera.stop_preview()
        self.view.lv.stop()
        if still_img:
            self.view.lv.set_image(still_img)

    def schedule_stop_live_view(self, still_img=None):
        """ does not stop camera previews """
        self.live_view_running = False
        self.live_view_still_img = still_img

    def is_live_view_overlay_finished(self):
        return self.view.lv.is_started and not self.view.lv.is_overlay

    def live_view_show_arrow(self):
        self.view.lv.show_arrow = True

    def live_view_hide_arrow(self):
        self.view.lv.show_arrow = False

    def set_text(self, text_lines, big_font=False):
        self.view.textbox.draw_text(text_lines, big_font)

    def capture_image_worker(self):
        while self.is_running:
            image_number, image_name, medium_name, prev_name = self.capture_names.get()

            # (1) capture the image
            logger.info("capture_image_worker: capturing image to: %s", image_name)
            self.camera.pause_preview()
            self.camera.capture_image(image_name) # this blocks

            # (2) view: start the 'end animation overlay' and resume LV
            if self.live_view_running:
                self.camera.start_preview() # resume previews ASAP
                self.view.lv.start()
            else: # "pending" stop_live_view
                self.stop_live_view(self.live_view_still_img)

            self.view.lv.end_overlay()

            # (3) lights - default brightness (only during live view)
            if self.live_view_running:
                self.lights.set_brightness(self.conf["devices"]["lights_default"])
            else:
                self.lights.pause()

            # (4) load captured images and scale them
            logger.debug("capture_image_worker: reading and scalling images")
            img = pygame.image.load(image_name).convert()
            img_lv = pygame.transform.scale(img, (view.LivePreview.WIDTH, view.LivePreview.HEIGHT))
            img_prev = pygame.transform.scale(img_lv, (view.SmallPhotoPreview.WIDTH, view.SmallPhotoPreview.HEIGHT))

            # (5) view: set the preview image
            self.view.main_previews[image_number].set_image(img_prev)
            self.view.main_previews[image_number].end_overlay()

            # (6) save the scalled images
            pygame.image.save(img_prev, prev_name)
            pygame.image.save(img_lv, medium_name)

            # (7) finish the task and send the results
            logger.debug("capture_image_worker: DONE")
            self.capture_names.task_done()
            self.model.set_current_session_imgs(image_number, (img, img_lv, img_prev))

    def capture_image(self, image_number, file_paths):
        # lights - maximum brightness
        self.lights.set_brightness(self.conf["devices"]["lights_full"])

        # view: capture begin animation
        self.view.lv.pause()
        self.view.lv.begin_overlay()
        self.view.main_previews[image_number].begin_overlay()

        # schedule worker thread to capture image
        obj = (image_number, file_paths[0], file_paths[1], file_paths[2])
        self.capture_names.put(obj)

    def print_camera_preview(self):
        img = self.view.lv.image
        self.printer.print_image(img)

    @staticmethod
    def load_captured_image(file_path):
        img = pygame.image.load(file_path).convert()
        return img

    def enqueue_animate_montage(self, img_list):
        self.view.lv.enqueue_animate_montage(img_list, self.conf["control"]["montage_fps"])

    def notify_idle_previews_changed(self):
        prev_num = 1
        for img_list in self.model.get_idle_previews_image_lists():
            #logger.debug("preview[%d] = %s <- %s" % (prev_num, self.view.idle_previews[prev_num], img_list))
            self.view.idle_previews[prev_num].start_animate(img_list, 0) # if fps == 0 -> sync whith display FPS
            prev_num += 1

    def notify_finished_session(self, sess):
        """ Start work related with finished session processing - uploading and printing"""
        self.printer.print_session(sess.id, sess.medium_img_list, sess.random_tags)
        if self.conf["upload"]["enabled"]:
            self.upload_pipe.send((sess.id, sess.get_medium_img_paths(), sess.get_full_img_paths(), sess.random_tags))