1

I am a really beginner in video editing. Sorry if this question is silly.

I heard videos consist of key frames (I-frames) and inter-frames (P-frames and B-frames).

Say I have a video of 10 seconds, and I ask ffmpeg to extract from 4.3 to 10.

ffmpeg -ss 4.3 -i input.mp4 output.mp4

From my observation, ffmpeg seems to reencode the whole output file.

enter image description here

Assume the original video has I frames at 1, 3, 5, 7, 9 seconds. I think ffmpeg can just insert a keyframe at 4.3, reencode frames from 4.3 to 5, and leave all data afterwards intact.

Is my idea realistic? Can ffmpeg do so?

I ask this is because if my input video is very long, my method can cut the video very fast.

1 Answer 1

2

heavy scripting

#!/bin/bash
cd /tmp
f="/mnt/public/upload/test/tg/2024-07-20_10꞉11꞉34.MOV"
# f="/mnt/public/upload/test/tg/2024-07-19_13꞉39꞉18.mp4"
t="tmp.mp4"
o="output.mp4"

IFS=, read vid wid hei sar fmt fps tbn <<< $(ffprobe -v 0 -select_streams v:0 -show_entries stream=codec_name,width,height,sample_aspect_ratio,r_frame_rate,time_base,pix_fmt -of csv=p=0 "$f")
if [ "$sar" = "N/A" ]; then sar=1; fi
tbn=${tbn#*/}
echo $vid $wid $hei $sar $fmt $fps $tbn

beg=4.3
end=$( echo "$beg + 10" | bc -l )
ofs=$(ffprobe -read_intervals ${beg}%${end} -skip_frame nokey -select_streams v:0 -show_entries frame=pts_time -of default=nw=1:nk=1 "$f" -v 16 | head -n 2 | tail -n 1)
echo "---> convert from $beg to $ofs"
ffmpeg -noautorotate -ss $beg -to $ofs -i "$f" -c:v $vid -video_track_timescale $tbn -an "$t" -y -hide_banner

echo "file '$t'
file '$f'
inpoint $ofs" > 1.txt
ffmpeg -f concat -safe 0 -i 1.txt -ss $beg -i "$f" -map 0:v:0 -map 1:a:0 -c copy "$o" -y -hide_banner
mpv --no-config --keep-open "$o"

this ↑ variant doesn't work sometimes with mp4, so you can try variant with using temporary mkv segments ↓

#!/bin/bash
cd /tmp
# f="/mnt/public/upload/test/tg/2024-07-20_10꞉11꞉34.MOV"
f="/mnt/public/upload/test/tg/2024-07-19_13꞉39꞉18.mp4"
t="tmp.mkv"
o="output.mp4"
beg=4.3
ffmpeg -i "$f" -c copy -an -f segment -segment_times $beg -reset_timestamps 1 tmp_%d.mkv -hide_banner -y
echo "---> convert tmp_0.mkv from $beg"
vid=$(ffprobe -v 0 -select_streams v:0 -show_entries stream=codec_name -of csv=p=0 "$f")
ffmpeg -noautorotate -ss $beg -i "tmp_0.mkv" -c:v $vid "$t" -y -hide_banner
echo "file '$t'
file 'tmp_1.mkv'
" > 1.txt
ffmpeg -f concat -i 1.txt -ss $beg -i "$f" -map 0:v:0 -map 1:a:0 -c copy "$o" -y -hide_banner
mpv --no-config --keep-open "$o"
1
  • Your scripting skill is awesome! Why doesn't ffmpeg implement this strategy by default? What is the drawback?
    – Gqqnbig
    Commented Jul 20 at 7:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.