52,10 → 52,7 |
# any sane system though). |
# * FEATURE: Funky modes (more to come...) |
# * FEATURE: Polaroid funky mode (-kp) |
# * FEATURE: Reel funky mode (-kr) (rough initial version) |
# * 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 |
# |
|
set -e |
222,16 → 219,6 |
EX_NOINPUT=66 EX_SOFTWARE=70 EX_CANTCREAT=73 \ |
EX_INTERRUPTED=79 # This one is not on sysexits.h |
|
# Workaounds: |
# Argument order in FFmpeg is important -ss before or after -i will make |
# the capture work or not depending on the file. XXX: I've yet to find why :P |
# Anyway, this is used to change the order. See -Wo. |
# Admittedly the workaraound is abit obscure: those variables will be added to |
# the ffmpeg arguments, before and after -i, replacing spaces by the timestamp. |
# e.g.: for second 50 '-ss ' will become '-ss 50' while '' will stay empty |
# By default -ss goes before -i. |
declare wa_ss_af="" wa_ss_be="-ss " |
|
# Experimental in 1.0.7b: transformations/filters |
# Operations are decomposed into independent optional steps, this will allow |
# to add some intermediate steps (e.g. polaroid mode) |
245,7 → 232,7 |
# Individual filters take the form: |
# filt_name( vidcapfile, timestamp in seconds.milliseconds, width, height ) |
# They're executed in order by filter_vidcap() |
declare -a FILTERS_IND=( 'filt_resize' 'filt_apply_stamp' ) |
declare -a FILTERS_IND=( filt_apply_stamp ) |
# Global filters take the form |
# filtall_name( vidcapfile1, vidcapfile2, ... ) |
# They're executed in order by filter_all_vidcaps |
528,17 → 515,14 |
# And print the output name to stdout |
# See $safe_rename_pattern |
# safe_rename($1 = original file, $2 = target file) |
# XXX: Note it fails if target has no extension |
safe_rename() { |
local from="$1" |
local to="$2" |
|
# Output extension |
local ext=$(sed -r 's/.*\.(.*)/\1/' <<<$to) |
# Input extension |
local iext=$(sed -r 's/.*\.(.*)/\1/' <<<$to) |
# Input filename without extension |
local b=${to%.$iext} |
# Extension |
local ext=$(sed -r 's/.*\.(.*)/\1/g' <<<"$to") |
# Basename without extension |
local b=$(basename "$2" ".$ext") |
|
# safe_rename_pattern is override-able, ensure it has a valid value: |
if ! grep -q '%e' <<<"$safe_rename_pattern" || |
549,14 → 533,14 |
|
local n=1 |
while [ -f "$to" ]; do # Only executes if $2 exists |
to=$(sed "s#%b#$b#g" <<<"$safe_rename_pattern") |
to=$(sed "s#%N#$n#g" <<<"$to") |
to=$(sed "s#%e#$ext#g" <<<"$to") |
to=$(sed "s/%b/$b/g" <<<"$safe_rename_pattern") |
to=$(sed "s/%N/$n/g" <<<"$to") |
to=$(sed "s/%e/$ext/g" <<<"$to") |
|
let 'n++'; |
done |
|
mv -- "$from" "$to" |
mv "$from" "$to" |
echo "$to" |
} |
|
743,6 → 727,8 |
unset -f randcolour randfound randccomp |
} |
|
randomize_look |
|
# Add to $TIMECODES the timecodes at which a capture should be taken |
# from the current video |
# compute_timecodes($1 = timecode_from, $2 = interval, $3 = numcaps) |
825,13 → 811,10 |
mplayer -sws 9 -ao null -benchmark -vo "png:z=0" -quiet \ |
-frames 1 -ss $stamp $shoehorned "$f" >/dev/null 2>&1 |
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 |
# XXX: For some reason -ss before -i failed on my mkv sample |
# while after -i it failed on my wmv9 sample ¿? |
ffmpeg -y -ss $stamp -i "$f" -an -dframes 1 -vframes 1 -vcodec png \ |
-f rawvideo $shoehorned $VIDCAPFILE >/dev/null 2>&1 |
else |
error "Internal error!" |
return $EX_SOFTWARE |
851,14 → 834,9 |
# Applies all individual vidcap filters |
# filter_vidcap($1 = filename, $2 = timestamp, $3 = width, $4 = height) |
filter_vidcap() { |
# For performance purposes each filter simply prints a set of options |
# to 'convert'. That's less flexible but enough right now for the current |
# filters. |
local cmdopts= |
for filter in ${FILTERS_IND[@]}; do |
cmdopts+=" $( $filter "$1" "$2" "$3" "$4" ) " |
$filter "$1" "$2" "$3" "$4" |
done |
eval "convert '$1' $cmdopts '$1'" |
} |
|
# Applies all global vidcap filters |
867,21 → 845,25 |
true |
} |
|
filt_resize() { |
local f="$1" t=$2 w=$3 h=$4 |
|
# Note the '!', required to change the aspect ratio |
echo " \( -geometry ${w}x${h}! \) " |
} |
|
# Draw a timestamp in the file |
# filt_apply_stamp($1 = filename, $2 = timestamp, $3 = width, $4 = height) |
filt_apply_stamp() { |
local filename=$1 timestamp=$2 width=$3 height=$4 |
|
echo -n " \( -box '#000000aa' -fill '$fg_tstamps' -pointsize '$pts_tstamps' " |
echo -n " -gravity '$grav_timestamp' -stroke none -strokewidth 3 -annotate +5+5 " |
echo " ' $(pretty_stamp $stamp) ' \) -flatten " |
local temp=$(new_temp_file ".png") |
mv "$filename" "$temp" |
# Add the timestamp to each vidcap, doing it here is much powerful/simple |
# than with the next montage command |
# Note the '!', it is necessary to apply aspect ratio change |
convert -box '#000000aa' -geometry ${width}x${height}! \ |
-fill "$fg_tstamps" -pointsize "$pts_tstamps" -gravity "$grav_timestamp" \ |
-stroke none -strokewidth 3 -annotate +5+5 " "$(pretty_stamp $stamp)" " \ |
"$temp" "$filename" |
if [ ! -f "$filename" ]; then |
error "Failed to add timestamp to capture" |
mv "$temp" "$filename" # Leave things as before |
return $EX_CANTCREAT |
fi |
} |
|
# Apply a Polaroid-like effect |
893,53 → 875,16 |
local angle=$(( ($RANDOM % 37) - 18 )) |
# Tweaking the size gives a nice effect too |
# w=$(( $w - ( $RANDOM % ( $w / 3 ) ) )) |
|
echo -n "-bordercolor white -border 6 -bordercolor grey60 -border 1 " |
echo -n "-background none -rotate $angle " |
echo -n "-background black \( +clone -shadow 60x4+4+4 \) +swap " |
echo "-background none -flatten -trim +repage" |
# -geometry ${w}x \ |
convert "$file" \ |
-bordercolor white -border 6 \ |
-bordercolor grey60 -border 1 \ |
-background none -rotate $angle \ |
-background black \( +clone -shadow 60x4+4+4 \) +swap \ |
-background none -flatten \ |
"$file" |
} |
|
# This one requires much more work, the results are pretty rough, but ok as |
# a starting point / proof of concept |
filt_reel() { |
local file="$1" ts=$2 w=$3 h=$4 |
# Base reel dimensions |
local rw=$(rmultiply $w,0.08) # 8% width |
local rh=$(( $rw / 2 )) |
# Ellipse center |
local ecx=$(( $rw / 2 )) ecy=0 |
# Ellipse x, y radius |
local erx=$(( (rw/2)*60/100 )) # 60% halt rect width |
local ery=$(( $erx / 2)) |
|
local base_reel=$(new_temp_file .png) reel_strip=$(new_temp_file .png) |
|
# Create the reel pattern... |
convert -size ${rw}x${rh} 'xc:black' \ |
-fill white -draw "ellipse $ecx,$ecy $erx,$ery 0,360" -flatten \ |
\( +clone -flip \) -append \ |
-fuzz '40%' -transparent white \ |
"$base_reel" |
# FIXME: Error handling |
|
# Repeat it until the height is reached and crop to the exact height |
local sh=$(imh "$base_reel") in= |
local repeat=$( ceilmultiply $h/$sh) |
while [ $repeat -gt 1 ]; do |
in+=" '$base_reel' " |
let 'repeat--' |
done |
eval convert "$base_reel" $in -append -crop $(imw "$base_reel")x${h}+0+0 \ |
"$reel_strip" |
|
# As this options will be appended to the commandline we cannot |
# order the arguments optimally (eg: reel.png image.png reel.png +append) |
# A bit of trickery must be done flipping the image. Note also that the |
# second strip will be appended flipped, which is intended. |
echo -n "'$reel_strip' +append -flop '$reel_strip' +append -flop " |
} |
|
# Creates a contact sheet by calling the delegate |
# create_contact_sheet($1 = columns, $2 = context, $3 = width, $4 = height, |
# $5...$# = vidcaps) : output |
1003,9 → 948,7 |
# I believe no image should ever be wider/taller than the diagonal (note the |
# ceilmultiply is there to simply round the result) |
local diagonal=$(ceilmultiply $(pyth_th $width $height) 1) |
# XXX: The width, though isn't guaranteed (e.g. using filt_reel it ends wider) |
# adding 3% to the diagonal *should* be enough to compensate |
local canvasw=$(( ( $diagonal + $(rmultiply $diagonal,0.3) ) * $cols )) |
local canvasw=$(( $diagonal * $cols )) |
local canvash=$(( $diagonal )) |
|
# The number of rows required to hold all the snaps |
1521,8 → 1464,6 |
-j|--jpeg Output in jpeg (by default output is in png). |
-q|--quiet Don't print progess messages just errors. Repeat to |
mute completely even on error. |
-Wo Workaround: Change ffmpeg's arguments order, might |
work with some files that fail otherwise. |
-Ij|-Ik |
--mincho Use the kana/kanji/hiragana font (EXPERIMENTAL) might |
also work for Hangul and Cyrillic. |
1593,7 → 1534,7 |
|
# TODO: use no name at all with -u noarg |
#eval set -- "${default_options} ${@}" |
TEMP=$(getopt -s bash -o i:n:u:T:f:t:S:jhFMH:c:ma:l:De::UqAO:I::k:W: \ |
TEMP=$(getopt -s bash -o i:n:u:T:f:t:S:jhFMH:c:ma:l:De::UqAO:I::k: \ |
--long "interval:,numcaps:,username:,title:,from:,to:,stamp:,jpeg,help,"\ |
"shoehorn:,mplayer,ffmpeg,height:,columns:,manual,aspect:,highlight:,"\ |
"extended::,fullname,quiet,autoaspect,override:,mincho,funky:" \ |
1752,14 → 1693,6 |
override "$2" "command line" |
shift |
;; |
-W) # Workaround mode, see wa_ss_* declarations at the start for details |
if [ "$2" != "o" ]; then |
error "Wrong argument. Use -Wo instead of -W$2." |
exit $EX_USAGE |
fi |
wa_ss_af='-ss ' wa_ss_be='' |
shift |
;; |
-k|--funky) # Funky modes |
case $(tolower "$2") in |
p|polaroid) |
1769,10 → 1702,6 |
# The timestamp must change location to be visible |
grav_timestamp=NorthWest |
;; |
r|reel) # Undocumented for good reason! |
info "Enabled reel mode." |
FILTERS_IND+=( 'filt_reel' ) |
;; |
*) |
error "Unknown funky mode. Got '$2'." |
exit $EX_UAGE |