+
+ // if there are b-frames compute the render offset
+ // (we'll need it for both the video frame & the chapter track)
+ if ( m->init_delay )
+ {
+ offset = ( buf->start + m->init_delay ) * m->samplerate / 90000 -
+ m->sum_dur;
+ }
+ /* Add the sample before the new frame.
+ It is important that this be calculated prior to the duration
+ of the new video sample, as we want to sync to right after it.
+ (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;
+
+ // this chapter is postioned by writing out the previous chapter.
+ // the duration of the previous chapter is the duration up to but
+ // not including the current frame minus the duration of all
+ // chapters up to the previous.
+ duration = m->sum_dur - m->chapter_duration + offset;
+ if ( duration <= 0 )
+ {
+ /* The initial & final chapters can have very short durations
+ * (less than the error in our total duration estimate) so
+ * the duration calc above can result in a negative number.
+ * when this happens give the chapter a short duration (1/3
+ * of an ntsc frame time). */
+ duration = 1000 * m->samplerate / 90000;
+ }
+
+ sample = MP4GenerateChapterSample( m, duration, buf->new_chap );
+
+ if( !MP4WriteSample(m->file,
+ m->chapter_track,
+ sample->sample,
+ sample->length,
+ sample->duration,
+ 0, true) )
+ {
+ hb_error("Failed to write to output file, disk full?");
+ *job->die = 1;
+ }
+ free(sample);
+ m->current_chapter = buf->new_chap;
+ m->chapter_duration += duration;
+ }
+
+ // since we're changing the sample rate we need to keep track of
+ // the truncation bias so that the audio and video don't go out
+ // of sync. m->sum_dur_in is the sum of the input durations so far.
+ // m->sum_dur is the sum of the output durations. Their difference
+ // (in output sample rate units) is the accumulated truncation bias.
+ int64_t bias = ( m->sum_dur_in * m->samplerate / 90000 ) - m->sum_dur;
+ int64_t dur_in = buf->stop - buf->start;
+ duration = dur_in * m->samplerate / 90000 + bias;
+ if ( duration <= 0 )
+ {
+ /* We got an illegal mp4/h264 duration. This shouldn't
+ be possible and usually indicates a bug in the upstream code.
+ Complain in the hope that someone will go find the bug but
+ try to fix the error so that the file will still be playable. */
+ hb_log("MP4Mux: illegal duration %lld, bias %lld, start %lld (%lld),"
+ "stop %lld (%lld), sum_dur %lld",
+ duration, bias, buf->start * m->samplerate / 90000, buf->start,
+ buf->stop * m->samplerate / 90000, buf->stop, m->sum_dur );
+ /* we don't know when the next frame starts so we can't pick a
+ valid duration for this one so we pick something "short"
+ (roughly 1/3 of an NTSC frame time) and rely on the bias calc
+ for the next frame to correct things (a duration underestimate
+ just results in a large bias on the next frame). */
+ duration = 1000 * m->samplerate / 90000;
+ }