Clip long video segment quickly - ffmpeg

Let's say I have a video called Concert.mp4. I want to extract a performance from it quickly with minimal reencoding. I want to do the equivalent of this, but faster:
ffmpeg -i "Concert.mp4" -ss 00:11:45 -to 00:18:15 -preset veryfast -y artist.mp4
This takes 17 seconds, which is way too long for our needs.
Now, it turns out that 11:45 and 18:15 don't fall on iframes, so if you try this you will get a 3 second delay at the beginning before the video shows:
ffmpeg -i "Concert.mp4" -ss 00:11:45 -to 00:18:15 -c copy -y artist.mp4
Running this command, we can see where we need to cut:
ffprobe -read_intervals "11:00%19:00" -v error -skip_frame nokey -show_entries frame=pkt_pts_time -select_streams v -of csv=p=0 "Concert.mp4" > frames.txt
So what we need to do is encode the first 3.708 seconds, copy the middle, and then encode the last 5.912 seconds.
I can get the 3 segments to all look perfect (by themselves) like this:
ffmpeg -ss 698.698 -i "Concert.mp4" -ss 6.302 -t 3.708 -c:v libx264 -c:a copy -c:s copy -y clipbegin.mp4
ffmpeg -ss 708.708 -to 1089.088 -i "Concert.mp4" -c copy -y clipmiddle.mp4
ffmpeg -ss 1089.088 -i "Concert.mp4" -t 5.912 -c:v libx264 -c:a copy -c:s copy -y clipend.mp4
ffmpeg -f concat -i segments.txt -c copy -y artist.mp4
segments.txt of course contains the following:
file 'clipbegin.mkv'
file 'clipmiddle.mkv'
file 'clipend.mkv'
I saw this solution presented here, but no amount of tweaking gets it to work for me:
https://superuser.com/a/1039134/73272
As far as I can tell, this method doesn't work at all. It crashes VLC pretty hard no matter what I try.
The combined video keeps glitching after the 3 seconds, probably because the PTS times are different or something (using some options, I have seen warning messages to this effect). Is there anything I can add to the commands above to get this to work? The only requirement is that the middle command must not re-encode the video, but must do a fast copy.
Thanks in advance.

OK, so the answer was just that the latest VLC seems to be buggy. What I did above plays just fine with a very slight pause at the cut point in ffplay, mplayer and PotPlayer.
Following #Gyan's advice, I set the profile and level to match the original (using -profile:v main -level:v 4) and even the slight pause went away.
ffmpeg -ss 698.698 -i "Concert.mp4" -ss 6.302 -t 3.708 -c:v libx264 -c:a copy -c:s copy -profile:v main -level:v 4 -y clipbegin.mp4
ffmpeg -ss 708.708 -to 1089.088 -i "Concert.mp4" -c copy -y clipmiddle.mp4
ffmpeg -ss 1089.088 -i "Concert.mp4" -t 5.912 -c:v libx264 -c:a copy -c:s copy -profile:v main -level:v 4 -y clipend.mp4
ffmpeg -f concat -i segments.txt -c copy -y artist.mp4

Related

How to add a hard code of subs to this filter_complex

ffmpeg -ss 00:11:47.970 -t 3.090 -i "file.mkv" -ss 00:11:46.470 -t 1.500 -i "file" -ss 00:11:51.060 -t 0.960 -i "file.mkv" -an -c:v libvpx -crf 31 -b:v 10000k -y -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[outv][outa];[outv]scale='min(960,iw)':-1[outv];[outv]subtitles='file.srt'[outv]" -map [outv] file_out.webm -map [outa] file.mp3
I have a filter where take three different points in a file concat them together and scale them down this part works
Im looking to see how to add to the filter_complex a sub burn in step rendering the subs from the exact timings usings a file that I specify when I use the above code it doesn't work
The subtitles filter is receiving a concatenated stream. It does not contain the timestamps from the original segments. So the subtitles filter starts from the beginning. I'm assuming this is the problem when you said, "it doesn't work".
The simple method to solve this is to make temporary files then concatenate them.
Output segments
ffmpeg -ss 00:11:47.970 -t 3.090 -copyts -i "file.mkv" -filter_complex "scale='min(960,iw)':-1,subtitles='file.srt',setpts=PTS-STARTPTS;asetpts=PTS-STARTPTS" -crf 31 -b:v 10000k temp1.webm
ffmpeg -ss 00:11:46.470 -t 1.500 -copyts -i "file.mkv" -filter_complex "scale='min(960,iw)':-1,subtitles='file.srt',setpts=PTS-STARTPTS;asetpts=PTS-STARTPTS" -crf 31 -b:v 10000k temp2.webm
ffmpeg -ss 00:11:51.060 -t 0.960 -copyts -i "file.mkv" -filter_complex "scale='min(960,iw)':-1,subtitles='file.srt',setpts=PTS-STARTPTS;asetpts=PTS-STARTPTS" -crf 31 -b:v 10000k temp3.webm
The timestamps are reset when fast seek is used (-ss before -i). -copytswill preserve the timestamps so the subtitles filter knows where to start the subtitles.
Make input.txt:
file 'temp1.webm'
file 'temp2.webm'
file 'temp3.webm'
Concatenate with the concat demuxer:
ffmpeg -f concat -i input.txt -c copy output.webm
-c copy enables stream copy mode so it avoids re-encoding to concatenate.

How to replace the video track in a video file with a still image?

I am trying to use ffmpeg to replace the video track in a video file with a still image. I tried some commands I got from other questions such as the one here
ffmpeg -i x.png -i orig.mp4 final.mp4
ffmpeg -r 1/5 -i x.png -r 30 -i orig.mp4 final.mp4
But these didn't work. I'm not sure which of these arguments are required or not. The output should be accepted by YouTube as a valid video - I was able to simply remove the video track, but apparently they don't let you upload a video without a video track.
You can try looping the still image like this:
ffmpeg -loop 1 -i x.png -i orig.mp4 final.mp4
Then you can tweak the encoding process by introducing the following quality parameters:
ffmpeg -loop 1 -i x.png -i orig.mp4 -crf 22 -preset slow final.mp4
they are described here.
If your colorspace gets rejected by YouTube you can try adding: -pix_fmt yuv420p.
Solution: A final solution is something like this:
Where -t 30 is an example duration of 30 seconds.
Using -c:a copy will directly copy the original audio without a new re-encoding (is faster).
ffmpeg -loop 1 -i x.png -i orig.mp4 -map 0 -map 1:a -c:v libx264 -pix_fmt yuv420p -crf 22 -preset slow -c:a copy -shortest final.mp4

FFMPEG duplicating the first frame

I want to use FFMPEG (the latest version) to cut a 24 fps matroska file. So I am using -ss and -t, but I noticed with VLC that the very first frame is ALWAYS duplicated one time, no matter the file or the duration I choose. While it is not a really serious issue, but I wanted to know if there was a way to prevent that.
Here is the command I am using:
ffmpeg -ss 00:01:26.086 -i file.mkv -t 00:00:02.000 -c:v libx264 -crf 18 output.mp4
add -vsync vfr in your cmd may be helpful
ffmpeg -ss 00:01:26.086 -i file.mkv -vsync vfr -t 00:00:02.000 -c:v libx264 -crf 18 output.mp4

Cutting movie with ffmpeg result in audio/video desync

I've concate long ago set of movies taken during some lecture. Now I want to cut them for each question/answer.
I do it like this.
ffmpeg -ss 00:00:34.7 -t 00:10:44.6 -y -i input_movie.mp4 -vcodec copy -acodec copy output_1.mp4
ffmpeg -ss 00:11:22.2 -y -i input_movie.mp4 -vcodec copy -acodec copy output_2.mp4
Yet, for the second part I can't set proper starting point so audio and video would be in sync.
Usually I could fix it with small tweeks in cut start time (like .1, .2, and so on). For this case this doesn't work.
When I play second cut in mplayer video is few second behind audio (where audio is cut properly). When I jump forward and back - all is again in sync.
Where's the problem? How to fix it?
When I cut with RE-ENCODING - problem is gone.
ffmpeg -ss 00:00:34.7 -t 00:10:44.6 -y -i input_movie.mp4 -c:v libx264 -c:a aac -strict experimental -b:a 128koutput_1.mp4

Why the following ffmpeg command outpus an eleven minutes long video?

Why the following ffmpeg command outpus an eleven minutes long video?
ffmpeg -ss 600 -i 01x01TheStrongestMan.mp4 -to 660 -vcodec copy -acodec copy -y outputxxx.mp4
I want to slice the video from the 600 second to the 660 second, the output should be a 1 minute long video.
How can I do that and why my command is wrong?
Thanks.
Here's a few little test examples I did which may shed some light.
Seek before: (Quicker but less accurate)
ffmpeg -ss 600 -to 660 -i movie.mkv -vcodec copy -acodec copy -y output1.mp4
Seek after: (Slower but more accurate)
ffmpeg -i movie.mkv -ss 600 -to 660 -vcodec copy -acodec copy -y output2.mp4
Seek before and after: (Quick and accurate)
ffmpeg -ss 500 -i movie.mkv -ss 100 -to 160 -vcodec copy -acodec copy -y output3.mp4
However........
Depending on which frames are which, you'll not always get accurate cuts/trims. You'll also get different results, or find one method better than another, depending on whether you are just copying streams, or encoding.

Resources