From bbee468ba9fc7dbab75382c4937140f4e9c72bf0 Mon Sep 17 00:00:00 2001 From: Martijn Braam Date: Tue, 30 Jun 2020 17:38:35 +0200 Subject: [PATCH] Initial commit --- camera.py | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100755 camera.py diff --git a/camera.py b/camera.py new file mode 100755 index 0000000..5524c32 --- /dev/null +++ b/camera.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +import subprocess +import os +import glob + + +def get_orientation(): + for device in glob.glob('/sys/bus/iio/devices/iio:device*'): + if os.path.isfile(os.path.join(device, 'in_accel_x_raw')): + break + else: + return 0 + + with open(os.path.join(device, 'in_accel_x_raw')) as handle: + x = int(handle.read().strip()) + with open(os.path.join(device, 'in_accel_y_raw')) as handle: + y = int(handle.read().strip()) + with open(os.path.join(device, 'in_accel_z_raw')) as handle: + z = int(handle.read().strip()) + + max_abs = max(abs(x), abs(y), abs(z)) + if x == max_abs: + # portrait + return "portrait" + if -x == max_abs: + # upside down portrait + return "portrait" + if y == max_abs: + # landscale counterclockwise + return "ccw" + if -y == max_abs: + # landscape clockwise + return "cw" + if z == max_abs: + # flat on back + return "flat" + if -z == max_abs: + # flat on screen + return "flat" + return "cw" + + +def setup(node, res, debug=False): + speed = 30 + if '@' in res: + res, speed = res.split('@') + + command = ['sudo', 'media-ctl', '-d', '/dev/media1', '--set-v4l2', + '"{}":0[fmt:UYVY8_2X8/{}@1/{}]'.format(node, res, speed)] + if debug: + print(command) + p = subprocess.run(command, timeout=5) + if p.returncode != 0: + return False + + width, height = res.split('x') + fmt = ['width=' + width, 'height=' + height, 'pixelformat=UYVY'] + command = ['sudo', 'v4l2-ctl', '--device', '/dev/video1', '--set-fmt-video={}'.format(','.join(fmt))] + if debug: + print(command) + p = subprocess.run(command, timeout=5) + if p.returncode != 0: + return False + + +def take_snapshot(node, res, name, rotate, skip=5, debug=False): + setup(node, res, debug=debug) + + speed = 30 + if '@' in res: + res, speed = res.split('@') + command = ['sudo', 'v4l2-ctl', '--device', '/dev/video1', '--stream-mmap', '--stream-to=/tmp/frame.raw', + '--stream-count=1', '--stream-skip={}'.format(skip)] + if debug: + print(command) + p = subprocess.run(command, timeout=10) + if p.returncode != 0: + return False + + command = ['convert', '-size', res, 'uyvy:/tmp/frame.raw', '-rotate', rotate, name] + if debug: + print(command) + p = subprocess.run(command, timeout=15) + if p.returncode != 0: + return False + + command = ['sudo', 'rm', '-rf', '/tmp/frame.raw'] + if debug: + print(command) + subprocess.run(command, timeout=5) + + return True + + +def record(node, res, name, rotate, debug=False): + setup(node, res, debug=debug) + + speed = 30 + if '@' in res: + res, speed = res.split('@') + + command = ['ffmpeg', '-f', 'v4l2', '-framerate', str(speed), '-video_size', res, '-i', '/dev/video1', '-preset', + 'ultrafast', name] + if debug: + print(command) + p = subprocess.run(command) + if p.returncode != 0: + return False + + +def set_route(camera): + if camera == 'ov5640': + links = [ + '"gc2145 3-003c":0->"sun6i-csi":0[0]', + '"ov5640 3-004c":0->"sun6i-csi":0[1]' + ] + elif camera == 'gc2145': + links = [ + '"ov5640 3-004c":0->"sun6i-csi":0[0]', + '"gc2145 3-003c":0->"sun6i-csi":0[1]' + ] + else: + raise Exception("Something wrong") + for link in links: + subprocess.run(['sudo', 'media-ctl', '-d', '/dev/media1', '--links', link]) + + +def main(): + import argparse + + modes_ov5640 = { + 'max': '1920x1080@20', + '1080p': '1920x1080@20', + '1080p20': '1920x1080@20', + '1080p15': '1920x1080@15', + '720p': '1280x720@30', + '720p60': '1280x720@60', + '720p50': '1280x720@50', + '720p30': '1280x720@30', + '720p25': '1280x720@25', + '720p24': '1280x720@24', + } + modes_gc2145 = { + '1080p': '1920x1080@30', + '720p': '1280x720@30', + '1080p15': '1920x1080@15', + } + + options = set(modes_ov5640.keys()) + options.update(modes_gc2145.keys()) + + parser = argparse.ArgumentParser(description="PinePhone camera tool") + parser.add_argument('action', choices=['still', 'movie']) + parser.add_argument('--resolution', '-r', choices=options, default='1080p') + parser.add_argument('--camera', '-c', choices=['rear', 'front'], default='rear') + parser.add_argument('--debug', '-d', action="store_true") + parser.add_argument('filename') + args = parser.parse_args() + + orientation = get_orientation() + if args.camera == "rear": + set_route("ov5640") + node = 'ov5640 3-004c' + if orientation == "portrait": + angle = '90' + elif orientation == "cw": + angle = '0' + elif orientation == "ccw": + angle = '180' + else: + angle = '0' + modes = modes_ov5640 + else: + set_route("gc2145") + node = 'gc2145 3-003c' + angle = '270' + modes = modes_gc2145 + + mode = modes[args.resolution] + + if args.action == "still": + take_snapshot(node, mode, args.filename, angle, debug=args.debug) + elif args.action == "movie": + record(node, mode, args.filename, angle, debug=args.debug) + else: + print("Unsupported action") + exit(1) + + +if __name__ == "__main__": + main() +