1/* 2 Colour conversion routines (RGB <-> YUV) in plain C 3 (C) 2000 Nemosoft Unv. nemosoft@smcc.demon.nl 4 (C) 2001 added 420p, LIMIT(x) jens@gecius.de 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19*/ 20 21 22#include "ccvt.h" 23 24#define PUSH_RGB24 1 25#define PUSH_BGR24 2 26#define PUSH_RGB32 3 27#define PUSH_BGR32 4 28 29/* this is a shameless copy from ov511.c to limit the resulting rgb-values 30 to [0..255]. 31*/ 32 33#define LIMIT(x) ( (x) > 0xffff ? 0xff : ( (x) <= 0xff ? 0 : ( (x) >> 8 ) ) ) 34 35/* This is a really simplistic approach. Speedups are welcomed. */ 36static void ccvt_420i(int width, int height, unsigned char *src, unsigned char *dst, int push) 37{ 38 int line, col, linewidth; 39 int y, u, v, yy, vr, ug, vg, ub; 40 int r, g, b; 41 unsigned char *py, *pu, *pv; 42 43 linewidth = width + (width >> 1); 44 py = src; 45 pu = py + 4; 46 pv = pu + linewidth; 47 48 y = *py; 49 yy = y << 8; 50 u = *pu - 128; 51 ug = 88 * u; 52 ub = 454 * u; 53 v = *pv - 128; 54 vg = 183 * v; 55 vr = 359 * v; 56 57 /* The biggest problem is the interlaced data, and the fact that odd 58 and even lines have V and U data, resp. 59 */ 60 for (line = 0; line < height; line++) { 61 for (col = 0; col < width; col++) { 62 r = LIMIT(yy + vr); 63 g = LIMIT(yy - ug - vg); 64 b = LIMIT(yy + ub ); 65 66 switch(push) { 67 case PUSH_RGB24: 68 *dst++ = r; 69 *dst++ = g; 70 *dst++ = b; 71 break; 72 73 case PUSH_BGR24: 74 *dst++ = b; 75 *dst++ = g; 76 *dst++ = r; 77 break; 78 79 case PUSH_RGB32: 80 *dst++ = r; 81 *dst++ = g; 82 *dst++ = b; 83 *dst++ = 0; 84 break; 85 86 case PUSH_BGR32: 87 *dst++ = b; 88 *dst++ = g; 89 *dst++ = r; 90 *dst++ = 0; 91 break; 92 } 93 94 y = *py++; 95 yy = y << 8; 96 if ((col & 3) == 3) 97 py += 2; // skip u/v 98 if (col & 1) { 99 if ((col & 3) == 3) { 100 pu += 4; // skip y 101 pv += 4; 102 } 103 else { 104 pu++; 105 pv++; 106 } 107 u = *pu - 128; 108 ug = 88 * u; 109 ub = 454 * u; 110 v = *pv - 128; 111 vg = 183 * v; 112 vr = 359 * v; 113 } 114 } /* ..for col */ 115 if (line & 1) { // odd line: go to next band 116 pu += linewidth; 117 pv += linewidth; 118 } 119 else { // rewind u/v pointers 120 pu -= linewidth; 121 pv -= linewidth; 122 } 123 } /* ..for line */ 124} 125 126void ccvt_420i_rgb24(int width, int height, void *src, void *dst) 127{ 128 ccvt_420i(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_RGB24); 129} 130 131void ccvt_420i_bgr24(int width, int height, void *src, void *dst) 132{ 133 ccvt_420i(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_BGR24); 134} 135 136void ccvt_420i_rgb32(int width, int height, void *src, void *dst) 137{ 138 ccvt_420i(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_RGB32); 139} 140 141void ccvt_420i_bgr32(int width, int height, void *src, void *dst) 142{ 143 ccvt_420i(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_BGR32); 144} 145 146 147/* This is a really simplistic approach. Speedups are welcomed. */ 148/* Derived this from the above 420i for 4:2:0 planar */ 149static void ccvt_420p(int width, int height, unsigned char *src, unsigned char *srcu, 150 unsigned char *srcv, unsigned char *dst, int push) 151{ 152 int line, col, linewidth; 153 int y, yy; 154 int u, v; 155 int vr, ug, vg, ub; 156 int r, g, b; 157 unsigned char *py, *pu, *pv; 158 159 linewidth = width - (width >> 1); 160 py = src; 161 pu = srcu; 162 pv = srcv; 163 164 y = *py; 165 yy = y << 8; 166 u = *pu - 128; 167 ug = 88 * u; 168 ub = 454 * u; 169 v = *pv - 128; 170 vg = 183 * v; 171 vr = 359 * v; 172 173 for (line = 0; line < height; line++) { 174 for (col = 0; col < width; col++) { 175 r = LIMIT(yy + vr); 176 g = LIMIT(yy - ug - vg); 177 b = LIMIT(yy + ub ); 178 switch(push) { 179 case PUSH_RGB24: 180 *dst++ = r; 181 *dst++ = g; 182 *dst++ = b; 183 break; 184 185 case PUSH_BGR24: 186 *dst++ = b; 187 *dst++ = g; 188 *dst++ = r; 189 break; 190 191 case PUSH_RGB32: 192 *dst++ = r; 193 *dst++ = g; 194 *dst++ = b; 195 *dst++ = 0; 196 break; 197 198 case PUSH_BGR32: 199 *dst++ = b; 200 *dst++ = g; 201 *dst++ = r; 202 *dst++ = 0; 203 break; 204 } 205 206 y = *py++; 207 yy = y << 8; 208 if ( (col & 1) == 1) { 209 pu++; // increase u/v every second y 210 pv++; 211 } 212 u = *pu - 128; 213 ug = 88 * u; 214 ub = 454 * u; 215 v = *pv - 128; 216 vg = 183 * v; 217 vr = 359 * v; 218 } // ..for col 219 if ( line & 1 ) { // even line: rewind u/v 220 pu -= linewidth; 221 pv -= linewidth; 222 } 223 } /* ..for line */ 224} 225 226void ccvt_420p_rgb24(int width, int height, void *src, void *srcu, void *srcv, void *dst) 227{ 228 ccvt_420p(width, height, (unsigned char *)src, (unsigned char *)srcu, 229 (unsigned char *)srcv, (unsigned char *)dst, PUSH_RGB24); 230} 231 232void ccvt_420p_bgr24(int width, int height, void *src, void *srcu, void *srcv, void *dst) 233{ 234 ccvt_420p(width, height, (unsigned char *)src, (unsigned char *)srcu, 235 (unsigned char *)srcv, (unsigned char *)dst, PUSH_BGR24); 236} 237 238void ccvt_420p_rgb32(int width, int height, void *src, void *srcu, void *srcv, void *dst) 239{ 240 ccvt_420p(width, height, (unsigned char *)src, (unsigned char *)srcu, 241 (unsigned char *)srcv, (unsigned char *)dst, PUSH_RGB32); 242} 243 244void ccvt_420p_bgr32(int width, int height, void *src, void *srcu, void *srcv, void *dst) 245{ 246 ccvt_420p(width, height, (unsigned char *)src, (unsigned char *)srcu, 247 (unsigned char *)srcv, (unsigned char *)dst, PUSH_BGR32); 248} 249 250 251/* This is a really simplistic approach. Speedups are welcomed. */ 252/* Derived this from the above 4:2:0 planar for yuyv */ 253/* Format: YUYV YUYV YUYV YUYV... */ 254static void ccvt_yuyv(int width, int height, unsigned char *src, unsigned char *dst, int push) 255{ 256 int line, col, linewidth; 257 int y, yy; 258 int u, v; 259 int vr, ug, vg, ub; 260 int r, g, b; 261 unsigned char *py, *pu, *pv; 262 263 linewidth = width - (width >> 1); 264 py = src; 265 pu = src + 1; 266 pv = src + 3; 267 268 y = *py; 269 yy = y << 8; 270 u = *pu - 128; 271 ug = 88 * u; 272 ub = 454 * u; 273 v = *pv - 128; 274 vg = 183 * v; 275 vr = 359 * v; 276 277 for (line = 0; line < height; line++) { 278 for (col = 0; col < width; col++) { 279 r = LIMIT(yy + vr); 280 g = LIMIT(yy - ug - vg); 281 b = LIMIT(yy + ub ); 282 switch(push) { 283 case PUSH_RGB24: 284 *dst++ = r; 285 *dst++ = g; 286 *dst++ = b; 287 break; 288 289 case PUSH_BGR24: 290 *dst++ = b; 291 *dst++ = g; 292 *dst++ = r; 293 break; 294 295 case PUSH_RGB32: 296 *dst++ = r; 297 *dst++ = g; 298 *dst++ = b; 299 *dst++ = 0; 300 break; 301 302 case PUSH_BGR32: 303 *dst++ = b; 304 *dst++ = g; 305 *dst++ = r; 306 *dst++ = 0; 307 break; 308 } 309 310 py += 2; 311 y = *py; 312 yy = y << 8; 313 if ( (col & 1) == 1) { 314 pu += 4; // skip yvy every second y 315 pv += 4; // skip yuy every second y 316 } 317 u = *pu - 128; 318 ug = 88 * u; 319 ub = 454 * u; 320 v = *pv - 128; 321 vg = 183 * v; 322 vr = 359 * v; 323 } // ..for col 324 } /* ..for line */ 325} 326 327void ccvt_yuyv_rgb24(int width, int height, void *src, void *dst) 328{ 329 ccvt_yuyv(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_RGB24); 330} 331 332void ccvt_yuyv_bgr24(int width, int height, void *src, void *dst) 333{ 334 ccvt_yuyv(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_BGR24); 335} 336 337void ccvt_yuyv_rgb32(int width, int height, void *src, void *dst) 338{ 339 ccvt_yuyv(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_RGB32); 340} 341 342void ccvt_yuyv_bgr32(int width, int height, void *src, void *dst) 343{ 344 ccvt_yuyv(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_BGR32); 345} 346 347 348void ccvt_420i_420p(int width, int height, void *src, void *dsty, void *dstu, void *dstv) 349{ 350 short *s, *dy, *du, *dv; 351 int line, col; 352 353 s = (short *)src; 354 dy = (short *)dsty; 355 du = (short *)dstu; 356 dv = (short *)dstv; 357 for (line = 0; line < height; line++) { 358 for (col = 0; col < width; col += 4) { 359 *dy++ = *s++; 360 *dy++ = *s++; 361 if (line & 1) 362 *dv++ = *s++; 363 else 364 *du++ = *s++; 365 } /* ..for col */ 366 } /* ..for line */ 367} 368 369void ccvt_420i_yuyv(int width, int height, void *src, void *dst) 370{ 371 int line, col, linewidth; 372 unsigned char *py, *pu, *pv, *d; 373 374 linewidth = width + (width >> 1); 375 py = (unsigned char *)src; 376 pu = src + 4; 377 pv = pu + linewidth; 378 d = (unsigned char *)dst; 379 380 for (line = 0; line < height; line++) { 381 for (col = 0; col < width; col += 4) { 382 /* four pixels in one go */ 383 *d++ = *py++; 384 *d++ = *pu++; 385 *d++ = *py++; 386 *d++ = *pv++; 387 388 *d++ = *py++; 389 *d++ = *pu++; 390 *d++ = *py++; 391 *d++ = *pv++; 392 393 py += 2; 394 pu += 4; 395 pv += 4; 396 } /* ..for col */ 397 if (line & 1) { // odd line: go to next band 398 pu += linewidth; 399 pv += linewidth; 400 } 401 else { // rewind u/v pointers 402 pu -= linewidth; 403 pv -= linewidth; 404 } 405 } /* ..for line */ 406} 407 408