From 91948dd02f961c7dad3a855cf7edbf0f860af9a0 Mon Sep 17 00:00:00 2001 From: jbrjake Date: Fri, 30 Mar 2007 00:50:20 +0000 Subject: H.264 B-frame muxing for MP4, including B-pyramids. The latter are QuickTime incompatible. "Most software today is very much like an Egyptian pyramid with millions of bricks piled on top of each other, with no structural integrity, but just done by brute force and thousands of slaves." -- Alan Kay git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@464 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- libhb/muxmp4.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'libhb/muxmp4.c') diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index f06527295..1d599fbb5 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -11,6 +11,9 @@ void AddIPodUUID(MP4FileHandle, MP4TrackId); +/* B-frame muxing variables */ +MP4SampleId thisSample = 0; +uint64_t initDelay; struct hb_mux_object_s { @@ -64,7 +67,7 @@ static int MP4Init( hb_mux_object_t * m ) /* Stolen from mp4creator */ MP4SetVideoProfileLevel( m->file, 0x7F ); - if (job->areBframes == 1) + if (job->areBframes >= 1) { hb_log("muxmp4: Adjusting duration for B-frames"); mux_data->track = MP4AddH264VideoTrack( m->file, job->arate, @@ -238,8 +241,37 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, duration = MP4_INVALID_DURATION; } - MP4WriteSample( m->file, mux_data->track, buf->data, buf->size, - duration, 0, buf->key ); + /* If for some reason the first frame muxmp4 gets isn't a key-frame, + drop frames until we get one. (Yes, very bad. Quick and dirty.) + This is for QuickTime--when it sees a non-IDR frame first, it + displays a white box instead of video until the second GOP. + Also, you've got to save the skipped duration to keep from + throwing off the offset values. */ + if((mux_data->track == 1) && (thisSample == 0) && (buf->key != 1)) + { + initDelay +=duration; + return 0; + } + /* When we do get the first keyframe, use its duration as the + initial delay added to the frame order offset for b-frames. + Because of b-pyramid, double this duration when there are + b-pyramids, as denoted by job->areBframes equalling 2. */ + if ((mux_data->track == 1) && (thisSample == 0) && (buf->key == 1)) + { + initDelay += duration * job->areBframes; + thisSample++; + } + + /* Here's where the sample actually gets muxed. + If it's an audio sample, don't offset the sample's playback. + If it's a video sample and there are no b-frames, ditto. + If there are b-frames, offset by the initDelay plus the + difference between the presentation time stamp x264 gives + and the decoding time stamp from the buffer data. */ + MP4WriteSample( m->file, mux_data->track, buf->data, buf->size, + duration, ((mux_data->track != 1) || (job->areBframes==0)) ? 0 : ( initDelay + ((buf->encodedPTS - buf->start) * job->arate / 90000)), + (buf->key == 1) ); + return 0; } -- cgit v1.2.3