class App: def __init__(self, preview=False, max_video_length=MAX_VIDEO_LENGTH): log.info("booting up..") self.final_dir = self._setup_dirs() self.max_video_length = max_video_length self.video_recorder = VideoRecorder(preview=preview) self.audio_recorder = AudioRecorder() time.sleep(2) log.info("ready!") def _setup_dirs(self): final_dir = os.path.expanduser('~/media/') if (os.path.isdir(final_dir) == False): os.mkdir(final_dir) return final_dir def _make_filename(self): return datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S") def has_space(self): statvfs = os.statvfs("/") megabytes_available = int(statvfs.f_frsize * statvfs.f_bavail / 1024 / 1024) log.info(f"Still {megabytes_available}MB left on device") return megabytes_available > MIN_DISK_SPACE_MB def on_keyboard_release(self, key): if key == keyboard.Key.enter: if lock.locked(): self.stop_recording() elif self.has_space(): self.start_recording() else: return False if key == keyboard.Key.esc: if lock.locked(): self.stop_recording() return False def timer(self, seconds, current_video): log.info(f"going to sleep for {seconds}s and then stop recording") for i in range(seconds): if not lock.locked(): log.info("looks like recording has ended before timeout") return elif current_video != self.file_name: log.info("there is a different ongoing recording") return time.sleep(1) log.info("time's up!, stopping recording") self.stop_recording() def start_recording(self): lock.acquire() self.start_datetime = datetime.datetime.now() self.file_name = self._make_filename() timer_thread = threading.Thread(target=self.timer, args=(self.max_video_length, self.file_name)) timer_thread.start() self.tmp_dir = tempfile.mkdtemp() log.info("starting threads...") self.video_recorder.start(self.file_name, self.tmp_dir) self.audio_recorder.start(self.file_name, self.tmp_dir) def stop_recording(self): log.info("stopping threads...") if not self.audio_recorder.stop(): return if not self.video_recorder.stop(): return now = datetime.datetime.now() video_length = (now - self.start_datetime).seconds if video_length > MIN_VIDEO_LENGTH: log.info("starting mux...") cmd = ( f"ffmpeg -i {self.tmp_dir}/{self.file_name}.wav -i {self.tmp_dir}/{self.file_name}.h264 " f"-c:v copy -c:a aac -strict experimental {self.final_dir}/{self.file_name}.mp4" ) subprocess.run(cmd, capture_output=True, shell=True) log.info(f"{self.file_name}.mp4 is ready!") else: log.info(f"Video was to short: {video_length}, removing it") shutil.rmtree(self.tmp_dir) log.info(f"{self.tmp_dir} removed") lock.release() def run(self): def on_release(button): if lock.locked(): self.stop_recording() elif self.has_space(): self.start_recording() else: return False button = Button(2) button.when_released = on_release listener = keyboard.Listener(on_release=self.on_keyboard_release) listener.start() pause()
if new_state == State.ACTIVE: # Motion has been detected, so the scene is now ACTIVE. if state == State.IDLE: # Transitioning from IDLE to ACTIVE, so we need to start recording. VideoRecorder.start() state = State.ACTIVE elif new_state == State.RECORDING: state = State.RECORDING elif new_state == State.IDLE: if state != State.IDLE: # Transitioning from RECORDING to IDLE. Stop the recording. state = State.IDLE VideoRecorder.stop() # draw the text on the frame if state == State.IDLE: text = "Idle." elif state == State.RECORDING: text = "Idle, Recording..." elif state == State.ACTIVE: text = "Active, Recording..." else: raise ValueError("Unexpected value for state: ", state) cv2.putText(frame, "Status: {}".format(text), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) # Check to see if the frame should be displayed to screen.