Index: libhb/reader.c===================================================================--- libhb/reader.c (revision 1573)+++ libhb/reader.c (working copy)@@ -69,7 +69,7 @@ while( !*r->die && !r->job->done && hb_fifo_is_full( fifo ) ) { /*- * Loop until the incoming fifo is reaqdy to receive+ * Loop until the incoming fifo is ready to receive * this buffer. */ hb_snooze( 50 );@@ -326,9 +326,17 @@ } }- /* send an empty buffer upstream to signal we're done */- hb_fifo_push( r->job->fifo_mpeg2, hb_buffer_init(0) );+ /* send empty buffers upstream to video & audio decoders to signal we're done */+ push_buf( r, r->job->fifo_mpeg2, hb_buffer_init(0) );+ hb_audio_t *audio;+ for( n = 0;+ ( audio = hb_list_item( r->job->title->list_audio, n ) ) != NULL;+ ++n )+ {+ push_buf( r, audio->priv.fifo_in, hb_buffer_init(0) );+ }+ hb_list_empty( &list ); hb_buffer_close( &ps ); if (r->dvd)Index: libhb/deca52.c===================================================================--- libhb/deca52.c (revision 1573)+++ libhb/deca52.c (working copy)@@ -144,11 +144,16 @@ hb_work_private_t * pv = w->private_data; hb_buffer_t * buf;- if( buf_in && *buf_in )+ if ( (*buf_in)->size <= 0 ) {- pv->sequence = (*buf_in)->sequence;+ /* EOF on input stream - send it downstream & say that we're done */+ *buf_out = *buf_in;+ *buf_in = NULL;+ return HB_WORK_DONE; }+ pv->sequence = (*buf_in)->sequence;+ hb_list_add( pv->list, *buf_in ); *buf_in = NULL;Index: libhb/enclame.c===================================================================--- libhb/enclame.c (revision 1573)+++ libhb/enclame.c (working copy)@@ -140,6 +140,14 @@ hb_work_private_t * pv = w->private_data; hb_buffer_t * buf;+ if ( (*buf_in)->size <= 0 )+ {+ /* EOF on input - send it downstream & say we're done */+ *buf_out = *buf_in;+ *buf_in = NULL;+ return HB_WORK_DONE;+ }+ hb_list_add( pv->list, *buf_in ); *buf_in = NULL;Index: libhb/decsub.c===================================================================--- libhb/decsub.c (revision 1573)+++ libhb/decsub.c (working copy)@@ -51,9 +51,16 @@ { hb_work_private_t * pv = w->private_data; hb_buffer_t * in = *buf_in;- int size_sub, size_rle;+ if ( in->size <= 0 )+ {+ /* EOF on input stream - send it downstream & say that we're done */+ *buf_out = in;+ *buf_in = NULL;+ return HB_WORK_DONE;+ }+ pv->stream_id = in->id; size_sub = ( in->data[0] << 8 ) | in->data[1];Index: libhb/encx264.c===================================================================--- libhb/encx264.c (revision 1573)+++ libhb/encx264.c (working copy)@@ -30,16 +30,16 @@ * to x264_encoder_encode. Since frames are uniquely identified by their * timestamp, we use some bits of the timestamp as an index. The LSB is * chosen so that two successive frames will have different values in the- * bits over any plausible range of frame rates. (Starting with bit 9 allows- * any frame rate slower than 175fps.) The MSB determines the size of the array.+ * bits over any plausible range of frame rates. (Starting with bit 8 allows+ * any frame rate slower than 352fps.) The MSB determines the size of the array. * It is chosen so that two frames can't use the same slot during the * encoder's max frame delay (set by the standard as 16 frames) and so * that, up to some minimum frame rate, frames are guaranteed to map to- * different slots. (An MSB of 16 which is 2^(16-9+1) = 256 slots guarantees- * no collisions down to a rate of 1.4 fps).+ * different slots. (An MSB of 17 which is 2^(17-8+1) = 1024 slots guarantees+ * no collisions down to a rate of .7 fps). */-#define FRAME_INFO_MAX2 (9) // 2^9 = 512; 90000/512 = 175 frames/sec-#define FRAME_INFO_MIN2 (16) // 2^16 = 65536; 90000/65536 = 1.4 frames/sec+#define FRAME_INFO_MAX2 (8) // 2^8 = 256; 90000/256 = 352 frames/sec+#define FRAME_INFO_MIN2 (17) // 2^17 = 128K; 90000/131072 = 1.4 frames/sec #define FRAME_INFO_SIZE (1 << (FRAME_INFO_MIN2 - FRAME_INFO_MAX2 + 1)) #define FRAME_INFO_MASK (FRAME_INFO_SIZE - 1)@@ -377,228 +377,311 @@ return pv->frame_info[i].duration; }-int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,- hb_buffer_t ** buf_out )+static hb_buffer_t *nal_encode( hb_work_object_t *w, x264_picture_t *pic_out,+ int i_nal, x264_nal_t *nal ) {- hb_work_private_t * pv = w->private_data;- hb_job_t * job = pv->job;- hb_buffer_t * in = *buf_in, * buf;- x264_picture_t pic_out;- int i_nal;- x264_nal_t * nal;- int i;+ hb_buffer_t *buf = NULL;+ hb_work_private_t *pv = w->private_data;+ hb_job_t *job = pv->job;- if( in->data )+ /* Get next DTS value to use */+ int64_t dts_start = pv->dts_next;++ /* compute the stop time based on the original frame's duration */+ int64_t dts_stop = dts_start + get_frame_duration( pv, pic_out->i_pts );+ pv->dts_next = dts_stop;++ /* Should be way too large */+ buf = hb_buffer_init( 3 * job->width * job->height / 2 );+ buf->size = 0;+ buf->frametype = 0;+ buf->start = dts_start;+ buf->stop = dts_stop;++ /* Store the output presentation time stamp from x264 for use by muxmp4+ in off-setting b-frames with the CTTS atom. */+ buf->renderOffset = pic_out->i_pts - dts_start + pv->init_delay;+ if ( buf->renderOffset < 0 ) {- /*- * Point x264 at our current buffers Y(UV) data.- */- pv->pic_in.img.plane[0] = in->data;-- if( job->grayscale )+ if ( dts_start - pic_out->i_pts > pv->max_delay ) {- /* XXX x264 has currently no option for grayscale encoding */- memset( pv->pic_in.img.plane[1], 0x80, job->width * job->height / 4 );- memset( pv->pic_in.img.plane[2], 0x80, job->width * job->height / 4 );+ pv->max_delay = dts_start - pic_out->i_pts;+ hb_log( "encx264: init_delay too small: "+ "is %lld need %lld", pv->init_delay,+ pv->max_delay ); }- else+ buf->renderOffset = 0;+ }++ /* Encode all the NALs we were given into buf.+ NOTE: This code assumes one video frame per NAL (but there can+ be other stuff like SPS and/or PPS). If there are multiple+ frames we only get the duration of the first which will+ eventually screw up the muxer & decoder. */+ int i;+ for( i = 0; i < i_nal; i++ )+ {+ int data = buf->alloc - buf->size;+ int size = x264_nal_encode( buf->data + buf->size, &data, 1, &nal[i] );+ if( size < 1 ) {- /*- * Point x264 at our buffers (Y)UV data- */- pv->pic_in.img.plane[1] = in->data + job->width * job->height;- pv->pic_in.img.plane[2] = in->data + 5 * job->width *- job->height / 4;+ continue; }- if( pv->dts_next == -1 )+ if( job->mux & HB_MUX_AVI ) {- /* we don't have a start time yet so use the first frame's- * start. All other frame times will be determined by the- * sum of the prior output frame durations in *DTS* order- * (not by the order they arrive here). This timing change is- * essential for VFR with b-frames but a complete nop otherwise.- */- pv->dts_next = in->start;- }- if( in->new_chap && job->chapter_markers )- {- /* chapters have to start with an IDR frame so request that this- frame be coded as IDR. Since there may be up to 16 frames- currently buffered in the encoder remember the timestamp so- when this frame finally pops out of the encoder we'll mark- its buffer as the start of a chapter. */- pv->pic_in.i_type = X264_TYPE_IDR;- if( pv->next_chap == 0 )+ if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST ) {- pv->next_chap = in->start;- pv->chap_mark = in->new_chap;+ buf->frametype = HB_FRAME_KEY; }- /* don't let 'work_loop' put a chapter mark on the wrong buffer */- in->new_chap = 0;+ buf->size += size;+ continue; }- else++ /* H.264 in .mp4 or .mkv */+ int naltype = buf->data[buf->size+4] & 0x1f;+ if ( naltype == 0x7 || naltype == 0x8 ) {- pv->pic_in.i_type = X264_TYPE_AUTO;+ // Sequence Parameter Set & Program Parameter Set go in the+ // mp4 header so skip them here+ continue; }- pv->pic_in.i_qpplus1 = 0;- /* XXX this is temporary debugging code to check that the upstream- * modules (render & sync) have generated a continuous, self-consistent- * frame stream with the current frame's start time equal to the- * previous frame's stop time.- */- if( pv->last_stop != in->start )+ /* H.264 in mp4 (stolen from mp4creator) */+ buf->data[buf->size+0] = ( ( size - 4 ) >> 24 ) & 0xFF;+ 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;++ /* Decide what type of frame we have. */+ switch( pic_out->i_type ) {- hb_log("encx264 input continuity err: last stop %lld start %lld",- pv->last_stop, in->start);+ case X264_TYPE_IDR:+ buf->frametype = HB_FRAME_IDR;+ /* if we have a chapter marker pending and this+ frame's presentation time stamp is at or after+ the marker's time stamp, use this as the+ chapter start. */+ if( pv->next_chap != 0 && pv->next_chap <= pic_out->i_pts )+ {+ pv->next_chap = 0;+ buf->new_chap = pv->chap_mark;+ }+ break;++ case X264_TYPE_I:+ buf->frametype = HB_FRAME_I;+ break;++ case X264_TYPE_P:+ buf->frametype = HB_FRAME_P;+ break;++ case X264_TYPE_B:+ buf->frametype = HB_FRAME_B;+ break;++ /* This is for b-pyramid, which has reference b-frames+ However, it doesn't seem to ever be used... */+ case X264_TYPE_BREF:+ buf->frametype = HB_FRAME_BREF;+ break;++ // If it isn't the above, what type of frame is it??+ default:+ buf->frametype = 0;+ break; }- pv->last_stop = in->stop;- // Remember info about this frame that we need to pass across- // the x264_encoder_encode call (since it reorders frames).- save_frame_info( pv, in );+ /* Since libx264 doesn't tell us when b-frames are+ themselves reference frames, figure it out on our own. */+ if( (buf->frametype == HB_FRAME_B) &&+ (nal[i].i_ref_idc != NAL_PRIORITY_DISPOSABLE) )+ buf->frametype = HB_FRAME_BREF;- /* Feed the input DTS to x264 so it can figure out proper output PTS */- pv->pic_in.i_pts = in->start;+ buf->size += size;+ }+ // make sure we found at least one video frame+ if ( buf->size <= 0 )+ {+ // no video: back up the output time stamp then free the buf+ pv->dts_next = buf->start;+ hb_buffer_close( &buf );+ }+ return buf;+}- x264_encoder_encode( pv->x264, &nal, &i_nal,- &pv->pic_in, &pic_out );+static hb_buffer_t *x264_encode( hb_work_object_t *w, hb_buffer_t *in )+{+ hb_work_private_t *pv = w->private_data;+ hb_job_t *job = pv->job;++ /* Point x264 at our current buffers Y(UV) data. */+ pv->pic_in.img.plane[0] = in->data;++ if( job->grayscale )+ {+ /* XXX x264 has currently no option for grayscale encoding */+ memset( pv->pic_in.img.plane[1], 0x80, job->width * job->height / 4 );+ memset( pv->pic_in.img.plane[2], 0x80, job->width * job->height / 4 ); } else {- x264_encoder_encode( pv->x264, &nal, &i_nal,- NULL, &pic_out );- /* No more delayed B frames */- if( i_nal == 0 )+ /* Point x264 at our buffers (Y)UV data */+ pv->pic_in.img.plane[1] = in->data + job->width * job->height;+ pv->pic_in.img.plane[2] = in->data + 5 * job->width * job->height / 4;+ }++ if( pv->dts_next == -1 )+ {+ /* we don't have a start time yet so use the first frame's+ * start. All other frame times will be determined by the+ * sum of the prior output frame durations in *DTS* order+ * (not by the order they arrive here). This timing change is+ * essential for VFR with b-frames but a complete nop otherwise.+ */+ pv->dts_next = in->start;+ }+ if( in->new_chap && job->chapter_markers )+ {+ /* chapters have to start with an IDR frame so request that this+ frame be coded as IDR. Since there may be up to 16 frames+ currently buffered in the encoder remember the timestamp so+ when this frame finally pops out of the encoder we'll mark+ its buffer as the start of a chapter. */+ pv->pic_in.i_type = X264_TYPE_IDR;+ if( pv->next_chap == 0 ) {- *buf_out = NULL;- return HB_WORK_DONE;+ pv->next_chap = in->start;+ pv->chap_mark = in->new_chap; }- else- {- /* Since we output at least one more frame, drop another empty- one onto our input fifo. We'll keep doing this automatically- until we stop getting frames out of the encoder. */- hb_fifo_push(w->fifo_in, hb_buffer_init(0));- }+ /* don't let 'work_loop' put a chapter mark on the wrong buffer */+ in->new_chap = 0; }+ else+ {+ pv->pic_in.i_type = X264_TYPE_AUTO;+ }+ pv->pic_in.i_qpplus1 = 0;- if( i_nal )+ /* XXX this is temporary debugging code to check that the upstream+ * modules (render & sync) have generated a continuous, self-consistent+ * frame stream with the current frame's start time equal to the+ * previous frame's stop time.+ */+ if( pv->last_stop != in->start ) {- /* Should be way too large */- buf = hb_buffer_init( 3 * job->width * job->height / 2 );- buf->size = 0;- buf->frametype = 0;+ hb_log("encx264 input continuity err: last stop %lld start %lld",+ pv->last_stop, in->start);+ }+ pv->last_stop = in->stop;- /* Get next DTS value to use */- int64_t dts_start = pv->dts_next;+ // Remember info about this frame that we need to pass across+ // the x264_encoder_encode call (since it reorders frames).+ save_frame_info( pv, in );- /* compute the stop time based on the original frame's duration */- int64_t dts_stop = dts_start + get_frame_duration( pv, pic_out.i_pts );- pv->dts_next = dts_stop;+ /* Feed the input DTS to x264 so it can figure out proper output PTS */+ pv->pic_in.i_pts = in->start;- for( i = 0; i < i_nal; i++ )- {- int size, data;+ x264_picture_t pic_out;+ int i_nal;+ x264_nal_t *nal;- data = buf->alloc - buf->size;- if( ( size = x264_nal_encode( buf->data + buf->size, &data,- 1, &nal[i] ) ) < 1 )- {- continue;- }+ x264_encoder_encode( pv->x264, &nal, &i_nal, &pv->pic_in, &pic_out );+ if ( i_nal > 0 )+ {+ return nal_encode( w, &pic_out, i_nal, nal );+ }+ return NULL;+}- if( job->mux & HB_MUX_AVI )- {- if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST )- {- buf->frametype = HB_FRAME_KEY;- }- buf->size += size;- continue;- }+int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,+ hb_buffer_t ** buf_out )+{+ hb_work_private_t *pv = w->private_data;+ hb_buffer_t *in = *buf_in;- /* H.264 in .mp4 */- switch( buf->data[buf->size+4] & 0x1f )- {- case 0x7:- case 0x8:- /* SPS, PPS */- break;+ if( in->size <= 0 )+ {+ // EOF on input. Flush any frames still in the decoder then+ // send the eof downstream to tell the muxer we're done.+ x264_picture_t pic_out;+ int i_nal;+ x264_nal_t *nal;+ hb_buffer_t *last_buf = NULL;- default:- /* H.264 in mp4 (stolen from mp4creator) */- buf->data[buf->size+0] = ( ( size - 4 ) >> 24 ) & 0xFF;- 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;- switch( pic_out.i_type )- {- /* Decide what type of frame we have. */- case X264_TYPE_IDR:- buf->frametype = HB_FRAME_IDR;- /* if we have a chapter marker pending and this- frame's presentation time stamp is at or after- the marker's time stamp, use this as the- chapter start. */- if( pv->next_chap != 0 && pv->next_chap <= pic_out.i_pts )- {- pv->next_chap = 0;- buf->new_chap = pv->chap_mark;- }- break;- case X264_TYPE_I:- buf->frametype = HB_FRAME_I;- break;- case X264_TYPE_P:- buf->frametype = HB_FRAME_P;- break;- case X264_TYPE_B:- buf->frametype = HB_FRAME_B;- break;- /* This is for b-pyramid, which has reference b-frames- However, it doesn't seem to ever be used... */- case X264_TYPE_BREF:- buf->frametype = HB_FRAME_BREF;- break;- /* If it isn't the above, what type of frame is it?? */- default:- buf->frametype = 0;- }+ while (1)+ {+ x264_encoder_encode( pv->x264, &nal, &i_nal, NULL, &pic_out );+ if ( i_nal <= 0 )+ break;- /* Since libx264 doesn't tell us when b-frames are- themselves reference frames, figure it out on our own. */- if( (buf->frametype == HB_FRAME_B) && (nal[i].i_ref_idc != NAL_PRIORITY_DISPOSABLE) )- buf->frametype = HB_FRAME_BREF;+ hb_buffer_t *buf = nal_encode( w, &pic_out, i_nal, nal );+ if ( last_buf == NULL )+ *buf_out = buf;+ else+ last_buf->next = buf;+ last_buf = buf;+ }+ // Flushed everything - add the eof to the end of the chain.+ if ( last_buf == NULL )+ *buf_out = in;+ else+ last_buf->next = in;- /* Store the output presentation time stamp- from x264 for use by muxmp4 in off-setting- b-frames with the CTTS atom. */- buf->renderOffset = pic_out.i_pts - dts_start + pv->init_delay;- if ( buf->renderOffset < 0 )- {- if ( dts_start - pic_out.i_pts > pv->max_delay )- {- pv->max_delay = dts_start - pic_out.i_pts;- hb_log( "encx264: init_delay too small: "- "is %lld need %lld", pv->init_delay,- pv->max_delay );- }- buf->renderOffset = 0;- }- buf->size += size;- }- }- /* Send out the next dts values */- buf->start = dts_start;- buf->stop = dts_stop;+ *buf_in = NULL;+ return HB_WORK_DONE; }- else- buf = NULL;+ // Not EOF - encode the packet & wrap it in a NAL+ if ( pv->init_delay && in->stop - in->start > pv->init_delay )+ {+ // This frame's duration is larger than the time allotted for b-frame+ // reordering. That means that if it's used as a reference the decoder+ // won't be able to move it early enough to render it in correct+ // sequence & the playback will have odd jumps & twitches. To make+ // sure this doesn't happen we pretend this frame is multiple+ // frames, each with duration <= init_delay. Since each of these+ // new frames contains the same image the visual effect is identical+ // to the original but the resulting stream can now be coded without+ // error. We take advantage of the fact that x264 buffers frame+ // data internally to feed the same image into the encoder multiple+ // times, just changing its start & stop times each time.+ int64_t orig_stop = in->stop;+ int64_t new_stop = in->start;+ hb_buffer_t *last_buf = NULL;- *buf_out = buf;+ // We want to spread the new frames uniformly over the total time+ // so that we don't end up with a very short frame at the end.+ // In the number of pieces calculation we add in init_delay-1 to+ // round up but not add an extra piece if the frame duration is+ // a multiple of init_delay. The final increment of frame_dur is+ // to restore the bits that got truncated by the divide on the+ // previous line. If we don't do this we end up with an extra tiny+ // frame at the end whose duration is npieces-1.+ int64_t frame_dur = orig_stop - new_stop;+ int64_t npieces = ( frame_dur + pv->init_delay - 1 ) / pv->init_delay;+ frame_dur /= npieces;+ ++frame_dur;+ while ( in->start < orig_stop )+ {+ new_stop += frame_dur;+ if ( new_stop > orig_stop )+ new_stop = orig_stop;+ in->stop = new_stop;+ hb_buffer_t *buf = x264_encode( w, in );+ if ( last_buf == NULL )+ *buf_out = buf;+ else+ last_buf->next = buf;+ last_buf = buf;+ in->start = new_stop;+ }+ }+ else+ {+ *buf_out = x264_encode( w, in );+ } return HB_WORK_OK; }Index: libhb/encavcodec.c===================================================================--- libhb/encavcodec.c (revision 1573)+++ libhb/encavcodec.c (working copy)@@ -191,9 +191,11 @@ AVFrame * frame; hb_buffer_t * in = *buf_in, * buf;- if(!in->data)+ if ( in->size <= 0 ) {- *buf_out = NULL;+ /* EOF on input - send it downstream & say we're done */+ *buf_out = in;+ *buf_in = NULL; return HB_WORK_DONE; }Index: libhb/muxmp4.c===================================================================--- libhb/muxmp4.c (revision 1573)+++ libhb/muxmp4.c (working copy)@@ -285,9 +285,6 @@ MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height)); }- /* firstAudioTrack will be used to reference the first audio track when we add a chapter track */- MP4TrackId firstAudioTrack = 0;- /* add the audio tracks */ for( i = 0; i < hb_list_count( title->list_audio ); i++ ) {@@ -344,15 +341,10 @@ /* If we ever upgrade mpeg4ip, the line above should be replaced with the line below.*/ // MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (u_int16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown));- /* store a reference to the first audio track,- so we can use it to feed the chapter text track's sample rate */ if (i == 0) {- firstAudioTrack = mux_data->track;- /* Enable the first audio track */ MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.flags", (TRACK_ENABLED | TRACK_IN_MOVIE)); }- else /* Disable the other audio tracks so QuickTime doesn't play them all at once. */@@ -365,14 +357,17 @@ if (job->chapter_markers) {- /* add a text track for the chapters */- MP4TrackId textTrack;- textTrack = MP4AddChapterTextTrack(m->file, firstAudioTrack);+ /* add a text track for the chapters. We add the 'chap' atom to track+ one which is usually the video track & should never be disabled.+ The Quicktime spec says it doesn't matter which media track the+ chap atom is on but it has to be an enabled track. */+ MP4TrackId textTrack;+ textTrack = MP4AddChapterTextTrack(m->file, 1); m->chapter_track = textTrack; m->chapter_duration = 0; m->current_chapter = job->chapter_start;- }+ } /* Add encoded-by metadata listing version and build date */ char *tool_string;@@ -501,30 +496,21 @@ if( m->job->chapter_markers ) { int64_t duration = m->sum_dur - m->chapter_duration;- if ( duration <= 0 )+ /* The final chapter can have a very short duration - if it's less+ * than a second just skip it. */+ if ( duration >= m->samplerate ) {- /* 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;- }- struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, duration,- m->current_chapter + 1 );-- 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;+ struct hb_text_sample_s *sample = MP4GenerateChapterSample( m, duration,+ m->current_chapter + 1 );+ 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); }- free(sample); } if (job->areBframes)Index: libhb/encxvid.c===================================================================--- libhb/encxvid.c (revision 1573)+++ libhb/encxvid.c (working copy)@@ -149,10 +149,11 @@ xvid_enc_frame_t frame; hb_buffer_t * in = *buf_in, * buf;- /* If this is the last empty frame, we're done */- if(!in->data)+ if ( in->size <= 0 ) {- *buf_out = NULL;+ /* EOF on input - send it downstream & say we're done */+ *buf_out = in;+ *buf_in = NULL; return HB_WORK_DONE; }@@ -160,7 +161,6 @@ buf = hb_buffer_init( 3 * job->width * job->height / 2 ); buf->start = in->start; buf->stop = in->stop;- //buf->chap = in->chap; memset( &frame, 0, sizeof( frame ) );Index: libhb/decdca.c===================================================================--- libhb/decdca.c (revision 1573)+++ libhb/decdca.c (working copy)@@ -113,6 +113,14 @@ hb_work_private_t * pv = w->private_data; hb_buffer_t * buf;+ if ( (*buf_in)->size <= 0 )+ {+ /* EOF on input stream - send it downstream & say that we're done */+ *buf_out = *buf_in;+ *buf_in = NULL;+ return HB_WORK_DONE;+ }+ hb_list_add( pv->list, *buf_in ); *buf_in = NULL;Index: libhb/declpcm.c===================================================================--- libhb/declpcm.c (revision 1573)+++ libhb/declpcm.c (working copy)@@ -133,14 +133,15 @@ hb_buffer_t ** buf_out ) { hb_work_private_t * pv = w->private_data;- hb_buffer_t *in;+ hb_buffer_t *in = *buf_in; hb_buffer_t *buf = NULL;- /* need an input buffer to do anything */- if( ! buf_in || ! ( in = *buf_in ) )+ if ( in->size <= 0 ) {- *buf_out = buf;- return HB_WORK_OK;+ /* EOF on input stream - send it downstream & say that we're done */+ *buf_out = in;+ *buf_in = NULL;+ return HB_WORK_DONE; } pv->sequence = in->sequence;Index: libhb/enctheora.c===================================================================--- libhb/enctheora.c (revision 1573)+++ libhb/enctheora.c (working copy)@@ -122,23 +122,22 @@ hb_buffer_t * in = *buf_in, * buf; yuv_buffer yuv; ogg_packet op;- static int last_p = 0;- memset(&op, 0, sizeof(op));- memset(&yuv, 0, sizeof(yuv));-- /* If this is the last empty frame, we're done */- if(!in->data)+ if ( in->size <= 0 ) {- if (!last_p)- {- last_p++;- goto finish;- }- *buf_out = NULL;+ // EOF on input - send it downstream & say we're done.+ // XXX may need to flush packets via a call to+ // theora_encode_packetout(&pv->theora, 1, &op);+ // but we don't have a timestamp to put on those packets so we+ // drop them for now.+ *buf_out = in;+ *buf_in = NULL; return HB_WORK_DONE; }+ memset(&op, 0, sizeof(op));+ memset(&yuv, 0, sizeof(yuv));+ yuv.y_width = job->width; yuv.y_height = job->height; yuv.y_stride = job->width;@@ -153,8 +152,7 @@ theora_encode_YUVin(&pv->theora, &yuv);-finish:- theora_encode_packetout(&pv->theora, last_p, &op);+ theora_encode_packetout(&pv->theora, 0, &op); buf = hb_buffer_init( op.bytes + sizeof(op) ); memcpy(buf->data, &op, sizeof(op));Index: libhb/sync.c===================================================================--- libhb/sync.c (revision 1573)+++ libhb/sync.c (working copy)@@ -23,7 +23,6 @@ int64_t next_start; /* start time of next output frame */ int64_t next_pts; /* start time of next input frame */- int64_t start_silence; /* if we're inserting silence, the time we started */ int64_t first_drop; /* PTS of first 'went backwards' frame dropped */ int drop_count; /* count of 'time went backwards' drops */@@ -72,7 +71,6 @@ static void InitAudio( hb_work_object_t * w, int i ); static int SyncVideo( hb_work_object_t * w ); static void SyncAudio( hb_work_object_t * w, int i );-static int NeedSilence( hb_work_object_t * w, hb_audio_t *, int i ); static void InsertSilence( hb_work_object_t * w, int i, int64_t d ); static void UpdateState( hb_work_object_t * w );@@ -151,13 +149,6 @@ for( i = 0; i < hb_list_count( title->list_audio ); i++ ) {- if ( pv->sync_audio[i].start_silence )- {- hb_log( "sync: added %d ms of silence to audio %d",- (int)((pv->sync_audio[i].next_pts -- pv->sync_audio[i].start_silence) / 90), i );- }- audio = hb_list_item( title->list_audio, i ); if( audio->config.out.codec == HB_ACODEC_AC3 ) {@@ -727,6 +718,13 @@ while( !hb_fifo_is_full( fifo ) && ( buf = hb_fifo_see( audio->priv.fifo_raw ) ) ) {+ /* if the next buffer is an eof send it downstream */+ if ( buf->size <= 0 )+ {+ buf = hb_fifo_get( audio->priv.fifo_raw );+ hb_fifo_push( fifo, buf );+ return;+ } if ( (int64_t)( buf->start - sync->next_pts ) < 0 ) { // audio time went backwards.@@ -780,45 +778,8 @@ buf = hb_fifo_get( audio->priv.fifo_raw ); OutputAudioFrame( job, audio, buf, sync, fifo, i ); }-- if( NeedSilence( w, audio, i ) )- {- InsertSilence( w, i, (90000 * AC3_SAMPLES_PER_FRAME) /- sync->audio->config.in.samplerate );- } }-static int NeedSilence( hb_work_object_t * w, hb_audio_t * audio, int i )-{- hb_work_private_t * pv = w->private_data;- hb_job_t * job = pv->job;- hb_sync_audio_t * sync = &pv->sync_audio[i];-- if( hb_fifo_size( audio->priv.fifo_in ) ||- hb_fifo_size( audio->priv.fifo_raw ) ||- hb_fifo_size( audio->priv.fifo_sync ) ||- hb_fifo_size( audio->priv.fifo_out ) )- {- /* We have some audio, we are fine */- return 0;- }-- /* No audio left in fifos */-- if( hb_thread_has_exited( job->reader ) )- {- /* We might miss some audio to complete encoding and muxing- the video track */- if ( sync->start_silence == 0 )- {- hb_log("sync: reader has exited, adding silence to audio %d", i);- sync->start_silence = sync->next_pts;- }- return 1;- }- return 0;-}- static void InsertSilence( hb_work_object_t * w, int i, int64_t duration ) { hb_work_private_t * pv = w->private_data;Index: libhb/encfaac.c===================================================================--- libhb/encfaac.c (revision 1573)+++ libhb/encfaac.c (working copy)@@ -16,12 +16,11 @@ unsigned long input_samples; unsigned long output_bytes; uint8_t * buf;-+ uint8_t * obuf; hb_list_t * list; int64_t pts;-+ int64_t framedur; int out_discrete_channels;- }; int encfaacInit( hb_work_object_t *, hb_job_t * );@@ -57,9 +56,12 @@ /* pass the number of channels used into the private work data */ pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);- pv->faac = faacEncOpen( audio->config.out.samplerate, pv->out_discrete_channels, &pv->input_samples,- &pv->output_bytes );+ pv->faac = faacEncOpen( audio->config.out.samplerate, pv->out_discrete_channels,+ &pv->input_samples, &pv->output_bytes ); pv->buf = malloc( pv->input_samples * sizeof( float ) );+ pv->obuf = malloc( pv->output_bytes );+ pv->framedur = 90000LL * pv->input_samples /+ ( audio->config.out.samplerate * pv->out_discrete_channels ); cfg = faacEncGetCurrentConfiguration( pv->faac ); cfg->mpegVersion = MPEG4;@@ -113,7 +115,6 @@ free( bytes ); pv->list = hb_list_init();- pv->pts = -1; return 0; }@@ -128,6 +129,7 @@ hb_work_private_t * pv = w->private_data; faacEncClose( pv->faac ); free( pv->buf );+ free( pv->obuf ); hb_list_empty( &pv->list ); free( pv ); w->private_data = NULL;@@ -141,9 +143,6 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data;- hb_audio_t * audio = w->audio;- hb_buffer_t * buf;- uint64_t pts, pos; if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) {@@ -151,31 +150,64 @@ return NULL; }+ uint64_t pts, pos; hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), &pts, &pos );+ int size = faacEncEncode( pv->faac, (int32_t *)pv->buf, pv->input_samples,+ pv->obuf, pv->output_bytes );- buf = hb_buffer_init( pv->output_bytes );- buf->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate;- buf->stop = buf->start + 90000 * pv->input_samples / audio->config.out.samplerate / pv->out_discrete_channels;- buf->size = faacEncEncode( pv->faac, (int32_t *) pv->buf,- pv->input_samples, buf->data, pv->output_bytes );- buf->frametype = HB_FRAME_AUDIO;+ // AAC needs four frames before it can start encoding so we'll get nothing+ // on the first three calls to the encoder.+ if ( size > 0 )+ {+ hb_buffer_t * buf = hb_buffer_init( size );+ memcpy( buf->data, pv->obuf, size );+ buf->size = size;+ buf->start = pv->pts;+ pv->pts += pv->framedur;+ buf->stop = pv->pts;+ buf->frametype = HB_FRAME_AUDIO;+ return buf;+ }+ return NULL;+}- if( !buf->size )+static hb_buffer_t *Flush( hb_work_object_t *w, hb_buffer_t *bufin )+{+ hb_work_private_t *pv = w->private_data;++ // pad whatever data we have out to four input frames.+ int nbytes = hb_list_bytes( pv->list );+ int pad = pv->input_samples * sizeof(float) * 4 - nbytes;+ if ( pad > 0 ) {- /* Encoding was successful but we got no data. Try to encode- more */- hb_buffer_close( &buf );- return Encode( w );+ hb_buffer_t *tmp = hb_buffer_init( pad );+ memset( tmp->data, 0, pad );+ hb_list_add( pv->list, tmp ); }- else if( buf->size < 0 )++ // There are up to three frames buffered in the encoder plus one+ // in our list buffer so four calls to Encode should get them all.+ hb_buffer_t *bufout = NULL, *buf = NULL;+ while ( hb_list_bytes( pv->list ) >= pv->input_samples * sizeof(float) ) {- hb_log( "faacEncEncode failed" );- hb_buffer_close( &buf );- return NULL;+ hb_buffer_t *b = Encode( w );+ if ( b )+ {+ if ( bufout == NULL )+ {+ bufout = b;+ }+ else+ {+ buf->next = b;+ }+ buf = b;+ } }-- return buf;+ // add the eof marker to the end of our buf chain+ buf->next = bufin;+ return bufout; } /***********************************************************************@@ -189,6 +221,16 @@ hb_work_private_t * pv = w->private_data; hb_buffer_t * buf;+ if ( (*buf_in)->size <= 0 )+ {+ // EOF on input. Finish encoding what we have buffered then send+ // it & the eof downstream.++ *buf_out = Flush( w, *buf_in );+ *buf_in = NULL;+ return HB_WORK_DONE;+ }+ hb_list_add( pv->list, *buf_in ); *buf_in = NULL;Index: libhb/decavcodec.c===================================================================--- libhb/decavcodec.c (revision 1573)+++ libhb/decavcodec.c (working copy)@@ -164,6 +164,14 @@ unsigned char *parser_output_buffer; int parser_output_buffer_len;+ if ( (*buf_in)->size <= 0 )+ {+ /* EOF on input stream - send it downstream & say that we're done */+ *buf_out = *buf_in;+ *buf_in = NULL;+ return HB_WORK_DONE;+ }+ *buf_out = NULL; cur = ( in->start < 0 )? pv->pts_next : in->start;@@ -842,6 +850,14 @@ static int decavcodecaiWork( hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out ) {+ if ( (*buf_in)->size <= 0 )+ {+ /* EOF on input stream - send it downstream & say that we're done */+ *buf_out = *buf_in;+ *buf_in = NULL;+ return HB_WORK_DONE;+ }+ hb_work_private_t *pv = w->private_data; if ( ! pv->context ) {Index: libhb/muxcommon.c===================================================================--- libhb/muxcommon.c (revision 1573)+++ libhb/muxcommon.c (working copy)@@ -24,7 +24,7 @@ hb_mux_data_t * mux_data; uint64_t frames; uint64_t bytes;-+ int eof; } hb_track_t; static hb_track_t * GetTrack( hb_list_t * list, hb_job_t *job )@@ -40,8 +40,8 @@ buf = hb_fifo_see( track2->fifo ); if( !buf ) {- // XXX libmkv uses a very simple minded muxer that will fail if the- // audio & video are out of sync. To keep them in sync we require+ // XXX the libmkv muxer will produce unplayable files if the+ // audio & video are far out of sync. To keep them in sync we require // that *all* fifos have a buffer then we take the oldest. // Unfortunately this means we can hang in a deadlock with the // reader process filling the fifos. With the current libmkv@@ -58,6 +58,14 @@ // fifos don't have data. continue; }+ if ( buf->size <= 0 )+ {+ // EOF - mark this track as done+ buf = hb_fifo_get( track2->fifo );+ hb_buffer_close( &buf );+ track2->eof = 1;+ continue;+ } if( !track || buf->start < pts ) { track = track2;@@ -67,6 +75,22 @@ return track; }+static int AllTracksDone( hb_list_t * list )+{+ hb_track_t * track;+ int i;++ for( i = 0; i < hb_list_count( list ); i++ )+ {+ track = hb_list_item( list, i );+ if ( track->eof == 0 )+ {+ return 0;+ }+ }+ return 1;+}+ static void MuxerFunc( void * _mux ) { hb_mux_t * mux = _mux;@@ -101,34 +125,6 @@ } }- /* Wait for one buffer for each track */- while( !*job->die && !job->done )- {- int ready;-- ready = 1;- if( !hb_fifo_size( job->fifo_mpeg4 ) )- {- ready = 0;- }- for( i = 0; i < hb_list_count( title->list_audio ); i++ )- {- audio = hb_list_item( title->list_audio, i );- if( !hb_fifo_size( audio->priv.fifo_out ) )- {- ready = 0;- break;- }- }-- if( ready )- {- break;- }-- hb_snooze( 50 );- }- /* Create file, write headers */ if( job->pass == 0 || job->pass == 2 ) {@@ -153,10 +149,15 @@ } int thread_sleep_interval = 50;- while( !*job->die && !job->done )+ while( !*job->die ) { if( !( track = GetTrack( list, job ) ) ) {+ if ( AllTracksDone( list ) )+ {+ // all our input fifos have signaled EOF+ break;+ } hb_snooze( thread_sleep_interval ); continue; }Index: libhb/work.c===================================================================--- libhb/work.c (revision 1573)+++ libhb/work.c (working copy)@@ -265,7 +265,7 @@ } hb_log (" + PixelRatio: %d, width:%d, height: %d",job->pixel_ratio,job->width, job->height);- job->fifo_mpeg2 = hb_fifo_init( 2048 );+ job->fifo_mpeg2 = hb_fifo_init( 128 ); job->fifo_raw = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); job->fifo_sync = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); job->fifo_render = hb_fifo_init( FIFO_CPU_MULT * cpu_count );@@ -585,9 +585,9 @@ audio->priv.config.vorbis.language = audio->config.lang.simple; /* set up the audio work structures */- audio->priv.fifo_in = hb_fifo_init( 256 );+ audio->priv.fifo_in = hb_fifo_init( 32 ); audio->priv.fifo_raw = hb_fifo_init( FIFO_CPU_MULT * cpu_count );- audio->priv.fifo_sync = hb_fifo_init( 256 );+ audio->priv.fifo_sync = hb_fifo_init( 32 ); audio->priv.fifo_out = hb_fifo_init( FIFO_CPU_MULT * cpu_count );@@ -638,7 +638,6 @@ job->reader = hb_reader_init( job ); hb_log( " + output: %s", job->file );- job->muxer = hb_muxer_init( job ); job->done = 0;@@ -658,6 +657,10 @@ HB_LOW_PRIORITY ); }+ // The muxer requires track information that's set up by the encoder+ // init routines so we have to init the muxer last.+ job->muxer = hb_muxer_init( job );+ done = 0; w = hb_list_item( job->list_work, 0 ); w->thread_sleep_interval = 50;Index: libhb/encvorbis.c===================================================================--- libhb/encvorbis.c (revision 1573)+++ libhb/encvorbis.c (working copy)@@ -252,6 +252,14 @@ hb_work_private_t * pv = w->private_data; hb_buffer_t * buf;+ if ( (*buf_in)->size <= 0 )+ {+ /* EOF on input - send it downstream & say we're done */+ *buf_out = *buf_in;+ *buf_in = NULL;+ return HB_WORK_DONE;+ }+ hb_list_add( pv->list, *buf_in ); *buf_in = NULL;