2
2
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
1THANKS! 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 – 2018-02-28T20:44:33.113
@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 – 2018-02-28T22:06:27.443@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 – 2018-02-28T23:43:56.330@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 – 2018-03-01T00:00:16.167@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 – 2018-03-03T00:49:56.507@EverT It outputs 21 lines because there are 21 keyframes in your input. You'll have to process the output further with another tool to eliminate the unwanted lines. I doubt it really matters where you place the option:
ffprobe
option placement isn't as important as it is inffmpeg
. – llogan – 2018-03-03T02:01:04.230