#!/bin/sh
# Generate smaller (pixels) (.mp4) video file from source.
#
# May be smaller in size (width x height) and bitrate/bytes.
# 
# Usage:
#     $0 $maxwidth inputvideofile
#
# The maximum width of the result in (CSS) pixels is given by maxwidth.
# If the video is resized then aspect ratio is preserved.
#
# Returns on stdout the path to the new file,
# or nothing if no file can (or need) be made.
# This won't return anything if the output file
# wouldn't be any smaller in bytes.
#
# Atomically creates/replaces result file.
# Concurrency-safe (with mutex).
#
# Output format is always .mp4.
#
# Output width and height and even number of pixels to allow 4:2:0 chroma.
maxwidth=$1
inputvideofile=$2

maxwidtheven="`echo $maxwidth | awk '{print 2 * int($1/2)}'`"
if [ "$maxwidtheven" != "$maxwidth" ]; then
    echo "INFO: $0: $maxwidth rounded down to $maxwidtheven for $inputvideofile." 1>&2
fi

srcwidth="`mediainfo --Inform='Video;%Width%' $inputvideofile`"
srcheight="`mediainfo --Inform='Video;%Height%' $inputvideofile`"
if [ "" = "$srcwidth" -o "" = "$srcheight" ]; then
    echo "ERROR: $0: srcwidth=$srcwidth srcheight=$srcheight for $inputvideofile." 1>&2
    exit 1
fi

if [ "$srcwidth" -le "$maxwidtheven" ]; then
    #echo "INFO: $0: srcwidth=$srcwidth <= $maxwidtheven for $inputvideofile." 1>&2
    exit 0
fi

# Video files can be auto-generated on the fly.
# Simplified compared to general still image processing.
AUTOGENFILEDIR=img/a/v
# If the rebuild flags exists and is newer than any cached result flag,
# unconditionally try to rebuild/refresh everything (carefully, under a lock).
# Else return immediately on cached positive or negative results.
# Assumes that a cached positive result is the most likely.
# Should be touched after any substantive change to image selection/generation.
REBUILDFLAG=img/a/.rebuild.flag

# Temporary files.
TEMPFILEBASE=$AUTOGENFILEDIR/.tmp.$$.
# Pre-tidy!
rm -f $TEMPFILEBASE
# Hook in handler to tidy up temp files on forced exit.
trap "rm -f $TEMPFILEBASE*; exit 1" 1 2 15

# Compute the new (even) height...
H="`echo $srcwidth $srcheight $maxwidtheven | awk '{print 2*int(($2*($3/$1))/2)}'`"

TARGETBASENAME="`basename $inputvideofile | sed -e 's/\.[^.]*$//'`".${maxwidtheven}x${H}.mp4
TARGETNAME=$AUTOGENFILEDIR/$TARGETBASENAME

# If target already exists and is newer, silently leave it in place.
if [ -s $TARGETNAME -a $TARGETNAME -nt $inputvideofile -a ! $REBUILDFLAG -nt $TARGETNAME ]; then
    echo $TARGETNAME
    exit 0
fi

# Failure flag, if used.
FLAGSDIR=$AUTOGENFILEDIR/.flags
FAILFLAG=$FLAGSDIR/${TARGETBASENAME}.FAIL
# If failure flag already exists and is newer, leave things as they are.
if [ -f $FAILFLAG -a $FAILFLAG -nt $inputvideofile -a ! $REBUILDFLAG -nt $FAILFLAG ]; then
    echo "INFO: $0: not attempting to rebuild failed $TARGETNAME" 1>&2
    exit 0
fi
# Clear fail flag since (re)build is happening.
rm -f $FAILFLAG

TEMPNAME=$TEMPFILEBASE.$TARGETBASENAME

# Convert...
VIDOPTS="-vf scale=${maxwidtheven}:${H}"
# DHD20231227: libav no longer supported nor part of Homebrew.
#FFMPEG=avconv
FFMPEG=ffmpeg
echo "INFO: $0: trying to generate smaller ${maxwidtheven}:${H} 'veryslow' video from $inputvideofile." 1>&2
if $FFMPEG </dev/null -loglevel error -i $inputvideofile ${VIDOPTS} -movflags +faststart -q:a 2 -preset veryslow $TEMPNAME && test -s $TEMPNAME; then
    : All OK.
else
    rm -f $TEMPNAME
    echo "INFO: $0: (re)trying to generate smaller ${maxwidtheven}:${H} 'slow' video from $inputvideofile." 1>&2
    if $FFMPEG </dev/null -loglevel error -i $inputvideofile ${VIDOPTS} -preset slow $TEMPNAME && test -s $TEMPNAME; then
        : All OK.
    else
        rm -f $TEMPNAME
    fi
fi

if [ ! -s $TEMPNAME ]; then
    echo "WARNING: $0: failed to generate ${maxwidtheven}:${H} scaled video from $inputvideofile." 1>&2
    rm -f $TEMPNAME ${TARGETNAME} ${TARGETNAME}L
    if [ ! -d "$FLAGSDIR" ]; then mkdir $FLAGSDIR; fi; touch $FAILFLAG
    exit 1
fi

TARGETSIZE="`wc -c < $TEMPNAME`"
if [ "$TARGETSIZE" -ge "`wc -c < $inputvideofile`" ]; then
    #echo "INFO: $0: failed to generate smaller ${maxwidtheven}:${H} video from $inputvideofile." 1>&2
    rm -f $TEMPNAME ${TARGETNAME} ${TARGETNAME}L
    if [ ! -d "$FLAGSDIR" ]; then mkdir $FLAGSDIR; fi; touch $FAILFLAG
    exit 0
fi

DURORIG="`mediainfo --Inform='Video;%Duration%' $inputvideofile`"
DURNEW="`mediainfo --Inform='Video;%Duration%' $TEMPNAME`"
if [ "$DURORIG" != "$DURNEW" ]; then
    # Allow a small length skew between old and new.
    # DHD20231227: after switch to ffmpeg from avconv now assumed to be ms.
    if [ "$DURNEW" -gt 0 -a "`echo $DURORIG $DURNEW | awk '{diff=$1-$2; if(diff<0){diff=-diff} print diff}'`" -le 3000 ]; then
        echo "INFO: $0: minor length change for lo-fi file (duration: new $DURNEW vs old $DURORIG) from $inputvideofile." 1>&2
    else
        echo "WARNING: $0: failed to correctly generate lo-fi file (duration: new $DURNEW vs old $DURORIG) from $inputvideofile." 1>&2
        rm -f $TEMPNAME ${TARGETNAME}L
        if [ ! -d "$FLAGSDIR" ]; then mkdir $FLAGSDIR; fi; touch $FAILFLAG
        exit 1
    fi
fi

chmod -f u+w $TARGETNAME > /dev/null 2>&1
mv -f $TEMPNAME $TARGETNAME
chmod a+r ${TARGETNAME}
echo "INFO: $0: generated video $TARGETNAME from $inputvideofile." 1>&2
echo $TARGETNAME

# Now attempt lo-fi 'L' smaller (fewer bytes) version.
# More effort in compression.
# Failure to generate this version is not an error.
LFILE="`script/compress_video_mp4 $TARGETNAME`"

exit 0
