Accurate cutting of video (+ audio) with ffmpeg

.mp4audiocodecffmpegvideo

I want my website to allow users to accurately create their own clips from a source video I provide.

I have a source video file that I first want to convert to something suitable for a website:

Input #0, matroska,webm, from 'source.mkv': 
Duration: 00:28:18.57, start: 0.000000, bitrate: 10183 kb/s 
Stream #0:0: Video: h264 (Constrained Baseline), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 48 tbc (default)
Stream #0:1: Audio: mp3, 44100 Hz, stereo, s16, 128 kb/s (default)

I use ffmpeg to convert it like so:

ffmpeg -i source.mkv -c:v libx264 -c:a aac -strict experimental -vf scale="960:-1" source.mp4

Watching this video back it is good enough quality and small enough file size for my needs, and loads/plays on my website.

I have a webpage that lets users select a start and endpoint on this video – and create a clip. Here's an example of the ffmpeg command that I use for that:

-ss 577.920 -i source.mp4 -t 011.980 -codec:v copy -codec:a copy -vf scale="960:-1" clip1.mp4

The problem is the clip is not always time-accurate enough. Usually the audio is accurate enough but the video stops half a second early or something.

Is there any way to make this accurate and in-sync to say, 0.2 of a second?

EDIT:
Adding -force_key_frames 00:00:00.2 didn't help.

EDIT:
I changed the clipping to use -c:v libx264 -c:a aac -strict experimental instead of -codec:v copy -codec:a copy with good (ish) results.

The file can play externally without issue – but when I load it into my html5 video element and play it – the last part of the video (audio is fine) freezes. The last part that freezes is less than a second long.

Should I try it with another video encoder? What is the best alternative for libx264? Bearing in mind I will probably want this to be on a public website.

But hang on doesn't the fact that it plays accurately without issue with a player like MPC or Windows Media Player suggest that it is a problem with either Google Chrome or the HTML video element? Or am I using an unsupported encoding or something?

Best Answer

The behavior of -ss changes depending if it used as an input or output option, and is often slower but can be more accurate when used as an output option. See the answer to ffmpeg converts video from specified time period slowly for more details and examples.

To change output quality for source.mp4 use the -crf option with a value between 18-28 (23 is default). See the CRF section of the FFmpeg and x264 Encoding Guide for examples.

Your trimming command can be simplified:

ffmpeg -ss 577.92 -i source.mp4 -ss 0 -t 11.98 -c copy -map 0 clip1.mp4

I replaced -codec:v copy -codec:a copy with -c copy -map 0. This will copy all streams instead of just the first video and audio streams--although the input only has two streams due to your previous command. Since you can not scale without re-encoding, therefore being mutually exclusive with -codec:v copy, and since your input is already scaled to the set size I removed the filter options.

If it is still not accurate enough then try:

ffmpeg -i source.mp4 -ss 577.92 -t 11.98 -c copy -map 0 clip1.mp4

It will be slower, but probably more accurate. See the links in the answer in the first link I provided for a description of the differences of these two examples.

Lastly, you should run source.mp4 through qt-faststart (located in the tools directory in ffmpeg source), or use the -movflags faststart option. This will relocate some data to the beginning of the file so it can begin playback before it is completely downloaded.

Related Question