From e44ee38aef85e48601e54a13939f2a299bb583e0 Mon Sep 17 00:00:00 2001 From: Hui Su Date: Wed, 13 Jun 2012 19:03:31 -0700 Subject: [PATCH] Add lossless compression mode. This commit adds lossless compression capability to the experimental branch. The lossless experiment can be enabled using --enable-lossless in configure. When the experiment is enabled, the encoder will use lossless compression mode by command line option --lossless, and the decoder automatically recognizes a losslessly encoded clip and decodes accordingly. To achieve the lossless coding, this commit has changed the following: 1. To encode at lossless mode, encoder forces the use of unit quantizer, i.e, Q 0, where effective quantization is 1. Encoder also disables the usage of 8x8 transform and allows only 4x4 transform; 2. At Q 0, the first order 4x4 DCT/IDCT have been switched over to a pair of forward and inverse Walsh-Hadamard Transform (http://goo.gl/EIsfy), with proper scaling applied to match the range of the original 4x4 DCT/IDCT pair; 3. At Q 0, the second order remains to use the previous walsh-hadamard transform pair. However, to maintain the reversibility in second order transform at Q 0, scaling down is applied to first order DC coefficients prior to forward transform, and scaling up is applied to the second order output prior to quantization. Symmetric upscaling and downscaling are added around inverse second order transform; 4. At lossless mode, encoder also disables a number of minor features to ensure no loss is introduced, these features includes: a. Trellis quantization optimization b. Loop filtering c. Aggressive zero-binning, rounding and zero-bin boosting d. Mode based zero-bin boosting Lossless coding test was performed on all clips within the derf set, to verify that the commit has achieved lossless compression for all clips. The average compression ratio is around 2.57 to 1. (http://goo.gl/dEShs) Change-Id: Ia3aba7dd09df40dd590f93b9aba134defbc64e34 --- configure | 1 + vp8/common/idct.h | 12 +++ vp8/common/idctllm.c | 158 +++++++++++++++++++++++++++++++++++++++ vp8/common/onyx.h | 1 + vp8/decoder/decodframe.c | 29 +++++++ vp8/decoder/dequantize.c | 85 +++++++++++++++++++++ vp8/decoder/dequantize.h | 7 ++ vp8/decoder/idct_blk.c | 111 +++++++++++++++++++++++++++ vp8/encoder/dct.c | 97 +++++++++++++++++++++++- vp8/encoder/dct.h | 6 ++ vp8/encoder/onyx_if.c | 31 ++++++++ vp8/encoder/quantize.c | 11 +++ vp8/encoder/ratectrl.c | 9 +++ vp8/vp8_cx_iface.c | 4 + vpx/vpx_encoder.h | 6 ++ vpxenc.c | 26 +++++++ 16 files changed, 593 insertions(+), 1 deletion(-) diff --git a/configure b/configure index b1a3f6651..5f39413f2 100755 --- a/configure +++ b/configure @@ -232,6 +232,7 @@ EXPERIMENT_LIST=" newintramodes adaptive_entropy pred_filter + lossless " CONFIG_LIST=" external_build diff --git a/vp8/common/idct.h b/vp8/common/idct.h index e8ca23d66..bafa662e6 100644 --- a/vp8/common/idct.h +++ b/vp8/common/idct.h @@ -31,6 +31,10 @@ #include "arm/idct_arm.h" #endif +#if CONFIG_LOSSLESS +#define WHT_UPSCALE_FACTOR 3 +#define Y2_WHT_UPSCALE_FACTOR 2 +#endif #ifndef vp8_idct_idct8 #define vp8_idct_idct8 vp8_short_idct8x8_c @@ -85,6 +89,14 @@ extern prototype_second_order(vp8_idct_iwalsh1); #endif extern prototype_second_order(vp8_idct_iwalsh16); +#if CONFIG_LOSSLESS +extern prototype_idct(vp8_short_inv_walsh4x4_x8_c); +extern prototype_idct(vp8_short_inv_walsh4x4_1_x8_c); +extern prototype_idct_scalar_add(vp8_dc_only_inv_walsh_add_c); +extern prototype_second_order(vp8_short_inv_walsh4x4_lossless_c); +extern prototype_second_order(vp8_short_inv_walsh4x4_1_lossless_c); +#endif + typedef prototype_idct((*vp8_idct_fn_t)); typedef prototype_idct_scalar_add((*vp8_idct_scalar_add_fn_t)); typedef prototype_second_order((*vp8_second_order_fn_t)); diff --git a/vp8/common/idctllm.c b/vp8/common/idctllm.c index 75ce8d44d..acb856d53 100644 --- a/vp8/common/idctllm.c +++ b/vp8/common/idctllm.c @@ -23,6 +23,7 @@ * x * sqrt(2) * cos (pi/8) = x + x * (sqrt(2) *cos(pi/8)-1). **************************************************************************/ #include "vpx_ports/config.h" +#include "vp8/common/idct.h" #include @@ -195,6 +196,163 @@ void vp8_short_inv_walsh4x4_1_c(short *in, short *out) } } +#if CONFIG_LOSSLESS +void vp8_short_inv_walsh4x4_lossless_c(short *input, short *output) +{ + int i; + int a1, b1, c1, d1; + short *ip = input; + short *op = output; + + for (i = 0; i < 4; i++) + { + a1 = ((ip[0] + ip[3]))>>Y2_WHT_UPSCALE_FACTOR; + b1 = ((ip[1] + ip[2]))>>Y2_WHT_UPSCALE_FACTOR; + c1 = ((ip[1] - ip[2]))>>Y2_WHT_UPSCALE_FACTOR; + d1 = ((ip[0] - ip[3]))>>Y2_WHT_UPSCALE_FACTOR; + + op[0] = (a1 + b1 + 1)>>1; + op[1] = (c1 + d1)>>1; + op[2] = (a1 - b1)>>1; + op[3] = (d1 - c1)>>1; + + ip += 4; + op += 4; + } + + ip = output; + op = output; + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[12]; + b1 = ip[4] + ip[8]; + c1 = ip[4] - ip[8]; + d1 = ip[0] - ip[12]; + + + op[0] = ((a1 + b1 + 1)>>1)<>1)<>1)<>1)<>Y2_WHT_UPSCALE_FACTOR)+ 1)>>1; + op[1] = op[2] = op[3] = ((ip[0]>>Y2_WHT_UPSCALE_FACTOR)>>1); + + ip = tmp; + op = out; + for(i = 0; i<4; i++) + { + op[0] =((ip[0]+ 1)>>1)<>1))<> 1; + + for (i = 0; i < 4; i++) + { + a1 = ((ip[0] + ip[3]))>>WHT_UPSCALE_FACTOR; + b1 = ((ip[1] + ip[2]))>>WHT_UPSCALE_FACTOR; + c1 = ((ip[1] - ip[2]))>>WHT_UPSCALE_FACTOR; + d1 = ((ip[0] - ip[3]))>>WHT_UPSCALE_FACTOR; + + op[0] = (a1 + b1 + 1)>>1; + op[1] = (c1 + d1)>>1; + op[2] = (a1 - b1)>>1; + op[3] = (d1 - c1)>>1; + + ip += 4; + op += shortpitch; + } + + ip = output; + op = output; + for (i = 0; i < 4; i++) + { + a1 = ip[shortpitch*0] + ip[shortpitch*3]; + b1 = ip[shortpitch*1] + ip[shortpitch*2]; + c1 = ip[shortpitch*1] - ip[shortpitch*2]; + d1 = ip[shortpitch*0] - ip[shortpitch*3]; + + + op[shortpitch*0] = (a1 + b1 + 1)>>1; + op[shortpitch*1] = (c1 + d1)>>1; + op[shortpitch*2] = (a1 - b1)>>1; + op[shortpitch*3] = (d1 - c1)>>1; + + ip++; + op++; + } +} + +void vp8_short_inv_walsh4x4_1_x8_c(short *in, short *out, int pitch) +{ + int i; + short tmp[4]; + short *ip = in; + short *op = tmp; + int shortpitch = pitch >> 1; + + op[0] =((ip[0]>>WHT_UPSCALE_FACTOR) + 1)>>1; + op[1] = op[2] = op[3] = ((ip[0]>>WHT_UPSCALE_FACTOR)>>1); + + + ip = tmp; + op = out; + for(i = 0; i<4; i++) + { + op[shortpitch*0] =(ip[0]+ 1)>>1; + op[shortpitch*1] = op[shortpitch*2] = op[shortpitch*3] = ip[0]>>1; + ip ++; + op ++; + } +} + +void vp8_dc_only_inv_walsh_add_c(short input_dc, unsigned char *pred_ptr, unsigned char *dst_ptr, int pitch, int stride) +{ + int r, c; + short tmp[16]; + vp8_short_inv_walsh4x4_1_x8_c( &input_dc, tmp, 4<<1); + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = tmp[r*4 + c] + pred_ptr[c] ; + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dst_ptr[c] = (unsigned char) a ; + } + + dst_ptr += stride; + pred_ptr += pitch; + } +} +#endif void vp8_dc_only_idct_add_8x8_c(short input_dc, unsigned char *pred_ptr, diff --git a/vp8/common/onyx.h b/vp8/common/onyx.h index 574c8bfb5..8d4cb3e97 100644 --- a/vp8/common/onyx.h +++ b/vp8/common/onyx.h @@ -153,6 +153,7 @@ extern "C" int worst_allowed_q; int best_allowed_q; int cq_level; + int lossless; // two pass datarate control int two_pass_vbrbias; // two pass datarate control tweaks diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c index cb1f6d14e..4d6ebbe33 100644 --- a/vp8/decoder/decodframe.c +++ b/vp8/decoder/decodframe.c @@ -140,6 +140,35 @@ void mb_init_dequantizer(VP8D_COMP *pbi, MACROBLOCKD *xd) xd->block[i].dequant = pc->Y1dequant[QIndex]; } +#if CONFIG_LOSSLESS + if(!QIndex) + { + pbi->common.rtcd.idct.idct1 = vp8_short_inv_walsh4x4_1_x8_c; + pbi->common.rtcd.idct.idct16 = vp8_short_inv_walsh4x4_x8_c; + pbi->common.rtcd.idct.idct1_scalar_add = vp8_dc_only_inv_walsh_add_c; + pbi->common.rtcd.idct.iwalsh1 = vp8_short_inv_walsh4x4_1_lossless_c; + pbi->common.rtcd.idct.iwalsh16 = vp8_short_inv_walsh4x4_lossless_c; + pbi->dequant.idct_add = vp8_dequant_idct_add_lossless_c; + pbi->dequant.dc_idct_add = vp8_dequant_dc_idct_add_lossless_c; + pbi->dequant.dc_idct_add_y_block = vp8_dequant_dc_idct_add_y_block_lossless_c; + pbi->dequant.idct_add_y_block = vp8_dequant_idct_add_y_block_lossless_c; + pbi->dequant.idct_add_uv_block = vp8_dequant_idct_add_uv_block_lossless_c; + } + else + { + pbi->common.rtcd.idct.idct1 = vp8_short_idct4x4llm_1_c; + pbi->common.rtcd.idct.idct16 = vp8_short_idct4x4llm_c; + pbi->common.rtcd.idct.idct1_scalar_add = vp8_dc_only_idct_add_c; + pbi->common.rtcd.idct.iwalsh1 = vp8_short_inv_walsh4x4_1_c; + pbi->common.rtcd.idct.iwalsh16 = vp8_short_inv_walsh4x4_c; + pbi->dequant.idct_add = vp8_dequant_idct_add_c; + pbi->dequant.dc_idct_add = vp8_dequant_dc_idct_add_c; + pbi->dequant.dc_idct_add_y_block = vp8_dequant_dc_idct_add_y_block_c; + pbi->dequant.idct_add_y_block = vp8_dequant_idct_add_y_block_c; + pbi->dequant.idct_add_uv_block = vp8_dequant_idct_add_uv_block_c; + } +#endif + for (i = 16; i < 24; i++) { xd->block[i].dequant = pc->UVdequant[QIndex]; diff --git a/vp8/decoder/dequantize.c b/vp8/decoder/dequantize.c index f83032766..a6247b2ee 100644 --- a/vp8/decoder/dequantize.c +++ b/vp8/decoder/dequantize.c @@ -20,6 +20,11 @@ extern void vp8_short_idct4x4llm_1_c(short *input, short *output, int pitch); extern void vp8_short_idct8x8_c(short *input, short *output, int pitch); extern void vp8_short_idct8x8_1_c(short *input, short *output, int pitch); +#if CONFIG_LOSSLESS +extern void vp8_short_inv_walsh4x4_x8_c(short *input, short *output, int pitch); +extern void vp8_short_inv_walsh4x4_1_x8_c(short *input, short *output, int pitch); +#endif + #ifdef DEC_DEBUG extern int dec_debug; #endif @@ -119,6 +124,86 @@ void vp8_dequant_dc_idct_add_c(short *input, short *dq, unsigned char *pred, } } +#if CONFIG_LOSSLESS +void vp8_dequant_idct_add_lossless_c(short *input, short *dq, unsigned char *pred, + unsigned char *dest, int pitch, int stride) +{ + short output[16]; + short *diff_ptr = output; + int r, c; + int i; + + for (i = 0; i < 16; i++) + { + input[i] = dq[i] * input[i]; + } + + vp8_short_inv_walsh4x4_x8_c(input, output, 4 << 1); + + vpx_memset(input, 0, 32); + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = diff_ptr[c] + pred[c]; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dest[c] = (unsigned char) a; + } + + dest += stride; + diff_ptr += 4; + pred += pitch; + } +} + +void vp8_dequant_dc_idct_add_lossless_c(short *input, short *dq, unsigned char *pred, + unsigned char *dest, int pitch, int stride, + int Dc) +{ + int i; + short output[16]; + short *diff_ptr = output; + int r, c; + + input[0] = (short)Dc; + + for (i = 1; i < 16; i++) + { + input[i] = dq[i] * input[i]; + } + + vp8_short_inv_walsh4x4_x8_c(input, output, 4 << 1); + vpx_memset(input, 0, 32); + + for (r = 0; r < 4; r++) + { + for (c = 0; c < 4; c++) + { + int a = diff_ptr[c] + pred[c]; + + if (a < 0) + a = 0; + + if (a > 255) + a = 255; + + dest[c] = (unsigned char) a; + } + + dest += stride; + diff_ptr += 4; + pred += pitch; + } +} +#endif + void vp8_dequantize_b_2x2_c(BLOCKD *d) { int i; diff --git a/vp8/decoder/dequantize.h b/vp8/decoder/dequantize.h index d0f162b48..af84603bb 100644 --- a/vp8/decoder/dequantize.h +++ b/vp8/decoder/dequantize.h @@ -96,6 +96,13 @@ extern prototype_dequant_idct_add_y_block(vp8_dequant_idct_add_y_block); #endif extern prototype_dequant_idct_add_uv_block(vp8_dequant_idct_add_uv_block); +#if CONFIG_LOSSLESS +extern prototype_dequant_idct_add(vp8_dequant_idct_add_lossless_c); +extern prototype_dequant_dc_idct_add(vp8_dequant_dc_idct_add_lossless_c); +extern prototype_dequant_dc_idct_add_y_block(vp8_dequant_dc_idct_add_y_block_lossless_c); +extern prototype_dequant_idct_add_y_block(vp8_dequant_idct_add_y_block_lossless_c); +extern prototype_dequant_idct_add_uv_block(vp8_dequant_idct_add_uv_block_lossless_c); +#endif #ifndef vp8_dequant_block_2x2 #define vp8_dequant_block_2x2 vp8_dequantize_b_2x2_c diff --git a/vp8/decoder/idct_blk.c b/vp8/decoder/idct_blk.c index 16ac46c48..ee23130de 100644 --- a/vp8/decoder/idct_blk.c +++ b/vp8/decoder/idct_blk.c @@ -19,6 +19,12 @@ void vp8_dequant_idct_add_c(short *input, short *dq, unsigned char *pred, unsigned char *dest, int pitch, int stride); void vp8_dc_only_idct_add_c(short input_dc, unsigned char *pred_ptr, unsigned char *dst_ptr, int pitch, int stride); +#if CONFIG_LOSSLESS +void vp8_dequant_idct_add_lossless_c(short *input, short *dq, unsigned char *pred, + unsigned char *dest, int pitch, int stride); +void vp8_dc_only_idct_add_lossless_c(short input_dc, unsigned char *pred_ptr, + unsigned char *dst_ptr, int pitch, int stride); +#endif void vp8_dequant_dc_idct_add_y_block_c (short *q, short *dq, unsigned char *pre, @@ -164,3 +170,108 @@ void vp8_dequant_idct_add_uv_block_8x8_c vp8_dequant_idct_add_8x8_c (q, dq, pre, dstv, 8, stride); } +#if CONFIG_LOSSLESS +void vp8_dequant_dc_idct_add_y_block_lossless_c + (short *q, short *dq, unsigned char *pre, + unsigned char *dst, int stride, char *eobs, short *dc) +{ + int i, j; + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + if (*eobs++ > 1) + vp8_dequant_dc_idct_add_lossless_c (q, dq, pre, dst, 16, stride, dc[0]); + else + vp8_dc_only_inv_walsh_add_c(dc[0], pre, dst, 16, stride); + + q += 16; + pre += 4; + dst += 4; + dc ++; + } + + pre += 64 - 16; + dst += 4*stride - 16; + } +} + +void vp8_dequant_idct_add_y_block_lossless_c + (short *q, short *dq, unsigned char *pre, + unsigned char *dst, int stride, char *eobs) +{ + int i, j; + + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + if (*eobs++ > 1) + vp8_dequant_idct_add_lossless_c (q, dq, pre, dst, 16, stride); + else + { + vp8_dc_only_inv_walsh_add_c(q[0]*dq[0], pre, dst, 16, stride); + ((int *)q)[0] = 0; + } + + q += 16; + pre += 4; + dst += 4; + } + + pre += 64 - 16; + dst += 4*stride - 16; + } +} + +void vp8_dequant_idct_add_uv_block_lossless_c + (short *q, short *dq, unsigned char *pre, + unsigned char *dstu, unsigned char *dstv, int stride, char *eobs) +{ + int i, j; + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (*eobs++ > 1) + vp8_dequant_idct_add_lossless_c (q, dq, pre, dstu, 8, stride); + else + { + vp8_dc_only_inv_walsh_add_c(q[0]*dq[0], pre, dstu, 8, stride); + ((int *)q)[0] = 0; + } + + q += 16; + pre += 4; + dstu += 4; + } + + pre += 32 - 8; + dstu += 4*stride - 8; + } + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 2; j++) + { + if (*eobs++ > 1) + vp8_dequant_idct_add_lossless_c (q, dq, pre, dstv, 8, stride); + else + { + vp8_dc_only_inv_walsh_add_c(q[0]*dq[0], pre, dstv, 8, stride); + ((int *)q)[0] = 0; + } + + q += 16; + pre += 4; + dstv += 4; + } + + pre += 32 - 8; + dstv += 4*stride - 8; + } +} +#endif + diff --git a/vp8/encoder/dct.c b/vp8/encoder/dct.c index 6f9c68ef7..568d0e087 100644 --- a/vp8/encoder/dct.c +++ b/vp8/encoder/dct.c @@ -11,6 +11,7 @@ #include #include "vpx_ports/config.h" +#include "vp8/common/idct.h" #if CONFIG_INT_8X8FDCT @@ -457,4 +458,98 @@ void vp8_short_walsh4x4_c(short *input, short *output, int pitch) ip += 4; op += 4; } -} \ No newline at end of file +} + +#if CONFIG_LOSSLESS +void vp8_short_walsh4x4_lossless_c(short *input, short *output, int pitch) +{ + int i; + int a1, b1, c1, d1; + short *ip = input; + short *op = output; + int pitch_short = pitch >>1; + + for (i = 0; i < 4; i++) + { + a1 = (ip[0 * pitch_short] + ip[3 * pitch_short])>>Y2_WHT_UPSCALE_FACTOR; + b1 = (ip[1 * pitch_short] + ip[2 * pitch_short])>>Y2_WHT_UPSCALE_FACTOR; + c1 = (ip[1 * pitch_short] - ip[2 * pitch_short])>>Y2_WHT_UPSCALE_FACTOR; + d1 = (ip[0 * pitch_short] - ip[3 * pitch_short])>>Y2_WHT_UPSCALE_FACTOR; + + op[0] = (a1 + b1 + 1)>>1; + op[4] = (c1 + d1)>>1; + op[8] = (a1 - b1)>>1; + op[12]= (d1 - c1)>>1; + + ip++; + op++; + } + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[3]; + b1 = ip[1] + ip[2]; + c1 = ip[1] - ip[2]; + d1 = ip[0] - ip[3]; + + op[0] = ((a1 + b1 + 1)>>1)<>1)<>1)<>1)<>1; + + for (i = 0; i < 4; i++) + { + a1 = ip[0 * pitch_short] + ip[3 * pitch_short]; + b1 = ip[1 * pitch_short] + ip[2 * pitch_short]; + c1 = ip[1 * pitch_short] - ip[2 * pitch_short]; + d1 = ip[0 * pitch_short] - ip[3 * pitch_short]; + + op[0] = (a1 + b1 +1)>>1; + op[4] = (c1 + d1)>>1; + op[8] = (a1 - b1)>>1; + op[12]= (d1 - c1)>>1; + + ip++; + op++; + } + ip = output; + op = output; + + for (i = 0; i < 4; i++) + { + a1 = ip[0] + ip[3]; + b1 = ip[1] + ip[2]; + c1 = ip[1] - ip[2]; + d1 = ip[0] - ip[3]; + + op[0] = ((a1 + b1 +1)>>1)<>1)<>1)<>1)<quarter_pixel_search = 1; sf->half_pixel_search = 1; sf->iterative_sub_pixel = 1; +#if CONFIG_LOSSLESS + sf->optimize_coefficients = 0; +#else sf->optimize_coefficients = 1; +#endif sf->no_skip_block4x4_search = 1; sf->first_step = 0; @@ -1587,6 +1591,23 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->oxcf.best_allowed_q = q_trans[oxcf->best_allowed_q]; cpi->oxcf.cq_level = q_trans[cpi->oxcf.cq_level]; +#if CONFIG_LOSSLESS + cpi->oxcf.lossless = oxcf->lossless; + if(cpi->oxcf.lossless) + { + cpi->rtcd.fdct.short4x4 = vp8_short_walsh4x4_x8_c; + cpi->rtcd.fdct.fast4x4 = vp8_short_walsh4x4_x8_c; + cpi->rtcd.fdct.short8x4 = vp8_short_walsh8x4_x8_c; + cpi->rtcd.fdct.fast8x4 = vp8_short_walsh8x4_x8_c; + cpi->rtcd.fdct.walsh_short4x4 = vp8_short_walsh4x4_lossless_c; + cpi->common.rtcd.idct.idct1 = vp8_short_inv_walsh4x4_1_x8_c; + cpi->common.rtcd.idct.idct16 = vp8_short_inv_walsh4x4_x8_c; + cpi->common.rtcd.idct.idct1_scalar_add = vp8_dc_only_inv_walsh_add_c; + cpi->common.rtcd.idct.iwalsh1 = vp8_short_inv_walsh4x4_1_c; + cpi->common.rtcd.idct.iwalsh16 = vp8_short_inv_walsh4x4_lossless_c; + } +#endif + cpi->baseline_gf_interval = DEFAULT_GF_INTERVAL; cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; @@ -2984,6 +3005,12 @@ void loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm) { cm->filter_level = 0; } +#if CONFIG_LOSSLESS + else if(cpi->oxcf.lossless) + { + cm->filter_level = 0; + } +#endif else { struct vpx_usec_timer timer; @@ -3139,7 +3166,11 @@ static void encode_frame_to_data_rate // For 2 Pass Only used where GF/ARF prediction quality // is above a threshold cpi->zbin_mode_boost = 0; +#if CONFIG_LOSSLESS + cpi->zbin_mode_boost_enabled = FALSE; +#else cpi->zbin_mode_boost_enabled = TRUE; +#endif if ( cpi->gfu_boost <= 400 ) { cpi->zbin_mode_boost_enabled = FALSE; diff --git a/vp8/encoder/quantize.c b/vp8/encoder/quantize.c index c0b1be324..dace31cba 100644 --- a/vp8/encoder/quantize.c +++ b/vp8/encoder/quantize.c @@ -313,6 +313,17 @@ void vp8cx_init_quantizer(VP8_COMP *cpi) { int qzbin_factor = (vp8_dc_quant(Q,0) < 148) ? 84 : 80; +#if CONFIG_LOSSLESS + if(cpi->oxcf.lossless) + { + if (Q==0) + { + qzbin_factor = 64; + qrounding_factor = 64; + } + } +#endif + // dc values quant_val = vp8_dc_quant(Q, cpi->common.y1dc_delta_q); invert_quant(cpi->Y1quant[Q] + 0, diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c index 5ea74456a..52424aa7a 100644 --- a/vp8/encoder/ratectrl.c +++ b/vp8/encoder/ratectrl.c @@ -264,6 +264,10 @@ void vp8_setup_key_frame(VP8_COMP *cpi) cpi->common.txfm_mode = ALLOW_8X8; +#if CONFIG_LOSSLESS + if(cpi->oxcf.lossless) + cpi->common.txfm_mode = ONLY_4X4; +#endif //cpi->common.filter_level = 0; // Reset every key frame. cpi->common.filter_level = cpi->common.base_qindex * 3 / 8 ; @@ -292,6 +296,11 @@ void vp8_setup_inter_frame(VP8_COMP *cpi) cpi->common.txfm_mode = ALLOW_8X8; +#if CONFIG_LOSSLESS + if(cpi->oxcf.lossless) + cpi->common.txfm_mode = ONLY_4X4; +#endif + if(cpi->common.refresh_alt_ref_frame) { vpx_memcpy( &cpi->common.fc, diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index 96dcedca9..be32c3719 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -317,6 +317,10 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, oxcf->tuning = vp8_cfg.tuning; +#if CONFIG_LOSSLESS + oxcf->lossless = cfg.lossless; +#endif + /* printf("Current VP8 Settings: \n"); printf("target_bandwidth: %d\n", oxcf->target_bandwidth); diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h index 4863dcd17..971a4368d 100644 --- a/vpx/vpx_encoder.h +++ b/vpx/vpx_encoder.h @@ -592,6 +592,12 @@ extern "C" { */ unsigned int kf_max_dist; + + /*!\brief Enable lossless compression mode + * + * If this flag is set, the decoder will be in lossless compression mode. + */ + unsigned int lossless; } vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */ diff --git a/vpxenc.c b/vpxenc.c index 94235f48a..e4b4422d6 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -966,6 +966,10 @@ static const arg_def_t q_hist_n = ARG_DEF(NULL, "q-hist", 1, "Show quantizer histogram (n-buckets)"); static const arg_def_t rate_hist_n = ARG_DEF(NULL, "rate-hist", 1, "Show rate histogram (n-buckets)"); +#if CONFIG_LOSSLESS +static const arg_def_t lossless_enabled = ARG_DEF(NULL, "lossless", 0, + "Enable lossless compression"); +#endif static const arg_def_t *main_args[] = { &debugmode, @@ -973,6 +977,9 @@ static const arg_def_t *main_args[] = &deadline, &best_dl, &good_dl, &rt_dl, &verbosearg, &psnrarg, &recontest, &use_ivf, &q_hist_n, &rate_hist_n, +#if CONFIG_LOSSLESS + &lossless_enabled, +#endif NULL }; @@ -1670,6 +1677,10 @@ int main(int argc, const char **argv_) cfg.g_w = 0; cfg.g_h = 0; +#if CONFIG_LOSSLESS + cfg.lossless = 0; +#endif + /* Now parse the remainder of the parameters. */ for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { @@ -1753,10 +1764,22 @@ int main(int argc, const char **argv_) cfg.kf_max_dist = arg_parse_uint(&arg); else if (arg_match(&arg, &kf_disabled, argi)) cfg.kf_mode = VPX_KF_DISABLED; +#if CONFIG_LOSSLESS + else if (arg_match(&arg, &lossless_enabled, argi)) + cfg.lossless = 1; +#endif else argj++; } +#if CONFIG_LOSSLESS + if (cfg.lossless) + { + cfg.rc_min_quantizer = 0; + cfg.rc_max_quantizer = 0; + } +#endif + /* Handle codec specific options */ #if CONFIG_VP8_ENCODER @@ -1929,6 +1952,9 @@ int main(int argc, const char **argv_) SHOW(kf_mode); SHOW(kf_min_dist); SHOW(kf_max_dist); +#if CONFIG_LOSSLESS + SHOW(lossless); +#endif } if(pass == (one_pass_only ? one_pass_only - 1 : 0)) { -- 2.40.0