1 /*
2 
3 cx2341x HM12 conversion routines
4 
5 (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
20 
21  */
22 
23 #include "libv4lconvert-priv.h"
24 #include <string.h>
25 
26 /* The HM12 format is used in the Conexant cx23415/6/8 MPEG encoder devices.
27    It is a macroblock format with separate Y and UV planes, each plane
28    consisting of 16x16 values. All lines are always 720 bytes long. If the
29    width of the image is less than 720, then the remainder is padding.
30 
31    The height has to be a multiple of 32 in order to get correct chroma
32    values.
33 
34    It is basically a by-product of the MPEG encoding inside the device,
35    which is available for raw video as a 'bonus feature'.
36  */
37 
38 #define CLIP(color) \
39 	(unsigned char)(((color) > 0xff) ? 0xff : (((color) < 0) ? 0 : (color)))
40 
41 static const int stride = 720;
42 
v4lconvert_hm12_to_rgb(const unsigned char * src,unsigned char * dest,int width,int height,int rgb)43 static void v4lconvert_hm12_to_rgb(const unsigned char *src, unsigned char *dest,
44 		int width, int height, int rgb)
45 {
46 	unsigned int y, x, i, j;
47 	const unsigned char *y_base = src;
48 	const unsigned char *uv_base = src + stride * height;
49 	const unsigned char *src_y;
50 	const unsigned char *src_uv;
51 	int mb_size = 256;
52 	int r = rgb ? 0 : 2;
53 	int b = 2 - r;
54 
55 	for (y = 0; y < height; y += 16) {
56 		int mb_y = (y / 16) * (stride / 16);
57 		int mb_uv = (y / 32) * (stride / 16);
58 		int maxy = (height - y < 16 ? height - y : 16);
59 
60 		for (x = 0; x < width; x += 16, mb_y++, mb_uv++) {
61 			int maxx = (width - x < 16 ? width - x : 16);
62 
63 			src_y = y_base + mb_y * mb_size;
64 			src_uv = uv_base + mb_uv * mb_size;
65 
66 			if (y & 0x10)
67 				src_uv += mb_size / 2;
68 
69 			for (i = 0; i < maxy; i++) {
70 				int idx = (x + (y + i) * width) * 3;
71 
72 				for (j = 0; j < maxx; j++) {
73 					int y = src_y[j];
74 					int u = src_uv[j & ~1];
75 					int v = src_uv[j | 1];
76 					int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
77 					int rg = (((u - 128) << 1) + (u - 128) +
78 						((v - 128) << 2) + ((v - 128) << 1)) >> 3;
79 					int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
80 
81 					dest[idx+r] = CLIP(y + v1);
82 					dest[idx+1] = CLIP(y - rg);
83 					dest[idx+b] = CLIP(y + u1);
84 					idx += 3;
85 				}
86 				src_y += 16;
87 				if (i & 1)
88 					src_uv += 16;
89 			}
90 		}
91 	}
92 }
93 
v4lconvert_hm12_to_rgb24(const unsigned char * src,unsigned char * dest,int width,int height)94 void v4lconvert_hm12_to_rgb24(const unsigned char *src, unsigned char *dest,
95 		int width, int height)
96 {
97 	v4lconvert_hm12_to_rgb(src, dest, width, height, 1);
98 }
99 
v4lconvert_hm12_to_bgr24(const unsigned char * src,unsigned char * dest,int width,int height)100 void v4lconvert_hm12_to_bgr24(const unsigned char *src, unsigned char *dest,
101 		int width, int height)
102 {
103 	v4lconvert_hm12_to_rgb(src, dest, width, height, 0);
104 }
105 
de_macro_uv(unsigned char * dstu,unsigned char * dstv,const unsigned char * src,int w,int h)106 static void de_macro_uv(unsigned char *dstu, unsigned char *dstv,
107 		const unsigned char *src, int w, int h)
108 {
109 	unsigned int y, x, i, j;
110 
111 	for (y = 0; y < h; y += 16) {
112 		for (x = 0; x < w; x += 8) {
113 			const unsigned char *src_uv = src + y * stride + x * 32;
114 			int maxy = (h - y < 16 ? h - y : 16);
115 			int maxx = (w - x < 8 ? w - x : 8);
116 
117 			for (i = 0; i < maxy; i++) {
118 				int idx = x + (y + i) * w;
119 
120 				for (j = 0; j < maxx; j++) {
121 					dstu[idx+j] = src_uv[2 * j];
122 					dstv[idx+j] = src_uv[2 * j + 1];
123 				}
124 				src_uv += 16;
125 			}
126 		}
127 	}
128 }
129 
de_macro_y(unsigned char * dst,const unsigned char * src,int w,int h)130 static void de_macro_y(unsigned char *dst, const unsigned char *src,
131 		int w, int h)
132 {
133 	unsigned int y, x, i;
134 
135 	for (y = 0; y < h; y += 16) {
136 		for (x = 0; x < w; x += 16) {
137 			const unsigned char *src_y = src + y * stride + x * 16;
138 			int maxy = (h - y < 16 ? h - y : 16);
139 			int maxx = (w - x < 16 ? w - x : 16);
140 
141 			for (i = 0; i < maxy; i++) {
142 				memcpy(dst + x + (y + i) * w, src_y, maxx);
143 				src_y += 16;
144 			}
145 		}
146 	}
147 }
148 
v4lconvert_hm12_to_yuv420(const unsigned char * src,unsigned char * dest,int width,int height,int yvu)149 void v4lconvert_hm12_to_yuv420(const unsigned char *src, unsigned char *dest,
150 		int width, int height, int yvu)
151 {
152 	de_macro_y(dest, src, width, height);
153 	dest += width * height;
154 	src += stride * height;
155 	if (yvu)
156 		de_macro_uv(dest + width * height / 4, dest, src, width / 2, height / 2);
157 	else
158 		de_macro_uv(dest, dest + width * height / 4, src, width / 2, height / 2);
159 }
160