Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cut a video in between key frames without re-encoding the full video using ffpmeg?

I would like to cut a video at the beginning at any particular timestamp, and it need to be precise, so the nearest key frame is not good enough.

Also, these videos are rather long - an hour or longer - so I would like to avoid re-encoding this altogether if possible, or otherwise only re-encode a minimal fraction of the total duration. Thus, would like to maximise the use of -vcodec copy.

How can I accomplish this using ffmpeg?

NOTE: See scenario, and my own rough idea for a possible solution below.


Scenario:

  • Original video
    • Length of 1:00:00
    • Has a key frame every 10s
  • Desired cut:
    • From 0:01:35 through till the end
  • Attempt #1:
    • Using -ss 0:01:35 -i blah.mp4 -vcodec copy, what results is a file where:
    • audio starts at 0:01:30
    • video also starts at 0:01:30
    • this starts both the audio and the video too early
  • using -i blah.mp4 -ss 0:01:35 -vcodec copy, what results is a file where:
    • audio starts at 0:01:35,
    • but the video is blank/ black for the first 5 seconds,
      • until 0:01:40, when the video starts
    • this starts the audio on time, but the video starts too late

Rough idea

  • (1) cut 0:01:30 to 0:01:40
    • re-encode this to have new key frames, including one at the target time of 0:01:35
    • then cut this to get the 5 seconds from 0:01:35 through 0:01:40
  • (2) cut 0:01:40 through till the end
    • without re-encoding, using -vcodec copy
  • (3) ffmpeg concat the first short clip (the 5 second one) with the second long clip

I know/ can work out the commands for (2) and (3), but am unsure about what commands are needed for (1).

like image 219
bguiz Avatar asked Aug 23 '20 14:08

bguiz


2 Answers

List timestamps of key frames:

ffprobe -v error -select_streams v:0 -skip_frame nokey -show_entries frame=pkt_pts_time -of csv=p=0 input.mp4

It will output something like:

0.000000
2.502000
3.795000
6.131000
10.344000
12.554000
16.266000
...

Let's say you want to delete timestamps 0 to 5, and then stream copy the remainder. The closest following key frame is 6.131.

Re-encode 5 to 6.131. Ensure the input and output match attributes and formats. For MP4 default settings should do most of the work, assuming H.264/AAC, but you may have to manually match the profile.

ffmpeg -i input.mp4 -ss 5 -to 6.131 trimmed.mp4

Make input.txt for the concat demuxer:

file 'trimmed.mp4'
file 'input.mp4'
inpoint 6.131

Concatenate:

ffmpeg -f concat -i input.mp4 -c copy output.mp4
like image 52
llogan Avatar answered Nov 18 '22 18:11

llogan


try

ffmpeg -i src.mp4 -vcodec copy -reset_timestamps 1 -map 0 out.mp4

or

ffmpeg -i src.mp4 -vcodec copy -reset_timestamps 1 -map 0 src_.m3u8

which generates hls playlists

like image 22
krishna Avatar answered Nov 18 '22 16:11

krishna