#!/bin/bash -e
#
# Copyright 2015-2016 ELVEES NeoTek JSC
# Copyright 2019 RnD Center "ELVEES", JSC
# SPDX-License-Identifier: BSD-2-Clause
#
# Author: Anton Leontiev <aleontiev@elvees.com>
#
# This is a functional and speed test for Avico VPU found in MCom.
#

set_default() {
    DEVICE=/dev/v4l/by-path/platform-37100000.codec-video-index0
    DURATION=2
    SIZE=1280x720
    EXPECTED_MD5=032037c500294c5f6577b892a4d96912
    NTHREADS=2
    FPS_THRESHOLD=30
    CHECK=0
}

failed() {
    echo 'TEST FAILED'
}

help() {
    echo 'fc-avico - tool to check and benchmark Avico VPU'
    echo 'Usage: fc-avico [options] [device]'
    echo
    echo 'Options:'
    echo '    -c           Check output file integrity'
    if [ $CHECK -eq 1 ]; then
        echo "                 (default: enabled)"
    else
        echo "                 (default: disabled)"
    fi
    echo '    -d DURATION  Video duration in seconds'
    echo "                 (default: $DURATION)"
    echo '    -h           Show help'
    echo '    -l THRESHOLD Lower limit of the FPS'
    echo "                 (default: $FPS_THRESHOLD)"
    echo '    -m MD5       Expected MD5 sum of output video'
    echo "                 (default: $EXPECTED_MD5)"
    echo '    -n NTHREADS  Number of threads to run'
    echo "                 (default: $NTHREADS)"
    echo '    -r RES       Set RES resolution'
    echo "                 (default: $SIZE)"
    echo '    -u           Enable USERPTR memory type on output interface'
    echo "                 (default: MMAP memory type)"
    echo '    -v           Increase verbosity'
    echo
    echo "Default device is $DEVICE"
}

set_default;

while getopts 'cd:hl:m:n:r:uv' opt; do
    case $opt in
        c) CHECK=1;;
        d) DURATION=$((OPTARG));;  # cast to int
        h) set_default; help; exit 0;;
        l) FPS_THRESHOLD=$((OPTARG));; # cast to int
        m) EXPECTED_MD5=$OPTARG;;
        n) NTHREADS=$((OPTARG));;  # cast to int
        r) SIZE=$OPTARG;;
        u) USERPTR='-u';;
        v) set -x;;
        ?) exit 1;;
    esac
done

shift $(($OPTIND - 1))

[ -n "$1" ] && DEVICE="$1"
if [ $DURATION -le 0 ]; then
    echo 'Video duration must be greater than zero'
    exit 1
fi
if [ $NTHREADS -le 0 ]; then
    echo 'Threads number must be greater than zero'
    exit 1
fi

TMP_DIR="/tmp/$(basename $0)"
mkdir -p "$TMP_DIR"
pushd $TMP_DIR

trap failed 0

modprobe avico
lsmod | grep -q ^avico

test -c "$DEVICE"

CMD="ffmpeg -loglevel error -f lavfi \
        -i testsrc=duration=$DURATION:size=$SIZE \
        -pix_fmt yuv420p -y input.y4m"

if [ -e m420.y4m -a "$(cat cmd.txt 2>/dev/null)" != "$CMD" ]; then
    # Uncompressed file created with another arguments
    rm -f m420.y4m
fi

if [ ! -e m420.y4m ]; then
    rm -f cmd.txt
    # Prepare original video
    $CMD

    # Avico driver does not support pixel format other than M420, so we need
    # to convert video to M420.
    any2m420 -o m420.y4m input.y4m 2> /dev/null
    rm input.y4m
    echo "$CMD" > cmd.txt
fi

for ((i=0;i<NTHREADS;i++)); do
    m2m-test $USERPTR -d "$DEVICE" -v -o encoded_$i.264 m420.y4m | tee avico_$i.log &
done

wait

ORIGINAL_SIZE=`du m420.y4m | cut -f1`
for ((i=0;i<NTHREADS;i++)); do
    echo "Checking results for thread #$i"
    awk '
        /Total time in main loop/ { fps = substr($8, 2) + 0; };
        END { if (fps < min) exit 1; }
    ' min=$FPS_THRESHOLD avico_$i.log

    ENCODED_SIZE=`du encoded_$i.264 | cut -f1`

    test `expr $ORIGINAL_SIZE / 10` -gt $ENCODED_SIZE
    [ $CHECK -eq 1 ] && echo "$EXPECTED_MD5  encoded_$i.264" | md5sum -c
done

trap - 0
echo 'TEST PASSED'
