Subversion Repositories pub

Compare Revisions

Ignore whitespace Rev 303 → Rev 304

/video-contact-sheet/branches/1.0.7a/vcs
23,6 → 23,11
#
# Author: Toni Corvera <outlyer@outlyer.net>
#
# References:
# Pages from I've taken snippets or wrote code based on them.
# I refer to them in comments as e.g. [[R1]]. [[R1#3]] Means section 3 in R1
# [R1] http://wooledge.org/mywiki/BashFaq
#
 
declare -r VERSION="1.0.7b"
#
56,6 → 61,9
# * INTERNAL: Use /dev/shm as base tempdir if possible
# * BUGFIX: Fixed safe_rename(): Don't assume current dir, added '--' to mv
# * Added workaround for ffmpeg arguments order
# * Allow getting the output of ffmpeg/mplayer (with $stdout and $stderr)
# * INTERNAL: Renamed info() to inf() to eliminate ambiguities
# * INTERNAL: guess_aspect() doesn't operate globally
#
 
set -e
188,6 → 196,8
# Apparently Kochi Mincho includes Hangul *and* Cyrillic... which would be
# great :)
declare FONT_MINCHO=/usr/share/fonts/truetype/kochi/kochi-mincho.ttf
# Output of capturing programs is redirected here
declare stdout=/dev/null stderr=/dev/null
 
# }}} # End of override-able variables
 
292,6 → 302,8
'verbosity'
'plain_messages'
'FONT_MINCHO'
'stdout'
'stderr'
)
 
# Loads the configuration files if present
380,10 → 392,11
# rmultiply($1 = "operator1,operator2,...")
rmultiply() {
local exp=$(sed 's/[ ,]/*/g'<<<"$@") # bc expression
local f=$(bc -lq<<<"$exp") # exact float value
#local f=$(bc -lq<<<"$exp") # exact float value
# division is integer by default (without -l) so it's the smae
# as rounding to the lower int
bc -q <<<"( $f + 0.5 ) / 1"
#bc -q <<<"( $f + 0.5 ) / 1"
bc -q <<<"scale=5; v=( ($exp) + 0.5 ) ; scale=0 ; v/1"
}
 
# Like rmultiply() but always rounded upwards
466,13 → 479,11
# the indicated length
# pad($1 = minimum length, $2 = string)
pad() {
local len=$1
# printf "%0${1}d\n" "$2" # [[R1#18]] # Can't be used with non-numbers
local str=$2
 
while [ ${#str} -lt $len ]; do
str=0$str
while [ "${#str}" -lt $1 ]; do
str="0$str"
done
 
echo $str
}
 
604,7 → 615,7
# cleanup()
cleanup() {
if [ -z $TEMPSTUFF ]; then return 0 ; fi
info "Cleaning up..."
inf "Cleaning up..."
rm -rf ${TEMPSTUFF[*]}
TEMPSTUFF=( )
}
648,8 → 659,8
}
#
# Print an informational message
# info($1 = text)
info() {
# inf($1 = text)
inf() {
if [ $verbosity -ge $V_INFO ]; then
if [ $plain_messages -eq 0 ]; then
tput bold ; tput setaf 2;
658,9 → 669,9
fi >&2
}
#
# Same as info but with no colour ever.
# infoplain($1 = text)
infoplain() {
# Same as inf but with no colour ever.
# infplain($1 = text)
infplain() {
if [ $verbosity -ge $V_INFO ]; then
echo "$1" >&2
fi
709,14 → 720,14
# randomize_look()
randomize_look() {
 
mode=f
local mode=f lineno
 
if [ "f" == $mode ]; then # Random mode
# There're 5 rows of extra info printed
local ncolours=$(( $(convert -list color | wc -l) - 5 ))
randcolour() {
convert -list color | cut -d' ' -f1 |
head -n$(( 5 + ( $RANDOM % $ncolours ) )) | tail -n1
lineno=$(( 5 + ( $RANDOM % $ncolours ) ))
convert -list color | sed -n "${lineno}p" | cut -d' ' -f1 # [[R1#19]]
}
else # Pseudo-random mode, WIP!
randccomp() {
730,7 → 741,8
 
local nfonts=$(( $(convert -list type | wc -l) - 5 ))
randfont() {
convert -list type | cut -d' ' -f1 | head -n$(( 5 + ( $RANDOM % $nfonts ))) | tail -n1
lineno=$(( 5 + ( $RANDOM % $nfonts )))
convert -list type | sed -n "${lineno}p" | cut -d' ' -f1 # [[R1#19]]
}
 
bg_heading=$(randcolour)
745,7 → 757,7
font_heading=$(randfont)
font_sign=$(randfont)
font_title=$(randfont)
info "Randomization result:
inf "Randomization result:
Chosen backgrounds:
'$bg_heading' for the heading
'$bg_sign' for the signature
812,31 → 824,30
 
# Tries to guess an aspect ratio comparing width and height to some
# known values (e.g. VCD resolution turns into 4/3)
# guess_aspect()
# guess_aspect($1 = width, $2 = height)
guess_aspect() {
# mplayer's ID_ASPECT seems to be always 0 ¿?
local w=${VID[$W]} h=${VID[$H]}
local w=$1 h=$2 ar
if [ $w -eq 352 ]; then # VCD / DVD @ VCD Res. / Half-D1 / CVD
if [ $h -eq 288 ] || [ $h -eq 240 ]; then
aspect_ratio=4/3
ar=4/3
elif [ $h -eq 576 ] || [ $h -eq 480 ]; then # Half-D1 / CVD
aspect_ratio=4/3
ar=4/3
fi
elif [ $w -eq 704 ] || [ $w -eq 720 ]; then # DVD / DVB
# Actually for 720x576/720x480 16/9 is as good a guess
if [ $h -eq 576 ] || [ $h -eq 480 ]; then
aspect_ratio=4/3
ar=4/3
fi
elif [ $w -eq 480 ]; then # SVCD
if [ $h -eq 576 ] || [ $h -eq 480 ]; then
aspect_ratio=4/3
ar=4/3
fi
else
warn "Couldn't guess aspect ratio."
aspect_ratio=$(bc -lq <<<"$w / $h")
ar="$w/$h" # Don't calculate it yet
fi
local AR=$(sed -r 's/(\.[0-9]{2}).*/\1/g'<<<$aspect_ratio)
info "Aspect ratio set to $AR"
echo $ar
}
 
# Capture a frame
847,16 → 858,18
# globals: $shoehorned $decoder
 
if [ $decoder -eq $DEC_MPLAYER ]; then
mplayer -sws 9 -ao null -benchmark -vo "png:z=0" -quiet \
-frames 1 -ss $stamp $shoehorned "$f" >/dev/null 2>&1
{
mplayer -sws 9 -ao null -benchmark -vo "png:z=0" -quiet \
-frames 1 -ss $stamp $shoehorned "$f"
} >"$stdout" 2>"$stderr"
elif [ $decoder -eq $DEC_FFMPEG ]; then
# XXX: It would be nice to show a message if it takes too long
{ # Used to redirect output
{
# See wa_ss_* declarations at the start of the file for details
ffmpeg -y ${wa_ss_be/ / $stamp} -i "$f" ${wa_ss_af/ / $stamp} -an \
-dframes 1 -vframes 1 -vcodec png \
-f rawvideo $shoehorned $VIDCAPFILE
} >/dev/null 2>&1
} >"$stdout" 2>"$stderr"
else
error "Internal error!"
return $EX_SOFTWARE
1060,7 → 1073,7
cmdopts= # This command is pretty time-consuming, let's make it in a row
 
# Base canvas
info "Creating polaroid base canvas $row/$numrows..."
inf "Creating polaroid base canvas $row/$numrows..."
convert -size ${canvasw}x${canvash} xc:transparent "$rowfile"
 
# Step through vidcaps (col=[0..cols-1])
1077,11 → 1090,11
let 'accoffset=accoffset + w - offset'
shift
done
info "Composing polaroid row $row/$numrows..."
inf "Composing polaroid row $row/$numrows..."
eval convert "'$rowfile'" "$cmdopts" -trim +repage "'$rowfile'" >&2
done
 
info "Merging polaroid rows..."
inf "Merging polaroid rows..."
output=$(new_temp_file .png)
# Standard composition
#convert -background Transparent "${rowfiles[@]}" -append polaroid.png
1163,7 → 1176,7
error "File \"$f\" doesn't exist"
return $EX_NOINPUT
fi
info "Processing $f..."
inf "Processing $f..."
 
identify_video "$f" || {
error "Found unsupported value while identifying video. Can't continue."
1178,7 → 1191,8
if [ "0" == "$aspect_ratio" ]; then
aspect_ratio=$(bc -lq <<< "${VID[$W]} / ${VID[$H]}")
elif [ "-1" == "$aspect_ratio" ]; then
guess_aspect
aspect_ratio=$(guess_aspect ${VID[$W]} ${VID[$H]})
inf "Aspect ratio set to $(sed -r 's/(\.[0-9]{2}).*/\1/g'<<<$aspect_ratio)"
fi
local vidcap_width=$(compute_width $vidcap_height)
 
1221,7 → 1235,7
for stamp in $(clean_timestamps "${HLTIMECODES[*]}"); do
if [ $stamp -gt $numsecs ]; then let 'n++' && continue ; fi
pretty=$(pretty_stamp $stamp)
info "Generating highlight #${n}/${#HLTIMECODES[*]} ($pretty)..."
inf "Generating highlight #${n}/${#HLTIMECODES[*]} ($pretty)..."
 
capture "$f" $stamp || return $?
filter_vidcap "$VIDCAPFILE" $pretty $vidcap_width $vidcap_height || {
1236,7 → 1250,7
let 'n++'
done
 
info "Composing highlights contact sheet..."
inf "Composing highlights contact sheet..."
hlfile=$( create_contact_sheet $numcols $CTX_HL $vidcap_width $vidcap_height "${capfiles[@]}" )
unset hlcapfile pretty n capfiles
fi
1252,7 → 1266,7
# This shouldn't occur automatically anymore with the new code.
if fptest $stamp -gt $numsecs ; then let 'n++' && continue; fi
 
info "Generating capture #${n}/${#TIMECODES[*]} ($pretty)..."
inf "Generating capture #${n}/${#TIMECODES[*]} ($pretty)..."
 
capture "$f" $stamp || return $?
filter_vidcap "$VIDCAPFILE" $pretty $vidcap_width $vidcap_height || return $?
1265,7 → 1279,7
done
#filter_all_vidcaps "${capfiles[@]}"
 
info "Composing standard contact sheet..."
inf "Composing standard contact sheet..."
output=$(create_contact_sheet $numcols $CTX_STD $vidcap_width $vidcap_height "${capfiles[@]}")
unset capfile capfiles pretty n
 
1286,7 → 1300,7
let 'w=vidcap_width/2, h=vidcap_height/2'
for stamp in $(clean_timestamps "${TIMECODES[*]}"); do
pretty=$(pretty_stamp $stamp)
info "Generating capture from extended set: ${n}/${#TIMECODES[*]} ($pretty)..."
inf "Generating capture from extended set: ${n}/${#TIMECODES[*]} ($pretty)..."
capture "$f" $stamp || return $?
filter_vidcap "$VIDCAPFILE" $pretty $w $h || return $?
 
1295,7 → 1309,7
capfiles+=( "$capfile" )
let 'n++'
done
info "Composing extended contact sheet..."
inf "Composing extended contact sheet..."
extoutput=$( create_contact_sheet $(($numcols * 2)) $CTX_EXT $w $h "${capfiles[@]}" )
 
unset w h capfile pretty n
1393,7 → 1407,7
 
 
if [ "$HLTIMECODES" ] || [ "$extended_factor" != "0" ]; then
info "Merging contact sheets..."
inf "Merging contact sheets..."
fi
# If there were highlights then mix them in
if [ "$HLTIMECODES" ]; then
1408,8 → 1422,8
# Add the background
convert -background "$bg_contact" "$output" -flatten "$output"
 
# Let's add meta info and signature
info "Adding header and footer..."
# Let's add meta inf and signature
inf "Adding header and footer..."
# Newer method, incremental construction of the heading:
# FIXME: Height guessing could be better...
local meta2="Dimensions: ${VID[$W]}x${VID[$H]}
1507,7 → 1521,7
error "Failed to write the output file!"
return $EX_CANTCREAT
}
info "Done. Output wrote to $output_name"
inf "Done. Output wrote to $output_name"
 
cleanup
}
1514,7 → 1528,7
 
# Prints the program identification to stderr
show_vcs_info() { # Won't be printed in quiet modes
info "Video Contact Sheet *NIX v${VERSION}, (c) 2007 Toni Corvera" "sgr0"
inf "Video Contact Sheet *NIX v${VERSION}, (c) 2007 Toni Corvera" "sgr0"
}
 
# Prints the list of options to stdout
1596,8 → 1610,10
-M|--mplayer Force the usage of mplayer.
-F|--ffmpeg Force the usage of ffmpeg.
--shoehorn <arg> Pass "arg" to mplayer/ffmpeg. You shouldn't need it.
-D Debug mode: Currently just prints the parsed
commandline as the title and to stderr.
-D Debug mode. Used to test features/integrity. It:
* Prints the input command line
* Sets the title to reflect the command line
* Does a basic test of consistency.
 
Examples:
Create a contact sheet with default values (vidcaps at intervals of
1619,6 → 1635,61
 
# }}} # Core functionality
 
# {{{ # Debugging helpers
 
# Tests integrity of some operations.
# Used to test internal changes for consistency.
# It helps me to identify incorrect optimizations.
# unit_test()
unit_test() {
local t op val ret comm retval=0
 
# Tests are in the form "operation arguments correct_result #Description"
local TESTS=(
"rmultiply 1,1 1 #Identity"
"rmultiply 16/9,1 2 #Rounding" # 1.77 rounded 2
"rmultiply 4/3 1 #Rounding" # 1.33 rounded 1
"rmultiply 1,16/9 2 #Commutative property"
"rmultiply 1.7 2 #Alternate syntax"
 
"ceilmultiply 1,1 1 #"
"ceilmultiply 4/3 2 #" # 1.33 rounded 2
"ceilmultiply 7,1/2 4 #" # 3.5 rounded 4
"ceilmultiply 7/2 4 #Alternative syntax"
"ceilmultiply 1/2,7 4 #Commutative property"
 
"pad 10 0 0000000000 #Padding"
"pad 1 20 20 #Unneeded padding"
"pad 5 23.3 023.3 #Floating point padding"
 
"guess_aspect 720 576 4/3 #DVD AR Guess"
"guess_aspect 1024 576 1024/576 #Unsupported Wide AR Guess"
)
for t in "${TESTS[@]}" ; do
# Note the use of ! as separator, this is because # and / are used in
# many of the inputs
comm=$(sed 's!.* #!!g' <<<$t)
# Expected value
val=$(sed -r "s!.* (.*) #$comm\$!\1!g"<<<$t)
op=$(sed "s! $val #$comm\$!!g" <<<$t)
ret=$($op)
if [ -z "$comm" ]; then
comm=unnamed
fi
 
if [ "$ret" != "$val" ] && fptest "$ret" -ne "$val" ; then
error "Failed test ($comm): '$op $val'. Got result '$ret'."
let 'retval++'
else
inf "Passed test ($comm): '$op $val'."
fi
done
return $retval
}
 
# }}} # Debugging helpers
 
#### Execution starts here ####
 
# If tput isn't found simply ignore tput commands
1813,7 → 1884,7
-k|--funky) # Funky modes
case $(tolower "$2") in
p|polaroid) # Same as overlap + rotate + photoframe
info "Changed to polaroid funky mode."
inf "Changed to polaroid funky mode."
FILTERS_IND+=( 'filt_photoframe' 'filt_randrot' )
CSHEET_DELEGATE='csheet_overlap'
# The timestamp must change location to be visible
1830,11 → 1901,11
FILTERS_IND+=( 'filt_photoframe' )
;;
i|film)
info "Enabled film mode."
inf "Enabled film mode."
FILTERS_IND+=( 'filt_film' )
;;
x|random) # Random colours/fonts
info "Enabled random colours and fonts."
inf "Enabled random colours and fonts."
randomize_look
;;
*)
1853,7 → 1924,17
verbosity=$V_NONE
fi
;;
-D) echo "Command line: $0 $ARGS" && title="$(basename "$0") $ARGS" ; ;;
-D)
inf "Testing internal consistency..."
unit_test
if [ $? -eq 0 ]; then
warn "All tests passed"
else
error "Some tests failed!"
fi
warn "Command line: $0 $ARGS"
title="$(basename "$0") $ARGS"
;;
--) shift ; break ;;
*) error "Internal error! (remaining opts: $@)" ; exit $EX_SOFTWARE ;
esac