#!/bin/bash set -e # test encoders and decoders SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) TEST_NAME="$1" [ ! -z $TEST_NAME ] || TEST_NAME=${BASH_SOURCE[0]##*/} ENCDECLIST="$SCRIPT_DIR/${TEST_NAME}"_list.txt TEST_DIR="$ADTTMP/test" encode_file() { test=$1 dir=$2 mux=${test%%;*} tenc=${test##*;} type=${tenc%%=*} enc=${tenc##*=} codec=${enc%%:*} encoder=${enc##*:} file_name="$dir/$encoder.$mux" opts= # some codecs require extra options if [ "$codec" == "avui" ]; then opts="-s 720x486" elif [ "$codec" == "dnxhd" ]; then opts="-s 1280x720 -b:v 90M" elif [ "$codec" == "dvvideo" ]; then opts="-s 720x480 -pix_fmt yuv411p" elif [ "$codec" == "h261" ]; then opts="-s 176x144" elif [ "$codec" == "h263" ]; then opts="-s 128x96" elif [ "$codec" == "hevc" ]; then opts="-s 64x64" elif [ "$codec" == "roq" ]; then opts="-s 128x128" elif [ "$codec" == "xface" ]; then opts="-s 48x48" elif [ "$codec" == "g723_1" ]; then opts="-ar 8000 -b:a 6300" elif [ "$codec" == "gsm" ]; then opts="-ar 8000 -b:a 13000" elif [ "$codec" == "gsm_ms" ]; then opts="-ar 8000 -b:a 13000" elif [ "$codec" == "roq_dpcm" ]; then opts="-ar 22050" elif [ "$codec" == "s302m" ]; then opts="-ac 2" elif [ "$codec" == "vorbis" ]; then opts="-ac 2" fi src= if [ "$type" = "v" ]; then src=testsrc=s=32x32:d=0.1 elif [ "$type" = "a" ]; then src=sine=d=0.1 else # unknown codec type return 10 fi echo -e "trying muxer '$mux' with '$type' encoder '$encoder' for codec '$codec'\n" ret=0 CMD="ffmpeg -f lavfi -i $src -strict -2 $opts -c:$type $encoder -f $mux $file_name -y -hide_banner -nostdin" echo $CMD $CMD 2>&1 || ret=$? return $ret } probe_file() { file_name=$1 test=$2 mux=${test%%;*} tenc=${test##*;} enc=${tenc##*=} codec=${enc%%:*} # determine the codec/format ret=0 info=$(ffprobe -hide_banner -strict -2 "$file_name" 2>&1) || ret=$? if [ "$ret" != 0 ]; then echo "probing failed: $ret" return "$ret" fi # file formats can be a comma-separated list, e.g. matroska,webm file_formats=$(echo "$info" | grep "Input #" | sed "s/.*Input #[0-9]*, \([^ ]*\), from.*/\1/") file_formats=${file_formats//,/ } # there can be multiple streams, thus multiple codecs file_codecs=$(echo "$info" | grep "Stream #" | sed "s/.*Stream #.*:.*:.*: \([^ ,]*\).*/\1/") same_format= same_codec= # test if the file has the correct codec/format for file_format in $file_formats; do if [ "$mux" == "$file_format" ]; then same_format="$file_format" fi done if [ ! "$same_format" ]; then # wrong format echo "file has the wrong format: $file_formats" return 10 fi for file_codec in $file_codecs; do if [ "$codec" == "$file_codec" ]; then same_codec="$file_codec" fi done if [ ! "$same_codec" ]; then # wrong codec echo "file has the wrong codec: $file_codecs" return 11 fi return 0 } decode_file() { file_name=$1 ret=0 # The option '-t 1' is necessary, because the comfortnoise decoder never stops producing noise. CMD="ffmpeg -strict -2 -i $file_name -t 1 -c:v rawvideo -c:a pcm_s32le -f nut /dev/null -y -hide_banner -nostdin" echo $CMD $CMD 2>&1 || ret=$? return $ret } streamcopy_file() { file_name=$1 test=$2 mux=${test%%;*} file_name_copy="$file_name.copy.$mux" ret=0 # The option '-t 1' is necessary, because the comfortnoise decoder never stops producing noise. CMD="ffmpeg -strict -2 -i $file_name -t 1 -c copy -f $mux $file_name_copy -y -hide_banner -nostdin" echo $CMD $CMD 2>&1 || ret=$? return $ret } list_formats() { match="$1" old_IFS=$IFS # Set the field seperator to a newline IFS=" " # Get the raw list lines=$(ffmpeg -hide_banner -formats | grep "^ $match") for line in $lines; do item=$(echo "$line" | sed "s/^ [D ][E ] \([^ ]*\) .*/\1/") item=${item%%,*} echo "$item" done IFS=$old_IFS } list_codecs() { what=$1 match="$2" type="$3" old_IFS=$IFS # Set the field seperator to a newline IFS=" " # Get the raw list lines=$(ffmpeg -hide_banner -codecs | grep "^ $match$type") for line in $lines; do items=$(echo "$line" | grep "($what:") codec=$(echo "$line" | sed "s/^ [^ ]* \([^ ]*\) .*/\1/") if [ -z "$items" ]; then echo "${type,,}=$codec" else # de/encoder(s) name(s) differ from codec name items=$(echo "$items" | sed "s/.*($what: \([^)]*\) ).*/\1/") IFS=" " for item in $items; do echo "${type,,}=$codec:$item" done IFS=" " fi done IFS=$old_IFS } list_muxers() { muxs=$(list_formats ".E [^=]") echo $muxs } list_demuxers() { dems=$(list_formats "D. [^=]") echo $dems } list_video_encoders() { vencs=$(list_codecs encoders ".E" "V") echo $vencs } list_video_decoders() { vdecs=$(list_codecs decoders "D." "V") echo $vdecs } list_audio_encoders() { aencs=$(list_codecs encoders ".E" "A") echo $aencs } list_audio_decoders() { adecs=$(list_codecs decoders "D." "A") echo $adecs } read_tests() { filename=$1 old_IFS=$IFS # Set the field seperator to a newline IFS=" " # Get the raw list lines=$(cat "$filename") for line in $lines; do muxer=${line%%;*} tencs=${line##*;} if [ "$tencs" ]; then IFS=" " for tenc in $tencs; do echo "$muxer;$tenc" done IFS=" " fi done IFS=$old_IFS } echo "TEST: $TEST_NAME" echo -e "ADTTMP directory: $ADTTMP\n\n" mkdir -p "$TEST_DIR" ffmpeg -version 2>&1 echo -e "\n" # determine the supported muxers and encoders echo "muxers:" muxs=$(list_muxers) echo "$muxs" echo -e "\n" vencs=$(list_video_encoders) aencs=$(list_audio_encoders) echo "encoders:" encs="$vencs $aencs" echo "$encs" echo -e "\n" for mux in $muxs; do mux_tests= for tenc in $encs; do mux_tests="$mux_tests $mux;$tenc " done possible_tests="$possible_tests$mux_tests" done if [ -f $ENCDECLIST ]; then tests=$(read_tests $ENCDECLIST) else # create the list of working tests if it doesn't exist update="true" tests=$possible_tests fi num_tests=$(echo $tests | wc -w) echo -e "$num_tests tests\n" crashes= failures= skipped= num_test=0 num_success=0 for test in $tests; do num_test=$((num_test + 1)) echo "Test $num_test:" streamcopy=${test##*|} if [ "$update" ]; then streamcopy=1 fi test=${test%%|*} # skip the test, if the muxer/encoder is not available available=$(echo "$possible_tests" | grep " $test ") || true if [ ! "$available" ]; then skipped="${skipped}${test}\n" echo -e "SKIPPED: $test\n\n" continue fi mux=${test%%;*} tenc=${test##*;} ret=0 # try encoding a file # this also sets the file_name variable encode_file $test $TEST_DIR || ret=$? echo -e "\n" if [ "$ret" != "0" ]; then errmsg="$test; encoding return code: $ret" if [ "$ret" -gt 128 ]; then crashes="${crashes}${errmsg}\n" else failures="${failures}${errmsg}\n" fi echo -e "\nFAILED: $errmsg\n\n" continue fi ret=0 # test if the file has the correct format/codec err=$(probe_file "$file_name" $test) || ret=$? if [ "$ret" != "0" ]; then errmsg="$test; $err" if [ "$ret" -gt 128 ]; then crashes="${crashes}${errmsg}\n" else failures="${failures}${errmsg}\n" fi echo -e "\nFAILED: $errmsg\n\n" continue fi ret=0 # test decoding the file decode_file "$file_name" || ret=$? if [ "$ret" != "0" ]; then errmsg="$test; decoding return code: $ret" if [ "$ret" -gt 128 ]; then crashes="${crashes}${errmsg}\n" else failures="${failures}${errmsg}\n" fi echo -e "\nFAILED: $errmsg\n\n" continue fi streamcopy_orig="$streamcopy" if [ "$streamcopy" == "1" ]; then ret=0 # test streamcopying the file # this also sets the file_name_copy variable echo -e "\n" streamcopy_file "$file_name" "$test" || ret=$? if [ "$ret" != "0" ]; then errmsg="$test; streamcopy return code: $ret" if [ "$ret" -gt 128 ]; then crashes="${crashes}${errmsg}\n" else failures="${failures}${errmsg}\n" fi echo -e "\nFAILED: $errmsg\n\n" streamcopy=0 fi fi if [ "$streamcopy" == "1" ]; then ret=0 # test if the file has the correct format/codec err=$(probe_file "$file_name_copy" $test) || ret=$? if [ "$ret" != "0" ]; then errmsg="$test; streamcopy: $err" if [ "$ret" -gt 128 ]; then crashes="${crashes}${errmsg}\n" else failures="${failures}${errmsg}\n" fi echo -e "\nFAILED: $errmsg\n\n" streamcopy=0 fi fi works=$([ "$streamcopy" = "1" ] && echo works || echo fails) if [ "$streamcopy_orig" = "$streamcopy" ]; then echo -e "\nSUCCESS: correctly created file with format '$mux' and codec '$tenc'; streamcopying $works\n\n" num_success=$((num_success + 1)) fi if [ "$update" ]; then if [ "x$last_mux" != "x$mux" ]; then if [ "$last_mux" ]; then # newline echo "" >> $ENCDECLIST fi echo -n "$mux;" >> $ENCDECLIST fi last_mux=$mux echo -n " $tenc|$streamcopy" >> $ENCDECLIST fi done echo "done!" ret=0 num_crashes=0 num_failures=0 num_skipped=0 if [ "$crashes" ]; then num_crashes=$(echo -e "$crashes" | wc -l) num_crashes=$((num_crashes - 1)) fi if [ "$failures" ]; then num_failures=$(echo -e "$failures" | wc -l) num_failures=$((num_failures - 1)) fi if [ "$skipped" ]; then num_skipped=$(echo -e "$skipped" | wc -l) num_skipped=$((num_skipped - 1)) fi if [ "$num_crashes" != "0" ]; then ret=1 echo -e "\n\ncrashes: $num_crashes\n" echo -e "$crashes" fi if [ "$num_failures" != "0" ]; then ret=1 echo -e "\n\nfailures: $num_failures\n" echo -e "$failures" fi if [ "$num_skipped" != "0" ]; then echo -e "\n\nskipped: $num_skipped\n" echo -e "$skipped" fi if [ "$num_success" != "0" ]; then echo -e "\n\nsuccess: $num_success\n" else ret=1 echo -e "\n\nno single success: something is definitely wrong\n" fi exit $ret