[XviD-devel] Decoder performance

Edouard Gomez ed.gomez at free.fr
Sat Aug 9 17:30:53 CEST 2003


Edouard Gomez (ed.gomez at free.fr) wrote:
> A bit better now, i removed lot of branches in the decoder code, most of
> them were in the bframe mb decoding functions. It's a very small change
> but it gives good results. See:
> 
> BENCHMARKs: VC: 49,806s VO: 0,020s A: 0,000s Sys: 1,756s = 51,583s

Well i was wrong for MVs < 0. As usual, the "most usual" rounding bug
got me... i was using shifts instead of divisions.

This patch replaces all shifts:
foo = bar >> dec->quaterpel
by
foo = bar / (1+dec->quaterpel)

The code is still a lot more branchless. I used some LUTs for small sets
of values like for bframe dquants or bframe mb type... even if these two
functions  are  called  not  so  often, their  ranking  in  the  profile
changed... it's a bit better even if it's not an impressive speedup (you
won't notice it ;-). 

I also added cbp test to skip complete macroblocks when possible. 

Still wanting some feedback to see if the patch impacts the decoding.

-- 
Edouard Gomez-------------- next part --------------
--- orig/src/decoder.c
+++ mod/src/decoder.c
@@ -266,18 +266,20 @@
 	uint32_t i;
 	uint32_t iQuant = pMB->quant;
 	uint8_t *pY_Cur, *pU_Cur, *pV_Cur;
+	quant_intraFuncPtr dequant = (dec->quant_type == 0) ? dequant_intra : dequant4_intra;
 
 	if (reduced_resolution) {
 		pY_Cur = dec->cur.y + (y_pos << 5) * stride + (x_pos << 5);
 		pU_Cur = dec->cur.u + (y_pos << 4) * stride2 + (x_pos << 4);
 		pV_Cur = dec->cur.v + (y_pos << 4) * stride2 + (x_pos << 4);
-	}else{
+	} else {
 		pY_Cur = dec->cur.y + (y_pos << 4) * stride + (x_pos << 4);
 		pU_Cur = dec->cur.u + (y_pos << 3) * stride2 + (x_pos << 3);
 		pV_Cur = dec->cur.v + (y_pos << 3) * stride2 + (x_pos << 3);
 	}
 
-	memset(block, 0, 6 * 64 * sizeof(int16_t));	/* clear */
+	/* Clear the complete MB */
+	memset(block, 0, 6*64 * sizeof(int16_t));
 
 	for (i = 0; i < 6; i++) {
 		uint32_t iDcScaler = get_dc_scaler(iQuant, i < 4);
@@ -312,8 +314,8 @@
 		}
 
 		start_timer();
-		if (cbp & (1 << (5 - i)))	/* coded */
-		{
+		/* coded */
+		if (cbp & (1 << (5 - i))) {
 			int direction = dec->alternate_vertical_scan ?
 				2 : pMB->acpred_directions[i];
 
@@ -326,11 +328,7 @@
 		stop_prediction_timer();
 
 		start_timer();
-		if (dec->quant_type == 0) {
-			dequant_intra(&data[i * 64], &block[i * 64], iQuant, iDcScaler);
-		} else {
-			dequant4_intra(&data[i * 64], &block[i * 64], iQuant, iDcScaler);
-		}
+		dequant(&data[i * 64], &block[i * 64], iQuant, iDcScaler);
 		stop_iquant_timer();
 
 		start_timer();
@@ -395,6 +393,8 @@
 
 	int uv_dx, uv_dy;
 	VECTOR mv[4];	/* local copy of mvs */
+	dequanth263_interFuncPtr dequant = (dec->quant_type == 0) ? dequant_inter : dequant4_inter;
+	const int direction = dec->alternate_vertical_scan ? 2 : 0;
 
 	if (reduced_resolution) {
 		pY_Cur = dec->cur.y + (y_pos << 5) * stride + (x_pos << 5);
@@ -414,8 +414,8 @@
 	
 	if (pMB->mode == MODE_INTER || pMB->mode == MODE_INTER_Q) {
 
-		uv_dx = mv[0].x / (1 + dec->quarterpel);
-		uv_dy = mv[0].y / (1 + dec->quarterpel);
+		uv_dx = mv[0].x / (1+dec->quarterpel);
+		uv_dy = mv[0].y / (1+dec->quarterpel);
 		
 		uv_dx = (uv_dx >> 1) + roundtab_79[uv_dx & 0x3];
 		uv_dy = (uv_dy >> 1) + roundtab_79[uv_dy & 0x3];
@@ -453,18 +453,12 @@
 	} else {	/* MODE_INTER4V */
 		int sum;
 		
-		if(dec->quarterpel)
-			sum = (mv[0].x / 2) + (mv[1].x / 2) + (mv[2].x / 2) + (mv[3].x / 2);
-		else
-			sum = mv[0].x + mv[1].x + mv[2].x + mv[3].x;
-
+		sum = mv[0].x + mv[1].x + mv[2].x + mv[3].x;
+		sum /= (1+dec->quarterpel);
 		uv_dx = (sum >> 3) + roundtab_76[sum & 0xf];
 
-		if(dec->quarterpel)
-			sum = (mv[0].y / 2) + (mv[1].y / 2) + (mv[2].y / 2) + (mv[3].y / 2);
-		else
-			sum = mv[0].y + mv[1].y + mv[2].y + mv[3].y;
-
+		sum = mv[0].y + mv[1].y + mv[2].y + mv[3].y;
+		sum /= (1+dec->quarterpel);
 		uv_dy = (sum >> 3) + roundtab_76[sum & 0xf];
 
 		start_timer();
@@ -520,11 +514,12 @@
 		stop_comp_timer();
 	}
 
+	if (!cbp) return;
+
 	for (i = 0; i < 6; i++) {
-		int direction = dec->alternate_vertical_scan ? 2 : 0;
 
-		if (cbp & (1 << (5 - i)))	/* coded */
-		{
+		/* coded */
+		if (cbp & (1 << (5 - i))) {
 			memset(&block[i * 64], 0, 64 * sizeof(int16_t));	/* clear */
 
 			start_timer();
@@ -532,11 +527,7 @@
 			stop_coding_timer();
 
 			start_timer();
-			if (dec->quant_type == 0) {
-				dequant_inter(&data[i * 64], &block[i * 64], iQuant);
-			} else {
-				dequant4_inter(&data[i * 64], &block[i * 64], iQuant);
-			}
+			dequant(&data[i * 64], &block[i * 64], iQuant);
 			stop_iquant_timer();
 
 			start_timer();
@@ -609,6 +600,7 @@
 	uint8_t *const pY_Cur=dec->cur.y + (y_pos << 4) * stride + (x_pos << 4);
 	uint8_t *const pU_Cur=dec->cur.u + (y_pos << 3) * stride2 + (x_pos << 3);
 	uint8_t *const pV_Cur=dec->cur.v + (y_pos << 3) * stride2 + (x_pos << 3);
+	dequanth263_interFuncPtr dequant = (dec->quant_type == 0) ? dequant_inter : dequant4_inter;
 
 	pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
 
@@ -648,8 +640,8 @@
 	for (i = 0; i < 6; i++) {
 		int direction = dec->alternate_vertical_scan ? 2 : 0;
 
-		if (cbp & (1 << (5 - i)))	/* coded */
-		{
+		/* coded */
+		if (cbp & (1 << (5 - i))) {
 			memset(&block[i * 64], 0, 64 * sizeof(int16_t));	/* clear */
 
 			start_timer();
@@ -657,11 +649,7 @@
 			stop_coding_timer();
 
 			start_timer();
-			if (dec->quant_type == 0) {
-				dequant_inter(&data[i * 64], &block[i * 64], iQuant);
-			} else {
-				dequant4_inter(&data[i * 64], &block[i * 64], iQuant);
-			}
+			dequant(&data[i * 64], &block[i * 64], iQuant);
 			stop_iquant_timer();
 
 			start_timer();
@@ -805,17 +793,12 @@
 	mv.x += pmv.x;
 	mv.y += pmv.y;
 
-	if (mv.x < low) {
-		mv.x += range;
-	} else if (mv.x > high) {
-		mv.x -= range;
-	}
+	mv.x += (((mv.x-low)>>31) & range);
+	mv.x -= (((high-mv.x)>>31) & range);
+
+	mv.y += (((mv.y-low)>>31) & range);
+	mv.y -= (((high-mv.y)>>31) & range);
 
-	if (mv.y < low) {
-		mv.y += range;
-	} else if (mv.y > high) {
-		mv.y -= range;
-	}
 
 	ret_mv->x = mv.x;
 	ret_mv->y = mv.y;
@@ -1097,17 +1080,11 @@
 	mv_x += pmv_x;
 	mv_y += pmv_y;
 
-	if (mv_x < low) {
-		mv_x += range;
-	} else if (mv_x > high) {
-		mv_x -= range;
-	}
+	mv_x += (((mv_x-low)>>31) & range);
+	mv_x -= (((high-mv_x)>>31) & range);
 
-	if (mv_y < low) {
-		mv_y += range;
-	} else if (mv_y > high) {
-		mv_y -= range;
-	}
+	mv_y += (((mv_y-low)>>31) & range);
+	mv_y -= (((high-mv_y)>>31) & range);
 
 	mv->x = mv_x;
 	mv->y = mv_y;
@@ -1136,6 +1113,8 @@
 	uint32_t iQuant = pMB->quant;
 	uint8_t *pY_Cur, *pU_Cur, *pV_Cur;
 	int uv_dx, uv_dy;
+	const int direction = dec->alternate_vertical_scan ? 2 : 0;
+	dequanth263_interFuncPtr dequant = (dec->quant_type == 0) ? dequant_inter : dequant4_inter;
 
 	pY_Cur = dec->cur.y + (y_pos << 4) * stride + (x_pos << 4);
 	pU_Cur = dec->cur.u + (y_pos << 3) * stride2 + (x_pos << 3);
@@ -1146,29 +1125,20 @@
 		uv_dx = pMB->mvs[0].x;
 		uv_dy = pMB->mvs[0].y;
 
-		if (dec->quarterpel)
-		{
-			uv_dx /= 2;
-			uv_dy /= 2;
-		}
+		uv_dx /= (1+dec->quarterpel);
+		uv_dy /= (1+dec->quarterpel);
 
 		uv_dx = (uv_dx >> 1) + roundtab_79[uv_dx & 0x3];
 		uv_dy = (uv_dy >> 1) + roundtab_79[uv_dy & 0x3];
 	} else {
 		int sum;
 
-		if(dec->quarterpel)
-			sum = (pMB->mvs[0].x / 2) + (pMB->mvs[1].x / 2) + (pMB->mvs[2].x / 2) + (pMB->mvs[3].x / 2);
-		else
-			sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
-
+		sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
+		sum /= (1+dec->quarterpel);
 		uv_dx = (sum >> 3) + roundtab_76[sum & 0xf];
 
-		if(dec->quarterpel)
-			sum = (pMB->mvs[0].y / 2) + (pMB->mvs[1].y / 2) + (pMB->mvs[2].y / 2) + (pMB->mvs[3].y / 2);
-		else
-			sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
-
+		sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
+		sum /= (1+dec->quarterpel);
 		uv_dy = (sum >> 3) + roundtab_76[sum & 0xf];
 	}
 
@@ -1177,8 +1147,7 @@
 		interpolate16x16_quarterpel(dec->cur.y, dec->refn[ref].y, dec->qtmp.y, dec->qtmp.y + 64,
  								    dec->qtmp.y + 128, 16*x_pos, 16*y_pos,
 								    pMB->mvs[0].x, pMB->mvs[0].y, stride, 0);
-	}
-	else {
+	} else {
 		interpolate8x8_switch(dec->cur.y, dec->refn[ref].y, 16*x_pos, 16*y_pos,
 							  pMB->mvs[0].x, pMB->mvs[0].y, stride, 0);
 		interpolate8x8_switch(dec->cur.y, dec->refn[ref].y, 16*x_pos + 8, 16*y_pos,
@@ -1195,11 +1164,12 @@
 						  uv_dx, uv_dy, stride2, 0);
 	stop_comp_timer();
 
+	if (!cbp) return;
+
 	for (i = 0; i < 6; i++) {
-		int direction = dec->alternate_vertical_scan ? 2 : 0;
 
-		if (cbp & (1 << (5 - i)))	/* coded */
-		{
+		/* coded */
+		if (cbp & (1 << (5 - i))) {
 			memset(&block[i * 64], 0, 64 * sizeof(int16_t));	/* clear */
 
 			start_timer();
@@ -1207,11 +1177,7 @@
 			stop_coding_timer();
 
 			start_timer();
-			if (dec->quant_type == 0) {
-				dequant_inter(&data[i * 64], &block[i * 64], iQuant);
-			} else {
-				dequant4_inter(&data[i * 64], &block[i * 64], iQuant);
-			}
+			dequant(&data[i * 64], &block[i * 64], iQuant);
 			stop_iquant_timer();
 
 			start_timer();
@@ -1264,6 +1230,8 @@
 	uint32_t i;
 	uint8_t *pY_Cur, *pU_Cur, *pV_Cur;
     const uint32_t cbp = pMB->cbp;
+	const int direction = dec->alternate_vertical_scan ? 2 : 0;
+	dequanth263_interFuncPtr dequant = (dec->quant_type == 0) ? dequant_inter : dequant4_inter;
 
 	pY_Cur = dec->cur.y + (y_pos << 4) * stride + (x_pos << 4);
 	pU_Cur = dec->cur.u + (y_pos << 3) * stride2 + (x_pos << 3);
@@ -1277,14 +1245,11 @@
 		b_uv_dx = pMB->b_mvs[0].x;
 		b_uv_dy = pMB->b_mvs[0].y;
 
-		if (dec->quarterpel)
-		{
-			uv_dx /= 2;
-			uv_dy /= 2;
+		uv_dx /= (1+dec->quarterpel);
+		uv_dy /= (1+dec->quarterpel);
 
-			b_uv_dx /= 2;
-			b_uv_dy /= 2;
-		}
+		b_uv_dx /= 2;
+		b_uv_dy /= 2;
 
 		uv_dx = (uv_dx >> 1) + roundtab_79[uv_dx & 0x3];
 		uv_dy = (uv_dy >> 1) + roundtab_79[uv_dy & 0x3];
@@ -1294,33 +1259,20 @@
 	} else {
 		int sum;
 
-		if(dec->quarterpel)
-			sum = (pMB->mvs[0].x / 2) + (pMB->mvs[1].x / 2) + (pMB->mvs[2].x / 2) + (pMB->mvs[3].x / 2);
-		else
-			sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
-
+		sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
+		sum /= (1+dec->quarterpel);
 		uv_dx = (sum >> 3) + roundtab_76[sum & 0xf];
 
-		if(dec->quarterpel)
-			sum = (pMB->mvs[0].y / 2) + (pMB->mvs[1].y / 2) + (pMB->mvs[2].y / 2) + (pMB->mvs[3].y / 2);
-		else
-			sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
-
+		sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
+		sum /= (1+dec->quarterpel);
 		uv_dy = (sum >> 3) + roundtab_76[sum & 0xf];
 
-
-		if(dec->quarterpel)
-			sum = (pMB->b_mvs[0].x / 2) + (pMB->b_mvs[1].x / 2) + (pMB->b_mvs[2].x / 2) + (pMB->b_mvs[3].x / 2);
-		else
-			sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
-
+		sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
+		sum /= (1+dec->quarterpel);
 		b_uv_dx = (sum >> 3) + roundtab_76[sum & 0xf];
 
-		if(dec->quarterpel)
-			sum = (pMB->b_mvs[0].y / 2) + (pMB->b_mvs[1].y / 2) + (pMB->b_mvs[2].y / 2) + (pMB->b_mvs[3].y / 2);
-		else
-			sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
-
+		sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
+		sum /= (1+dec->quarterpel);
 		b_uv_dy = (sum >> 3) + roundtab_76[sum & 0xf];
 	}
 
@@ -1435,9 +1387,9 @@
 
 	stop_comp_timer();
 
-	for (i = 0; i < 6; i++) {
-		int direction = dec->alternate_vertical_scan ? 2 : 0;
+	if (!cbp) return;
 
+	for (i = 0; i < 6; i++) {
 		if (cbp & (1 << (5 - i)))	/* coded */
 		{
 			memset(&block[i * 64], 0, 64 * sizeof(int16_t));	/* clear */
@@ -1447,11 +1399,7 @@
 			stop_coding_timer();
 
 			start_timer();
-			if (dec->quant_type == 0) {
-				dequant_inter(&data[i * 64], &block[i * 64], iQuant);
-			} else {
-				dequant4_inter(&data[i * 64], &block[i * 64], iQuant);
-			}
+			dequant(&data[i * 64], &block[i * 64], iQuant);
 			stop_iquant_timer();
 
 			start_timer();
@@ -1486,12 +1434,23 @@
 int32_t __inline
 get_dbquant(Bitstream * bs)
 {
-	if (!BitstreamGetBit(bs))      /*  '0' */
+	uint32_t bits;
+	const int quants[4] = { 0, 0, -2, 2};
+
+	bits = BitstreamShowBits(bs, 2);
+	BitstreamSkip(bs, 1<<(bits>>1));
+	return(quants[bits]);
+
+/*
+	BitstreamSkip(bs, mb_type+1);
+
+	if (!BitstreamGetBit(bs))
 		return (0);
-	else if (!BitstreamGetBit(bs)) /* '10' */
+	else if (!BitstreamGetBit(bs))
 		return (-2);
-	else                           /* '11' */
+	else
 		return (2);
+*/
 }
 
 /*
@@ -1506,16 +1465,21 @@
 get_mbtype(Bitstream * bs)
 {
 	int32_t mb_type;
+	uint32_t bits;
+	const int type[16] =
+		{
+			-1,
+			3,
+			2, 2,
+			1, 1, 1, 1,
+			0, 0, 0, 0, 0, 0, 0, 0
+		};
+
+	bits = BitstreamShowBits(bs, 4);
+	mb_type = type[bits];
+	BitstreamSkip(bs, mb_type+1);
 
-	for (mb_type = 0; mb_type <= 3; mb_type++) {
-		if (BitstreamGetBit(bs))
-			break;
-	}
-
-	if (mb_type <= 3)
-		return (mb_type);
-	else
-		return (-1);
+	return (mb_type);
 }
 
 void


More information about the XviD-devel mailing list