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