All pastes #1078556 Raw Edit

someone

public text v1 · immutable
#1078556 ·published 2008-07-21 17:31 UTC
rendered paste body
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; Index: contrib/Jamfile===================================================================--- contrib/Jamfile	(revision 1573)+++ contrib/Jamfile	(working copy)@@ -387,6 +387,7 @@     cd `dirname $(>)` && CONTRIB=`pwd` && rm -rf libtheora &&     (gzip -dc libtheora.tar.gz | tar xf - ) && cd libtheora &&     ./configure --prefix=$CONTRIB --with-ogg=$CONTRIB --with-vorbis=$CONTRIB --cache-file=$CONTRIB/config.cache --disable-shared \+            --disable-asm \             --disable-oggtest --disable-vorbistest --disable-sdltest --disable-examples &&     $(MAKE) && $(MAKE) install &&     $(STRIP) $CONTRIB/lib/libtheora.a