]> granicus.if.org Git - handbrake/commitdiff
Adds an interjob structure to preserve some encode data across jobs within an instanc...
authorjbrjake <jb.rubin@gmail.com>
Thu, 4 Jun 2009 17:52:01 +0000 (17:52 +0000)
committerjbrjake <jb.rubin@gmail.com>
Thu, 4 Jun 2009 17:52:01 +0000 (17:52 +0000)
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2482 b64f7644-9d1e-0410-96f1-a4d463321fa5

libhb/common.c
libhb/encx264.c
libhb/hb.c
libhb/hb.h
libhb/render.c
libhb/sync.c
libhb/work.c

index 350132baea6ed0775d42ca33edad28f14f53efa5..cea4a50646636ba15b692d1c4b14fbcc4ae65a8e 100644 (file)
@@ -9,6 +9,7 @@
 #include <sys/time.h>
 
 #include "common.h"
+#include "hb.h"
 
 /**********************************************************************
  * Global variables
@@ -215,9 +216,21 @@ int hb_calc_bitrate( hb_job_t * job, int size )
     length += 135000;
     length /= 90000;
 
+    if( size == -1 )
+    {
+        hb_interjob_t * interjob = hb_interjob_get( job->h );
+        avail = job->vbitrate * 125 * length;
+        avail += length * interjob->vrate * overhead / interjob->vrate_base;
+    }
+
     /* Video overhead */
     avail -= length * job->vrate * overhead / job->vrate_base;
 
+    if( size == -1 )
+    {
+        goto ret;
+    }
+
     for( i = 0; i < hb_list_count(job->list_audio); i++ )
     {
         /* Audio data */
@@ -266,6 +279,7 @@ int hb_calc_bitrate( hb_job_t * job, int size )
         avail -= length * audio->config.out.samplerate * overhead / samples_per_frame;
     }
 
+ret:
     if( avail < 0 )
     {
         return 0;
index d00479468744627a9ecfa3c1d075434edb798b70..880ca23ed3d92ccf361b25c02ff5515662166abb 100644 (file)
@@ -98,15 +98,28 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
      */
     if (job->vrate_base != 1080000)
     {
-        int fps = job->vrate / job->vrate_base;
-
-        /* adjust +1 when fps has remainder to bump { 23.976, 29.976, 59.94 } to { 24, 30, 60 } */
-        if (job->vrate % job->vrate_base)
-            fps += 1;
+        if (job->pass == 2 && !job->cfr )
+        {
+            /* Even though the framerate might be different due to VFR,
+               we still want the same keyframe intervals as the 1st pass,
+               so the 1st pass stats won't conflict on frame decisions.    */
+            hb_interjob_t * interjob = hb_interjob_get( job->h );
+            param.i_keyint_min     = ( interjob->vrate / interjob->vrate_base ) + 1;
+            param.i_keyint_max = ( 10 * interjob->vrate / interjob->vrate_base ) + 1;
+        }
+        else
+        {
+            int fps = job->vrate / job->vrate_base;
 
-        param.i_keyint_min = fps;
-        param.i_keyint_max = fps * 10;
+            /* adjust +1 when fps has remainder to bump
+               { 23.976, 29.976, 59.94 } to { 24, 30, 60 } */
+            if (job->vrate % job->vrate_base)
+                fps += 1;
 
+            param.i_keyint_min = fps;
+            param.i_keyint_max = fps * 10;
+        }
+        
         hb_log("encx264: keyint-min: %i, keyint-max: %i", param.i_keyint_min, param.i_keyint_max);
     }
 
index aa6679193be787d44b02fbbbe68eb57c085b7ae0..f5caa8cd613532b1cc6996c6bb6ccca21c4bb754 100644 (file)
@@ -38,6 +38,11 @@ struct hb_handle_s
     /* For MacGui active queue
        increments each time the scan thread completes*/
     int            scanCount;
+    
+    /* Stash of persistent data between jobs, for stuff
+       like correcting frame count and framerate estimates
+       on multi-pass encodes where frames get dropped.     */
+    hb_interjob_t * interjob;
 
 };
 
@@ -142,6 +147,8 @@ hb_handle_t * hb_init( int verbose, int update_check )
 
     h->pause_lock = hb_lock_init();
 
+    h->interjob = calloc( sizeof( hb_interjob_t ), 1 );
+
     /* libavcodec */
     hb_avcodec_init();
 
@@ -1475,3 +1482,9 @@ void hb_set_state( hb_handle_t * h, hb_state_t * s )
     hb_unlock( h->state_lock );
     hb_unlock( h->pause_lock );
 }
+
+/* Passes a pointer to persistent data */
+hb_interjob_t * hb_interjob_get( hb_handle_t * h )
+{
+    return h->interjob;
+}
index cc7a7eecc0df4f8016ba775c3e302e2a7c57b7e4..080d9795eeea28daf80df079ecc15d0c5673b1da 100644 (file)
@@ -70,6 +70,19 @@ void          hb_pause( hb_handle_t * );
 void          hb_resume( hb_handle_t * );
 void          hb_stop( hb_handle_t * );
 
+/* Persistent data between jobs. */
+typedef struct hb_interjob_s
+{
+    int last_job;          /* job->sequence_id & 0xFFFFFF */
+    int frame_count;       /* number of frames counted by sync */
+    uint64_t total_time;   /* real length in 90khz (i.e. / 90000 */
+    int render_dropped;    /* frames droped by telecine */
+    int vrate;             /* initial assigned vrate */
+    int vrate_base;        /* initial assigned vrate_base */
+} hb_interjob_t;
+
+hb_interjob_t * hb_interjob_get( hb_handle_t * ); 
+
 /* hb_get_state()
    Should be regularly called by the UI (like 5 or 10 times a second).
    Look at test/test.c to see how to use it. */
index fefec7792629c15df2697aa4747123266f13b3c0..34928d906b3c5aec62f24b859c93c86855af37a4 100644 (file)
@@ -668,6 +668,11 @@ void renderClose( hb_work_object_t * w )
                pv->count_frames, pv->drops, pv->dups );
     }
 
+    hb_interjob_t * interjob = hb_interjob_get( w->private_data->job->h );
+    
+    /* Preserve dropped frame count for more accurate framerates in 2nd passes. */
+    interjob->render_dropped = pv->dropped_frames;
+
     hb_log("render: lost time: %lld (%i frames)", pv->total_lost_time, pv->dropped_frames);
     hb_log("render: gained time: %lld (%i frames) (%lld not accounted for)", pv->total_gained_time, pv->extended_frames, pv->total_lost_time - pv->total_gained_time);
     if (pv->dropped_frames)
index 8ae1b78e84f74a64dde9365ce2ab4bf9780e148d..abcf11141c3300f112f6afb396396636aab13679 100644 (file)
@@ -96,28 +96,37 @@ int syncInit( hb_work_object_t * w, hb_job_t * job )
     pv->job            = job;
     pv->pts_offset     = INT64_MIN;
 
-    /* Calculate how many video frames we are expecting */
-    if (job->pts_to_stop)
+    if( job->pass == 2 )
     {
-        duration = job->pts_to_stop + 90000;
-    }
-    else if( job->frame_to_stop )
-    {
-        /* Set the duration to a rough estimate */
-        duration = ( job->frame_to_stop / ( job->vrate / job->vrate_base ) ) * 90000;
+        /* We already have an accurate frame count from pass 1 */
+        hb_interjob_t * interjob = hb_interjob_get( job->h );
+        pv->count_frames_max = interjob->frame_count;
     }
     else
     {
-        duration = 0;
-        for( i = job->chapter_start; i <= job->chapter_end; i++ )
+        /* Calculate how many video frames we are expecting */
+        if ( job->pts_to_stop )
+        {
+            duration = job->pts_to_stop + 90000;
+        }
+        else if( job->frame_to_stop )
+        {
+            /* Set the duration to a rough estimate */
+            duration = ( job->frame_to_stop / ( job->vrate / job->vrate_base ) ) * 90000;
+        }
+        else
         {
-            chapter   = hb_list_item( title->list_chapter, i - 1 );
-            duration += chapter->duration;
+            duration = 0;
+            for( i = job->chapter_start; i <= job->chapter_end; i++ )
+            {
+                chapter   = hb_list_item( title->list_chapter, i - 1 );
+                duration += chapter->duration;
+            }
+            duration += 90000;
+            /* 1 second safety so we're sure we won't miss anything */
         }
-        duration += 90000;
-        /* 1 second safety so we're sure we won't miss anything */
+        pv->count_frames_max = duration * job->vrate / job->vrate_base / 90000;
     }
-    pv->count_frames_max = duration * job->vrate / job->vrate_base / 90000;
 
     hb_log( "sync: expecting %d video frames", pv->count_frames_max );
     pv->busy |= 1;
@@ -156,6 +165,16 @@ void syncClose( hb_work_object_t * w )
     hb_log( "sync: got %d frames, %d expected",
             pv->count_frames, pv->count_frames_max );
 
+    /* save data for second pass */
+    if( job->pass == 1 )
+    {
+        /* Preserve frame count for better accuracy in pass 2 */
+        hb_interjob_t * interjob = hb_interjob_get( job->h );
+        interjob->frame_count = pv->count_frames;
+        interjob->last_job = job->sequence_id;
+        interjob->total_time = pv->next_start;
+    }
+
     if (pv->drops || pv->dups )
     {
         hb_log( "sync: %d frames dropped, %d duplicated", pv->drops, pv->dups );
index 5be4bdf9f958414f04503779cea8f988adebf099..92f04f483cf3691e3154b038b1187f7679582f01 100644 (file)
@@ -335,6 +335,25 @@ void hb_display_job_info( hb_job_t * job )
     }
 }
 
+/* Corrects framerates when actual duration and frame count numbers are known. */
+void correct_framerate( hb_job_t * job )
+{
+    int real_frames;
+
+    hb_interjob_t * interjob = hb_interjob_get( job->h );
+
+    if( ( job->sequence_id & 0xFFFFFF ) != ( interjob->last_job ) )
+        return; // Interjob information is for a different encode.
+
+    /* Cache the original framerate before altering it. */
+    interjob->vrate = job->vrate;
+    interjob->vrate_base = job->vrate_base;
+
+    real_frames = interjob->frame_count - interjob->render_dropped;
+    job->vrate = job->vrate_base * ( real_frames / ( interjob->total_time / 90000 ) );
+}
+
+
 /**
  * Job initialization rountine.
  * Initializes fifos.
@@ -363,6 +382,11 @@ static void do_job( hb_job_t * job, int cpu_count )
 
     title = job->title;
 
+    if( job->pass == 2 && !job->cfr )
+    {
+        correct_framerate( job );
+    }
+
     job->list_work = hb_list_init();
 
     hb_log( "starting job" );