4

I have many video files (flv/mp4) that change resolution mid-stream (720p/1080p/640).

I would like to use something like ffmpeg to automatically detect the change in resolution and split the videos into their individual scenes, keeping their existing encoding quality: segment without re-encoding (Video1-scene1.flv, Video1-scene2.flv, etc).

I have found various methods to split upon silence, upon scene change, upon black scenes, but nothing as simple as a change in resolution width.

These files often cause video editors/trimmers to crash, and manually identifying and removing low resolution scenes is very time consuming if I simply convert the entire video to 1080p.

The algorithm is probably as simple as comparing the current frame to the previous frame, and if they are different resolutions, split the video and start a new segment.

Can anyone help please?

EXAMPLE FILE (temporarily available): Example.flv

Below are a few related answers:

Cut part from video file from start position to end position with FFmpeg

https://stackoverflow.com/questions/36074224/how-to-split-video-or-audio-by-silent-parts

Automatically split large .mov video files into smaller files at black frames (scene changes)?

Split Up a Video Using FFMPEG through Scene Detection

Additional Resources:
Using Lord Neckbeard's solution, I am attaching the (unfortunately very manual) process that I eventually got to work on Windows10. Perhaps it can spawn other ideas around ffmpeg.
(I posted a separate question for anyone who is GURU enough to: Automate this process...)

drag video onto a batch file that contains:

ffprobe -v error -show_entries frame=pkt_pts_time,width,height -select_streams v -of csv=p=0 %1 > allkeyframes.txt

(allkeyframes.txt sample...)

13.652000,640,480
13.755000,640,480
13.597000,480,360
13.652000,480,360

paste this text in POWERSHELL:

$o=""
$n=0
foreach($line in (Get-Content allkeyframes.txt)){
  $nline = $line.Split(",")
  $nline2=($nline[1]+$nline[2])
  if ($nline2 -ne $preventry) {
    $n0=$nline[0]
    $o="$o,$n0"
    $n=$n0
}
  $preventry = $nline2
}
if ($o.length -gt 1){
echo $o.Remove(0,1) > resolutionchanges.txt
} else {
Write-Host "No resolution changes found" -ForegroundColor Red
}

(resolutionchanges.txt:)

13.597000,25.618000,33.628000,45.598000

enter the following in the command window, after pasting contents of resolutionchanges.txt and changing "input.flv" to the video name (Win10 refused my attempts at batching this):

ffmpeg -i input.flv -map 0 -c copy -segment_times 13.597000,25.618000,33.628000,45.598000 -reset_timestamps 1 -f segment output_%03d.flv

1

1 Answer 1

3

Lazyman solution is to use the scale filter to conform each input to a desired width x height.

For your proposed solution you can use ffprobe to determine when size changes occur.

ffprobe -v error -show_entries frame=pkt_pts_time,width,height -select_streams v -of csv=p=0 input.flv

Example output excerpt during width and height change (key_frame, pkt_pts_time, width, height):

0,89.081000,480,640
0,89.281000,480,640
0,89.481000,480,640
1,89.568000,640,480
0,89.592000,640,480
0,89.632000,640,480
1,97.749000,480,640

The size changes will likely occur on key frames which is where you can make the cuts if stream copying is a requirement. If you just want the key frames add the -skip_frame nokey option.

Then use the segment muxer:

ffmpeg -i input.flv -map 0 -c copy -segment_times 89.568,97.749 -reset_timestamps 1 -f segment output_%03d.flv
6
  • 1
    THANKS! This alone saves me weeks of effort! I am still hoping for something a little more efficient (ideally in ffmpeg alone), but except for 5 seconds of black on the first segment video, it appears to eventually work. I had no success piping in Windows10 nor with Batch files (inconsistently ignored variables), so any advice there would also be appreciated. (I'll add the Powershell script I had to manually use in case it helps anyone else).
    – EverT
    Feb 28, 2018 at 20:44
  • @EverT I'm not much of a Windows user, so I don't have any suggestions regarding Powershell, etc, but you can post a new question to address the Windows specific issue(s), and leave this specific Q&A to address the ffmpeg part. That will keep the questions from being too overreaching and broad, and you'll have a better chance of getting answers.
    – llogan
    Feb 28, 2018 at 22:06
  • @LordNeckbeard- Great advice. I broke out the pipe question separately. I left the 'sort-of-working' solution in for others, just in case a more direct approach isn't found. I wish I had the linux knowledge to complete your grep answer for those linux Googlers who might need it someday.
    – EverT
    Feb 28, 2018 at 23:43
  • @EverT Try adding -skip_frame nokey. I forgot about that when I wrote the answer. Must be getting optionitis: starting to forget them. Then you can skip piping to another process.
    – llogan
    Mar 1, 2018 at 0:00
  • @LordNeckbeard- Does it matter where? In a 30sec clip with 5 resolution changes, -skip_frame nokey reduces the ffprobe text from 848 lines to 21, but that would still trigger 21 segments instead of 5. Processing is significantly faster! (thanks!)
    – EverT
    Mar 3, 2018 at 0:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .