Answers.Body: <p>Using the encoder's scenecut to detect scenes is not advisable, since its purpose is efficient GOP splitting taking into account other encoding parameters. It is not a "pure" scene detector. Its propensity to mark a "scene change" increases as it gets closer to the the next forced keyframe target (set by <code>keyint</code>).</p>
  
  <p>Consider using <a href="https://github.com/Breakthrough/PySceneDetect" rel="noreferrer">https://github.com/Breakthrough/PySceneDetect</a> instead.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-10-02T15:30:11.927Z
Answers.Text: Yes I was using that library before. But much slower than ffmpeg. So was looking for a ffmpeg-based solution.
Answers.UserDisplayName: angel_30
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-10-02T08:58:14.997Z
Answers.LastActivityDate: 2019-10-02T08:58:14.997Z
Answers.UserDisplayName: Gyan
Answers.Body: <p>This script makes it simple, better results than other posts around town:
  <a href="https://gist.github.com/achesco/4dc2ebf13378a0a61fc26c7fe01f539e" rel="nofollow noreferrer">https://gist.github.com/achesco/4dc2ebf13378a0a61fc26c7fe01f539e</a></p>
  <blockquote>
  <p>Splits file.mp4 file to scenes with change more than 0.5 and saves
  output parts to /tmp/parts folder</p>
  </blockquote>
  <blockquote>
  <p>split.sh -d 0.5 -o /tmp/parts -f file.mp4</p>
  </blockquote>
  <p>Including the script here for reference (note the version below has some differences, primarily a bug fix):</p>
  <pre><code># Splits video to separate scenes files
  # Inspired by https://stackoverflow.com/a/38205105
  
  #!/bin/bash
  
  file=&quot;&quot;
  out=&quot;./&quot;
  diff=0.4
  bitrate=&quot;&quot;
  trim=0
  stripaudio=&quot;&quot;
  
  usage () {
    echo &quot;Usage: $(basename $0) [[[-o folder] [-d ratio]] | [-h]] -f file.mp4&quot;
    echo
    echo &quot;Options:&quot;
    echo &quot;-f, --file          Input file&quot;
    echo &quot;-o, --out           Outpup files folder path, default&quot;
    echo &quot;                    to current folder&quot;
    echo &quot;-d, --diff          Number from 0 to 1, default to 0.4.&quot;
    echo &quot;                    Scene change difference factor&quot;
    echo &quot;-b, --bitrate       Bitrate to encode parts&quot;
    echo &quot;-t, --trim          Trim last given seconds number, default 0&quot;
    echo &quot;-sa, --strip-audio  Strip audio&quot;
    echo &quot;-h, --help          Display this help message&quot;
    echo
    echo &quot;Example: split.sh -d 0.5 -o /tmp/parts -f file.mp4&quot;
    echo &quot;Splits file.mp4 file to scenes with change more than 0.5&quot;
    echo &quot;and saves output parts to /tmp/parts folder&quot;
  }
  
  if [ &quot;$1&quot; = &quot;&quot; ]; then
    usage
  fi
  
  while [ &quot;$1&quot; != &quot;&quot; ]; do
    case $1 in
      -f | --file )
        shift
        file=$1
        ;;
      -d | --diff )
        shift
        diff=$1
        ;;
      -o | --out )
        shift
        out=$1
        ;;
      -b | --bitrate )
        shift
        bitrate=&quot;-b $1&quot;
        ;;
      -t | --trim )
        shift
        trim=$1
        ;;
      -sa | --strip-audio )
        stripaudio=&quot;-an&quot;
        ;;
      -h | --help )
        usage
        exit
        ;;
      * )
        usage
        exit 1
    esac
    shift
  done
  
  cut_part () {
    duration_flag=&quot;&quot;
    if [ &quot;$3&quot; != &quot;&quot; ]; then
      duration_flag=&quot;-t&quot;
    fi
    ffmpeg -loglevel error -hide_banner -ss $1 -i $file $duration_flag $3 \
      -vcodec libx264 -movflags faststart $bitrate $stripaudio \
      -y $out/`printf &quot;%04d_%s&quot; $2 $filename` &lt; /dev/null
  }
  
  filename=`basename $file`
  mkdir -p $out
  timefrom=0
  i=1
  while read -r timestamp; do
    duration=`bc &lt;&lt;&lt; &quot;$timestamp-$timefrom-$trim&quot; | awk '{printf &quot;%f&quot;, $0}'`
    cut_part $timefrom $i $duration
    timefrom=$timestamp
    i=`expr $i + 1`
  done &lt; &lt;(
    ffmpeg -i $file -filter:v &quot;select='gt(scene,$diff)',showinfo&quot; -f null - 2&gt;&amp;1 | \
      grep Parsed_showinfo | grep pts_time:[0-9.]* -o | grep &quot;[0-9]*\.[0-9]*&quot; -o
  )
  
  if [ $timefrom != 0 ]; then
    cut_part $timefrom $i
  fi
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2024-07-31T11:26:31.880Z
Answers.Text: Instead of all that parsing, you can use this command: `ffprobe -show_entries frame=pts_time -of compact=nk=1:p=0 -f lavfi "movie=$file,select=gt(scene\,$diff)"`
Answers.UserDisplayName: OrangeDog
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-06-27T19:16:18.343Z
Answers.LastActivityDate: 2020-07-01T04:21:39.103Z
Answers.LastEditDate: 2020-07-01T04:21:39.103Z
Answers.UserDisplayName: dtmland
Body: <p>I'm trying to detect scenes and save them as individual files with <code>FFmpeg</code>. I found this long command somewhere, but it fails with a good detection. I change the scenecut value, but I don't see any effects.</p>
  
  <pre><code>ffmpeg -y -i test.mp4 -max_muxing_queue_size 1024 -vf yadif -preset:v fast -x264opts scenecut=20 -f segment -segment_format mp4 -segment_format_options movflags=faststart %05d.mp4
  </code></pre>
  
  <p>Is there a better command than this? There should be a shorter, more efficient command I guess.</p>
  
Tags: <video><ffmpeg><encoding><mp4><decoding>
Title: How to extract each video scene with FFmpeg
UserDisplayName: angel_30
ThreadText: # How to extract each video scene with FFmpeg
  
  (Asked by: username_0 on 2019-10-01)
  
  I'm trying to detect scenes and save them as individual files with `FFmpeg`. I found this long command somewhere, but it fails with a good detection. I change the scenecut value, but I don't see any effects.
  
  ```
  ffmpeg -y -i test.mp4 -max_muxing_queue_size 1024 -vf yadif -preset:v fast -x264opts scenecut=20 -f segment -segment_format mp4 -segment_format_options movflags=faststart %05d.mp4
  
  ```
  
  Is there a better command than this? There should be a shorter, more efficient command I guess.
  
  **Tags:** video, ffmpeg, encoding, mp4, decoding
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2019-10-02. Score: 5
  
  Using the encoder's scenecut to detect scenes is not advisable, since its purpose is efficient GOP splitting taking into account other encoding parameters. It is not a "pure" scene detector. Its propensity to mark a "scene change" increases as it gets closer to the the next forced keyframe target (set by `keyint`).
  
  Consider using <https://github.com/Breakthrough/PySceneDetect> instead.
  
  > **Comments:**
  > **username_0**: Yes I was using that library before. But much slower than ffmpeg. So was looking for a ffmpeg-based solution.  
  
  ---
  
  ### Answer by username_2 on 2020-06-27. Score: 1
  
  This script makes it simple, better results than other posts around town:
  <https://gist.github.com/achesco/4dc2ebf13378a0a61fc26c7fe01f539e>
  
  > Splits file.mp4 file to scenes with change more than 0.5 and saves
  > output parts to /tmp/parts folder
  
  > split.sh -d 0.5 -o /tmp/parts -f file.mp4
  
  Including the script here for reference (note the version below has some differences, primarily a bug fix):
  
  ```
  # Splits video to separate scenes files
  # Inspired by https://stackoverflow.com/a/38205105
  
  #!/bin/bash
  
  file=""
  out="./"
  diff=0.4
  bitrate=""
  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"
    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="-b $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 -i $file $duration_flag $3 \
      -vcodec libx264 -movflags faststart $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
  
  ```
  
  > **Comments:**
  > **username_3**: Instead of all that parsing, you can use this command: `ffprobe -show_entries frame=pts_time -of compact=nk=1:p=0 -f lavfi "movie=$file,select=gt(scene\,$diff)"`  
  
  ---
  
  