Commit 8e57a9a0 authored by Fiona Glaser's avatar Fiona Glaser

Add mb_info API for signalling constant macroblocks

Some use-cases of x264 involve encoding video with large constant areas of the frame.
Sometimes, the caller knows which areas these are, and can tell x264.
This API lets the caller do this and adds internal tracking of modifications to macroblocks to avoid problems.
This is really only suitable without B-frames.
An example use-case would be using x264 for VNC.
parent 4442eace
......@@ -385,6 +385,7 @@ typedef struct
} ref_pic_list_order[2][X264_REF_MAX];
/* P-frame weighting */
int b_weighted_pred;
x264_weight_t weight[X264_REF_MAX*2][3];
int i_mmco_remove_from_end;
......
......@@ -393,7 +393,7 @@ void x264_frame_deblock_row( x264_t *h, int mb_y )
x264_macroblock_cache_load_neighbours_deblock( h, mb_x, mb_y );
int mb_xy = h->mb.i_mb_xy;
int transform_8x8 = h->mb.mb_transform_size[h->mb.i_mb_xy];
int transform_8x8 = h->mb.mb_transform_size[mb_xy];
int intra_cur = IS_INTRA( h->mb.type[mb_xy] );
uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?mb_xy:mb_x];
......@@ -501,8 +501,19 @@ void x264_frame_deblock_row( x264_t *h, int mb_y )
int qp_left = (qp + qpl + 1) >> 1;
int qpc_left = (qpc + h->chroma_qp_table[qpl] + 1) >> 1;
int intra_left = IS_INTRA( h->mb.type[h->mb.i_mb_xy-1] );
int intra_deblock = intra_cur || intra_left;
if( intra_cur || intra_left )
/* Any MB that was coded, or that analysis decided to skip, has quality commensurate with its QP.
* But if deblocking affects neighboring MBs that were force-skipped, blur might accumulate there.
* So reset their effective QP to max, to indicate that lack of guarantee. */
if( h->fdec->mb_info && M32( bs[0][0] ) )
{
#define RESET_EFFECTIVE_QP(xy) h->fdec->effective_qp[xy] |= 0xff * !!(h->fdec->mb_info[xy] & X264_MBINFO_CONSTANT);
RESET_EFFECTIVE_QP(mb_xy);
RESET_EFFECTIVE_QP(h->mb.i_mb_left_xy[0]);
}
if( intra_deblock )
FILTER( _intra, 0, 0, qp_left, qpc_left );
else
FILTER( , 0, 0, qp_left, qpc_left );
......@@ -547,15 +558,22 @@ void x264_frame_deblock_row( x264_t *h, int mb_y )
int qp_top = (qp + qpt + 1) >> 1;
int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1;
int intra_top = IS_INTRA( h->mb.type[h->mb.i_mb_top_xy] );
int intra_deblock = intra_cur || intra_top;
if( (!b_interlaced || (!MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy]))
&& (intra_cur || intra_top) )
/* This edge has been modified, reset effective qp to max. */
if( h->fdec->mb_info && M32( bs[1][0] ) )
{
RESET_EFFECTIVE_QP(mb_xy);
RESET_EFFECTIVE_QP(h->mb.i_mb_top_xy);
}
if( (!b_interlaced || (!MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy])) && intra_deblock )
{
FILTER( _intra, 1, 0, qp_top, qpc_top );
}
else
{
if( intra_cur || intra_top )
if( intra_deblock )
M32( bs[1][0] ) = 0x03030303;
FILTER( , 1, 0, qp_top, qpc_top );
}
......
......@@ -210,6 +210,8 @@ static x264_frame_t *x264_frame_new( x264_t *h, int b_fdec )
}
if( PARAM_INTERLACED )
CHECKED_MALLOC( frame->field, i_mb_count * sizeof(uint8_t) );
if( h->param.analyse.b_mb_info )
CHECKED_MALLOC( frame->effective_qp, i_mb_count * sizeof(uint8_t) );
}
else /* fenc frame */
{
......@@ -289,6 +291,7 @@ void x264_frame_delete( x264_frame_t *frame )
x264_free( frame->f_row_qp );
x264_free( frame->f_row_qscale );
x264_free( frame->field );
x264_free( frame->effective_qp );
x264_free( frame->mb_type );
x264_free( frame->mb_partition );
x264_free( frame->mv[0] );
......@@ -354,6 +357,8 @@ int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src )
dst->i_pic_struct = src->i_pic_struct;
dst->extra_sei = src->extra_sei;
dst->opaque = src->opaque;
dst->mb_info = src->prop.mb_info;
dst->mb_info_free = src->prop.mb_info_free;
uint8_t *pix[3];
int stride[3];
......
......@@ -97,6 +97,7 @@ typedef struct x264_frame
int16_t (*mv16x16)[2];
int16_t (*lowres_mvs[2][X264_BFRAME_MAX+1])[2];
uint8_t *field;
uint8_t *effective_qp;
/* Stored as (lists_used << LOWRES_COST_SHIFT) + (cost).
* Doesn't need special addressing for intra cost because
......@@ -165,6 +166,10 @@ typedef struct x264_frame
/* user data */
void *opaque;
/* user frame properties */
uint8_t *mb_info;
void (*mb_info_free)( void* );
} x264_frame_t;
/* synchronized frame list */
......
......@@ -2995,6 +2995,8 @@ void x264_macroblock_analyse( x264_t *h )
if( h->param.rc.i_aq_mode && h->param.analyse.i_subpel_refine < 10 && abs(h->mb.i_qp - h->mb.i_last_qp) == 1 )
h->mb.i_qp = h->mb.i_last_qp;
if( h->param.analyse.b_mb_info )
h->fdec->effective_qp[h->mb.i_mb_xy] = h->mb.i_qp; /* Store the real analysis QP. */
x264_mb_analyse_init( h, &analysis, h->mb.i_qp );
/*--------------------------- Do the analysis ---------------------------*/
......@@ -3034,23 +3036,33 @@ intra_analysis:
}
else
{
int skip_invalid = h->i_thread_frames > 1 && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1];
/* If the current macroblock is off the frame, just skip it. */
if( HAVE_INTERLACED && !MB_INTERLACED && h->mb.i_mb_y * 16 >= h->param.i_height && !skip_invalid )
/* Special fast-skip logic using information from mb_info. */
if( h->fenc->mb_info && !SLICE_MBAFF && (h->fenc->mb_info[h->mb.i_mb_xy]&X264_MBINFO_CONSTANT) &&
!M32(h->mb.cache.pskip_mv) && (h->fenc->i_frame - h->fref[0][0]->i_frame) == 1 && !h->sh.b_weighted_pred &&
h->fref[0][0]->effective_qp[h->mb.i_mb_xy] <= h->mb.i_qp )
{
b_skip = 1;
/* Fast P_SKIP detection */
else if( h->param.analyse.b_fast_pskip )
{
if( skip_invalid )
// FIXME don't need to check this if the reference frame is done
{}
else if( h->param.analyse.i_subpel_refine >= 3 )
analysis.b_try_skip = 1;
else if( h->mb.i_mb_type_left[0] == P_SKIP ||
h->mb.i_mb_type_top == P_SKIP ||
h->mb.i_mb_type_topleft == P_SKIP ||
h->mb.i_mb_type_topright == P_SKIP )
b_skip = x264_macroblock_probe_pskip( h );
}
else
{
int skip_invalid = h->i_thread_frames > 1 && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1];
/* If the current macroblock is off the frame, just skip it. */
if( HAVE_INTERLACED && !MB_INTERLACED && h->mb.i_mb_y * 16 >= h->param.i_height && !skip_invalid )
b_skip = 1;
/* Fast P_SKIP detection */
else if( h->param.analyse.b_fast_pskip )
{
if( skip_invalid )
// FIXME don't need to check this if the reference frame is done
{}
else if( h->param.analyse.i_subpel_refine >= 3 )
analysis.b_try_skip = 1;
else if( h->mb.i_mb_type_left[0] == P_SKIP ||
h->mb.i_mb_type_top == P_SKIP ||
h->mb.i_mb_type_topleft == P_SKIP ||
h->mb.i_mb_type_topright == P_SKIP )
b_skip = x264_macroblock_probe_pskip( h );
}
}
}
......
......@@ -280,8 +280,10 @@ static void x264_slice_header_write( bs_t *s, x264_slice_header_t *sh, int i_nal
}
}
sh->b_weighted_pred = 0;
if( sh->pps->b_weighted_pred && sh->i_type == SLICE_TYPE_P )
{
sh->b_weighted_pred = sh->weight[0][0].weightfn || sh->weight[0][1].weightfn || sh->weight[0][2].weightfn;
/* pred_weight_table() */
bs_write_ue( s, sh->weight[0][0].i_denom );
bs_write_ue( s, sh->weight[0][1].i_denom );
......@@ -3196,6 +3198,10 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
}
x264_emms();
if( h->fdec->mb_info_free )
h->fdec->mb_info_free( h->fdec->mb_info );
/* generate buffering period sei and insert it into place */
if( h->i_thread_frames > 1 && h->fenc->b_keyframe && h->sps->vui.b_nal_hrd_parameters_present )
{
......
......@@ -41,7 +41,7 @@
#include "x264_config.h"
#define X264_BUILD 123
#define X264_BUILD 124
/* Application developers planning to link against a shared library version of
* libx264 from a Microsoft Visual Studio or similar development environment
......@@ -364,6 +364,8 @@ typedef struct x264_param_t
float f_psy_trellis; /* Psy trellis strength */
int b_psy; /* Toggle all psy optimizations */
int b_mb_info; /* Use input mb_info data in x264_picture_t */
/* the deadzone size that will be used in luma quantization */
int i_luma_deadzone[2]; /* {inter, intra} */
......@@ -689,18 +691,36 @@ typedef struct
typedef struct
{
/* All arrays of data here are ordered as follows:
* each 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.
* Macroblocks are 16x16 blocks of pixels (with respect to the luma plane). For the
* purposes of calculating the number of macroblocks, width and height are rounded up to
* the nearest 16. If in interlaced mode, height is rounded up to the nearest 32 instead. */
/* 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. */
* offsets differ between encoding passes is undefined. */
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* );
/* In: optional array of flags for each macroblock.
* Allows specifying additional information for the encoder such as which macroblocks
* remain unchanged. Usable flags are listed below.
* x264_param_t.analyse.b_mb_info must be set to use this, since x264 needs to track
* extra data internally to make full use of this information. */
uint8_t *mb_info;
/* In: optional callback to free mb_info when used. */
void (*mb_info_free)( void* );
/* The macroblock is constant and remains unchanged from the previous frame. */
#define X264_MBINFO_CONSTANT (1<<0)
/* More flags may be added in the future. */
/* Out: SSIM of the the frame luma (if x264_param_t.b_ssim is set) */
double f_ssim;
/* Out: Average PSNR of the frame (if x264_param_t.b_psnr is set) */
......
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