How to force the first frame to be key-frame?

2

1

I want to encode after seeking to a certain position, and i want to make the first frame a key-frame, here the command i used:

ffmpeg -ss 300  -i howimet.mp4 -acodec libfaac -ar 48000 -ab 128k -ac 2  -vcodec libx264 -vf "scale=480:270" -f mpegts -force_key_frames 300 -t 120 howimet2.ts

the -force_key_frames is set to seek position to make a key frame there. I use the following script (from here) to check if the first frame is key-frame

ffprobe -show_frames -v quiet howimet2.ts | awk -F= '   /pict_type=/ { if (index($2, "I")) { i=1; } else { i=0; } } 
  /pkt_pts_time/ { if (i && ($2 >= 0)) print $2; }  
' | head -n 1

The result show the first key-frame is not locate at second 0.

I guess my command is not correct. what am I missing?

jackode

Posted 2013-02-27T04:01:30.517

Reputation: 307

You shouldn't need to do anything to force the encoder to create the first frame as a keyframe. Anything else wouldn't make sense, really. Also note that -force_key_frames should be relative to the input, so 300 doesn't make sense either—it should be 0 if I'm not mistaken. Does the video play alright, or why are you asking? (Put differently, why is it so important, or what is the background of your question?) – slhck – 2013-02-27T06:54:33.183

i got the same result with -force_key_frames 0. The reason i want that be cause I implement a ffmpeg segmenter that will generate HSL segment on the fly. When user seek to a position, segmenter should be able to generate proper segment; the segment will be sent to client's player (ios movie player); by default, player will start play from first key-frame in the received segment. I want player to start playing from the first frame. Hope my explanation makes sense – jackode – 2013-02-27T08:07:04.920

I see. I have to admit I'm not an expert when it comes to streaming, but there's really no reason for an encoder not to use a keyframe as the first frame. If you use -vcodec libx264, FFmpeg will take whatever decoded picture it gets, feed it to x264, and the first thing x264 will do is create a keyframe. You can't start a video with a non-reference frame. If you manually check the output of ffprobe, what does it say about the first frame? – slhck – 2013-02-27T08:13:47.233

the above ffprobe script code said the first kframe is somewhere at second 1.441711. ffprobe -v quiet -print_format json -show_streams howimet2.ts tells me that "start_time": "1.400000", is it the reason? – jackode – 2013-02-28T01:19:11.270

1Yes, then in your case the start PTS (and time) have an offset. I don't know why this happens, but you should be able to just compensate for the offset by subtracting it. – slhck – 2013-02-28T09:19:44.377

I think i got the answer for my question. In fact, the first frame is a key-frame, but the reported timestamp was not 0.0 because of the offset. If you re-compose and put your comments as an answer i will accept it. – jackode – 2013-03-01T08:55:33.577

Answers

5

When encoding video, the first frame has to be a keyframe. It will be the first one fully encoded, and subsequent frames may use it for inter-frame prediction. Also, at the beginning of the coded video sequence, you will have an H.264 access unit that tells the decoder to refresh.

So, regardless of what you're doing: Unless you just copy the bitstream, you're re-encoding the video and your first frame has to be a keyframe.

Now, for whatever reason your stream has an offset in its start time. This means that all the presentation timestamps are also shifted according to this offset. If you inspect the head of the ffprobe -show_frames output, you'll see that frame 0 will indeed be a keyframe, but with a different PTS.

To compensate for this, you can subtract the start time from all PTS.

slhck

Posted 2013-02-27T04:01:30.517

Reputation: 182 472

The first frame doesn't have to be an I-Frame (KeyFrame), it can be a B-Frame (dependent on future frames, one of which is likely to be an I-Frame). – Adisak – 2014-04-24T21:13:30.240

@Adisak That's incorrect. If the first coded frame is not an I-frame, the decoder cannot start to decode because all it has is prediction differences, but no actual signal. A B or P picture always has at least one reference frame that has to be decoded first. – slhck – 2014-04-24T21:57:57.643

0

Set the GOP size with "-g"

Just to demonstrate accuracy, here's 1 second segments

ffmpeg -i  in.mkv -g 30  -hls_time 1 -hls_list_size 0 index.m3u8

Here's what the m3u8 looks like :

    #EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:1.001000,
index0.ts
#EXTINF:1.001000,
index1.ts
#EXTINF:1.001000,
index2.ts
#EXTINF:1.001000,
index3.ts
#EXTINF:1.001000,
index4.ts
#EXTINF:1.001000,
index5.ts
#EXTINF:1.001000,
index6.ts
#EXTINF:1.001000,
index7.ts
#EXTINF:1.001000,
index8.ts
#EXTINF:1.001000,
index9.ts
#EXTINF:1.001000,
index10.ts
#EXTINF:1.001000,
index11.ts
#EXTINF:1.001000,
index12.ts
#EXTINF:1.001000,
index13.ts
#EXTINF:1.001000,
....

Leroy Scandal

Posted 2013-02-27T04:01:30.517

Reputation: 1

0

Like mentioned, the first frame of your video has to be an I-Frame. Your issue comes from not the encoding (or copy if that's your flavor) but from the decoding. Having -ss before the input is inexact so ffmpeg is doing the best it can to get you to about where you wanted. Ffmpeg passed that location and thus tells you a non-zero first timestamp.

I would recommend trying a second -ss after your -i. Along the lines -ss 299 -i input -ss 1.

This says go to about the location you wanted, then decode for 1 second before processing. I am not sure if this will fix your pts issue but hopefully it will move you in the right direction.

To point out, I don't think the force_key_frames command is doing what you think it is. If its doing anything, it's likely just telling it to add a key frame in the output every 300 seconds but that is just a guess. Meaning only the first frame of your output would be a key frame (t=120).

https://ffmpeg.org/ffmpeg.html

dstob

Posted 2013-02-27T04:01:30.517

Reputation: 305