--- plugin_lumimasking.c 2003/10/02 13:54:27 1.1.2.5 +++ plugin_lumimasking.c 2010/03/09 10:00:14 1.9 @@ -1,10 +1,11 @@ /***************************************************************************** * * XVID MPEG-4 VIDEO CODEC - * - XviD plugin: performs a lumimasking algorithm on encoded frame - + * - Xvid plugin: performs a lumimasking algorithm on encoded frame - * * Copyright(C) 2002-2003 Peter Ross * 2002 Christoph Lampert + * 2008 Jason Garrett-Glaser * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,14 +21,18 @@ * along with this program ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: plugin_lumimasking.c,v 1.1.2.5 2003/10/02 13:54:27 edgomez Exp $ + * $Id: plugin_lumimasking.c,v 1.9 2010/03/09 10:00:14 Isibaar Exp $ * ****************************************************************************/ #include +#include +#include #include "../xvid.h" +#include "../global.h" #include "../portab.h" +#include "../utils/emms.h" /***************************************************************************** * Private data type @@ -37,6 +42,7 @@ { float *quant; float *val; + int method; } lumi_data_t; /***************************************************************************** @@ -46,7 +52,7 @@ static int lumi_plg_info(xvid_plg_info_t *info); static int lumi_plg_create(xvid_plg_create_t *create, lumi_data_t **handle); static int lumi_plg_destroy(lumi_data_t *handle, xvid_plg_destroy_t * destroy); -static int lumi_plg_before(lumi_data_t *handle, xvid_plg_data_t *data); +static int lumi_plg_frame(lumi_data_t *handle, xvid_plg_data_t *data); static int lumi_plg_after(lumi_data_t *handle, xvid_plg_data_t *data); /***************************************************************************** @@ -64,7 +70,9 @@ case XVID_PLG_DESTROY: return(lumi_plg_destroy((lumi_data_t *)handle, (xvid_plg_destroy_t*)param1)); case XVID_PLG_BEFORE : - return(lumi_plg_before((lumi_data_t *)handle, (xvid_plg_data_t *)param1)); + return 0; + case XVID_PLG_FRAME : + return(lumi_plg_frame((lumi_data_t *)handle, (xvid_plg_data_t *)param1)); case XVID_PLG_AFTER : return(lumi_plg_after((lumi_data_t *)handle, (xvid_plg_data_t *)param1)); } @@ -94,10 +102,12 @@ lumi_plg_create(xvid_plg_create_t *create, lumi_data_t **handle) { lumi_data_t *lumi; + xvid_plugin_lumimasking_t *param = (xvid_plugin_lumimasking_t *) create->param; if ((lumi = (lumi_data_t*)malloc(sizeof(lumi_data_t))) == NULL) return(XVID_ERR_MEMORY); + lumi->method = 0; lumi->quant = (float*)malloc(create->mb_width*create->mb_height*sizeof(float)); if (lumi->quant == NULL) { free(lumi); @@ -111,6 +121,9 @@ return(XVID_ERR_MEMORY); } + if (param != NULL) + lumi->method = param->method; + /* Bind the data structure to the handle */ *handle = lumi; @@ -154,90 +167,115 @@ int max_quant); static int -lumi_plg_before(lumi_data_t *handle, xvid_plg_data_t *data) +lumi_plg_frame(lumi_data_t *handle, xvid_plg_data_t *data) { int i, j; float global = 0.0f; - uint32_t mid_range = 0; - const float DarkAmpl = 14 / 2; - const float BrightAmpl = 10 / 2; - const float DarkThres = 70; - const float BrightThres = 200; + const float DarkAmpl = 14 / 4; + const float BrightAmpl = 10 / 3; + float DarkThres = 90; + float BrightThres = 200; const float GlobalDarkThres = 60; const float GlobalBrightThres = 170; - const float MidRangeThres = 20; - const float UpperLimit = 200; - const float LowerLimit = 25; + /* Arbitrary centerpoint for variance-based AQ. Roughly the same as used in x264. */ + float center = 14000.f; + /* Arbitrary strength for variance-based AQ. */ + float strength = 0.2f; + + if (data->type == XVID_TYPE_BVOP) return 0; /* Do this for all macroblocks individually */ for (j = 0; j < data->mb_height; j++) { for (i = 0; i < data->mb_width; i++) { - int k, l; + int k, l, sum = 0, sum_of_squares = 0; unsigned char *ptr; /* Initialize the current quant value to the frame quant */ handle->quant[j*data->mb_width + i] = (float)data->quant; - /* Reset the val value */ - handle->val[j*data->mb_width + i] = 0.0f; - /* Next steps compute the luminance-masking */ /* Get the MB address */ ptr = data->current.plane[0]; ptr += 16*j*data->current.stride[0] + 16*i; - /* Accumulate luminance */ - for (k = 0; k < 16; k++) - for (l = 0; l < 16; l++) - handle->val[j*data->mb_width + i] += ptr[k*data->current.stride[0] + l]; - - /* Normalize its value */ - handle->val[j*data->mb_width + i] /= 256.0f; - - /* Accumulate the global frame luminance */ - global += handle->val[j*data->mb_width + i]; - - /* Count the number of middle luminance blocks */ - if ((handle->val[j*data->mb_width + i] > LowerLimit) && - (handle->val[j*data->mb_width + i] < UpperLimit)) - mid_range++; + if (handle->method) { /* Variance masking mode */ + int variance = 0; + /* Accumulate sum and sum of squares over the MB */ + for (k = 0; k < 16; k++) { + for (l = 0; l < 16; l++) { + int val = ptr[k*data->current.stride[0] + l]; + sum += val; + sum_of_squares += val * val; + } + } + /* Variance = SSD - SAD^2 / (numpixels) */ + variance = sum_of_squares - sum * sum / 256; + handle->val[j*data->mb_width + i] = (float)variance; + } + else { /* Luminance masking mode */ + /* Accumulate luminance */ + for (k = 0; k < 16; k++) + for (l = 0; l < 16; l++) + sum += ptr[k*data->current.stride[0] + l]; + + handle->val[j*data->mb_width + i] = (float)sum/256.0f; + + /* Accumulate the global frame luminance */ + global += (float)sum/256.0f; + } } } - /* Normalize the global luminance accumulator */ - global /= data->mb_width*data->mb_height; - - /* Apply luminance masking only to frames where the global luminance is - * higher than DarkThreshold and lower than Bright Threshold, or where - * "middle" luminance blocks are lower than its corresponding threshold */ - if (((global < GlobalBrightThres) && (global > GlobalDarkThres)) || - (mid_range < MidRangeThres)) { - - /* Apply the luminance masking formulas to all MBs */ - for (i = 0; i < data->mb_height; i++) { - for (j = 0; j < data->mb_width; j++) { - if (handle->val[i*data->mb_width + j] < DarkThres) - handle->quant[i*data->mb_width + j] += DarkAmpl * (DarkThres - handle->val[i*data->mb_width + j]) / DarkThres; - else if (handle->val[i*data->mb_width + j] > BrightThres) - handle->quant[i*data->mb_width + j] += BrightAmpl * (handle->val[i*data->mb_width + j] - BrightThres) / (255 - BrightThres); + if (handle->method) { /* Variance masking */ + /* Apply the variance masking formula to all MBs */ + for (i = 0; i < data->mb_height; i++) + { + for (j = 0; j < data->mb_width; j++) + { + float value = handle->val[i*data->mb_width + j]; + float qscale_diff = strength * logf(value / center); + handle->quant[i*data->mb_width + j] *= (1.0f + qscale_diff); + } + } + } + else { /* Luminance masking */ + /* Normalize the global luminance accumulator */ + global /= data->mb_width*data->mb_height; + + DarkThres = DarkThres*global/127.0f; + BrightThres = BrightThres*global/127.0f; + + + /* Apply luminance masking only to frames where the global luminance is + * higher than DarkThreshold and lower than Bright Threshold */ + if ((global < GlobalBrightThres) && (global > GlobalDarkThres)) { + + /* Apply the luminance masking formulas to all MBs */ + for (i = 0; i < data->mb_height; i++) { + for (j = 0; j < data->mb_width; j++) { + if (handle->val[i*data->mb_width + j] < DarkThres) + handle->quant[i*data->mb_width + j] *= 1 + DarkAmpl * (DarkThres - handle->val[i*data->mb_width + j]) / DarkThres; + else if (handle->val[i*data->mb_width + j] > BrightThres) + handle->quant[i*data->mb_width + j] *= 1 + BrightAmpl * (handle->val[i*data->mb_width + j] - BrightThres) / (255 - BrightThres); + } } } } - /* Normalize the quantizer field */ - data->quant = normalize_quantizer_field(handle->quant, + /* Normalize the quantizer field */ + data->quant = normalize_quantizer_field(handle->quant, data->dquant, data->mb_width*data->mb_height, data->quant, - data->quant*2); + MAX(2,data->quant + data->quant/2)); - /* Plugin job finished */ - return(0); + /* Plugin job finished */ + return(0); } /*----------------------------------------------------------------------------