Skip to content

Instantly share code, notes, and snippets.

@pabloko
Created March 12, 2019 01:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pabloko/a441c65b193266c22eb5099fbeeba2fd to your computer and use it in GitHub Desktop.
Save pabloko/a441c65b193266c22eb5099fbeeba2fd to your computer and use it in GitHub Desktop.

Fast short previews from videos

Hi! as I needed to create bulk previews of long videos, like short cuts merged on one scaled video. As i searched for some examples to do this using ffmpeg, stumbled upon a common problem on every snippet there and here... long story short: seeking will make you waste a lot of time unless you seek cleverly.

This script will do the only fast seeking method seeming to work, -ss from input, pipe a chunk and exit that process. Several chunks are piped the encoder process that writes final file. Theres no temporary files, and if your source is h264, also no transcoding on input reading.

Demo

12 seconds of video generated in 14 seconds, almost 12 of them used by encoder scaling

Usage

./videosnap.sh video_in.mp4 video_out.mp4

Preconfigure your script with the settings you want (chunk number and duration, output scale, fps...)

Dependencies:

  • ffmpeg
  • ffprobe
  • linux (script is portable to windows)

Customize

  • You can change output settings to use -c:v copy and have almost inmediate video split+join as no transcoding will take place
  • You can change the function that set the split start+duration to your own data
  • Its possible to change output to gif, but file will be heavier and worse quality, and you probably will need more filters to make it look good.
  • Theres a known problem if you make a mistake on script and execute it, probably pty session will loose stdin

Flowchart

graph LR
A[init] -- duration_to_divisions --> B((ffmpeg chunk))
B --each division-->B
B --> D{ffmpeg out}
#!/bin/sh
# videoSNAPPER by Pabloko
start=`date +%s`
FILE=$1
OUT=$2
CHUNKS=12
CHUNK_LEN=1
OUT_WIDTH=360
OUT_HEIGHT=200 #must be divisible by 2, use -1 for auto
OUT_FPS=10
FFM="ffmpeg" #configure path to ffmpeg
DURATION=$(ffprobe -loglevel error $FILE -show_format 2>&1 | sed -n 's/duration=//p' | awk '{print int($0)}')
ADDER_PAD=`expr $CHUNKS + 2`
ADDER=`expr $DURATION / $ADDER_PAD`
{
for (( i=1 ; ((i-$CHUNKS-1)) ; i=(($i+1)) ))
do
$FFM -loglevel error -ss $((`expr $ADDER \* $i`)) -i $FILE -t $CHUNK_LEN -bsf:v h264_mp4toannexb -f h264 pipe:
done
} | $FFM -loglevel error -y -fflags +genpts -f h264 -i pipe: -c:v libx264 -crf 27 -preset ultrafast -r $OUT_FPS -filter:v scale=$OUT_WIDTH:$OUT_HEIGHT $OUT
end=`date +%s`
runtime=$((end-start))
me=`basename "$0"`
echo "$me: [$FILE] -> [$OUT] success in $runtime seconds"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment