[FFmpeg-devel] questions on live streaming of h.264 in a FLV container

Raymond Peck rpeck
Wed Sep 3 21:36:12 CEST 2008

Hey there!

We have a system which streams live video which is encoded into an FLV
container using ffmpeg.  Playback is through a Flash player.  The
streaming server ensures that the player gets data which begins on a
keyframe (not necessarily on an IDR frame. . .) by throwing away video
stream data until it sees a keyframe.

I'm trying to get it to work with libx264 instead of the other codec.
When I start the player so that it's listening to an empty pipe, and
then start the video stream, the player plays the x264/FLV video just
fine.  This is very encouraging.

However, when the player comes in in the middle of the steam I get no
video.  I'd love to hear any clues that anyone might have, especially
if they have a similar system running.  :-)

I see in the flvenc.c code that the "extradata", which contains the
SPS and PPS data, is sent only at the start of the output file.  I
understand from an overview of h.264 that "Special NAL unit types are
specified to setup (sic) and change SPS and PPS in-band".  I've tried
various things to inject the extradata before keyframes to try to get
the player to pick up the SPS/PPS.  See below.

So, questions are:

1. It seems that the player would require an IDR frame to start, but I
haven't yet found out how to easily detect an IDR frame.  Does this
seem necessary or can I start on any keyframe?  I believe I'm
currently not outputting B-frames, so perhaps x264 is making every
keyframe an IDR frame?  Or am I getting P-frames which predict from
frames that preceed the previous keyframe?

2. Is it in fact possible to re-inject the SPS/PPS data in a similar
way to how the code surrounding ff_isom_write_avcc() does, and expect
the player to pick it up?  The "in-band" comment above would seem to
indicate so. . .

3. Do I instead need to re-create the header like flv_write_header()
does, when the player connects?  If so, then injecting the extradata
on the keyframes will allow the web server to extract and then reinject
the data as needed. . .

The code that I have now replicates the header code as follows and
calls it before outputting keyframes in flvenc.c.  Note that I've
changed the VIDEODATA.FrameType from 1 (keyframe) to 5 (video
info/command frame).  Before doing this, VLC paused on every keyframe
when playing a static file with this extra data; now it plays

static int flv_write_sps_pps_video_atom(AVFormatContext *s, int
timestamp, int timestamp_ext, int32_t composition_time) {
    ByteIOContext *pb = s->pb;
    AVCodecContext *enc = video_enc;

    if (enc->codec_id == CODEC_ID_AAC || enc->codec_id == CODEC_ID_H264) {
	int data_size;
	int streamid = 0;

	fprintf(stderr, "adding AVCDecoderConfigurationRecord atom with ts
%d, composition_time %d\n", timestamp, composition_time);

	offset_t pos;
	put_byte(pb, enc->codec_type == CODEC_TYPE_VIDEO ?
	put_be24(pb, 0); // size patched later
	put_be24(pb, timestamp); // ts
	put_byte(pb, timestamp_ext); // ts ext
	put_be24(pb, streamid); // streamid
	pos = url_ftell(pb);
	if (enc->codec_id == CODEC_ID_AAC) {
	} else {
// this is what the header code does, but probably isn't what we want here:
//	    put_byte(pb, enc->codec_tag | FLV_FRAME_KEY); // flags
// instead, the FrameType should be "video info/command frame"
	    put_byte(pb, 5); // flags == video info/command frame
	    put_byte(pb, 7); // VIDEODATA CodecID = 7 (avc)
	    put_byte(pb, 0); // AVC sequence header (we hope that this is an
AVCDecoderConfigurationRecord, NOT an NALU tag)
	    put_be24(pb, composition_time); // composition time
	    ff_isom_write_avcc(pb, enc->extradata, enc->extradata_size);
	data_size = url_ftell(pb) - pos;
	url_fseek(pb, -data_size - 10, SEEK_CUR);
	put_be24(pb, data_size);
	url_fseek(pb, data_size + 10 - 3, SEEK_CUR);
	put_be32(pb, data_size + 11); // previous tag size


I'm very new to video encoding and to the ffmpeg internals and h.264,
so any clues are appreciated!


More information about the ffmpeg-devel mailing list