Subversion Repositories pub

Compare Revisions

No changes between revisions

Ignore whitespace Rev 361 → Rev 362

/video-contact-sheet/trunk/CHANGELOG
1,3 → 1,19
1.0.99: (2009-03-11) ("1.1.0 RC")
* FEATURE: Experimental support for DVDs (-V)
* FEATURE: Added JPEG 2000 output format (-j2)
* FEATURE/COSMETIC: Polaroid mode now produces a polaroid-like frame, the
older version is now renamed as simply 'photos'
New "funky" modes: newer polaroid, photos (older polaroid),
polaroidframe.
* Overrideable variables: DISABLE_SHADOWS and DISABLE_TIMESTAMPS (set to 1
* BUGFIX/COSMETIC: Re-added the missed space before filename
* BUGFIX/COSMETIC: Reworked alignment and padding
* Timestamps size is adjusted with smaller captures
* BUGFIX: Fixed polaroid/rotate bug where all images overlapped on the same
position (reported by Aleksandar Urošević, formerly unreproducible)
* Better detection of video/audio features by falling back to ffmpeg when
appropriate
 
1.0.12: (2008-04-16)
* BUGFIX/COSMETIC: Corrected 0ms timestamps
* COSMETIC: Re-added the (disabled for long) black border after highlights
/video-contact-sheet/trunk/debian-package/debian/changelog
1,3 → 1,12
vcs (1.0.99-upstream.0) experimental; urgency=low
 
* New version.
* debian/control:
- Added lsdvd as recommendation (required for dvd support)
- Using 'Homepage:'
 
-- Toni Corvera <outlyer@gmail.com> Wed, 11 Mar 2009 22:50:25 +0100
 
vcs (1.0.12-upstream.1) experimental; urgency=low
 
* debian/control: Added missing requirement (gsfonts)
/video-contact-sheet/trunk/debian-package/debian/rules
56,7 → 56,7
dh_installdirs
 
# Add here commands to install the package into debian/vcs.
$(MAKE) DESTDIR="$(CURDIR)/debian/vcs" install
$(MAKE) DESTDIR=$(CURDIR)/debian/vcs install
 
 
# Build architecture-independent files here.
/video-contact-sheet/trunk/debian-package/debian/control
4,14 → 4,14
Maintainer: Toni Corvera <outlyer@gmail.com>
Build-Depends: debhelper (>= 5)
Standards-Version: 3.7.2
Homepage: http://p.outlyer.net/vcs/
 
Package: vcs
Architecture: all
Depends: bc, bash, grep, imagemagick (>= 6.0), mktemp, mplayer, ffmpeg, gsfonts
Recommends: lsdvd
Description: vcs is a script that creates a contact sheet (preview) from videos
Video Contact Sheet *NIX (vcs for short) is a script that creates a contact
sheet (preview) from videos by taking still captures distributed over the
length of the video. The output image contains useful information on the video
such as codecs, file size, screen size, frame rate, and length.
.
Upstream homepage <http://p.outlyer.net/vcs/>.
/video-contact-sheet/trunk/debian-package/Makefile
7,8 → 7,8
clean:
 
install:
install -d "$(DESTDIR)$(prefix)/bin"
install -m755 -o0 -g0 vcs "$(DESTDIR)$(prefix)/bin/"
mkdir -p $(DESTDIR)$(prefix)/bin
install -m755 -o0 -g0 vcs $(DESTDIR)$(prefix)/bin
 
 
.PHONY: all install clean
/video-contact-sheet/trunk/vcs
5,7 → 5,7
# vcs
# Video Contact Sheet *NIX: Generates contact sheets (previews) of videos
#
# Copyright (C) 2007, 2008 Toni Corvera
# Copyright (C) 2007, 2008, 2009 Toni Corvera
# with patches from Phil Grundig and suggestions/corrections from
# many others (see homepage)
#
47,21 → 47,27
# <http://wiki.multimedia.cx/index.php?title=VC-1>
#
 
declare -r VERSION="1.0.12"
declare -r VERSION="1.0.99" # ("1.1.0 RC")
# {{{ # CHANGELOG
# History (The full changelog can be found at <http://p.outlyer.net/vcs/files/CHANGELOG>).
#
# 1.0.12: (2008-04-16)
# * BUGFIX/COSMETIC: Corrected 0ms timestamps
# * COSMETIC: Re-added the (disabled for long) black border after highlights
# * BUGFIX/COSMETIC: Corrected the count of captures in manual-only mode (-m)
# * FEATURE: Added a minimun length to use the end offset
# * BUGFIX: Fixed the regression on highlights from the last version (extra
# padding was being added my IM automatically)
# * INTERNAL: Simplified use of IM's identify
# * BUGFIX: Fixed parsing of manual timestamps including milliseconds
# (when seconds didn't include the s character they were accidentally
# multiplied by 10!)
# 1.0.99: (2009-3-11)
# * FEATURE: Experimental support for DVDs (-V)
# * FEATURE: Added JPEG 2000 output format (-j2)
# * FEATURE/COSMETIC: Polaroid mode now produces a polaroid-like frame, the
# older version is now renamed as simply 'photos'
# New "funky" modes: newer polaroid, photos (older polaroid),
# polaroidframe.
# * Overrideable variables: DISABLE_SHADOWS and DISABLE_TIMESTAMPS (set to
# 1 to disable)
# * BUGFIX/COSMETIC: Re-added the missed space before filename
# * BUGFIX/COSMETIC: Reworked alignment and padding
# * Timestamps size is adjusted with smaller captures
# * BUGFIX: Fixed polaroid/rotate bug where all images overlapped on the
# same position (reported by Aleksandar Urošević, formerly
# unreproducible)
# * Better detection of video/audio features by falling back to ffmpeg when
# appropriate
# }}} # CHANGELOG
 
set -e
72,6 → 78,8
# * [[R1#22]] states that not all bc versions understand '<', more info required
# * [[x1]] Find out why the order of ffmpeg arguments breaks some files.
# * [[x2]] Find out if egrep is safe to use or grep -E is more commonplace.
# * Better DVD support (e.g. real detection of aspect ratio)
# * Use ffmpeg's detected length if shorter than mplayer's
#
 
# }}} # TODO
122,6 → 130,8
 
# This is the horizontal padding added to each capture. Changing it might break
# extended set's alignement so keep this in mind if you tinker with it
# When shadows are enabled, 5 is substracted from this value in csheet_montage
# so keep this in mind!
declare -ri HPAD=8
# }}} # End of constants
 
153,6 → 163,7
declare bg_sign=SlateGray # Background for signature
declare bg_title=White # Background for the title (see -T)
declare bg_contact=White # Background of the thumbnails
declare bg_tstamps='#000000aa' # Background for the timestamps box
declare fg_heading=black # Font colour for meta info box
declare fg_sign=black # Font colour for signature
declare fg_tstamps=white # Font colour for timestamps
227,6 → 238,9
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
declare -i DVD_MODE=0 DVD_TITLE=1
declare DVD_FILE=
declare -i multiple_input_files=0
 
# }}} # End of override-able variables
 
253,6 → 267,7
# go there
# This holds the output of mplayer -identify on the current video
declare MPLAYER_CACHE=
declare FFMPEG_CACHE=
# This holds the parsed values of MPLAYER_CACHE, see also the Indexes in VID
# (defined in the constants block)
declare -a VID=
269,21 → 284,21
# This number of seconds is *not* captured from the end of the video
declare -i end_offset=$DEFAULT_END_OFFSET
 
# 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)
# Transformations/filters
# Operations are decomposed into independent optional steps, this allows
# to add some intermediate steps (e.g. polaroid/photo mode's frames)
# Filters in this context are functions.
# There're two kinds of filters and a delegate:
# * individual filters are run over each vidcap
# * global filters are run over all vidcaps at once
# * global filters are run over all vidcaps at once (currently deprecated)
# * The contact sheet creator delegates on some function to create the actual
# contact sheet
#
# Individual filters take the form:
# filt_name( vidcapfile, timestamp in seconds.milliseconds, width, height )
# filt_name( vidcapfile, timestamp in seconds.milliseconds, width, height, [context, [index]] )
# They're executed in order by filter_vidcap()
declare -a FILTERS_IND=( 'filt_resize' 'filt_apply_stamp' )
# Global filters take the form
declare -a FILTERS_IND=( 'filt_resize' 'filt_apply_stamp' 'filt_softshadow' )
# Deprecated: Global filters take the form
# filtall_name( vidcapfile1, vidcapfile2, ... )
# They're executed in order by filter_all_vidcaps
declare -a FILTERS_CS
301,8 → 316,9
# When set to 1 the signature won't contain the "Preview created by..." line
declare -i anonymous_mode=0
 
# See csheet_montage for more details
# See coherence_check for more details
declare -i DISABLE_SHADOWS=0
declare -i DISABLE_TIMESTAMPS=0
 
# }}} # Variables
 
341,6 → 357,7
'DEFAULT_END_OFFSET'
'MIN_LENGTH_FOR_END_OFFSET'
'DEBUG'
'DISABLE_.*'
)
 
# This is only used to exit when -DD is used
604,16 → 621,11
sed -r 's/\.([0-9][0-9]).*/.\1/'<<<$R
}
 
# Prints the size of a file in a human friendly form
# The units are in the IEC/IEEE/binary format (e.g. MiB -for mebibytes-
# instead of MB -for megabytes-)
# get_pretty_size($1 = file)
# Prints a given size in human friendly form
get_pretty_size() {
local f="$1"
local bytes=$1
local size=
 
local bytes=$(get_file_size "$f")
local size=""
 
if [ "$bytes" -gt $(( 1024**3 )) ]; then
local gibs=$(( $bytes / 1024**3 ))
local mibs=$(( ( $bytes % 1024**3 ) / 1024**2 ))
633,6 → 645,17
echo $size
}
 
# Prints the size of a file in a human friendly form
# The units are in the IEC/IEEE/binary format (e.g. MiB -for mebibytes-
# instead of MB -for megabytes-)
# get_pretty_file_size($1 = file)
get_pretty_file_size() {
local f="$1"
local bytes=$(get_file_size "$f")
 
get_pretty_size "$bytes"
}
 
# Rename a file, if the target exists, try with appending numbers to the name
# And print the output name to stdout
# See $safe_rename_pattern
686,6 → 709,29
cut -f1 <<<"$bytes"
}
 
# Gets the size of a block device
get_blockdev_size() {
# This is something I've never done so I'm still looking for the right
# way to do it portably.
# Alternatives:
# * fdisk -s (no need for privileged access, read-only)
# Prints the number of blocks. In Linux they're always 1024 AFAICT,
# but I'm not sure about other unices (the -in disk- block size for
# DVDs is 2048).
# * hal
# hal-find-by-property --key block.device --string <(REAL)DEVICE>
# hal-get-property --udi <DEVICEID> --key volume.disc.capacity
# Gets byte size but HAL is far from standard (only Linux
# and FreeBSD have it AFAIK)
# * sysfs
# cat /sys/block/<(KERNEL)DEVICE>/size
# Size is given in sectors (512 blocks). Linux only. *BSD has
# sysctl of which I've no clue.
local dev="$1"
local numblocks=$(/sbin/fdisk -s "$dev")
get_pretty_size $(( 1024 * $numblocks ))
}
 
# Tests the presence of all required programs
# test_programs()
test_programs() {
777,6 → 823,18
echo "[TRACE]: $@" >&2
}
 
#
# Tests if the filter chain contains the provided filter
# has_filter($1 = filtername)
has_filter() {
local filter= ref=$1
for filter in ${FILTERS_IND[@]} ; do
[ "$filter" == "$ref" ] || continue
return 0
done
return 1
}
 
# }}} # Convenience functions
 
# {{{ # Core functionality
1007,10 → 1065,16
# globals: $shoehorned $decoder
 
if [ $decoder -eq $DEC_MPLAYER ]; then
# Capture 5 frames and drop the first 4, fixes a weird bug/feature of mplayer ([M1])
{
# Capture 5 frames and drop the first 4, fixes a weird bug/feature of mplayer ([M1])
mplayer -sws 9 -ao null -benchmark -vo "png:z=0" -quiet \
-frames 5 -ss $stamp $shoehorned "$f"
if [ $DVD_MODE -eq 1 ]; then
mplayer -sws 9 -ao null -benchmark -vo "png:z=0" -quiet \
-frames 5 -ss $stamp $shoehorned -dvd-device "$DVD_FILE" \
"dvd://$DVD_TITLE"
else
mplayer -sws 9 -ao null -benchmark -vo "png:z=0" -quiet \
-frames 5 -ss $stamp $shoehorned "$f"
fi
} >"$stdout" 2>"$stderr"
rm -f 0000000{1,2,3,4}.png # Remove the first four
elif [ $decoder -eq $DEC_FFMPEG ]; then
1040,7 → 1104,7
}
 
# Applies all individual vidcap filters
# filter_vidcap($1 = filename, $2 = timestamp, $3 = width, $4 = height)
# filter_vidcap($1 = filename, $2 = timestamp, $3 = width, $4 = height, $5 = context, $6 = index[1..])
filter_vidcap() {
trace $FUNCNAME $@
# For performance purposes each filter simply prints a set of options
1048,7 → 1112,7
# filters.
local cmdopts=
for filter in ${FILTERS_IND[@]}; do
cmdopts="$cmdopts $( $filter "$1" "$2" "$3" "$4" ) "
cmdopts="$cmdopts $( $filter "$1" "$2" "$3" "$4" "$5" "$6" ) -flatten "
done
local t=$(new_temp_file .png)
eval "convert '$1' $cmdopts '$t'"
1071,30 → 1135,85
}
 
# Draw a timestamp in the file
# filt_apply_stamp($1 = filename, $2 = timestamp, $3 = width, $4 = height)
# filt_apply_stamp($1 = filename, $2 = timestamp, $3 = width, $4 = height, $5 = context, $6 = index)
filt_apply_stamp() {
trace $FUNCNAME $@
local filename=$1 timestamp=$2 width=$3 height=$4
local filename=$1 timestamp=$2 width=$3 height=$4 context=$5 index=$6
 
echo -n " \( -box '#000000aa' -fill '$fg_tstamps' -pointsize '$pts_tstamps' "
local pts=$pts_tstamps
if [ $height -lt 200 ]; then
pts=$(( $pts_tstamps / 3 ))
elif [ $height -lt 400 ]; then
pts=$(( $pts_tstamps * 2 / 3 ))
fi
# If the size is too small they won't be readable at all
if [ $pts -le 8 ]; then
pts=8
if [ $index -eq 1 ] && [ $context -ne $CTX_EXT ]; then
warn "Beware, using very small timestamps to accomodate smaller captures,\
you might prefer using -dt to disable them"
fi
fi
# The last -gravity None is used to "forget" the previous gravity (otherwise it would
# affect stuff like the polaroid frames)
echo -n " \( -box '$bg_tstamps' -fill '$fg_tstamps' -pointsize '$pts' "
echo -n " -gravity '$grav_timestamp' -stroke none -strokewidth 3 -annotate +5+5 "
echo " ' $(pretty_stamp $stamp) ' \) -flatten "
echo " ' $(pretty_stamp $stamp) ' \) -flatten -gravity None "
}
 
# Apply a Polaroid-like effect
# Apply a framed photo-like effect
# Taken from <http://www.imagemagick.org/Usage/thumbnails/#polaroid>
# filt_photoframe($1 = filename, $2 = timestamp, $3 = width, $4 = height)
filt_photoframe() {
filt_photoframe0() {
trace $FUNCNAME $@
# local file="$1" ts=$2 w=$3 h=$4
# Tweaking the size gives a nice effect too
# w=$(( $w - ( $RANDOM % ( $w / 3 ) ) ))
# TODO: Split softshadow in a filter
echo -n "-bordercolor white -border 6 -bordercolor grey60 -border 1 "
# The border is relative to the input size (since 1.0.99), with a maximum of 6
# Should probably be bigger for really big frames
# Note that only images below 21600px (e.g. 160x120) go below a 6px border
local border=$(( ($3*$4) / 3600 ))
[ $border -lt 7 ] || border=6
echo -n "-bordercolor white -border $border -bordercolor grey60 -border 1 "
echo -n "-background black \( +clone -shadow 60x4+4+4 \) +swap "
echo "-background none -flatten -trim +repage"
}
 
filt_photoframe() {
trace $FUNCNAME $@
# local file="$1" ts=$2 w=$3 h=$4
# Tweaking the size gives a nice effect too
# w=$(( $w - ( $RANDOM % ( $w / 3 ) ) ))
# The border is relative to the input size (since 1.0.99), with a maximum of 6
# Should probably be bigger for really big frames
# Note that only images below 21600px (e.g. 160x120) go below a 6px border
local border=$(( ($3*$4) / 3600 ))
[ $border -lt 7 ] || border=6
echo -n "-bordercolor white -border $border -bordercolor grey60 -border 1 "
}
 
filt_softshadow() {
# Before this was a filter, there was the global (montage) softshadow (50x2+10+10) and the
# photoframe inline softshadow 60x4+4+4
echo -n "\( -background black +clone -shadow 50x2+4+4 -background none \) +swap -flatten -trim +repage "
}
 
 
# Apply a polaroid-like border effect
# Based on filt_photoframe(), with a bigger lower border
# filt_polaroid($1 = filename, $2 = timestamp, $3 = width, $4 = height)
filt_polaroid() {
trace $FUNCNAME $@
# local file="$1" ts=$2 w=$3 h=$4
local border=$(( ($3*$4) / 3600 )) # Read filt_photoframe for details
[ $border -lt 7 ] || border=6
echo -n "-bordercolor white -mattecolor white -frame ${border}x${border} "
# FIXME: This is rather ugly (double-flipping) there's sure a better way
echo -n "\( -flip -splice 0x$(( $border*5 )) \) "
echo "-flip -bordercolor grey60 -border 1 +repage"
}
 
# Applies a random rotation
# Taken from <http://www.imagemagick.org/Usage/thumbnails/#polaroid>
# filt_randrot($1 = filename, $2 = timestamp, $3 = width, $4 = height)
1163,18 → 1282,23
shift 4
# Padding is no longer dependant upong context since alignment of the
# captures was far trickier then
local hpad=$HPAD vpad=4
local hpad= vpad= splice=
 
# Using transparent seems to make -shadow futile
# The shadows already add a good amount of padding
if has_filter filt_softshadow ; then
hpad=$(( $HPAD-5 ))
vpad=0
splice=5x10
else
hpad=$HPAD
vpad=4
splice=0x8
fi
 
montage -background Transparent "$@" -geometry +$hpad+$vpad -tile "$cols"x "$output"
# With the shadows moved to a filter, there's not enough spacing to header
convert "$output" -background Transparent -splice $splice "$output"
 
# This should actually be moved to a filter but with the current
# architecture I'm unable to come up with the correct convert options
if [ $DISABLE_SHADOWS -eq 0 ]; then
# This produces soft-shadows, which look much better than the montage ones
convert \( -shadow 50x2+10+10 "$output" \) "$output" -composite "$output"
fi
 
# FIXME: Error handling
echo $output
}
1237,9 → 1361,7
accoffset=0
cmdopts= # This command is pretty time-consuming, let's make it in a row
 
# Base canvas
inf "Creating polaroid base canvas $row/$numrows..."
convert -size ${canvasw}x${canvash} xc:transparent "$rowfile"
# Base canvas # Integrated in the row creation since 1.0.99
 
# Step through vidcaps (col=[0..cols-1])
for col in $(seq 0 $(( $cols - 1 ))); do
1248,23 → 1370,19
w=$(imw "$1")
 
# Stick the vicap in the canvas
#convert -geometry +${accoffset}+0 "$rowfile" "$1" -composite "$rowfile"
cmdopts="$cmdopts -geometry +${accoffset}+0 '$1' -composite "
cmdopts="$cmdopts '$1' -geometry +${accoffset}+0 -composite "
 
offset=$(( $minoffset + ( $RANDOM % $maxoffset ) ))
let 'accoffset=accoffset + w - offset'
shift
done
inf "Composing polaroid row $row/$numrows..."
eval convert "'$rowfile'" "$cmdopts" -trim +repage "'$rowfile'" >&2
inf "Composing overlapped row $row/$numrows..."
eval convert -size ${canvasw}x${canvash} xc:transparent -geometry +0+0 "$cmdopts" -trim +repage "'$rowfile'" >&2
done
 
inf "Merging polaroid rows..."
inf "Merging overlapped rows..."
output=$(new_temp_file .png)
# Standard composition
#convert -background Transparent "${rowfiles[@]}" -append polaroid.png
# Overlapped composition
convert -size ${canvasw}x$(( $canvash * $cols )) xc:transparent "$output"
 
cmdopts=
accoffset=0
local h
1275,13 → 1393,16
maxoffset=$(( $h / 4 ))
offset=$(( $minoffset + ( $RANDOM % $maxoffset ) ))
# The row is also offset horizontally
cmdopts="$cmdopts -geometry +$(( $RANDOM % $maxoffset ))+$accoffset '$row' -composite "
cmdopts="$cmdopts '$row' -geometry +$(( $RANDOM % $maxoffset ))+$accoffset -composite "
let 'accoffset=accoffset + h - offset'
done
# After the trim the top corners are too near the heading, we add some space
# with -splce
eval convert -background transparent "$output" $cmdopts -trim +repage \
-bordercolor Transparent -splice 0x10 "$output" >&2
# After the trim the image will be touching the outer borders and the heading and footer,
# older versions (prior to 1.0.99) used -splice 0x10 to correct the heading spacing, 1.0.99
# onwards uses -frame to add spacing in all borders + splice to add a bit more space on the
# upper border. Note splice uses the background colour while frame uses the matte colour
eval convert -size ${canvasw}x$(( $canvash * $cols )) xc:transparent -geometry +0+0 \
$cmdopts -trim +repage -bordercolor Transparent -background Transparent -mattecolor Transparent \
-frame 5x5 -splice 0x5 "$output" >&2
 
# FIXME: Error handling
echo $output
1303,7 → 1424,16
local f=$1
# Meta data extraction
# Note to self: Don't change the -vc as it would affect $vdec
MPLAYER_CACHE=$(mplayer -benchmark -ao null -vo null -identify -frames 0 -quiet "$f" 2>/dev/null | grep ^ID)
if [ $DVD_MODE -eq 0 ]; then
MPLAYER_CACHE=$(mplayer -benchmark -ao null -vo null -identify -frames 0 \
-quiet "$f" 2>/dev/null | grep ^ID)
# Used as fallback. Introduced in 1.0.99 so expect it to fail :P
FFMPEG_CACHE=$(ffmpeg -i "$f" -dframes 0 -vframes 0 /dev/null 2>&1 | grep Stream)
else
MPLAYER_CACHE=$(mplayer -benchmark -ao null -vo null -identify -frames 0 \
-quiet -dvd-device $DVD_FILE dvd://$DVD_TITLE \
2>/dev/null | grep ^ID)
fi
VID[$VCODEC]=$(grep ID_VIDEO_FORMAT <<<"$MPLAYER_CACHE" | cut -d'=' -f2) # FourCC
VID[$ACODEC]=$(grep ID_AUDIO_FORMAT <<<"$MPLAYER_CACHE" | cut -d'=' -f2)
VID[$VDEC]=$(grep ID_VIDEO_CODEC <<<"$MPLAYER_CACHE" | cut -d'=' -f2) # Decoder (!= Codec)
1310,7 → 1440,11
VID[$W]=$(grep ID_VIDEO_WIDTH <<<"$MPLAYER_CACHE" | cut -d'=' -f2)
VID[$H]=$(grep ID_VIDEO_HEIGHT <<<"$MPLAYER_CACHE" | cut -d'=' -f2)
VID[$FPS]=$(grep ID_VIDEO_FPS <<<"$MPLAYER_CACHE" | cut -d'=' -f2)
VID[$LEN]=$(grep ID_LENGTH <<<"$MPLAYER_CACHE"| cut -d'=' -f2)
if [ $DVD_MODE -eq 0 ]; then
VID[$LEN]=$(grep ID_LENGTH <<<"$MPLAYER_CACHE"| cut -d'=' -f2)
else
VID[$LEN]=$(grep ID_DVD_TITLE_${DVD_TITLE}_LENGTH <<<"$MPLAYER_CACHE"| cut -d'=' -f2)
fi
# For some reason my (one track) samples have two ..._NCH, first one 0
VID[$CHANS]=$(grep ID_AUDIO_NCH <<<"$MPLAYER_CACHE"|cut -d'=' -f2|head -2|tail -1)
 
1327,10 → 1461,110
VID[$FPS]="${VID[$FPS]:0:$(( ${#VID[$FPS]} - 1 ))}"
fi
 
# Fallback for values known to fail often
if [ "$FFMPEG_CACHE" ]; then
# FPS=1000.00 happens often for WMV
if [ "${VID[$FPS]}" == "1000.00" ]; then
local fps2=$(grep Stream <<<"$FFMPEG_CACHE" | grep Video | head -1 | \
egrep -o ', [0-9]+\.[0-9]+ ' | egrep -o '[0-9]+.*[0-9]')
if is_float "$fps2" ; then
VID[$FPS]=$fps2
fi
unset fps2
fi
# Number of channels 0 happens for WMA in non-x86
# Mplayer seems to default to 2 for >2, so ffmpeg might be a better default option
# if [ "${VID[$CHANS]}" ] && ( ! is_number "${VID[$CHANS]}" || [ ${VID[$CHANS]} -eq 0 ] ) ; then
local ch2=$(grep Stream <<<"$FFMPEG_CACHE" | grep Audio | head -1 | cut -d, -f3 | sed 's/^ //')
if [ "$ch2" ]; then
case $ch2 in
mono) VID[$CHANS]=1 ;;
stereo) VID[$CHANS]=2 ;;
5.1) VID[$CHANS]=6 ;;
*) ;;
esac
fi
# fi
fi
 
 
# Check sanity of the most important values
is_number "${VID[$W]}" && is_number "${VID[$H]}" && is_float "${VID[$LEN]}"
}
 
# Checks if the provided arguments make sense and are allowed to be used
# together
coherence_check() {
# If -m is used then -S must be used
if [ $manual_mode -eq 1 ] && [ -z $initial_stamps ]; then
error "You must provide timestamps (-S) when using manual mode (-m)"
return $EX_USAGE
fi
 
# Currently it's not allowed to use dvd mode with more than one input
# "file" (in this mode, input files are actually dvd titles of the file
# provided in -V)
if [ $DVD_MODE -eq 1 ] ; then
if [ $multiple_input_files -eq 1 ]; then
error "Only an input file is allowed in DVD mode"
return $EX_UNAVAILABLE
fi
 
# DVD Mode only works with mplayer, the decoder is changed when
# the DVD mode option is found, so if it's ffmpeg at this point,
# it's by user request (i.e. -F after -V)
if [ $decoder -ne $DEC_MPLAYER ]; then
warn "DVD mode requires the use of mplayer, falling back to it"
decoder=$DEC_MPLAYER
fi
fi
 
local filter=
if [ $DISABLE_TIMESTAMPS -eq 0 ] &&
local filts=( )
has_filter filt_polaroid && has_filter filt_apply_stamp ; then
 
for filter in ${FILTERS_IND[@]} ; do
if [ "$filter" == "filt_polaroid" ]; then
filts+=( $filter )
filts+=( filt_apply_stamp )
elif [ "$filter" == "filt_apply_stamp" ]; then
continue;
else
filts+=( $filter )
fi
done
FILTERS_IND=( ${filts[*]} )
unset filts
fi
# The shoftshadow and randrot filters must be in the correct place
# or they will affect the image incorrectly.
# Additionally the default filters can be disabled from the command
# line (with --disable), they're removed from the filter chain here
local filts=( ) end_filts=( )
for filter in ${FILTERS_IND[@]} ; do
case "$filter" in
filt_softshadow)
# Note the newer soft shadows code (1.0.99 onwards) behaves slightly
# differently. On previous versions disabling shadows only affected
# the montage shadow (but e.g. the polaroid mode preserved them),
# this is no longer true
if [ $DISABLE_SHADOWS -ne 1 ]; then
end_filts[100]="filt_softshadow"
fi
;;
filt_apply_stamp)
if [ $DISABLE_TIMESTAMPS -ne 1 ]; then
filts+=( "$filter" )
fi
;;
filt_randrot) end_filts[200]="filt_randrot" ;;
*) filts+=( "$filter" ) ;;
esac
done
FILTERS_IND=( ${filts[*]} ${end_filts[*]} )
}
 
# Main function.
# Creates the contact sheet.
# process($1 = file)
1340,12 → 1574,43
 
local numcols=
 
if [ ! -f "$f" ]; then
error "File \"$f\" doesn't exist"
return $EX_NOINPUT
# XXX: Some of this should be moved to coherence_check
if [ $DVD_MODE -eq 1 ]; then # DVD Mode
f="$DVD_FILE"
local dvdn="$f"
if [ -b "$dvdn" ]; then
dvdn="DVD"
elif [ ! -f "$dvdn" ]; then
error "File \"$dvdn\" doesn't exist"
return $EX_NOINPUT
fi
inf "Processing $dvdn..."
unset dvdn
if ! is_number "$1" ; then
error "DVD Title must be a number (e.g.: \$ vcs -V /dev/dvd 1)"
exit $EX_USAGE
fi
DVD_TITLE=$1
if [ $DVD_TITLE -eq 0 ]; then
local dt="$(lsdvd "$DVD_FILE" | grep 'Longest track:' | \
cut -d' ' -f3- | sed 's/^0*//')"
if ! is_number "$dt" ; then
error "Failed to autodetect longest DVD title"
exit $EX_INTERNAL
fi
DVD_TITLE=$dt
unset dt
inf "Using DVD Title #$DVD_TITLE"
fi
else
if [ ! -f "$f" ]; then
error "File \"$f\" doesn't exist"
return $EX_NOINPUT
fi
 
inf "Processing $f..."
fi
inf "Processing $f..."
 
identify_video "$f" || {
error "Found unsupported value while identifying video. Can't continue."
return $EX_SOFTWARE
1391,7 → 1656,7
 
# If the temporal vidcap already exists, abort
if [ -f $VIDCAPFILE ]; then
error "File 0000000$f.png exists and would be overwritten, move it out before running."
error "File $VIDCAPFILE exists and would be overwritten, move it out before running."
return $EX_CANTCREAT
fi
# mplayer will re-write also 00000001.png-00000004.png
1417,7 → 1682,7
inf "Generating highlight #${n}/${#HLTIMECODES[*]} ($pretty)..."
 
capture "$f" $stamp || return $?
filter_vidcap "$VIDCAPFILE" $pretty $vidcap_width $vidcap_height || {
filter_vidcap "$VIDCAPFILE" $pretty $vidcap_width $vidcap_height $CTX_HL $n || {
local r=$?
error "Failed to apply transformations to the capture."
return $r
1451,7 → 1716,7
inf "Generating capture #${n}/${#TIMECODES[*]} ($pretty)..."
 
capture "$f" $stamp || return $?
filter_vidcap "$VIDCAPFILE" $pretty $vidcap_width $vidcap_height || return $?
filter_vidcap "$VIDCAPFILE" $pretty $vidcap_width $vidcap_height $CTX_STD $n || return $?
 
# identified by capture number, padded to 6 characters
capfile=$(new_temp_file "-cap-$(pad 6 $n).png")
1493,7 → 1758,7
pretty=$(pretty_stamp $stamp)
inf "Generating capture from extended set: ${n}/${#TIMECODES[*]} ($pretty)..."
capture "$f" $stamp || return $?
filter_vidcap "$VIDCAPFILE" $pretty $w $h || return $?
filter_vidcap "$VIDCAPFILE" $pretty $w $h $CTX_EXT $n || return $?
 
capfile=$(new_temp_file "-excap-$(pad 6 $n).png")
mv "$VIDCAPFILE" "$capfile"
1611,9 → 1876,29
fi
 
 
local csw=$(imw "$output") exw= hlw=
local width=$csw
if [ "$HLTIMECODES" ] || [ "$extended_factor" != "0" ]; then
inf "Merging contact sheets..."
if [ "$HLTIMECODES" ]; then
local hlw=$(imw "$hlfile")
if [ $hlw -gt $width ]; then width=$hlw ; fi
fi
if [ "$extended_factor" != "0" ]; then
local exw=$(imw $extoutput)
if [ $exw -gt $width ]; then width=$exw ; fi
fi
fi
if [ $csw -lt $width ]; then
local csh=$(imh "$output")
# Expand the standard set to the maximum width of the sets by padding both sides
# For some reason the more obvious (to me) convert command-lines lose
# the transparency
convert \( -size $(( ($width - $csw) / 2 ))x$csh xc:transparent \) "$output" \
\( -size $(( ($width - $csw) / 2 ))x$csh xc:transparent \) +append "$output"
unset csh
fi
 
# If there were highlights then mix them in
if [ "$HLTIMECODES" ]; then
# For some reason adding the background also adds padding with:
1620,14 → 1905,27
# convert \( -background LightGoldenRod "$hlfile" -flatten \) \
# \( "$output" \) -append "$output"
# replacing it with a "-composite" operation apparently works
local geometry=$(identify -format '%wx%h' "$hlfile")
convert \( -size "$geometry" xc:LightGoldenRod "$hlfile" -composite \) \
\( -size "$(cut -d'x' -f1<<<$geometry)"x1 xc:black \) \
# Expand the highlights to the correct size by padding
local hlh=$(imh "$hlfile")
if [ $hlw -lt $width ]; then
convert \( -size $(( ($width - $hlw) / 2 ))x$hlh xc:transparent \) "$hlfile" \
\( -size $(( ($width - $hlw) / 2 ))x$hlh xc:transparent \) +append "$hlfile"
fi
convert \( -size ${width}x${hlh} xc:LightGoldenRod "$hlfile" -composite \) \
\( -size ${width}x1 xc:black \) \
"$output" -append "$output"
unset hlh
fi
# Extended captures
if [ "$extended_factor" != 0 ]; then
convert "$output" "$extoutput" -append "$output"
# Already set local exw=$(imw "$extoutput")
local exh=$(imh "$extoutput")
if [ $exw -lt $width ]; then
# Expand the extended set to be the correct size
convert \( -size $(( ($width - $exw) / 2 ))x$exh xc:transparent \) "$extoutput" \
\( -size $(( ($width - $exw) / 2 ))x$exh xc:transparent \) +append "$extoutput"
fi
convert "$output" -background Transparent "$extoutput" -append "$output"
fi
# Add the background
convert -background "$bg_contact" "$output" -flatten "$output"
1693,6 → 1991,28
# now the *complete header*
# * Add the contact sheet and append it to what we had.
# * Start a new image and annotate it with the signature, then append it too.
local filename_label="Filename"
local filesize_label="File size"
local filename_value=
local filesize_value=
if [ $DVD_MODE -eq 1 ]; then
local is_dev=0
test -b "$DVD_FILE" && is_dev=1
local dvd_label=$(lsdvd "$DVD_FILE" | grep -o 'Disc Title: .*' | cut -d' ' -f3-)
# lsdvd is guaranteed to be installed if DVD mode is enabled
if [ $is_dev -eq 1 ]; then # This is a real DVD, not an iso
filename_label="Disc label"
filename_value="$dvd_label"
filesize_label="Disc size"
filesize_value="$(get_blockdev_size "$DVD_FILE")"
else
filename_value="$(basename "$DVD_FILE") $filename_value (DVD Label: $dvd_label)"
filesize_value="$(get_pretty_file_size "$f")"
fi
else
filename_value="$(basename "$f")"
filesize_value="$(get_pretty_file_size "$f")"
fi
convert \
\( \
-size $(( ${headwidth} -18 ))x1 "xc:$bg_heading" +size \
1700,11 → 2020,11
-background "$bg_heading" -fill "$fg_heading" \
\( \
-gravity West \
\( label:"Filename:" \
-font "$fn_font" label:"$(basename "$f")" +append \
\( label:"$filename_label: " \
-font "$fn_font" label:"$filename_value" +append \
\) \
-font "$font_heading" \
label:"File size: $(get_pretty_size "$f")" \
label:"$filesize_label: $filesize_value" \
label:"Length: $(cut -d'.' -f1 <<<$(pretty_stamp ${VID[$LEN]}))" \
-append -crop ${headwidth}x${headheight}+0+0 \
\) \
1860,7 → 2180,7
 
# Prints the program identification to stderr
show_vcs_info() { # Won't be printed in quiet modes
inf "Video Contact Sheet *NIX v${VERSION}, (c) 2007 Toni Corvera" "sgr0"
inf "Video Contact Sheet *NIX v${VERSION}, (c) 2007-2009 Toni Corvera" "sgr0"
}
 
# Prints the list of options to stdout
1888,11 → 2208,19
as -i.
-t|--to <arg> Set ending time. No caps beyond this. Same format
as -i.
-V|--dvd <file.iso|dvd_device>
DVD Mode, use file.iso as DVD. In this mode the
<file> argument must point to the title number, e.g.:
$ vcs -V somedvd.iso 1
Passing title 0 will use the default (longest) title.
$ vcs -V /dev/dvd 0
Implies -A (auto aspect ratio)
-E|--end_offset <arg> This time is ignored, from the end of the video. Same
format as -i. This value is not used when a explicit
ending time is set. By default it is $DEFAULT_END_OFFSET.
-T|--title <arg> Add a title above the vidcaps.
-j|--jpeg Output in jpeg (by default output is in png).
-j2|--jpeg 2 Output in jpeg 2000
-q|--quiet Don't print progess messages just errors. Repeat to
mute completely even on error.
-h|--help Show this text.
1938,9 → 2266,14
Randomly rotate each image.
"photoframe": Use '-kf' or '--funky photoframe'
Adds a photo-like white frame to each image.
"polaroidframe": Use '-kL' or '--funky polaroidframe'
Adds a polaroid picture-like white frame to each image.
"photos": Use '-kc' or '--funky photos'
Combination of rotate, photoframe and overlap.
Same as -kp -kr -ko.
"polaroid": Use '-kp' or '--funky polaroid'
Combination of rotate, photoframe and overlap.
Same as -kr -ko -kf.
Combination of rotate, polaroidframe and overlap.
Same as -kL -kr -ko.
"film": Use '-ki' or '--funky film'
Imitates filmstrip look.
"random": Use '-kx' or '--funky random'
1999,11 → 2332,11
ARGS="$@"
 
# [[R0]]
TEMP=$(getopt -s bash -o i:n:u:T:f:t:S:jhFMH:c:ma:l:De::U::qAO:I::k:W:E:d: \
--long "interval:,numcaps:,username:,title:,from:,to:,stamp:,jpeg,help,"\
TEMP=$(getopt -s bash -o i:n:u:T:f:t:S:j::hFMH:c:ma:l:De::U::qAO:I::k:W:E:d:V: \
--long "interval:,numcaps:,username:,title:,from:,to:,stamp:,jpeg::,help,"\
"shoehorn:,mplayer,ffmpeg,height:,columns:,manual,aspect:,highlight:,"\
"extended::,fullname,anonymous,quiet,autoaspect,override:,mincho,funky:,"\
"end_offset:,disable:" \
"end_offset:,disable:,dvd:" \
-n $0 -- "$@")
 
eval set -- "$TEMP"
2098,7 → 2431,19
HLTIMECODES+=( $temp )
shift
;;
-j|--jpeg) output_format=jpg ;;
-j|--jpeg)
if [ "$2" ]; then # Arg is optional, 2 is for JPEG 2000
# 2000 is also accepted
if [ "$2" != "2" ] && [ "$2" != "2000" ]; then
error "Use -j for jpeg output or -j2 for JPEG 2000 output. Got '-j$2'."
exit $EX_USAGE
fi
output_format=jp2
else
output_format=jpg
fi
shift
;;
-h|--help) show_help ; exit $EX_OK ;;
--shoehorn)
shoehorned="$2"
2187,12 → 2532,23
shift
;;
-k|--funky) # Funky modes
case $(tolower "$2") in
p|polaroid) # Same as overlap + rotate + photoframe
case "$2" in # Note older versions (<1.0.99) were case-insensitive
p|polaroid) # Same as overlap + rotate + polaroid
inf "Changed to polaroid funky mode."
FILTERS_IND+=( 'filt_polaroid' 'filt_randrot' )
CSHEET_DELEGATE='csheet_overlap'
# XXX: The newer version has a lot less flexibility with these many
# hardcoded values...
grav_timestamp=South
fg_tstamps=Black
bg_tstamps=Transparent
pts_tstamps=$(( $pts_tstamps * 3 / 2 ))
;;
c|photos) # Same as overlap + rotate + photoframe, this is the older polaroid
inf "Changed to polaroid funky mode."
FILTERS_IND+=( 'filt_photoframe' 'filt_randrot' )
CSHEET_DELEGATE='csheet_overlap'
# The timestamp must change location to be visible
# The timestamp must change location to be visible most of the time
grav_timestamp=NorthWest
;;
o|overlap) # Random overlap mode
2205,6 → 2561,13
f|photoframe) # White photo frame
FILTERS_IND+=( 'filt_photoframe' )
;;
L|polaroidframe) # White polaroid frame
FILTERS_IND+=( 'filt_polaroid ')
grav_timestamp=South
fg_tstamps=Black
bg_tstamps=Transparent
pts_tstamps=$(( $pts_tstamps * 3 / 2 ))
;;
i|film)
inf "Enabled film mode."
FILTERS_IND+=( 'filt_film' )
2224,16 → 2587,16
case $(tolower "$2") in
# timestamp (no final s) is undocumented but will stay
t|timestamps|timestamp)
inf "Timestamps disabled."
# TODO: Can array splicing be done in a saner way?
declare -a tmp=${FILTERS_IND[@]}
unset FILTERS_IND
FILTERS_IND=${tmp[@]/filt_apply_stamp/}
unset tmp
if [ $DISABLE_TIMESTAMPS -eq 0 ]; then
inf "Timestamps disabled."
# They'll be removed from the filter chain in coherence_check
DISABLE_TIMESTAMPS=1
fi
;;
s|shadows|shadow)
if [ $DISABLE_SHADOWS -eq 0 ]; then
inf "Shadows disabled."
# They will be removed from the filter chain in coherence_check
DISABLE_SHADOWS=1
fi
;;
2244,6 → 2607,18
esac
shift
;;
-V|--dvd)
# DVD Mode requires lsdvd
if ! type -pf lsdvd >/dev/null ; then
error "DVD Support requires the lsdvd program"
exit $EX_UNAVAILABLE
fi
DVD_MODE=1
DVD_FILE="$2"
decoder=$DEC_MPLAYER
aspect_ratio=-1
shift
;;
-q|--quiet)
# -q to only show errors
# -qq to be completely quiet
2277,21 → 2652,21
if [ ! "$1" ]; then
show_help
exit $EX_USAGE
elif [ "$2" ]; then
multiple_input_files=1
fi
 
# }}} # Command line parsing
 
# The coherence check ensures the processed options are
# not incoherent/incompatible with the input files or with
# other given options
coherence_check
 
# Test requirements
test_programs || exit $EX_UNAVAILABLE
 
# If -m is used then -S must be used
if [ $manual_mode -eq 1 ] && [ -z $initial_stamps ]; then
error "You must provide timestamps (-S) when using manual mode (-m)"
exit $EX_USAGE
fi
 
set +e # Don't fail automatically
for arg do process "$arg" ; done
 
 
# vim:set ts=4 ai foldmethod=marker: #
/video-contact-sheet/trunk/.
Property changes:
Modified: svn:mergeinfo
Merged /video-contact-sheet/branches/1.0.99:r358-361