309,6 → 309,10 |
# It is executed by create_contact_sheet() |
declare CSHEET_DELEGATE=csheet_montage |
|
# Holds a list of captured frames (to avoid recapturing) |
# Format <timestamp>:<filename>[NL]<timestamp>:<filename>... |
declare CAPTURES= |
|
# Gravity of the timestamp (will be override-able in the future) |
declare grav_timestamp=SouthEast |
|
537,7 → 541,7 |
[[ ! $line =~ ^[[:space:]]*# ]] || continue # Don't feed comments |
parse_override "$line" |
por=$RESULT |
if [ "$por" ]; then |
if [[ $por ]]; then |
varname=${por/% *} # Everything up to the first space... |
tmp=${por#* } # Rest of string |
flag=${tmp/% *} |
852,10 → 856,9 |
|
## Natural number |
is_number() { |
# From [[abs]], test if '[ ]' can parse input as numbers. |
# Can't use '[[' since parses non-numbers as 0 |
# Returns 2 for failed test, expected to return 1 |
[ "$1" -ne 0 -o "$1" -eq 0 ] 2>/dev/null || return 1 |
# With '[[...]]', strings '-eq'uals 0, test if it's actually 0 |
#+or otherwise a valid number. Must return 1 on error. |
[[ ( $1 == '0' ) || ( $1 -gt 0 ) ]] 2>/dev/null || return 1 |
} |
## Number > 0 |
is_positive() { is_number "$1" && [[ $1 -gt 0 ]]; } |
889,8 → 892,8 |
is_fraction() { |
local P='^[0-9]+/[0-9]+$' |
[[ $1 =~ $P ]] && { |
local d=$(echo "$1" | cut -d'/' -f2) |
[ "$d" -ne 0 ] |
local d=${1#*/} # .../X |
[[ $d -ne 0 ]] |
} |
} |
## Decoder ($DEC_* constants) |
938,8 → 941,8 |
rtomult() { |
local n=$1 d=$2 |
local r=$(( $n % $d )) |
if [ $r -ne 0 ]; then |
let 'n += ( d - r )' |
if [[ $r -ne 0 ]]; then |
(( n += ( d - r ) , 1 )) |
fi |
echo $n |
} |
955,11 → 958,11 |
-le) op='<=' ;; |
-eq) op='==' ;; |
-ne) op='!=' ;; |
*) assert "[ \"'$1' '$2' '$3'\" ] && false" && return $EX_SOFTWARE |
*) assert "[[ \"'$1' '$2' '$3'\" ]] && false" && return $EX_SOFTWARE |
esac |
# Empty operands |
if [ -z "$1" ] || [ -z "$3" ]; then |
assert "[ \"'$1' '$2' '$3'\" ] && false" |
if [[ ( -z $1 ) || ( -z $3 ) ]]; then |
assert "[[ \"'$1'\" && \"'$3'\" ]] && false" |
else |
awk "BEGIN { if ($1 $op $3) exit 0 ; else exit 1 }" |
fi |
973,7 → 976,8 |
|
# Keep a number of decimals, last decimal rounded to lower |
keepdecimals_lower() { |
grep -q '\.' <<<"$1" || { echo "$1" ; return ; } |
local ERE='\.' |
[[ $1 =~ $ERE ]] || { echo "$1" ; return ; } |
local D=${1/#*.} # Decimals only |
echo ${1/%.*}.${D:0:$2} # Integer part + . + Number of decimals |
} |
1000,7 → 1004,7 |
# converts spaces to newlines in a x-platform way [[FNL]] |
# stonl([$1 = string]) |
stonl() { |
if [ "$1" ]; then |
if [[ $1 ]]; then |
awk '{gsub(" ", "\n");print}' <<<"$1" | egrep -v '^$' |
else |
awk '{gsub(" ", "\n");print}' | egrep -v '^$' |
1010,7 → 1014,7 |
# Converts newlines to spaces portably |
# nltos([$1 = string]) |
nltos() { |
if [ "$1" ]; then |
if [[ $1 ]]; then |
awk '{printf "%s ",$0}' <<<"$1" | sed 's/ *//' |
else |
awk '{printf "%s ",$0}' | sed 's/ *//' |
1025,7 → 1029,8 |
|
# Get file extension |
filext() { |
grep -o '\.[^.]*$' <<<"$1" | cut -d. -f2 |
#grep -o '\.[^.]*$' <<<"$1" | cut -d. -f2 |
expr match "$1" '.*\.\(.*\)' |
} |
|
# Wrapper around $RANDOM, not called directly, wrapped again in rand(). |
1073,7 → 1078,7 |
local v="$1" |
local -i hv=15031 |
local c= |
if [ "$v" ]; then |
if [[ $v ]]; then |
for i in $(seqr 0 ${#v} ); do |
c=$( ord ${v:$i:1} ) |
hv=$(( ( ( $hv << 1 ) + $c ) % $HASH_LIMIT )) |
1152,9 → 1157,10 |
# Seconds without unit. They must be preceded by h, m or s at this point |
local secs=$(echo $s | egrep -o '.?[0-9]*$') |
# When preceded by '.', they're ms |
[ "$secs" ] && grep -q '\.'<<<"$secs" && secs= |
local ERE='\.' |
[[ $secs && ( $secs =~ $ERE ) ]] && secs= |
# Quote and addition. Note BSD grep/egrep wants the anchor ($) or won't match |
[ "$secs" ] && secs=" \"$(egrep -o '[0-9]*$'<<<"$secs")\" + " |
[[ $secs ]] && secs=" \"$(egrep -o '[0-9]*$'<<<"$secs")\" + " |
t=${t//h/ * 3600 + } |
t=${t//m/ * 60 + } |
t=${t//s/ + } |
1163,7 → 1169,7 |
r=$(awkexf "$t" 2>/dev/null) |
|
# Negative and empty intervals |
assert "[ '$r' -a '$t' ]" |
assert "[[ '$r' && '$t' ]]" |
assert "fptest $r -gt 0" |
|
echo $r |
1372,7 → 1378,7 |
FFMPEG=$(type -pf ffmpeg) || true |
|
# Test we can actually use FFmpeg |
[ "$FFMPEG" ] && { |
[[ $FFMPEG ]] && { |
# Newer FF has -codecs, -formats, -protocols, older has only -formats |
#+png is a codec so it's on different lists on newer and older |
if ! "$FFMPEG" -formats 2>/dev/null | grep -q 'EV.* png' && \ |
1383,7 → 1389,7 |
fi |
} |
# Same for Mplayer |
[ "$MPLAYER" ] && { |
[[ $MPLAYER ]] && { |
if ! "$MPLAYER" -vo help 2>&1 | grep -q 'png' ; then |
warn "MPlayer can't output to png, won't be able to use it." |
MPLAYER='' |
1391,17 → 1397,17 |
fi |
} |
|
[ "$MPLAYER" ] || [ "$FFMPEG" ] || { |
[[ ( -n $MPLAYER ) || ( -n $FFMPEG ) ]] || { |
local pngwarn= |
[ $nopng -eq 1 ] && pngwarn=', with PNG output support,' |
[[ $nopng -eq 1 ]] && pngwarn=', with PNG output support,' |
error "mplayer and/or ffmpeg$pngwarn are required!" |
let 'retval++,1' |
(( retval++ ,1 )) |
} |
|
|
if [ $decoder -eq $DEC_FFMPEG ] && [ -z "$FFMPEG" ]; then |
if [[ ( $decoder -eq $DEC_FFMPEG ) && ( -z $FFMPEG ) ]]; then |
decoder=$DEC_MPLAYER |
elif [ $decoder -eq $DEC_MPLAYER ] && [ -z "$MPLAYER" ]; then |
elif [[ ( $decoder -eq $DEC_MPLAYER ) && ( -z $MPLAYER ) ]]; then |
decoder=$DEC_FFMPEG |
fi |
|
1409,13 → 1415,13 |
for prog in convert montage identify mktemp grep egrep cut sed awk ; do |
if ! type -pf "$prog" ; then |
error "Required program $prog not found!" |
let 'retval++,1' |
(( retval++ ,1 )) |
fi >/dev/null |
done |
# TODO: [[x2]] |
|
# Early exit |
[ $retval -eq 0 ] || return $EX_UNAVAILABLE |
[[ $retval -eq 0 ]] || return $EX_UNAVAILABLE |
|
# ImageMagick version. 6 is a must, I'm probably using some |
# features that require a higher minor version |
1424,7 → 1430,7 |
local ver |
ver=$(identify -version | head -n1 | grep -o 'ImageMagick[[:space:]]*[^ ]*' |\ |
cut -f 2 -d' ') |
if [ "$ver" ]; then |
if [[ $ver ]]; then |
local verx=${ver//-/.}.0 # Extra .0 in case rev doesn't exist |
local major=$(cut -d'.' -f1 <<<"$verx") |
local minor=$(cut -d'.' -f2 <<<"$verx") |
1431,22 → 1437,22 |
local micro=$(cut -d'.' -f3 <<<"$verx") |
local rev=$(cut -d'.' -f4 <<<"$verx") |
local serial=$(( $major * 100000 + $minor * 10000 + $micro * 100 + $rev)) |
if [ "$serial" -lt 630507 ]; then |
if [[ $serial -lt 630507 ]]; then |
error "ImageMagick 6.3.5-7 or higher is required. Found $ver." ; |
let 'retval++,1' |
(( retval++ ,1 )) |
fi |
else |
error "Failed to check ImageMagick version." |
let 'retval++,1' |
(( retval++ ,1 )) |
fi |
|
[ $retval -eq 0 ] || return $EX_UNAVAILABLE |
[[ $retval -eq 0 ]] || return $EX_UNAVAILABLE |
} |
|
# Test wether $GETOP is a compatible version; try to choose an alternate if |
# possible |
choose_getopt() { |
if ! type -pf $GETOPT ; then |
if ! type -pf "$GETOPT" ; then |
# getopt not in path |
error "Required program getopt not found!" |
return $EX_UNAVAILABLE |
1455,13 → 1461,13 |
# Try getopt. If there's more than one in the path, try all of them |
for goe in $(type -paf $GETOPT) ; do |
"$goe" -T || gor=$? |
if [ $gor -eq 4 ]; then |
if [[ $gor -eq 4 ]]; then |
# Correct getopt found |
GETOPT="$goe" |
break; |
fi |
done >/dev/null |
if [ $gor -ne 4 ]; then |
if [[ $gor -ne 4 ]]; then |
error "No compatible version of getopt in path, can't continue." |
error " For details on how to correct this problems, see <http://p.outlyer.net/vcs#getopt>" |
return $EX_UNAVAILABLE |
1473,7 → 1479,7 |
# Does nothing if none has been created so far |
# cleanup() |
cleanup() { |
if [ -z $TEMPSTUFF ]; then return 0 ; fi |
if [[ -z $TEMPSTUFF ]]; then return 0 ; fi |
inf "Cleaning up..." |
rm -rf "${TEMPSTUFF[@]}" |
unset VCSTEMPDIR |
1485,7 → 1491,7 |
# exithdlr() |
exithdlr() { |
# I don't think that's really required anyway |
if [ "$RANDFUNCTION" == "filerand" ]; then |
if [[ $RANDFUNCTION == 'filerand' ]]; then |
7<&- # Close FD 7 |
fi |
cleanup |
1498,8 → 1504,8 |
# |
# error($1 = text) |
error() { |
if [ $verbosity -ge $V_ERROR ]; then |
[ $plain_messages -eq 0 ] && echo -n "$prefix_err" |
if [[ $verbosity -ge $V_ERROR ]]; then |
[[ $plain_messages -eq 0 ]] && echo -n "$prefix_err" |
# sgr0 is always used, this way if |
# a) something prints inbetween messages it isn't affected |
# b) if plain_messages is overridden colour stops after the override |
1512,8 → 1518,8 |
# Print a non-fatal error or warning |
# warning($1 = text) |
warn() { |
if [ $verbosity -ge $V_WARN ]; then |
[ $plain_messages -eq 0 ] && echo -n "$prefix_warn" |
if [[ $verbosity -ge $V_WARN ]]; then |
[[ $plain_messages -eq 0 ]] && echo -n "$prefix_warn" |
echo "$1$suffix_fback" |
fi >&2 |
} |
1521,8 → 1527,8 |
# Print an informational message |
# inf($1 = text) |
inf() { |
if [ $verbosity -ge $V_INFO ]; then |
[ $plain_messages -eq 0 ] && echo -n "$prefix_inf" |
if [[ $verbosity -ge $V_INFO ]]; then |
[[ $plain_messages -eq 0 ]] && echo -n "$prefix_inf" |
echo "$1$suffix_fback" |
fi >&2 |
} |
1531,7 → 1537,7 |
# Same as inf but with no colour ever. |
# infplain($1 = text) |
infplain() { |
if [ $verbosity -ge $V_INFO ]; then |
if [[ $verbosity -ge $V_INFO ]]; then |
echo "$1" >&2 |
fi |
} |
1544,7 → 1550,6 |
# buffered($1 = feedback function, $2 = arguments) |
buffered() { |
local grab=$( $1 "$2" 2>&1 ) |
# BUFFER=( "${BUFFER[@]}" -- "$grab" ) |
BUFFER=$BUFFER$grab$NL |
} |
|
1552,7 → 1557,7 |
# Print buffered feedback to stderr |
# flush_buffered([$1 = indentation]) |
flush_buffered() { |
[ "${BUFFER[*]}" ] || return 0 |
[[ ${BUFFER[*]} ]] || return 0 |
echo "$BUFFER" | sed -e '$d' -e "s/^/$1/g" >&2 # sed: delete last line, indent with $1 |
BUFFER='' |
} |
1570,9 → 1575,9 |
# If no exit_code is provided, use $ERROR_CODE |
die() { |
local m=$1 ec=$2 |
[ "$ec" ] || ec=$ERROR_CODE |
[ "$ec" ] || ec=1 |
[ "$m" ] || m=$ERROR_MSG |
[[ $ec ]] || ec=$ERROR_CODE |
[[ $ec ]] || ec=1 |
[[ $m ]] || m=$ERROR_MSG |
error "$m" |
exit $ec |
} |
1583,7 → 1588,7 |
has_filter() { |
local filter= ref=$1 |
for filter in ${FILTERS_IND[@]} ; do |
[ "$filter" == "$ref" ] || continue |
[[ $filter == $ref ]] || continue |
return 0 |
done |
return 1 |
1618,7 → 1623,7 |
fi >/dev/null |
fi |
|
if [ -z "$HAS_COLORS" ]; then |
if [[ -z $HAS_COLORS ]]; then |
# tput was not an option, let's try ANSI escape codes instead [[AEC]] |
# TODO: Detect support |
# Alternatively: $ perl -e 'print "\e[31m\e[1m"' |
1632,7 → 1637,7 |
fi |
|
# Finally, if there's no colour support, use prefixes instead |
if [ -z "$HAS_COLORS" ]; then |
if [[ -z $HAS_COLORS ]]; then |
set_feedback_prefixes |
fi |
} |
1645,7 → 1650,7 |
# seqr($1 = from, $2 = to, $3 = increment) |
seqr() { |
local from=$1 to=$2 inc=$3 |
[ "$inc" ] || inc=1 |
[[ $inc ]] || inc=1 |
awk "BEGIN { for (i=$from;i<=$to;i+=$inc) print i }" |
} |
|
1828,7 → 1833,7 |
local runlen=$(awkexf "$end - $st") |
|
if fptest "($end-$eo-$st)" -le 0 ; then |
if fptest "$eo" -gt 0 && [ -z "$USR_end_offset" ] ; then |
if fptest "$eo" -gt 0 && [[ -z $USR_end_offset ]] ; then |
warn "Default end offset was too high for the video, ignoring it." |
eo=0 |
else |
2551,31 → 2556,31 |
# For some reason my (one track) samples have two ..._NCH, first one 0 |
#+Also multichannel is detected as 2 ch |
mi[$CHANS]=$(grep ID_AUDIO_NCH <<<"$MPLAYER_CACHE"| grep -v '=0' | cut -d'=' -f2|head -1) |
if [ $DVD_MODE -eq 0 ]; then |
if [[ $DVD_MODE -eq 0 ]]; then |
# For DVDs it prints ID_DVD_TITLE_x_LENGTH and ID_LENGTH. |
#+Both appear valid. |
mi[$LEN]=$(grep ID_DVD_TITLE_${DVD_TITLE}_LENGTH <<<"$MPLAYER_CACHE"| cut -d'=' -f2) |
[ "${mi[$LEN]}" ] || mi[$LEN]=$(grep ID_LENGTH <<<"$MPLAYER_CACHE"| head -1 | cut -d'=' -f2) |
[[ ${mi[$LEN]} ]] || mi[$LEN]=$(grep ID_LENGTH <<<"$MPLAYER_CACHE"| head -1 | cut -d'=' -f2) |
else |
mi[$LEN]=$(grep ID_DVD_TITLE_${DVD_TITLE}_LENGTH <<<"$MPLAYER_CACHE"| head -1 | cut -d'=' -f2) |
fi |
# Voodoo :P Remove (one) trailing zero |
if [ "${mi[$FPS]:$(( ${#mi[$FPS]} - 1 ))}" == "0" ]; then |
if [[ "${mi[$FPS]:$(( ${#mi[$FPS]} - 1 ))}" == '0' ]]; then |
mi[$FPS]="${mi[$FPS]:0:$(( ${#mi[$FPS]} - 1 ))}" |
fi |
mi[$ASPECT]=$(grep ID_VIDEO_ASPECT <<<"$MPLAYER_CACHE" | egrep -v '^0.0000$' | cut -d'=' -f2 | tail -1) |
# If none set, delete it |
[ "${mi[$ASPECT]}" ] && fptest "${mi[$ASPECT]}" -eq 0.0 && mi[$ASPECT]='' |
[[ ${mi[$ASPECT]} ]] && fptest "${mi[$ASPECT]}" -eq 0.0 && mi[$ASPECT]='' |
mi[$VCNAME]=$(get_vcodec_name "${mi[$VCODEC]}") |
if [ "${mi[$VDEC]}" == "ffodivx" ] && [ "${mi[$VCNAME]}" != "MPEG-4" ]; then |
if [[ ( ${mi[$VDEC]} == 'ffodivx' ) && ( ${mi[$VCNAME]} != 'MPEG-4' ) ]]; then |
mi[$VCNAME]="${mi[$VCNAME]} (MPEG-4)" |
elif [ "${mi[$VDEC]}" == "ffh264" ]; then # At least two different fourccs use h264, maybe more |
elif [[ ${mi[$VDEC]} == 'ffh264' ]]; then # At least two different fourccs use h264, maybe more |
mi[$VCNAME]="${mi[$VCNAME]} (h.264)" |
fi |
mi[$ACNAME]=$(get_acodec_name "${mi[$ACODEC]}") |
if [ "${mi[$ACODEC]}" == "samr" ] ; then |
if [[ ${mi[$ACODEC]} == 'samr' ]] ; then |
local adec=$(grep ID_AUDIO_CODEC <<<"$MPLAYER_CACHE" | head -1 | cut -d'=' -f2) |
if [ "$adec" == "ffamrnb" ]; then |
if [[ $adec == 'ffamrnb' ]]; then |
mi[$ACNAME]="AMR-NB"; |
fi |
fi |
2679,7 → 2684,7 |
# Newer CHANS and some older... |
fi[$CHANS]=$(egrep -o '[0-9]* channels' <<<"$as" | cut -d' ' -f1) |
# ...fallback for older |
if [ -z "${fi[$CHANS]}" ]; then |
if [[ -z ${fi[$CHANS]} ]]; then |
local chans=$(egrep -o 'Hz, [^,]*' <<<"$as" | cut -d' ' -f2) |
case $chans in |
mono) fi[$CHANS]=1 ;; |
2698,11 → 2703,11 |
# can be re-calculated. |
fi[$FPS]=$(egrep -o '[0-9]*\.?[0-9]*k? tb(r|\(r\))' <<<"$vs" | cut -d' ' -f1) |
# Let's convert e.g. 23.98 into 23.976...: |
if [ "${fi[$FPS]}" ] && grep -q '\.' <<<"${fi[$FPS]}" ; then |
if [[ ${fi[$FPS]} ]] && grep -q '\.' <<<"${fi[$FPS]}" ; then |
# Decimals, see if we got better values available |
local vsobs=$(grep "stream $vsid" <<<"$obs") |
# Observations regarding video stream found |
if [ "$vsobs" ] && grep -q " -> ${fi[$FPS]} (.*)" <<<"$vsobs" ; then |
if [[ $vsobs ]] && grep -q " -> ${fi[$FPS]} (.*)" <<<"$vsobs" ; then |
# FPS candidate |
local newfps=$(egrep -o -- '-> [^ ]* \([0-9]*/[0-9]*' <<<"$vsobs" | cut -d'(' -f2) |
is_fraction $newfps && fi[$FPS]=$(keepdecimals "$newfps" 3) |
2710,17 → 2715,17 |
fi |
# ...fallback for older. The older version I tried seems to round further, i.e. |
# 23.976 became 24 so no fix for this one |
if [ -z "${fi[$FPS]}" ]; then |
if [[ -z ${fi[$FPS]} ]]; then |
# No k suffix here, 1000 is 1000 |
fi[$FPS]=$(egrep -o '[0-9]*\.?[0-9]* fps' <<<"$vs" | cut -d' ' -f1) |
fi |
# Be consistent with mplayer's output: at least two decimals |
[ "${fi[$FPS]}" ] && { |
[[ ${fi[$FPS]} ]] && { |
fi[$FPS]=$(keepdecimals "${fi[$FPS]}" 3) |
fi[$FPS]=${fi[$FPS]/%0} # Strip 0$ |
} |
fi[$LEN]=$(egrep -o 'Duration: [^,]*' <<<"$FFMPEG_CACHE" | cut -d' ' -f2) |
if [ "${fi[$LEN]}" == "N/A" ]; then # It might be unable to detect |
if [[ ${fi[$LEN]} == 'N/A' ]]; then # It might be unable to detect |
fi[$LEN]="" |
fi |
fi[$LEN]=$( get_interval $(echo "${fi[$LEN]}" | sed -e 's/:/h/' -e 's/:/m/') ) |
2729,7 → 2734,7 |
# TODO: Replace tail -1 with some better option (see the double DAR example above) |
fi[$ASPECT]=$(egrep -o 'DAR [0-9]*:[0-9]*'<<<"$FFMPEG_CACHE" | tail -1 | cut -d' ' -f2 | sed 's#:#/#') |
# Due to calling ffmpeg on a single VOB when in DVD Device mode, the length will be partial |
[ $DVD_MODE -eq 0 ] || fi[$LEN]='' |
[[ $DVD_MODE -eq 0 ]] || fi[$LEN]='' |
fi[$VCNAME]=$(get_vcodec_name $(translate_ffmpeg_vcodec_id "${fi[$VCODEC]}")) |
fi[$ACNAME]=$(get_acodec_name $(translate_ffmpeg_acodec_id "${fi[$ACODEC]}")) |
VID_FFMPEG=("${fi[@]}") |
2845,7 → 2850,7 |
|
if [[ $FFMPEG ]]; then |
# FPS at least with two decimals |
if [ $(awkex "int(${VID[$FPS]})") == ${VID[$FPS]} ]; then |
if [[ $(awkex "int(${VID[$FPS]})") == ${VID[$FPS]} ]]; then |
VID[$FPS]="${VID[$FPS]}.00" |
fi |
fi |
3980,12 → 3985,12 |
case "$t" in |
timecode_from) |
x='$TC_NUMCAPS' |
[ $v -eq $TC_NUMCAPS ] || x='$TC_INTERVAL' |
[[ $v -eq $TC_NUMCAPS ]] || x='$TC_INTERVAL' |
v=$x |
;; |
decoder) |
x='$DEC_FFMPEG' |
[ $v -eq $DEC_FFMPEG ] || x='$DEC_MPLAYER' |
[[ $v -eq $DEC_FFMPEG ]] || x='$DEC_MPLAYER' |
v=$x |
;; |
verbosity) |