}
}
- /* 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(¶m, name, value);
/* Let x264 sanity check the options for us*/
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 );
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;
}
}
void AddIPodUUID(MP4FileHandle, MP4TrackId);
+/* B-frame muxing variables */
+MP4SampleId thisSample = 0;
+uint64_t initDelay;
struct hb_mux_object_s
{
/* 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,
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;
}