OSDN Git Service

Fix a hang in sync
[handbrake-jp/handbrake-jp-git.git] / libhb / muxcommon.c
index 43b9710..f47b442 100644 (file)
@@ -6,6 +6,8 @@
 
 #include "hb.h"
 
+#define MAX_BUFFERING (1024*1024*50)
+
 struct hb_mux_object_s
 {
     HB_MUX_COMMON;
@@ -25,6 +27,7 @@ typedef struct
     uint64_t        frames;
     uint64_t        bytes;
     mux_fifo_t      mf;
+    int             buffered_size;
 } hb_track_t;
 
 typedef struct
@@ -103,10 +106,24 @@ static void add_mux_track( hb_mux_t *mux, hb_mux_data_t *mux_data,
     mux->allRdy |= is_continuous << t;
 }
 
-static void mf_push( hb_track_t *track, hb_buffer_t *buf )
+static int mf_full( hb_track_t * track )
 {
+    if ( track->buffered_size > MAX_BUFFERING )
+        return 1;
+
+    return 0;
+}
+
+static void mf_push( hb_mux_t * mux, int tk, hb_buffer_t *buf )
+{
+    hb_track_t * track = mux->track[tk];
     uint32_t mask = track->mf.flen - 1;
     uint32_t in = track->mf.in;
+
+    if ( track->buffered_size > MAX_BUFFERING )
+    {
+        mux->rdy = mux->allRdy;
+    }
     if ( ( ( in + 1 ) & mask ) == ( track->mf.out & mask ) )
     {
         // fifo is full - expand it to double the current size.
@@ -135,6 +152,7 @@ static void mf_push( hb_track_t *track, hb_buffer_t *buf )
     }
     track->mf.fifo[in & mask] = buf;
     track->mf.in = in + 1;
+    track->buffered_size += buf->alloc;
 }
 
 static hb_buffer_t *mf_pull( hb_track_t *track )
@@ -145,6 +163,8 @@ static hb_buffer_t *mf_pull( hb_track_t *track )
         // the fifo isn't empty
         b = track->mf.fifo[track->mf.out & (track->mf.flen - 1)];
         ++track->mf.out;
+
+        track->buffered_size -= b->alloc;
     }
     return b;
 }
@@ -157,13 +177,11 @@ static hb_buffer_t *mf_peek( hb_track_t *track )
 
 static void MoveToInternalFifos( int tk, hb_mux_t *mux, hb_buffer_t * buf )
 {
-    hb_track_t *track = mux->track[tk];
-
     // move all the buffers on the track's fifo to our internal
     // fifo so that (a) we don't deadlock in the reader and
     // (b) we can control how data from multiple tracks is
     // interleaved in the output file.
-    mf_push( track, buf );
+    mf_push( mux, tk, buf );
     if ( buf->stop >= mux->pts )
     {
         // buffer is past our next interleave point so
@@ -178,9 +196,10 @@ static void OutputTrackChunk( hb_mux_t *mux, hb_track_t *track, hb_mux_object_t
 
     while ( ( buf = mf_peek( track ) ) != NULL && buf->start < mux->pts )
     {
-        m->mux( m, track->mux_data, mf_pull( track ) );
+        buf = mf_pull( track );
         track->frames += 1;
         track->bytes  += buf->size;
+        m->mux( m, track->mux_data, buf );
     }
 }
 
@@ -225,14 +244,24 @@ static int muxWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
         return HB_WORK_OK;
     }
 
+    int more = mux->rdy;
     // all tracks have at least 'interleave' ticks of data. Output
     // all that we can in 'interleave' size chunks.
-    while ( ( mux->rdy & mux->allRdy ) == mux->allRdy )
+    while ( (( mux->rdy & mux->allRdy ) == mux->allRdy && more) ||
+            ( mux->eof == mux->allEof ) ) 
     {
+        more = 0;
         for ( i = 0; i < mux->ntracks; ++i )
         {
             track = mux->track[i];
             OutputTrackChunk( mux, track, mux->m );
+            if ( mf_full( track ) )
+            {
+                // If the track's fifo is still full, advance
+                // the currint interleave point and try again.
+                mux->rdy = mux->allRdy;
+                break;
+            }
 
             // if the track is at eof or still has data that's past
             // our next interleave point then leave it marked as rdy.
@@ -244,6 +273,10 @@ static int muxWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
             {
                 mux->rdy &=~ ( 1 << i );
             }
+            if ( track->mf.out != track->mf.in )
+            {
+                more |= ( 1 << i );
+            }
         }
 
         // if all the tracks are at eof we're just purging their
@@ -281,6 +314,19 @@ void muxClose( hb_work_object_t * w )
     hb_lock( mux->mutex );
     if ( --mux->ref == 0 )
     {
+        // Update state before closing muxer.  Closing the muxer
+        // may initiate optimization which can take a while and
+        // we want the muxing state to be visible while this is
+        // happening.
+        if( job->pass == 0 || job->pass == 2 )
+        {
+            /* Update the UI */
+            hb_state_t state;
+            state.state = HB_STATE_MUXING;
+            state.param.muxing.progress = 0;
+            hb_set_state( job->h, &state );
+        }
+
         if( mux->m )
         {
             mux->m->end( mux->m );
@@ -293,12 +339,6 @@ void muxClose( hb_work_object_t * w )
             struct stat sb;
             uint64_t bytes_total, frames_total;
 
-            /* Update the UI */
-            hb_state_t state;
-            state.state = HB_STATE_MUXING;
-            state.param.muxing.progress = 0;
-            hb_set_state( job->h, &state );
-
             if( !stat( job->file, &sb ) )
             {
                 hb_deep_log( 2, "mux: file size, %"PRId64" bytes", (uint64_t) sb.st_size );
@@ -333,7 +373,12 @@ void muxClose( hb_work_object_t * w )
     
         for( i = 0; i < mux->ntracks; ++i )
         {
+            hb_buffer_t * b;
             track = mux->track[i];
+            while ( (b = mf_pull( track )) != NULL )
+            {
+                hb_buffer_close( &b );
+            }
             if( track->mux_data )
             {
                 free( track->mux_data );
@@ -377,6 +422,10 @@ static void mux_loop( void * _w )
         }
 
         w->status = w->work( w, &buf_in, NULL );
+        if( buf_in )
+        {
+            hb_buffer_close( &buf_in );
+        }
     }
 }
 
@@ -402,16 +451,8 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job )
         switch( job->mux )
         {
         case HB_MUX_MP4:
-        case HB_MUX_PSP:
-        case HB_MUX_IPOD:
             mux->m = hb_mux_mp4_init( job );
             break;
-        case HB_MUX_AVI:
-            mux->m = hb_mux_avi_init( job );
-            break;
-        case HB_MUX_OGM:
-            mux->m = hb_mux_ogm_init( job );
-            break;
         case HB_MUX_MKV:
             mux->m = hb_mux_mkv_init( job );
             break;
@@ -437,8 +478,7 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job )
     muxer->private_data->track = mux->ntracks;
     muxer->fifo_in = job->fifo_mpeg4;
     add_mux_track( mux, job->mux_data, 1 );
-    muxer->done = &job->done;
-    muxer->thread = hb_thread_init( muxer->name, mux_loop, muxer, HB_NORMAL_PRIORITY );
+    muxer->done = &muxer->private_data->mux->done;
 
     for( i = 0; i < hb_list_count( title->list_audio ); i++ )
     {