summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libhb/encx264.c49
-rw-r--r--libhb/internal.h3
-rw-r--r--libhb/muxmp4.c38
3 files changed, 82 insertions, 8 deletions
diff --git a/libhb/encx264.c b/libhb/encx264.c
index 69739635b..747bae9f2 100644
--- a/libhb/encx264.c
+++ b/libhb/encx264.c
@@ -121,7 +121,16 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
}
}
- /* Here's where the strings are passed to libx264 for parsing. */
+ /* Note b-pyramid here, so the initial delay can be doubled */
+ if (!(strcmp(name, "b-pyramid")))
+ {
+ if (atoi(value) > 0)
+ {
+ job->areBframes = 2;
+ }
+ }
+
+ /* Here's where the strings are passed to libx264 for parsing. */
ret = x264_param_parse(&param, name, value);
/* Let x264 sanity check the options for us*/
@@ -240,6 +249,9 @@ int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
pv->pic_in.i_type = X264_TYPE_AUTO;
pv->pic_in.i_qpplus1 = 0;
+ /* Feed the input DTS to x264 so it can figure out proper output PTS */
+ pv->pic_in.i_pts = in->start;
+
x264_encoder_encode( pv->x264, &nal, &i_nal,
&pv->pic_in, &pv->pic_out );
@@ -285,10 +297,37 @@ int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
buf->data[buf->size+1] = ( ( size - 4 ) >> 16 ) & 0xFF;
buf->data[buf->size+2] = ( ( size - 4 ) >> 8 ) & 0xFF;
buf->data[buf->size+3] = ( ( size - 4 ) >> 0 ) & 0xFF;
- if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST )
- {
- buf->key = 1;
- }
+
+ /* For IDR (key frames), buf->key = 1,
+ and the same for regular I-frames. */
+ if( (pv->pic_out.i_type == X264_TYPE_IDR) || (pv->pic_out.i_type == X264_TYPE_I) )
+ {
+ buf->key = 1;
+ }
+ /* For B-frames, buf->key = 2 */
+ else if( (pv->pic_out.i_type == X264_TYPE_B) )
+ {
+ buf->key = 2;
+ }
+ /* This is for b-pyramid, which has reference b-frames
+ However, it doesn't seem to ever be used...
+ They just show up as buf->key == 2 like
+ regular b-frames. */
+ else if( (pv->pic_out.i_type == X264_TYPE_BREF) )
+ {
+ buf->key = 3;
+ }
+ /* For P-frames, buf->key = 0 */
+ else
+ {
+ buf->key = 0;
+ }
+
+ /* Store the output presentation time stamp
+ from x264 for use by muxmp4 in off-setting
+ b-frames with the CTTS atom. */
+ buf->encodedPTS = pv->pic_out.i_pts;
+
buf->size += size;
}
}
diff --git a/libhb/internal.h b/libhb/internal.h
index fb5731881..577ad3032 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -39,6 +39,9 @@ struct hb_buffer_s
int64_t stop;
int key;
+ /* Holds the output PTS from x264, for use by b-frame offsets in muxmp4.c */
+ int64_t encodedPTS;
+
int x;
int y;
int width;
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;
}