#!/bin/bash

usage() {
## ugly linebreaks in order to make help2man more happy
    cat <<!
Usage:
    $0 [command] [args]

Commands:
     set-fps <FPS> /dev/videoX  Set device fps (if format is already
                                negotiated).

     set-timeout-image <IMAGE> /dev/videoX  Set timeout on device, and 
                                            optionally the placeholder picture,
                                            instead of default null frame.

     set-caps <CAPS> /dev/videoX  Fix format for the device (using GStreamer
                                  caps), so it will be maintained until reset,
                                  regardless of future readers/writers.

Options:
    FPS      frames per second, either as integer ('30') or fraction ('50/2')
    IMAGE    image file ("no-input.png"), or 'videotestsrc'
    CAPS     GStreamer caps ("video/x-raw-yuv, width=640, height=480"),
             or 'any'
    /dev/videoX  the v4l2-loopback device file you want to act on
!
    exit 1
}

version() {
cat <<!
$0 0.6

Copyright (c) 2012 IOhannes m zmoelnig <zmoelnig@iem.at>
Copyright (c) 2012 Anton Novikov (random.plant@gmail.com)
!
    exit 1
}
die() {
    echo "$@" 1>&2
    exit 1
}

parse_device() {
    if [ -e "$1" ]; then
        device="$1"
    elif [ -e "/dev/video$1" ]; then
        device="/dev/video$1"
    else
        die "can't parse device"
    fi
    sysfs=/sys/devices/virtual/video4linux/${device##*/}
}

check_application() {
 which $1 > /dev/null || die "can't find $1"
}


set_fps() {
    fps="$1"
    parse_device "$2"
    [ -z "$fps" ] && usage

    echo "@$fps" | sudo tee "$sysfs/format" >/dev/null || die "Set fps failed"
    echo OK
}

set_caps() {
    caps="$1"
    parse_device "$2"
    [ -z "$caps" ] && usage

    [ "$caps" = 'any' ] && {
        check_application v4l2-ctl
        v4l2-ctl -d $device -c keep_format=0
        return
    }

    [ -n "`cat $sysfs/format`" ] && die "Device is busy"
    declare -a params
    declare -a nofps_params
    IFS=',' read -ra params <<< "$caps"
    for p in "${params[@]}"; do
        if echo "$p" | grep -q framerate; then
            fps=`echo "$p" | sed -r 's/.*(=|\))//g'`
            echo "$fps" | grep -q '[^0-9/]' && die "could not parse framerate param"
            echo "@$fps" | sudo tee $sysfs/format >/dev/null || die "could not set fps attr"
            #echo "fps: $fps"
        else
            nofps_params=("${nofps_params[@]}" "$p")
        fi
    done
    {
        IFS=','
        nofps_caps="${nofps_params[*]}"
    }
    #echo "nofps_caps: $nofps_caps"
    check_application v4l2-ctl
    check_application gst-launch-1.0

    v4l2-ctl -d $device -c keep_format=1 || exit 1
    v4l2-ctl -d $device -c sustain_framerate=1 || exit 1
    gst-launch-1.0 videotestsrc num-buffers=1 ! "$nofps_caps" ! v4l2sink device=$device || die "output to $device failed"
}

set_timeout_image() {
    imagefile="$1"
    parse_device "$2"

    [ -z "$imagefile" ] && return
    [ -n "`cat $sysfs/format`" ] || die "Device has no format negotiated"

    check_application v4l2-ctl
    check_application gst-launch-1.0

    v4l2-ctl -d $device -c timeout_image_io=1
    if [ "$imagefile" = 'videotestsrc' ]; then
        gst-launch-1.0 videotestsrc num-buffers=1 ! v4l2sink device=$device
    else
        uri="file://`readlink -f $imagefile`" || die "no file"
        echo "Reading from $uri"
        gst-launch-1.0 uridecodebin uri=$uri ! videoconvert ! videoscale ! imagefreeze ! identity error-after=2 ! v4l2sink show-preroll-frame=false device=$device
    fi
    timeout=`v4l2-ctl -d $device -C timeout | sed -n 's/^timeout: //p'`
    [ -n "$timeout" ] || die "couldn't get timeout"
    echo "timeout: $timeout"
    [ "$timeout" = 0 ] && {
        echo 'Timeout is currently disabled; you can set it to some positive value, e.g.:'
        echo "$ v4l2-ctl -d $device -c timeout=3000"
    }
}

command="$1"
shift
case "$command" in
    "-h"|"--help")
	usage
	;;
    "-v"|"--version")
	version
	;;
    "set-fps")
        set_fps "$@"
        ;;
    "set-caps")
        set_caps "$@"
        ;;
    "set-timeout-image")
        set_timeout_image "$@"
        ;;
    *)
        usage
        ;;
esac
