diff options
author | jbrjake <[email protected]> | 2007-04-16 16:58:57 +0000 |
---|---|---|
committer | jbrjake <[email protected]> | 2007-04-16 16:58:57 +0000 |
commit | 1b38e1511ba75646540f6d2b90b21713614de392 (patch) | |
tree | d82a8a528f2c1d6201167d26e5615b5a23b0d145 /libhb/muxmp4.c | |
parent | a715de4c2ff593e121fbfa394409eff4e493415b (diff) |
Much better B-frame muxing frame-reordering. This will preserve the sps/pps info, properly offset the first frame, and flush any remaining frames at the end of the encode.
Patch by: Nyx
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@513 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/muxmp4.c')
-rw-r--r-- | libhb/muxmp4.c | 57 |
1 files changed, 30 insertions, 27 deletions
diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index 8a1ee6b2d..e37da3b24 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -67,26 +67,13 @@ static int MP4Init( hb_mux_object_t * m ) /* Stolen from mp4creator */ MP4SetVideoProfileLevel( m->file, 0x7F ); - if (job->areBframes >= 1) - { - hb_log("muxmp4: Adjusting duration for B-frames"); - mux_data->track = MP4AddH264VideoTrack( m->file, job->arate, - MP4_INVALID_DURATION+1, job->width, job->height, - job->config.h264.sps[1], /* AVCProfileIndication */ - job->config.h264.sps[2], /* profile_compat */ - job->config.h264.sps[3], /* AVCLevelIndication */ - 3 ); /* 4 bytes length before each NAL unit */ - } - else - { - hb_log("muxmp4: Using default duration as there are no B-frames"); mux_data->track = MP4AddH264VideoTrack( m->file, job->arate, MP4_INVALID_DURATION, job->width, job->height, job->config.h264.sps[1], /* AVCProfileIndication */ job->config.h264.sps[2], /* profile_compat */ job->config.h264.sps[3], /* AVCLevelIndication */ 3 ); /* 4 bytes length before each NAL unit */ - } + MP4AddH264SequenceParameterSet( m->file, mux_data->track, job->config.h264.sps, job->config.h264.sps_length ); @@ -241,24 +228,13 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, duration = MP4_INVALID_DURATION; } - /* 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) && (job->vcodec == HB_VCODEC_X264)) - { - 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) && (job->vcodec == HB_VCODEC_X264)) { - initDelay += duration * job->areBframes; + initDelay = buf->renderOffset; thisSample++; } @@ -269,7 +245,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, 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) || (job->vcodec != HB_VCODEC_X264)) ? 0 : ( initDelay + ((buf->encodedPTS - buf->start) * job->arate / 90000)), + duration, ((mux_data->track != 1) || (job->areBframes==0) || (job->vcodec != HB_VCODEC_X264)) ? 0 : ( buf->renderOffset * job->arate / 90000), (buf->key == 1) ); return 0; @@ -282,6 +258,33 @@ static int MP4End( hb_mux_object_t * m ) char filename[1024]; memset( filename, 0, 1024 ); #endif + /* Walk the entire video sample table and find the minumum ctts value. */ + { + MP4SampleId count = MP4GetTrackNumberOfSamples( m->file, 1); + MP4SampleId i; + MP4Duration renderingOffset = 2000000000, tmp; + + // Find the smallest rendering offset + for(i = 1; i <= count; i++) + { + tmp = MP4GetSampleRenderingOffset(m->file, 1, i); + if(tmp < renderingOffset) + renderingOffset = tmp; + } + + // Adjust all ctts values down by renderingOffset + for(i = 1; i <= count; i++) + { + MP4SetSampleRenderingOffset(m->file,1,i, + MP4GetSampleRenderingOffset(m->file,1,i) - renderingOffset); + } + + // Insert track edit to get A/V back in sync. The edit amount is + // the rendering offset of the first sample. + MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, MP4GetSampleRenderingOffset(m->file,1,1), + MP4GetTrackDuration(m->file, 1), 0); + } + MP4Close( m->file ); #if 0 |