Public feed #888466

1244 Patched

public diff v1 · immutable
Raw Edit
·published 2008-02-02 03:43 UTC
rendered paste body
Index: libhb/encx264.c===================================================================--- libhb/encx264.c	(revision 1244)+++ libhb/encx264.c	(working copy)@@ -25,6 +25,24 @@  #define DTS_BUFFER_SIZE 32  +/*+ * The frame info struct remembers information about each frame across calls+ * 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.+ * 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).+ */+#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_SIZE (1 << (FRAME_INFO_MIN2 - FRAME_INFO_MAX2 + 1))+#define FRAME_INFO_MASK (FRAME_INFO_SIZE - 1)+ struct hb_work_private_s {     hb_job_t       * job;@@ -32,15 +50,15 @@     x264_picture_t   pic_in;     uint8_t         *x264_allocated_pic; -    // Internal queue of DTS start/stop values.-    int64_t        dts_start[DTS_BUFFER_SIZE];-    int64_t        dts_stop[DTS_BUFFER_SIZE];+    int64_t        dts_next;    // DTS start time value for next output frame+    int64_t        last_stop;   // Debugging - stop time of previous input frame     int64_t        init_delay;--    int64_t        dts_write_index;-    int64_t        dts_read_index;     int64_t        next_chap; +    struct {+        int64_t duration;+    } frame_info[FRAME_INFO_SIZE];+     char             filename[1024]; }; @@ -247,8 +265,7 @@      pv->x264_allocated_pic = pv->pic_in.img.plane[0]; -    pv->dts_write_index = 0;-    pv->dts_read_index = 0;+    pv->dts_next = -1;     pv->next_chap = 0;      if (job->areBframes)@@ -268,7 +285,7 @@            will use the duration of frames running at 23.976fps instead.. */         if (job->vfr)         {-            pv->init_delay = 3754;+            pv->init_delay = 7506;         }             /* The delay is 2 frames for regular b-frames, 3 for b-pyramid.@@ -296,6 +313,22 @@     /* TODO */ } +/*+ * see comments in definition of 'frame_info' in pv struct for description+ * of what these routines are doing.+ */+static void save_frame_info( hb_work_private_t * pv, hb_buffer_t * in )+{+    int i = (in->start >> FRAME_INFO_MAX2) & FRAME_INFO_MASK;+    pv->frame_info[i].duration = in->stop - in->start;+}++static int64_t get_frame_duration( hb_work_private_t * pv, int64_t pts )+{+    int i = (pts >> FRAME_INFO_MAX2) & FRAME_INFO_MASK;+    return pv->frame_info[i].duration;+}+ int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,                   hb_buffer_t ** buf_out ) {@@ -330,6 +363,16 @@                 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@@ -351,11 +394,22 @@         }         pv->pic_in.i_qpplus1 = 0; -        // Remember current PTS value, use as DTS later-        pv->dts_start[pv->dts_write_index & (DTS_BUFFER_SIZE-1)] = in->start;-        pv->dts_stop[pv->dts_write_index & (DTS_BUFFER_SIZE-1)]  = in->stop;-        pv->dts_write_index++;+        /* 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 )+        {+            hb_log("encx264 input continuity err: last stop %lld  start %lld",+                    pv->last_stop, in->start);+        }+        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 );+         /* Feed the input DTS to x264 so it can figure out proper output PTS */         pv->pic_in.i_pts = in->start; @@ -386,17 +440,15 @@         /* Should be way too large */         buf        = hb_buffer_init( 3 * job->width * job->height / 2 );         buf->size  = 0;-        buf->start = in->start;-        buf->stop  = in->stop;         buf->frametype   = 0; -        int64_t dts_start, dts_stop;-         /* Get next DTS value to use */-        dts_start = pv->dts_start[pv->dts_read_index & (DTS_BUFFER_SIZE-1)];-        dts_stop  = pv->dts_stop[pv->dts_read_index & (DTS_BUFFER_SIZE-1)];-        pv->dts_read_index++;+        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;+         for( i = 0; i < i_nal; i++ )         {             int size, data;@@ -469,11 +521,7 @@                      /* Store the output presentation time stamp                        from x264 for use by muxmp4 in off-setting-                       b-frames with the CTTS atom.-                       For now, just add 1000000 to the offset so that the-                       value is pretty much guaranteed to be positive.  The-                       muxing code will minimize the renderOffset at the end. */-+                       b-frames with the CTTS atom. */                     buf->renderOffset = pic_out.i_pts - dts_start + pv->init_delay;                      /* Send out the next dts values */Index: libhb/render.c===================================================================--- libhb/render.c	(revision 1244)+++ libhb/render.c	(working copy)@@ -20,11 +20,13 @@     hb_buffer_t        * buf_scale;     hb_fifo_t          * subtitle_queue;     hb_fifo_t          * delay_queue;-    int                  frames_to_extend;     int                  dropped_frames;     int                  extended_frames;     uint64_t             last_start[4];     uint64_t             last_stop[4];+    uint64_t             lost_time[4];+    uint64_t             total_lost_time;+    uint64_t             total_gained_time; };  int  renderInit( hb_work_object_t *, hb_job_t * );@@ -280,9 +282,22 @@             {                 if( job->vfr )                 {-                    pv->frames_to_extend += 4;+                    /* We need to compensate for the time lost by dropping this frame.+                       Spread its duration out in quarters, because usually dropped frames+                       maintain a 1-out-of-5 pattern and this spreads it out amongst the remaining ones.+                       Store these in the lost_time array, which has 4 slots in it.+                       Because not every frame duration divides evenly by 4, and we can't lose the+                       remainder, we have to go through an awkward process to preserve it in the 4th array index. */+                    uint64_t temp_duration = buf_tmp_out->stop - buf_tmp_out->start;+                    pv->lost_time[0] += (temp_duration / 4);+                    pv->lost_time[1] += (temp_duration / 4);+                    pv->lost_time[2] += (temp_duration / 4);+                    pv->lost_time[3] += ( temp_duration - (temp_duration / 4) - (temp_duration / 4) - (temp_duration / 4) );+                    +                    pv->total_lost_time += temp_duration;                     pv->dropped_frames++;-                    hb_fifo_get( pv->subtitle_queue );+                    +                    hb_fifo_get( pv->subtitle_queue );                                         buf_tmp_in = NULL;                 }                 else@@ -304,8 +319,11 @@             pv->last_start[i] = pv->last_start[i-1];             pv->last_stop[i] = pv->last_stop[i-1];         }-        pv->last_start[0] = in->start;-        pv->last_stop[0] = in->stop;+        +        /* In order to make sure we have continuous time stamps, store+           the current frame's duration as starting when the last one stopped. */+        pv->last_start[0] = pv->last_stop[1];+        pv->last_stop[0] = pv->last_start[0] + (in->stop - in->start);     }          /* Apply subtitles */@@ -385,13 +403,17 @@      if( *buf_out )     {-        if( pv->frames_to_extend )+        /* The current frame exists. That means it hasn't been dropped by a filter.+           Make it accessible as ivtc_buffer so we can edit its duration if needed. */+        ivtc_buffer = *buf_out;++        if( pv->lost_time[3] > 0 )         {             /*-             * A frame's been dropped by VFR detelecine.+             * A frame's been dropped earlier by VFR detelecine.              * Gotta make up the lost time. This will also-             * slow down the video to 23.976fps.-             * The dropped frame ran for 3003 ticks, so+             * slow down the video.+             * The dropped frame's has to be accounted for, so              * divvy it up amongst the 4 frames left behind.              * This is what the delay_queue is for;              * telecined sequences start 2 frames before@@ -399,29 +421,53 @@              * ones you need a 2 frame delay between              * reading input and writing output.              */-            ivtc_buffer = *buf_out;+                                   +            /* We want to extend the outputted frame's duration by the value+              stored in the 4th slot of the lost_time array. Because we need+              to adjust all the values in the array so they're contiguous,+              extend the duration inside the array first, before applying+              it to the current frame buffer. */+            pv->last_stop[3] += pv->lost_time[3];             -            /* The 4th cached frame will be the to use. */-            ivtc_buffer->start = pv->last_start[3];-            ivtc_buffer->stop = pv->last_stop[3];--            if (pv->frames_to_extend % 4)-                ivtc_buffer->stop += 751;-            else-                ivtc_buffer->stop += 750;+            /* Log how much time has been added back in to the video. */+            pv->total_gained_time += pv->lost_time[3];             -            /* Set the 3rd cached frame to start when this one stops,-               and to stop 3003 ticks later -- a normal 29.97fps-               length frame. If it needs to be extended as well to-               make up lost time, it'll be handled on the next-               loop through the renderer.                            */-            int temp_duration = pv->last_stop[2] - pv->last_start[2];-            pv->last_start[2] = ivtc_buffer->stop;-            pv->last_stop[2] = ivtc_buffer->stop + temp_duration;+            /* We've pulled the 4th value from the lost_time array+               and added it to the last_stop array's 4th slot. Now, rotate the+                lost_time array so the 4th slot now holds the 3rd's value, and+               so on down the line, and set the 0 index to a value of 0. */+            int i;+            for( i=2; i >=  0; i--)+            {+                pv->lost_time[i+1] = pv->lost_time[i];+            }+            pv->lost_time[0] = 0;             -            pv->frames_to_extend--;+            /* Log how many frames have had their durations extended. */             pv->extended_frames++;         }+        +        /* We can't use the given time stamps. Previous frames+           might already have been extended, throwing off the+           raw values fed to render.c. Instead, their+           stop and start times are stored in arrays.+           The 4th cached frame will be the to use.+           If it needed its duration extended to make up+           lost time, it will have happened above. */+        ivtc_buffer->start = pv->last_start[3];+        ivtc_buffer->stop = pv->last_stop[3];+        +        /* Set the 3rd cached frame to start when this one stops,+           and so on down the line. If any of them need to be+           extended as well to make up lost time, it'll be handled+           on the next loop through the renderer.  */+        int i;   +        for (i = 2; i >= 0; i--)+        {+            int temp_duration = pv->last_stop[i] - pv->last_start[i];+            pv->last_start[i] = pv->last_stop[i+1];+            pv->last_stop[i] = pv->last_start[i] + temp_duration;+        }      } @@ -431,11 +477,14 @@ void renderClose( hb_work_object_t * w ) {     hb_work_private_t * pv = w->private_data;   -        -    hb_log("render: dropped frames: %i (%i ticks)", pv->dropped_frames, (pv->dropped_frames * 3003) );-    hb_log("render: extended frames: %i (%i ticks)", pv->extended_frames, ( ( pv->extended_frames / 4 ) * 3003 ) );-    hb_log("render: Lost time: %i frames (%i ticks)", (pv->dropped_frames * 4) - (pv->extended_frames), (pv->dropped_frames * 3003) - ( ( pv->extended_frames / 4 ) * 3003 ) ); +    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 )+    {+        hb_log("render: average dropped frame duration: %lld", (pv->total_lost_time / pv->dropped_frames) );+    }+         /* Cleanup subtitle queue */     if( pv->subtitle_queue )     {@@ -476,12 +525,17 @@     /* Setup FIFO queue for subtitle cache */     pv->subtitle_queue = hb_fifo_init( 8 );         pv->delay_queue = hb_fifo_init( 8 );-    pv->frames_to_extend = 0;     pv->dropped_frames = 0;     pv->extended_frames = 0;     pv->last_start[0] = 0;     pv->last_stop[0] = 0;-    +    pv->total_lost_time = 0;+    pv->total_gained_time = 0;+    pv->lost_time[0] = 0;+    pv->lost_time[1] = 0;+    pv->lost_time[2] = 0;+    pv->lost_time[3] = 0;+     /* Setup filters */     /* TODO: Move to work.c? */     if( job->filters )Index: contrib/patch-x264-vbv-2pass.patch===================================================================--- contrib/patch-x264-vbv-2pass.patch	(revision 1244)+++ contrib/patch-x264-vbv-2pass.patch	(working copy)@@ -1,6 +1,6 @@ Index: encoder/ratecontrol.c ===================================================================---- encoder/ratecontrol.c	(revision 680)+--- encoder/ratecontrol.c	(revision 736) +++ encoder/ratecontrol.c	(working copy) @@ -43,6 +43,7 @@      int p_tex_bits;@@ -12,14 +12,14 @@      int i_count; @@ -1149,7 +1150,7 @@          return;- +      rct->buffer_fill_final += rct->buffer_rate - bits; -    if( rct->buffer_fill_final < 0 && !rct->b_2pass ) +    if( rct->buffer_fill_final < 0 )          x264_log( h, X264_LOG_WARNING, "VBV underflow (%.0f bits)\n", rct->buffer_fill_final );      rct->buffer_fill_final = x264_clip3f( rct->buffer_fill_final, 0, rct->buffer_size );  }-@@ -1325,6 +1326,28 @@+@@ -1325,6 +1326,22 @@                  double w = x264_clip3f( time*100, 0.0, 1.0 );                  q *= pow( (double)total_bits / rcc->expected_bits_sum, w );              }@@ -37,21 +37,15 @@ +                        expected_size = qscale2bits(&rce, q); +                        expected_vbv = rcc->buffer_fill + rcc->buffer_rate - expected_size; +                    }-+/*    x264_log( h, X264_LOG_INFO,-+              "frame %d rcc expected vbv = %d encoding expected vbv = %d\n",-+              (int)(h->fenc->i_frame),-+              (int)(rce.expected_vbv),-+              (int)(expected_vbv));*/-+ +                } +            }              q = x264_clip3f( q, lmin, lmax );          }          else /* 1pass ABR */-@@ -1455,6 +1478,137 @@+@@ -1455,6 +1472,137 @@      /* the rest of the variables are either constant or thread-local */  }- + +FILE *fh_vbv; + +static int find_underflow( x264_t *h, double *fills, int *t0, int *t1, int over )@@ -84,15 +78,17 @@ +    return start>=0 && end>=0; +} +-+static void fix_underflow( x264_t *h, int t0, int t1, double adjustment )++static void fix_underflow( x264_t *h, int t0, int t1, double adjustment, double qscale_min, double qscale_max) +{ +    x264_ratecontrol_t *rcc = h->rc;++    double qscale_new; +    int i; +    if(t0 > 0) +        t0++;-+//  printf("interval [%d,%d] %.4f\n", t0, t1, adjustment);-+    for(i=t0; i<=t1; i++)-+        rcc->entry[i].new_qscale *= adjustment;++    for(i=t0; i<=t1; i++) {++        qscale_new = rcc->entry[i].new_qscale *= adjustment;++        rcc->entry[i].new_qscale = x264_clip3f(qscale_new, qscale_min, qscale_max);++    } +} + +static double count_expected_bits( x264_t *h )@@ -136,9 +132,10 @@ +    double all_available_bits = h->param.rc.i_bitrate * 1000. * rcc->num_entries / rcc->fps; +    double expected_bits, prev_bits, adjustment; +    int i, t0, t1, space;++    double qscale_min = qp2qscale(h->param.rc.i_qp_min);++    double qscale_max = qp2qscale(h->param.rc.i_qp_max); + +    fills++;-+//  fh_vbv = fopen("vbv.log", "w"); + +	//adjust overall stream size +    do {@@ -149,7 +146,7 @@ +		//fix underflows +        while(find_underflow(h, fills, &t0, &t1, 0)) +        {-+            fix_underflow(h, t0, t1, 1.001);++            fix_underflow(h, t0, t1, 1.001, qscale_min, qscale_max); +            space = 1; +        } +@@ -160,7 +157,7 @@ +		//fix overflows +        while(find_underflow(h, fills, &t0, &t1, 1)) +        {-+            fix_underflow(h, t0, t1, adjustment);++            fix_underflow(h, t0, t1, adjustment, qscale_min, qscale_max); +            t0 = t1; +            space = 1; +        }@@ -171,30 +168,27 @@ +    fills[-1] = rcc->buffer_size * (1. - h->param.rc.f_vbv_buffer_init); +    t0 = 0; +    while(find_underflow(h, fills, &t0, &t1, 0))-+        fix_underflow(h, t0, t1, 1.001);++        fix_underflow(h, t0, t1, 1.001, qscale_min, qscale_max); +-+//  debug_dump_vbv(h);-+ +    //store expected vbv filling values for tracking when encoding +    for(i=0; i<rcc->num_entries; i++) +        rcc->entry[i].expected_vbv = rcc->buffer_size - fills[i]; +-+//  fclose(fh_vbv); +    x264_free(fills-1); +} +  static int init_pass2( x264_t *h )  {      x264_ratecontrol_t *rcc = h->rc;-@@ -1543,7 +1697,6 @@+@@ -1543,7 +1691,6 @@          rcc->last_non_b_pict_type = -1;          rcc->last_accum_p_norm = 1;          rcc->accum_p_norm = 0; -        rcc->buffer_fill = rcc->buffer_size * h->param.rc.f_vbv_buffer_init;- +          /* find qscale */          for(i=0; i<rcc->num_entries; i++){-@@ -1580,15 +1733,9 @@+@@ -1580,18 +1727,11 @@          /* find expected bits */          for(i=0; i<rcc->num_entries; i++){              ratecontrol_entry_t *rce = &rcc->entry[i];@@ -209,12 +203,15 @@ -            rcc->buffer_fill = rcc->buffer_fill_final; +            expected_bits += qscale2bits(rce, rce->new_qscale);          }- - //printf("expected:%llu available:%llu factor:%lf avgQ:%lf\n", (uint64_t)expected_bits, all_available_bits, rate_factor);-@@ -1599,6 +1746,10 @@++-//printf("expected:%llu available:%llu factor:%lf avgQ:%lf\n", (uint64_t)expected_bits, all_available_bits, rate_factor);+         if(expected_bits > all_available_bits) rate_factor -= step;+     }++@@ -1599,6 +1739,10 @@      if(filter_size > 1)          x264_free(blurred_qscale);- + +    if(rcc->b_vbv) +        vbv_pass2(h); +    expected_bits = count_expected_bits(h);@@ -222,17 +219,17 @@      if(fabs(expected_bits/all_available_bits - 1.0) > 0.01)      {          double avgq = 0;-@@ -1606,7 +1757,8 @@+@@ -1606,7 +1750,8 @@              avgq += rcc->entry[i].new_qscale;          avgq = qscale2qp(avgq / rcc->num_entries);- + -        x264_log(h, X264_LOG_WARNING, "Error: 2pass curve failed to converge\n"); +        if ((expected_bits > all_available_bits) || (!rcc->b_vbv)) +            x264_log(h, X264_LOG_WARNING, "Error: 2pass curve failed to converge\n");          x264_log(h, X264_LOG_WARNING, "target: %.2f kbit/s, expected: %.2f kbit/s, avg QP: %.4f\n",                   (float)h->param.rc.i_bitrate,                   expected_bits * rcc->fps / (rcc->num_entries * 1000.),-@@ -1625,7 +1777,7 @@+@@ -1625,7 +1770,7 @@              else                  x264_log(h, X264_LOG_WARNING, "try increasing target bitrate\n");          }@@ -240,9 +237,10 @@ +        else if(!(rcc->b_2pass && rcc->b_vbv))              x264_log(h, X264_LOG_WARNING, "internal error\n");      }- -@@ -1633,3 +1785,4 @@++@@ -1633,3 +1778,4 @@  }+  -  ++Index: contrib/Jamfile===================================================================--- contrib/Jamfile	(revision 1244)+++ contrib/Jamfile	(working copy)@@ -359,9 +359,11 @@     {         LIBX264_PATCH += " $(PATCH) -p1 < ../patch-x264-solaris.patch && " ;     }-# AQ is temporarily disabled    LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-aq.patch && " ;+# VBV 2 Pass v3 (must be applied *before* patch-x264-vaq48.patch) Uncomment to use both+    LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-vbv-2pass.patch && " ;+# VAQ .48 Patch (Dark_Shikari)    +	LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-vaq48.patch && " ;     LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-idr.patch && " ;-    LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-vbv-2pass.patch && " ;     Depends $(<) : $(>) ;     Depends lib  : $(<) ; }Index: contrib/version_x264.txt===================================================================--- contrib/version_x264.txt	(revision 1244)+++ contrib/version_x264.txt	(working copy)@@ -1 +1 @@-http://download.m0k.org/handbrake/contrib/x264-r720.tar.gz +http://download.m0k.org/handbrake/contrib/x264-r736.tar.gz