changeset 19950:e99cd69dd08e

Patch by Karolina Lindqvist <karolina.lindqvist@kramnet.se> "This patch is the MMX optimizations for the zrmjpeg filter, which is used by the zr2 video output driver." With some small changes by me: - column width=80 - kept jpeg_enc_* functions static because they confuse the current vo_zr.c - did not include jpeg_enc.h because jpeg_enc functions are still static
author rik
date Sat, 23 Sep 2006 15:31:21 +0000
parents bf6bdb785567
children efd20a1e577a
files libmpcodecs/vf_zrmjpeg.c
diffstat 1 files changed, 125 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/libmpcodecs/vf_zrmjpeg.c	Sat Sep 23 15:24:24 2006 +0000
+++ b/libmpcodecs/vf_zrmjpeg.c	Sat Sep 23 15:31:21 2006 +0000
@@ -31,11 +31,13 @@
 #include "libavcodec/avcodec.h"
 #include "libavcodec/dsputil.h"
 #include "libavcodec/mpegvideo.h"
+//#include "jpeg_enc.h" /* this file is not present yet */
 
 #undef malloc
 #undef free
 #undef realloc
 
+extern int avcodec_inited;
 
 /* some convenient #define's, is this portable enough? */
 #define VERBOSE(...) mp_msg(MSGT_DECVIDEO, MSGL_V, "vf_zrmjpeg: " __VA_ARGS__)
@@ -60,6 +62,9 @@
 	uint16_t huff_code_ac_chrominance[256];
 } MJpegContext;
 
+// The get_pixels routine to use. The real routine comes from dsputil
+static void (*get_pixels)(DCTELEM *restrict block, const uint8_t *pixels, int line_size);
+
 /* Begin excessive code duplication ************************************/
 /* Code coming from mpegvideo.c and mjpeg.c in ../libavcodec ***********/
 
@@ -75,6 +80,10 @@
 	4520,   6270,  5906,  5315,  4520,  3552,  2446,  1247
 };
 
+/*
+ * This routine is like the routine with the same name in mjpeg.c,
+ * except for some coefficient changes.
+ */
 static void convert_matrix(MpegEncContext *s, int (*qmat)[64], 
 		uint16_t (*qmat16)[2][64], const uint16_t *quant_matrix,
 		int bias, int qmin, int qmax) {
@@ -130,6 +139,9 @@
     	}
 }
 
+/*
+ * This routine is a clone of mjpeg_encode_dc
+ */
 static inline void encode_dc(MpegEncContext *s, int val, 
 		uint8_t *huff_size, uint16_t *huff_code) {
 	int mant, nbits;
@@ -142,19 +154,15 @@
 			val = -val;
 			mant--;
 		}
-        
-		/* compute the log (XXX: optimize) */
-		nbits = 0;
-		while (val != 0) {
-			val = val >> 1;
-			nbits++;
-		}
-            
+		nbits= av_log2_16bit(val) + 1;
 		put_bits(&s->pb, huff_size[nbits], huff_code[nbits]);
 		put_bits(&s->pb, nbits, mant & ((1 << nbits) - 1));
 	}
 }
 
+/*
+ * This routine is a duplicate of encode_block in mjpeg.c
+ */
 static void encode_block(MpegEncContext *s, DCTELEM *block, int n) {
 	int mant, nbits, code, i, j;
 	int component, dc, run, last_index, val;
@@ -199,12 +207,7 @@
                 		mant--;
             		}
             
-            		/* compute the log (XXX: optimize) */
-            		nbits = 0;
-			while (val != 0) {
-				val = val >> 1;
-				nbits++; 
-			}
+			nbits= av_log2_16bit(val) + 1;
 			code = (run << 4) | nbits;
 
 			put_bits(&s->pb, huff_size_ac[code], 
@@ -241,9 +244,6 @@
 	struct MpegEncContext *s;
 	int cheap_upsample;
 	int bw;
-	int y_ps;
-	int u_ps;
-	int v_ps;
 	int y_rs;
 	int u_rs;
 	int v_rs;
@@ -253,7 +253,7 @@
  * changes, it allows for black&white encoding (it skips the U and V
  * macroblocks and it outputs the huffman code for 'no change' (dc) and
  * 'all zero' (ac)) and it takes 4 macroblocks (422) instead of 6 (420) */
-static void zr_mjpeg_encode_mb(jpeg_enc_t *j) {
+static always_inline void zr_mjpeg_encode_mb(jpeg_enc_t *j) {
 
 	MJpegContext *m = j->s->mjpeg_ctx;
 
@@ -279,11 +279,58 @@
     	}
 }
 
+/*
+ * Taking one MCU (YUYV) from 8-bit pixel planar storage and
+ * filling it into four 16-bit pixel DCT macroblocks.
+ */
+static always_inline void fill_block(jpeg_enc_t *j, int x, int y,
+		unsigned char *y_data, unsigned char *u_data,
+		unsigned char *v_data)
+{
+	int i, k;
+	short int *dest;
+	unsigned char *source;
+
+	// The first Y, Y0
+	get_pixels(j->s->block[0], y*8*j->y_rs + 16*x + y_data, j->y_rs);
+	// The second Y, Y1
+	get_pixels(j->s->block[1], y*8*j->y_rs + 16*x + 8 + y_data, j->y_rs);
+
+	if (!j->bw && j->cheap_upsample) {
+		source = y * 4 * j->u_rs + 8*x + u_data;
+		dest = j->s->block[2];
+		for (i = 0; i < 4; i++) {
+			for (k = 0; k < 8; k++) {
+				dest[k] = source[k];   // First row
+				dest[k+8] = source[k]; // Duplicate to next row
+
+			}
+			dest += 16;
+			source += j->u_rs;
+		}
+		source = y * 4 * j->v_rs + 8*x + v_data;
+		dest = j->s->block[3];
+		for (i = 0; i < 4; i++) {
+			for (k = 0; k < 8; k++) {
+				dest[k] = source[k];
+				dest[k+8] = source[k];
+			}
+			dest += 16;
+			source += j->u_rs;
+		}
+	} else if (!j->bw && !j->cheap_upsample) {
+		// U
+		get_pixels(j->s->block[2], y*8*j->u_rs + 8*x + u_data, j->u_rs);
+		// V
+		get_pixels(j->s->block[3], y*8*j->v_rs + 8*x + v_data, j->v_rs);
+	}
+}
+
 /* this function can take all kinds of YUV colorspaces
  * YV12, YVYU, UYVY. The necesary parameters must be set up by the caller
- * y_ps means "y pixel size", y_rs means "y row size".
+ * y_rs means "y row size".
  * For YUYV, for example, is u_buf = y_buf + 1, v_buf = y_buf + 3, 
- * y_ps = 2, u_ps = 4, v_ps = 4, y_rs = u_rs = v_rs.
+ * y_rs = u_rs = v_rs.
  *
  *  The actual buffers must be passed with mjpeg_encode_frame, this is
  *  to make it possible to call encode on the buffer provided by the
@@ -301,46 +348,41 @@
 /* The encoder doesn't know anything about interlacing, the halve height
  * needs to be passed and the double rowstride. Which field gets encoded
  * is decided by what buffers are passed to mjpeg_encode_frame */
-static jpeg_enc_t *jpeg_enc_init(int w, int h, int y_psize, int y_rsize, 
-		int u_psize, int u_rsize, int v_psize, int v_rsize,
+static jpeg_enc_t *jpeg_enc_init(int w, int h, int y_rsize, 
+			  int u_rsize, int v_rsize,
 		int cu, int q, int b) {
 	jpeg_enc_t *j;
 	int i = 0;
-	VERBOSE("JPEG encoder init: %dx%d %d %d %d %d %d %d\n",
-			w, h, y_psize, y_rsize, u_psize, 
-			u_rsize, v_psize, v_rsize);
+	VERBOSE("JPEG encoder init: %dx%d %d %d %d cu=%d q=%d bw=%d\n",
+			w, h, y_rsize, u_rsize, v_rsize, cu, q, b);
 
-	j = malloc(sizeof(jpeg_enc_t));
+	j = av_mallocz(sizeof(jpeg_enc_t));
 	if (j == NULL) return NULL;
 
-	j->s = malloc(sizeof(MpegEncContext));
-	memset(j->s,0x00,sizeof(MpegEncContext));
+	j->s = av_mallocz(sizeof(MpegEncContext));
 	if (j->s == NULL) {
-		free(j);
+		av_free(j);
 		return NULL;
 	}
 
 	/* info on how to access the pixels */
-	j->y_ps = y_psize; 
-	j->u_ps = u_psize; 
-	j->v_ps = v_psize;
 	j->y_rs = y_rsize; 
 	j->u_rs = u_rsize; 
 	j->v_rs = v_rsize;
 
-	j->s->width = w;
+	j->s->width = w;		// image width and height
 	j->s->height = h;
-	j->s->qscale = q;
+	j->s->qscale = q;		// Encoding quality
 
 	j->s->mjpeg_data_only_frames = 0;
 	j->s->out_format = FMT_MJPEG;
-	j->s->intra_only = 1;
-	j->s->encoding = 1;
+	j->s->intra_only = 1;		// Generate only intra pictures for jpeg
+	j->s->encoding = 1;		// Set mode to encode
 	j->s->pict_type = I_TYPE;
 	j->s->y_dc_scale = 8;
 	j->s->c_dc_scale = 8;
 
-	j->s->mjpeg_write_tables = 1;
+	j->s->mjpeg_write_tables = 1;	// setup to write tables
 	j->s->mjpeg_vsample[0] = 1;
 	j->s->mjpeg_vsample[1] = 1;
 	j->s->mjpeg_vsample[2] = 1;
@@ -351,23 +393,40 @@
 	j->cheap_upsample = cu;
 	j->bw = b;
 
+	// Is this needed?
+	/* if libavcodec is used by the decoder then we must not
+	 * initialize again, but if it is not initialized then we must
+	 * initialize it here. */
+	if (!avcodec_inited) {
+		avcodec_init();
+		avcodec_register_all();
+		avcodec_inited=1;
+	}
+
 	if (mjpeg_init(j->s) < 0) {
-		free(j->s);
-		free(j);
+		av_free(j->s);
+		av_free(j);
 		return NULL;
 	}
 
 	/* alloc bogus avctx to keep MPV_common_init from segfaulting */
-	j->s->avctx = calloc(sizeof(*j->s->avctx), 1);
-	/* Set up to encode mjpeg */
+	j->s->avctx = avcodec_alloc_context();
+	if (j->s->avctx == NULL) {
+		av_free(j->s);
+		av_free(j);
+		return NULL;
+	}
+
+	// Set some a minimum amount of default values that are needed
 	j->s->avctx->codec_id = CODEC_ID_MJPEG;
+	j->s->avctx->dct_algo = FF_DCT_AUTO;
+	j->s->intra_quant_bias= 1<<(QUANT_BIAS_SHIFT-1); //(a + x/2)/x
+	j->s->avctx->thread_count = 1;
 
 	/* make MPV_common_init allocate important buffers, like s->block */
-	j->s->avctx->thread_count = 1;
-
 	if (MPV_common_init(j->s) < 0) {
-		free(j->s);
-		free(j);
+		av_free(j->s);
+		av_free(j);
 		return NULL;
 	}
 
@@ -375,24 +434,28 @@
 	j->s->mb_height = j->s->height/8;
 	j->s->mb_intra = 1;
 
+	// Init q matrix
 	j->s->intra_matrix[0] = ff_mpeg1_default_intra_matrix[0];
 	for (i = 1; i < 64; i++) 
 		j->s->intra_matrix[i] = clip_uint8(
 			(ff_mpeg1_default_intra_matrix[i]*j->s->qscale) >> 3);
+	// precompute matrix
 	convert_matrix(j->s, j->s->q_intra_matrix, j->s->q_intra_matrix16, 
 			j->s->intra_matrix, j->s->intra_quant_bias, 8, 8);
+
+	get_pixels = j->s->dsp.get_pixels;
+
 	return j;
 }	
 
-static int jpeg_enc_frame(jpeg_enc_t *j, unsigned char *y_data, 
-		unsigned char *u_data, unsigned char *v_data, char *bufr) {
-	int i, k, mb_x, mb_y, overflow;
-	short int *dest;
-	unsigned char *source;
+static int jpeg_enc_frame(jpeg_enc_t *j, uint8_t *y_data,
+		   uint8_t *u_data, uint8_t *v_data, uint8_t *bufr) {
+	int mb_x, mb_y, overflow;
 	/* initialize the buffer */
 
 	init_put_bits(&j->s->pb, bufr, 1024*256);
 
+	// Emit the mjpeg header blocks
 	mjpeg_picture_header(j->s);
 
 	j->s->header_bits = put_bits_count(&j->s->pb);
@@ -403,72 +466,11 @@
 
 	for (mb_y = 0; mb_y < j->s->mb_height; mb_y++) {
 		for (mb_x = 0; mb_x < j->s->mb_width; mb_x++) {
-			/* conversion 8 to 16 bit and filling of blocks
-			 * must be mmx optimized */
-			/* fill 2 Y macroblocks and one U and one V */
-			source = mb_y * 8 * j->y_rs + 
-				16 * j->y_ps * mb_x + y_data;
-			dest = j->s->block[0];
-			for (i = 0; i < 8; i++) {
-				for (k = 0; k < 8; k++) {
-					dest[k] = source[k*j->y_ps];
-				}
-				dest += 8;
-				source += j->y_rs;
-			}
-			source = mb_y * 8 * j->y_rs + 
-				(16*mb_x + 8)*j->y_ps + y_data;
-			dest = j->s->block[1];
-			for (i = 0; i < 8; i++) {
-				for (k = 0; k < 8; k++) {
-					dest[k] = source[k*j->y_ps];
-				}
-				dest += 8;
-				source += j->y_rs;
-			}
-			if (!j->bw && j->cheap_upsample) {
-				source = mb_y*4*j->u_rs + 
-					8*mb_x*j->u_ps + u_data;
-				dest = j->s->block[2];
-				for (i = 0; i < 4; i++) {
-					for (k = 0; k < 8; k++) {
-						dest[k] = source[k*j->u_ps];
-						dest[k+8] = source[k*j->u_ps];
-					}
-					dest += 16;
-					source += j->u_rs;
-				}
-				source = mb_y*4*j->v_rs + 
-					8*mb_x*j->v_ps + v_data;
-				dest = j->s->block[3];
-				for (i = 0; i < 4; i++) {
-					for (k = 0; k < 8; k++) {
-						dest[k] = source[k*j->v_ps];
-						dest[k+8] = source[k*j->v_ps];
-					}
-					dest += 16;
-					source += j->u_rs;
-				}
-			} else if (!j->bw && !j->cheap_upsample) {
-				source = mb_y*8*j->u_rs + 
-					8*mb_x*j->u_ps + u_data;
-				dest = j->s->block[2];
-				for (i = 0; i < 8; i++) {
-					for (k = 0; k < 8; k++) 
-						dest[k] = source[k*j->u_ps];
-					dest += 8;
-					source += j->u_rs;
-				}
-				source = mb_y*8*j->v_rs + 
-					8*mb_x*j->v_ps + v_data;
-				dest = j->s->block[3];
-				for (i = 0; i < 8; i++) {
-					for (k = 0; k < 8; k++) 
-						dest[k] = source[k*j->v_ps];
-					dest += 8;
-					source += j->u_rs;
-				}
-			}
+			/*
+			 * Fill one DCT block (8x8 pixels) from
+			 * 2 Y macroblocks and one U and one V
+			 */
+			fill_block(j, mb_x, mb_y, y_data, u_data, v_data);
 			emms_c(); /* is this really needed? */
 
 			j->s->block_last_index[0] = 
@@ -509,8 +511,8 @@
 
 static void jpeg_enc_uninit(jpeg_enc_t *j) {
 	mjpeg_close(j->s);
-	free(j->s);
-	free(j);
+	av_free(j->s);
+	av_free(j);
 }
 
 struct vf_priv_s {
@@ -654,11 +656,11 @@
 
 	priv->y_stride = width;
 	priv->c_stride = width/2;
-	priv->j = jpeg_enc_init(width, height/priv->fields, 1, 
-			priv->fields*priv->y_stride, 1, 
-			priv->fields*priv->c_stride, 1, 
-			priv->fields*priv->c_stride, 1, 
-			priv->quality, priv->bw);
+	priv->j = jpeg_enc_init(width, height/priv->fields,
+				priv->fields*priv->y_stride,
+				priv->fields*priv->c_stride,
+				priv->fields*priv->c_stride,
+				1, priv->quality, priv->bw);
 
 	if (!priv->j) return 0;
 	return vf_next_config(vf, width, height, d_width, d_height, flags,