summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjbrjake <[email protected]>2007-12-28 19:48:37 +0000
committerjbrjake <[email protected]>2007-12-28 19:48:37 +0000
commit568f0b0c21a4b80c0ba7951237310ca31ea3e93e (patch)
tree0f1ddf8f50f3c9600effc922e7a2039484db925a
parent9f682a8b9f0b92bc9180024e88ea356d8813d203 (diff)
Better b-frame muxing. Instead of using an arbitrarily long offset and then later walking the file to find the smallest one, now x264 uses the smallest delay it can from the start. This significantly cuts down muxing time.
As a side effect, it also makes fixing chapter markers + b-frames easy, so that's included too in muxmp4 (thanks, van!). git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1152 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--libhb/encx264.c29
-rw-r--r--libhb/muxmkv.c4
-rw-r--r--libhb/muxmp4.c52
3 files changed, 46 insertions, 39 deletions
diff --git a/libhb/encx264.c b/libhb/encx264.c
index b7e08b8cc..acdb08173 100644
--- a/libhb/encx264.c
+++ b/libhb/encx264.c
@@ -35,6 +35,7 @@ struct hb_work_private_s
// Internal queue of DTS start/stop values.
int64_t dts_start[DTS_BUFFER_SIZE];
int64_t dts_stop[DTS_BUFFER_SIZE];
+ int64_t init_delay;
int64_t dts_write_index;
int64_t dts_read_index;
@@ -250,6 +251,32 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
pv->dts_read_index = 0;
pv->next_chap = 0;
+ if (job->areBframes)
+ {
+ /* Basic initDelay value is the clockrate divided by the FPS
+ -- the length of one frame in clockticks. */
+ pv->init_delay = (float)90000 / (float)((float)job->vrate / (float)job->vrate_base);
+
+ /* 23.976-length frames are 3753.75 ticks long. That means 25%
+ will come out as 3753, 75% will be 3754. The delay has to be
+ the longest possible frame duration, 3754. However, 3753.75
+ gets truncated to 3753, so if that's what it is, ++ it. */
+ if (pv->init_delay == 3753)
+ pv->init_delay++;
+
+ /* For VFR, libhb sees the FPS as 29.97, but the longest frames
+ will use the duration of frames running at 23.976fps instead.. */
+ if (job->vfr)
+ {
+ pv->init_delay = 3754;
+ }
+
+ /* The delay is 2 frames for regular b-frames, 3 for b-pyramid.
+ Since job->areBframes is 1 for b-frames and 2 for b-pyramid,
+ add one to it and use it as a multiplier. */
+ pv->init_delay *= ( job->areBframes + 1);
+ }
+
return 0;
}
@@ -447,7 +474,7 @@ int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
value is pretty much guaranteed to be positive. The
muxing code will minimize the renderOffset at the end. */
- buf->renderOffset = pic_out.i_pts - dts_start + 1000000;
+ buf->renderOffset = pic_out.i_pts - dts_start + pv->init_delay;
/* Send out the next dts values */
buf->start = dts_start;
diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c
index 746b8b21a..1f5d4ae48 100644
--- a/libhb/muxmkv.c
+++ b/libhb/muxmkv.c
@@ -224,9 +224,9 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
if (mux_data == job->mux_data)
{
/* Video */
- if ((job->vcodec == HB_VCODEC_X264) && (buf->frametype & HB_FRAME_REF))
+ if ((job->vcodec == HB_VCODEC_X264) && (job->areBframes))
{
- timecode = (buf->start + (buf->renderOffset - 1000000)) * TIMECODE_SCALE;
+ timecode = (buf->start + (buf->renderOffset)) * TIMECODE_SCALE;
}
else
{
diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c
index 13e2247a1..157ce2351 100644
--- a/libhb/muxmp4.c
+++ b/libhb/muxmp4.c
@@ -11,10 +11,6 @@
void AddIPodUUID(MP4FileHandle, MP4TrackId);
-/* B-frame muxing variables */
-MP4SampleId thisSample = 0;
-uint64_t initDelay;
-
struct hb_mux_object_s
{
HB_MUX_COMMON;
@@ -375,7 +371,21 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
(This is because of how durations for text tracks work in QT) */
if( job->chapter_markers && buf->new_chap )
{
- struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, (m->sum_dur - m->chapter_duration) );
+ struct hb_text_sample_s *sample;
+
+ /* If this is an x264 encode with bframes the IDR frame we're
+ trying to mark will be displayed offset by its renderOffset
+ so we need to offset the chapter by the same amount.
+ MP4 render offsets don't seem to work for text tracks so
+ we have to fudge the duration instead. */
+ duration = m->sum_dur - m->chapter_duration;
+
+ if ( job->areBframes )
+ {
+ duration += buf->renderOffset * job->arate / 90000;
+ }
+
+ sample = MP4GenerateChapterSample( m, duration );
if( !MP4WriteSample(m->file,
m->chapter_track,
@@ -389,7 +399,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
}
free(sample);
m->current_chapter++;
- m->chapter_duration = m->sum_dur;
+ m->chapter_duration = duration;
}
/* Video */
@@ -412,16 +422,6 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
duration = MP4_INVALID_DURATION;
}
- /* 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->frametype & HB_FRAME_KEY) && (job->vcodec == HB_VCODEC_X264))
- {
- initDelay = buf->renderOffset;
- 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.
@@ -468,27 +468,7 @@ static int MP4End( hb_mux_object_t * m )
}
if (job->areBframes)
- /* 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),