strix

A simple web UI for motion
git clone https://www.brianlane.com/git/strix
Log | Files | Refs | LICENSE

commit 583c9e1b78e6ec0e933b9ee9d53746954f63842f
parent b864d6dd93a17949f1dcb40b5744ff8b30902d11
Author: Brian C. Lane <bcl@brianlane.com>
Date:   Sun, 16 Jul 2017 19:58:02 -0700

Implement event processing

Moves the debug images to their own subdirectory, makes .webm videos of
the images. Makes a thumbnail of the middle image, and moves the
directory to one named for the timestamp of the first image.

Diffstat:
Msrc/strix/__init__.py | 2+-
Msrc/strix/queue.py | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 73 insertions(+), 12 deletions(-)

diff --git a/src/strix/__init__.py b/src/strix/__init__.py @@ -106,7 +106,7 @@ def run() -> bool: queue_quit = threading.Event() queue_thread = threading.Thread(name="queue-thread", target=queue.monitor_queue, - args=(queue_path,queue_quit)) + args=(base_dir,queue_quit)) queue_thread.start() try: diff --git a/src/strix/queue.py b/src/strix/queue.py @@ -17,27 +17,87 @@ from glob import glob import multiprocessing as mp import os +import shutil +import subprocess import time import threading +from PIL import Image + from typing import List +THUMBNAIL_SIZE = (640, 480) + ## Handle watching the queue and dispatching movie creation and directory moving -def process_event(event: str) -> None: +def process_event(base_dir: str, event: str) -> None: print("Processing %s" % event) + print("base_dir = %s" % base_dir) + + # The actual path is the event with _ replaced by / + event_path = os.path.join(base_dir, event.replace("_", os.path.sep)) + if not os.path.isdir(event_path): + print("ERROR: event_path '%s' doesn't exist" % event_path) + return + + debug_path = os.path.join(event_path, "debug") + try: + os.mkdir(debug_path, mode=0o755) + except Exception as e: + print("ERROR: Failed to create debug directory: %s" % e) + return + + # Move the debug images into ./debug/ + try: + for debug_img in glob(os.path.join(event_path, "*m.jpg")): + shutil.move(debug_img, debug_path) + except Exception as e: + print("ERROR: Failed to move debug images") + + ffmpeg_cmd = ["ffmpeg", "-f", "image2", "-pattern_type", "glob", "-r", "10", "-i", "*.jpg", "-c:v", + "libvpx", "-crf", "10", "-b:v", "2M", "video.webm"] + + # Make a movie out of the jpg images with ffmpeg + try: + subprocess.run(ffmpeg_cmd, cwd=event_path, check=True) + except Exception as e: + print("ERROR: Failed to create video: %s" % e) + + # Make a movie out of the debug jpg images with ffmpeg + try: + subprocess.run(ffmpeg_cmd, cwd=debug_path, check=True) + except Exception as e: + print("ERROR: Failed to create debug video: %s" % e) + + # Create a thumbnail of the middle image of the capture, on the theory that it + # has the best chance of being 'interesting'. + try: + images = sorted(list(glob(os.path.join(event_path, "*.jpg")))) + middle = images[int(len(images)/2)] + im = Image.open(middle) + # im.size will get the actual size of the image + im.thumbnail(THUMBNAIL_SIZE) + im.save(os.path.join(event_path, "thumbnail.jpg"), "JPEG") + except Exception as e: + print("ERROR: Failed to create thumbnail: %s" % e) - # Convert event to a path, replace _ with / - # Make sure it exists - # Make a ./debug/ directory and move the *m.jpg files into it - # Make a movie out of the jpg files with ffmpeg - # Make a movie out of the debug images - # Create a thumbnail # Move the directory to its final location + try: + # Use the time of the first image + first_jpg = os.path.split(images[0])[1] + first_time = first_jpg.rsplit("-", 1)[0] + event_path_base = os.path.split(event_path)[0] + dest_path = os.path.join(event_path_base, first_time) + print("INFO: Destination path is %s" % dest_path) + if not os.path.exists(dest_path): + os.rename(event_path, dest_path) + except Exception as e: + print("ERROR: Moving %s to destination failed: %s" % (event_path, e)) -def monitor_queue(queue_path: str, quit: threading.Event) -> None: +def monitor_queue(base_dir: str, quit: threading.Event) -> None: threads = [] # type: List[mp.Process] + queue_path = os.path.abspath(os.path.join(base_dir, "queue/")) while not quit.is_set(): time.sleep(5) # Remove any threads from the list that have finished @@ -46,9 +106,10 @@ def monitor_queue(queue_path: str, quit: threading.Event) -> None: threads.remove(t) print("Checking %s" % queue_path) - for event in glob(os.path.join(queue_path, "*")): - os.unlink(event) - thread = mp.Process(target=process_event, args=(event,)) + for event_file in glob(os.path.join(queue_path, "*")): + os.unlink(event_file) + event = os.path.split(event_file)[-1] + thread = mp.Process(target=process_event, args=(base_dir, event)) threads.append(thread) thread.start()