[x264-devel] commit: Add API tool to apply arbitrary quantizer offsets ( Jason Garrett-Glaser )

git at videolan.org git at videolan.org
Wed Jun 2 07:38:31 CEST 2010


x264 | branch: master | Jason Garrett-Glaser <darkshikari at gmail.com> | Fri May 28 14:27:22 2010 -0700| [a6c6afa85053443dc459e096e8e681dc21d43ade] | committer: Jason Garrett-Glaser 

Add API tool to apply arbitrary quantizer offsets
The calling application can now pass a "map" of quantizer offsets to apply to each frame.
An optional callback to free the map can also be included.
This allows all kinds of flexible region-of-interest coding and similar.

> http://git.videolan.org/gitweb.cgi/x264.git/?a=commit;h=a6c6afa85053443dc459e096e8e681dc21d43ade
---

 common/common.c       |    2 +-
 encoder/encoder.c     |    7 +++++--
 encoder/ratecontrol.c |   36 +++++++++++++++++++++++++-----------
 encoder/ratecontrol.h |    4 ++--
 x264.h                |   20 +++++++++++++++++++-
 5 files changed, 52 insertions(+), 17 deletions(-)

diff --git a/common/common.c b/common/common.c
index 2458f65..48e1bbc 100644
--- a/common/common.c
+++ b/common/common.c
@@ -998,6 +998,7 @@ static void x264_log_default( void *p_unused, int i_level, const char *psz_fmt,
  ****************************************************************************/
 int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height )
 {
+    memset( pic, 0, sizeof( x264_picture_t ) );
     pic->i_type = X264_TYPE_AUTO;
     pic->i_qpplus1 = 0;
     pic->img.i_csp = i_csp;
@@ -1010,7 +1011,6 @@ int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_heigh
     pic->img.i_stride[0] = i_width;
     pic->img.i_stride[1] = i_width / 2;
     pic->img.i_stride[2] = i_width / 2;
-    pic->param = NULL;
     pic->i_pic_struct = PIC_STRUCT_AUTO;
     return 0;
 }
diff --git a/encoder/encoder.c b/encoder/encoder.c
index 2f9e7f6..89107a3 100644
--- a/encoder/encoder.c
+++ b/encoder/encoder.c
@@ -2250,11 +2250,14 @@ int     x264_encoder_encode( x264_t *h,
 
         if( h->param.rc.b_mb_tree && h->param.rc.b_stat_read )
         {
-            if( x264_macroblock_tree_read( h, fenc ) )
+            if( x264_macroblock_tree_read( h, fenc, pic_in->prop.quant_offsets ) )
                 return -1;
         }
         else
-            x264_adaptive_quant_frame( h, fenc );
+            x264_adaptive_quant_frame( h, fenc, pic_in->prop.quant_offsets );
+
+        if( pic_in->prop.quant_offsets_free )
+            pic_in->prop.quant_offsets_free( pic_in->prop.quant_offsets );
 
         if( h->frames.b_have_lowres )
             x264_frame_init_lowres( h, fenc );
diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c
index bf0a400..d09de98 100644
--- a/encoder/ratecontrol.c
+++ b/encoder/ratecontrol.c
@@ -235,7 +235,7 @@ static NOINLINE uint32_t x264_ac_energy_mb( x264_t *h, int mb_x, int mb_y, x264_
     return var;
 }
 
-void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame )
+void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_offsets )
 {
     /* constants chosen to result in approximately the same overall bitrate as without AQ.
      * FIXME: while they're written in 5 significant digits, they're only tuned to 2. */
@@ -256,11 +256,22 @@ void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame )
         /* Need to init it anyways for MB tree */
         if( h->param.rc.f_aq_strength == 0 )
         {
-            memset( frame->f_qp_offset, 0, h->mb.i_mb_count * sizeof(float) );
-            memset( frame->f_qp_offset_aq, 0, h->mb.i_mb_count * sizeof(float) );
-            if( h->frames.b_have_lowres )
+            if( quant_offsets )
+            {
                 for( int mb_xy = 0; mb_xy < h->mb.i_mb_count; mb_xy++ )
-                    frame->i_inv_qscale_factor[mb_xy] = 256;
+                    frame->f_qp_offset[mb_xy] = frame->f_qp_offset_aq[mb_xy] = quant_offsets[mb_xy];
+                if( h->frames.b_have_lowres )
+                    for( int mb_xy = 0; mb_xy < h->mb.i_mb_count; mb_xy++ )
+                        frame->i_inv_qscale_factor[mb_xy] = x264_exp2fix8( frame->f_qp_offset[mb_xy] );
+            }
+            else
+            {
+                memset( frame->f_qp_offset, 0, h->mb.i_mb_count * sizeof(float) );
+                memset( frame->f_qp_offset_aq, 0, h->mb.i_mb_count * sizeof(float) );
+                if( h->frames.b_have_lowres )
+                    for( int mb_xy = 0; mb_xy < h->mb.i_mb_count; mb_xy++ )
+                        frame->i_inv_qscale_factor[mb_xy] = 256;
+            }
         }
         /* Need variance data for weighted prediction */
         if( h->param.analyse.i_weighted_pred == X264_WEIGHTP_FAKE || h->param.analyse.i_weighted_pred == X264_WEIGHTP_SMART )
@@ -299,9 +310,10 @@ void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame )
             for( int mb_x = 0; mb_x < width; mb_x++ )
             {
                 float qp_adj;
+                int mb_xy = mb_x + mb_y*h->mb.i_mb_stride;
                 if( h->param.rc.i_aq_mode == X264_AQ_AUTOVARIANCE )
                 {
-                    qp_adj = frame->f_qp_offset[mb_x + mb_y*h->mb.i_mb_stride];
+                    qp_adj = frame->f_qp_offset[mb_xy];
                     qp_adj = strength * (qp_adj - avg_adj);
                 }
                 else
@@ -309,10 +321,12 @@ void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame )
                     uint32_t energy = x264_ac_energy_mb( h, mb_x, mb_y, frame );
                     qp_adj = strength * (x264_log2( X264_MAX(energy, 1) ) - 14.427f);
                 }
-                frame->f_qp_offset[mb_x + mb_y*h->mb.i_mb_stride] =
-                frame->f_qp_offset_aq[mb_x + mb_y*h->mb.i_mb_stride] = qp_adj;
+                if( quant_offsets )
+                    qp_adj += quant_offsets[mb_xy];
+                frame->f_qp_offset[mb_xy] =
+                frame->f_qp_offset_aq[mb_xy] = qp_adj;
                 if( h->frames.b_have_lowres )
-                    frame->i_inv_qscale_factor[mb_x + mb_y*h->mb.i_mb_stride] = x264_exp2fix8(qp_adj);
+                    frame->i_inv_qscale_factor[mb_xy] = x264_exp2fix8(qp_adj);
             }
     }
 
@@ -327,7 +341,7 @@ void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame )
     }
 }
 
-int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame )
+int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets )
 {
     x264_ratecontrol_t *rc = h->rc;
     uint8_t i_type_actual = rc->entry[frame->i_frame].pict_type;
@@ -363,7 +377,7 @@ int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame )
         rc->qpbuf_pos--;
     }
     else
-        x264_adaptive_quant_frame( h, frame );
+        x264_adaptive_quant_frame( h, frame, quant_offsets );
     return 0;
 fail:
     x264_log(h, X264_LOG_ERROR, "Incomplete MB-tree stats file.\n");
diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h
index e052b2a..dd139eb 100644
--- a/encoder/ratecontrol.h
+++ b/encoder/ratecontrol.h
@@ -29,8 +29,8 @@ void x264_ratecontrol_delete( x264_t * );
 
 void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init );
 
-void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame );
-int  x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame );
+void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_offsets );
+int  x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets );
 int  x264_reference_build_list_optimal( x264_t *h );
 void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next );
 void x264_ratecontrol_start( x264_t *, int i_force_qp, int overhead );
diff --git a/x264.h b/x264.h
index 95efd88..a4b3400 100644
--- a/x264.h
+++ b/x264.h
@@ -35,7 +35,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 96
+#define X264_BUILD 97
 
 /* x264_t:
  *      opaque handler for encoder */
@@ -508,6 +508,22 @@ typedef struct
 
 typedef struct
 {
+    /* In: an array of quantizer offsets to be applied to this image during encoding.
+     *     These are added on top of the decisions made by x264.
+     *     Offsets can be fractional; they are added before QPs are rounded to integer.
+     *     Adaptive quantization must be enabled to use this feature.  Behavior if quant
+     *     offsets differ between encoding passes is undefined.
+     *
+     *     Array contains one offset per macroblock, in raster scan order.  In interlaced
+     *     mode, top-field MBs and bottom-field MBs are interleaved at the row level. */
+    float *quant_offsets;
+    /* In: optional callback to free quant_offsets when used.
+     *     Useful if one wants to use a different quant_offset array for each frame. */
+    void (*quant_offsets_free)( void* );
+} x264_image_properties_t;
+
+typedef struct
+{
     /* In: force picture type (if not auto)
      *     If x264 encoding parameters are violated in the forcing of picture types,
      *     x264 will correct the input picture type and log a warning.
@@ -537,6 +553,8 @@ typedef struct
     x264_param_t *param;
     /* In: raw data */
     x264_image_t img;
+    /* In: optional information to modify encoder decisions for this frame */
+    x264_image_properties_t prop;
     /* Out: HRD timing information. Output only when i_nal_hrd is set. */
     x264_hrd_t hrd_timing;
     /* private user data. libx264 doesn't touch this,



More information about the x264-devel mailing list