Skip to content

Instantly share code, notes, and snippets.

@achesco
Last active October 25, 2025 04:38
Show Gist options
  • Save achesco/4dc2ebf13378a0a61fc26c7fe01f539e to your computer and use it in GitHub Desktop.
Save achesco/4dc2ebf13378a0a61fc26c7fe01f539e to your computer and use it in GitHub Desktop.

Revisions

  1. achesco renamed this gist Aug 20, 2017. 1 changed file with 0 additions and 0 deletions.
  2. achesco created this gist Jun 1, 2017.
    98 changes: 98 additions & 0 deletions Detect and split video to scenes with ffmpeg
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    # Splits video to separate scenes files
    # Inspired by https://stackoverflow.com/a/38205105

    #!/bin/bash

    file=""
    out="./"
    diff=0.4
    bitrate="512k"
    trim=0
    stripaudio=""

    usage () {
    echo "Usage: $(basename $0) [[[-o folder] [-d ratio]] | [-h]] -f file.mp4"
    echo
    echo "Options:"
    echo "-f, --file Input file"
    echo "-o, --out Outpup files folder path, default"
    echo " to current folder"
    echo "-d, --diff Number from 0 to 1, default to 0.4."
    echo " Scene change difference factor"
    echo "-b, --bitrate Bitrate to encode parts, default to 512k"
    echo "-t, --trim Trim last given seconds number, default 0"
    echo "-sa, --strip-audio Strip audio"
    echo "-h, --help Display this help message"
    echo
    echo "Example: split.sh -d 0.5 -o /tmp/parts -f file.mp4"
    echo "Splits file.mp4 file to scenes with change more than 0.5"
    echo "and saves output parts to /tmp/parts folder"
    }

    if [ "$1" = "" ]; then
    usage
    fi

    while [ "$1" != "" ]; do
    case $1 in
    -f | --file )
    shift
    file=$1
    ;;
    -d | --diff )
    shift
    diff=$1
    ;;
    -o | --out )
    shift
    out=$1
    ;;
    -b | --bitrate )
    shift
    bitrate=$1
    ;;
    -t | --trim )
    shift
    trim=$1
    ;;
    -sa | --strip-audio )
    stripaudio="-an"
    ;;
    -h | --help )
    usage
    exit
    ;;
    * )
    usage
    exit 1
    esac
    shift
    done

    cut_part () {
    duration_flag=""
    if [ "$3" != "" ]; then
    duration_flag="-t"
    fi
    ffmpeg -loglevel error -hide_banner -ss $1 $duration_flag $3 -i $file \
    -vcodec libx264 -movflags faststart -b $bitrate $stripaudio \
    -y $out/`printf "%04d_%s" $2 $filename` < /dev/null
    }

    filename=`basename $file`
    mkdir -p $out
    timefrom=0
    i=1
    while read -r timestamp; do
    duration=`bc <<< "$timestamp-$timefrom-$trim" | awk '{printf "%f", $0}'`
    cut_part $timefrom $i $duration
    timefrom=$timestamp
    i=`expr $i + 1`
    done < <(
    ffmpeg -i $file -filter:v "select='gt(scene,$diff)',showinfo" -f null - 2>&1 | \
    grep Parsed_showinfo | grep pts_time:[0-9.]* -o | grep "[0-9]*\.[0-9]*" -o
    )

    if [ $timefrom != 0 ]; then
    cut_part $timefrom $i
    fi