Commit 7adf25b1 authored by Fiona Glaser's avatar Fiona 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.
parent 6589ad6d
......@@ -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;
}
......
......@@ -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 );
......
......@@ -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");
......
......@@ -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 );
......
......@@ -35,7 +35,7 @@
#include <stdarg.h>
#define X264_BUILD 96
#define X264_BUILD 97
/* x264_t:
* opaque handler for encoder */
......@@ -506,6 +506,22 @@ typedef struct
uint8_t *plane[4]; /* Pointers to each plane */
} x264_image_t;
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)
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment