[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