summary refs log tree commit diff
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2021-02-23 13:41:37 +0100
committerRobert Günzler <r@gnzler.io>2021-04-26 02:09:46 +0200
commit900e7d13e097c486fd002b724f065d4dea30ac33 (patch)
tree02b95a735a6d564d1df9888dd51937fd5d620030
parent0600844602da163a523ba629be5e912908e3b9bc (diff)
add bin/gpctl; gopro control cli
-rwxr-xr-xbin/gpctl141
1 files changed, 141 insertions, 0 deletions
diff --git a/bin/gpctl b/bin/gpctl
new file mode 100755
index 0000000..e74a71f
--- /dev/null
+++ b/bin/gpctl
@@ -0,0 +1,141 @@
+#!/bin/env python3.8
+
+import argparse
+import logging
+import sys
+import signal
+import subprocess
+import datetime
+import os.path
+import time
+import urllib.request, urllib.parse
+from goprocam import GoProCamera, constants
+
+# setup logging facilities
+logging.basicConfig(level=logging.INFO)
+
+
+def setup_cam(dev='gp0'):
+    logging.info(f"Connecting to gopro camera at {dev}")
+    return GoProCamera.GoPro(ip_address=GoProCamera.GoPro.getWebcamIP(dev),
+                             mac_address='0e:7c:80:b5:82:0e',
+                             camera=constants.gpcontrol,
+                             webcam_device=dev)
+
+
+def configure_cam(gp,
+                  resolution="720p",
+                  fps="60",
+                  fov="0",
+                  autooff=constants.Setup.AutoOff.Never):
+    gp.video_settings(resolution, fps)
+    gp.gpControlSet(constants.Setup.AUTO_OFF, autooff)
+
+
+def take_photo(gp, outdir='.'):
+    logging.info('Snapping picture!')
+    mediauri = gp.take_photo()
+    medianame = os.path.basename(urllib.parse.urlparse(mediauri).path)
+    outpath = os.path.join(outdir, medianame)
+    logging.info(f"Saving to {outpath}")
+    urllib.request.urlretrieve(mediauri, filename=outpath)
+
+
+def webcam(gp,
+           outdir='.',
+           resolution=constants.Webcam.Resolution.R720p,
+           fov=constants.Webcam.FOV.Wide):
+    # prepare v4l2 device
+    if not os.path.exists('/dev/video9'):
+        logging.info('Creating v4l2 device node at /dev/video9')
+        subprocess.run([
+            'doas -n modprobe v4l2loopback video_nr=9 card_label=GoPro9 exclusive_caps=1'
+        ],
+                       shell=True,
+                       check=True)
+
+    logging.info('Starting webcam mode')
+    gp.webcamFOV(fov)
+    gp.startWebcam(resolution)
+
+    try:
+        # gracefull handle sigterm
+        def sigterm_handler(sig, frame):
+            raise SystemExit('SIGTERM')
+
+        signal.signal(signal.SIGTERM, sigterm_handler)
+        # pipe video from camera to v4l2 device
+        udp_stream = f"udp://{gp.getWebcamIP()}:8554"
+        ffmpeg_args = [
+            f"ffmpeg -hide_banner -loglevel warning -probesize 3072 -fflags nobuffer -flags low_delay -i {udp_stream} -vsync 2 -ar 44100 -vcodec rawvideo -pix_fmt yuv420p -f v4l2 /dev/video9"
+        ]
+        logging.info('Running ffmpeg')
+        # [
+        #     'ffmpeg -hide_banner -loglevel warning -probesize 5000 -analyzeduration 22000 -r 30 -i udp://@:8554 -an -vcodec rawvideo -pix_fmt yuv420p -r 30 -s 1280x720 -flush_packets 1 -f v4l2 /dev/video9'
+        # ]
+        subprocess.run(ffmpeg_args, shell=True, check=True)
+    except (KeyboardInterrupt, SystemExit, Exception):
+        # allow camera to shut down
+        time.sleep(1)
+        # stop webcam mode
+        logging.info('Stopping webcam mode')
+        gp.stopWebcam()
+        # done
+        logging.info('Exiting...')
+
+
+parser = argparse.ArgumentParser(description='gopro cli utility')
+parser.add_argument('-o',
+                    '--output',
+                    nargs=1,
+                    type=str,
+                    metavar='OUTPUT',
+                    default='.',
+                    help='Directory to save files to.')
+parser.add_argument('-r',
+                    '--resolution',
+                    nargs=1,
+                    type=str,
+                    metavar='RES',
+                    choices=('1080', '720', '420'),
+                    default='1080p',
+                    help='Video resolution')
+parser.add_argument('-f',
+                    '--fps',
+                    nargs=1,
+                    type=str,
+                    metavar='FPS',
+                    default='60',
+                    help='Video frame rate')
+parser.add_argument('-v',
+                    '--fov',
+                    nargs=1,
+                    type=str,
+                    metavar='FOV',
+                    choices=('wide', 'linear', 'narrow'),
+                    default='wide',
+                    help='Video field of view')
+
+parser.add_argument('--take-photo',
+                    action='store_true',
+                    help='Take a photo and save it to OUTPUT.')
+parser.add_argument('--webcam',
+                    action='store_true',
+                    help='Start webcam mode and register as v4l2 device')
+
+args = parser.parse_args()
+
+# get camera network device from environment
+# should be up and connected (with an ip address assigned)
+gp = setup_cam(os.getenv('GOPRO_DEVICE', 'gp0'))
+# configure_cam(gp, resolution=args.resolution, fps=args.fps, fov=args.fov)
+
+try:
+    if args.take_photo:
+        take_photo(gp, args.output)
+    if args.webcam:
+        webcam(gp)
+
+except Exception as err:
+    logging.error(f"error: {err}")
+    exit(1)