Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 130 lines (105 sloc) 5.389 kb
#!/bin/bash
set -e # die on error
[[ ${!DEBUG[@]} ]] && set -x # show debug output if DEBUG was set
set -u # warn about trying to access unset vars
# clean up temp during exit
function clean_up(){
[[ -e /proc/$FF_PID ]] && kill $FF_PID # Make sure that the ffmpeg instance gets killed upon exit
[[ ${!DEBUG[@]} ]] || rm -rf $WORK_DIR # wipe the temp dir, but only if not debugging
exit
}
# Thanks to http://www.prupert.co.uk/2010/05/11/finally-a-bash-progress-indicator-for-ffmpeg-that-works/
display_ffmpeg_progress () { # Calculate/collect progress
START=$(date +%s); FR_CNT=0; ETA=0; ELAPSED=0
while [[ -e /proc/$FF_PID ]]; do # Is FFmpeg running?
sleep 1
VSTATS=$( grep -Eo "frame=\s*[0-9]+" "$ff_log" | tail -n1 | grep -Eo "[0-9]+" ) # Parse vstats file.
if [[ -n $VSTATS ]] && [[ $VSTATS -gt $FR_CNT ]]; then # Parsed sane or no?
FR_CNT=$VSTATS
PERCENTAGE=$(( 100 * FR_CNT / MAXTHUMB )) # Progbar calc.
ELAPSED=$(( $(date +%s) - START ))
remaining=$(echo "( $ELAPSED / $FR_CNT ) * ( $MAXTHUMB + 1 - $FR_CNT )" | bc)
ETA=$(date -d @${remaining} -u +%H:%M:%S) # ETA calc.
# Text for stats output.
echo -ne "\rFrame:$FR_CNT of $((MAXTHUMB+1)) Time:$(date -d @$ELAPSED -u +%H:%M:%S) ETA:$ETA Percent:$PERCENTAGE"
fi
done
}
# Original credit for this script goes to Rich Jerrido:
# http://www.outsidaz.org/blog/2009/10/26/screencap-generation-via-ffmpeg-and-imagemagick/
# TODO: Provide these as command-line options
# Video file to work on
VIDEO=$(readlink -e "$1")
# Number of Thumbnails to be created. It is advisable to use a number that makes a perfect square such as 9,16,25
MAXTHUMB=25
# Size of thumbnails
THUMBSIZE="202"
# output directory
OUTPUT_DIR=$(dirname "$VIDEO")
# working directory
WORK_DIR="/tmp/thumbnail"
IMAGE_FORMAT=png
# Check for dependencies
for dep in {convert,montage}; do
hash $dep 2>&- || { echo >&2 "I require '$dep' but it's not installed. It's available as part of the ImageMagick suite. Aborting."; exit 1; }
done
for dep in {ffmpeg,ffprobe}; do
hash $dep 2>&- || { echo >&2 "I require '$dep' but it's not installed. Hint: Install the 'ffmpeg' package. Aborting."; exit 1; }
done
hash 'bc' 2>&- || { echo >&2 "I require 'bc' but it's not installed. Aborting."; exit 1; }
# clear work directory before each run
rm -rf "$WORK_DIR"
# create work dir if non-existent
[[ -w "$WORK_DIR" ]] || mkdir -p "$WORK_DIR"
# create output dir if non-existent
[[ -w "$OUTPUT_DIR" ]] || mkdir -p "$OUTPUT_DIR"
## These variables gather some information about the video file
video_info=$( ffprobe "$VIDEO" 2>&1 )
duration_string=$( grep -Eo "Duration: [0-9]{2,}:[0-9]{2}:[0-9]{2}.[0-9]{2}" <<< "$video_info" | cut -f2 -d" " )
IFS=':' read -ra duration_array <<< "$duration_string"
duration_hours=${duration_array[0]}
duration_minutes=${duration_array[1]}
duration_seconds=${duration_array[2]}
duration=$( echo "$duration_seconds + 60*$duration_minutes + 3600*$duration_hours" | bc )
fps=$( sed -n "s/.*, \(.*\) tbr.*/\1/p" <<< "$video_info" )
size=$( grep "Video:" <<< "$video_info" | grep -Eo '[0-9]+x[0-9]+' )
width=$( cut -f 1 -d "x" <<< $size )
height=$( cut -f 2 -d "x" <<< $size )
codec=$( grep -Eo "Video: [^ ,]+" <<< "$video_info" | cut -f 2 -d " " )
video_basename=$( basename "$VIDEO" )
echo "*** You specified an input file of -> $VIDEO"
echo "*** You specified a working directory of -> $WORK_DIR"
echo "*** You specified a output directory of -> $OUTPUT_DIR"
video_no_ext="${video_basename%.*}"
temp_image="$WORK_DIR/$video_no_ext.$IMAGE_FORMAT"
output_image="$OUTPUT_DIR/$video_no_ext.$IMAGE_FORMAT"
interval=$( echo "($duration - 60) / $MAXTHUMB" | bc )
trap 'clean_up' INT # Quit on ^C instead of killing the ffmpeg process and continuing
echo "*** Extracting ${MAXTHUMB} frames... " # leave the extra spaces on the end for the counter to delete
ff_log="$WORK_DIR/ffmpeg_output"
# Dump MAXTHUMB+1 frames from the video, starting at 00:00:30 and evenly spaced till the end
ffmpeg -y -i "$VIDEO" -ss 30 -r "1/$interval" -vframes $((MAXTHUMB + 1)) -bt 100000000 "$WORK_DIR/${video_no_ext}_%03d.$IMAGE_FORMAT" 2> "$ff_log" &
FF_PID=$!
# Show the progress and wait for ffmpeg to finish
display_ffmpeg_progress
# delete the first from, since it seems the first and second are always the same...
rm "$WORK_DIR/${video_no_ext}_001.$IMAGE_FORMAT"
i=1
echo
echo -n "*** Resizing frames... "
shopt -s nullglob
for img in "$WORK_DIR/${video_no_ext}"_*.$IMAGE_FORMAT; do
count=$( printf %03s $i ) # use space-padding for the counter
echo -en "\b\b\b$count" # Show a counter as it goes, to give progress
convert -quality 100 -resize "$THUMBSIZE" "$img" "$img" & # do this in the background so we don't have to wait for it
i=$(( i + 1 ))
done
wait # make sure all those background converts have finished
echo
echo "*** Assembling montage..."
montage -background black -borderwidth 0 -geometry "+1+1" "$WORK_DIR/${video_no_ext}*.${IMAGE_FORMAT}" "$temp_image"
LABEL="Filename: $video_basename | Codec: $codec | Size: $size | Length: $duration_string | FPS: $fps"
echo "*** I will apply the following label -> $LABEL"
convert -gravity North -splice 0x28 -background black -fill white -font DejaVu-Sans-Book -pointsize 12 -annotate +0+6 "$LABEL" "$temp_image" "$output_image"
echo "*** Final screencap image is stored here -> $output_image"
clean_up
Jump to Line
Something went wrong with that request. Please try again.