00001 /*
00002 Colour conversion routines (RGB <-> YUV) in plain C
00003 (C) 2000 Nemosoft Unv. nemosoft@smcc.demon.nl
00004
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013 GNU General Public License for more details.
00014
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018 */
00019
00020
00021 #include "ccvt.h"
00022
00023 #define PUSH_RGB24 1
00024 #define PUSH_BGR24 2
00025 #define PUSH_RGB32 3
00026 #define PUSH_BGR32 4
00027
00028 /* This is a really simplistic approach. Speedups are welcomed. */
00029 static void ccvt_420i(int width, int height, unsigned char *src, unsigned char *dst, int push)
00030 {
00031 int line, col, linewidth;
00032 int y, u, v, yy, vr, ug, vg, ub;
00033 int r, g, b;
00034 unsigned char *py, *pu, *pv;
00035
00036 linewidth = width + (width >> 1);
00037 py = src;
00038 pu = py + 4;
00039 pv = pu + linewidth;
00040
00041 y = *py++;
00042 yy = y << 8;
00043 u = *pu - 128;
00044 ug = 88 * u;
00045 ub = 454 * u;
00046 v = *pv - 128;
00047 vg = 183 * v;
00048 vr = 359 * v;
00049
00050 /* The biggest problem is the interlaced data, and the fact that odd
00051 add even lines have V and U data, resp.
00052 */
00053 for (line = 0; line < height; line++) {
00054 for (col = 0; col < width; col++) {
00055 r = (yy + vr) >> 8;
00056 g = (yy - ug - vg) >> 8;
00057 b = (yy + ub ) >> 8;
00058
00059 switch(push) {
00060 case PUSH_RGB24:
00061 *dst++ = r;
00062 *dst++ = g;
00063 *dst++ = b;
00064 break;
00065
00066 case PUSH_BGR24:
00067 *dst++ = b;
00068 *dst++ = g;
00069 *dst++ = r;
00070 break;
00071
00072 case PUSH_RGB32:
00073 *dst++ = r;
00074 *dst++ = g;
00075 *dst++ = b;
00076 *dst++ = 0;
00077 break;
00078
00079 case PUSH_BGR32:
00080 *dst++ = b;
00081 *dst++ = g;
00082 *dst++ = r;
00083 *dst++ = 0;
00084 break;
00085 }
00086
00087 y = *py++;
00088 yy = y << 8;
00089 if ((col & 3) == 3)
00090 py += 2; // skip u/v
00091 if (col & 1) {
00092 if ((col & 3) == 3) {
00093 pu += 4; // skip y
00094 pv += 4;
00095 }
00096 else {
00097 pu++;
00098 pv++;
00099 }
00100 u = *pu - 128;
00101 ug = 88 * u;
00102 ub = 454 * u;
00103 v = *pv - 128;
00104 vg = 183 * v;
00105 vr = 359 * v;
00106 }
00107 } /* ..for col */
00108 if (line & 1) { // odd line: go to next band
00109 pu += linewidth;
00110 pv += linewidth;
00111 }
00112 else { // rewind u/v pointers
00113 pu -= linewidth;
00114 pv -= linewidth;
00115 }
00116 } /* ..for line */
00117 }
00118
00119 void ccvt_420i_rgb24(int width, int height, void *src, void *dst)
00120 {
00121 ccvt_420i(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_RGB24);
00122 }
00123
00124 void ccvt_420i_bgr24(int width, int height, void *src, void *dst)
00125 {
00126 ccvt_420i(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_BGR24);
00127 }
00128
00129 void ccvt_420i_rgb32(int width, int height, void *src, void *dst)
00130 {
00131 ccvt_420i(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_RGB32);
00132 }
00133
00134 void ccvt_420i_bgr32(int width, int height, void *src, void *dst)
00135 {
00136 ccvt_420i(width, height, (unsigned char *)src, (unsigned char *)dst, PUSH_BGR32);
00137 }
00138
00139
00140 void ccvt_420i_420p(int width, int height, void *src, void *dsty, void *dstu, void *dstv)
00141 {
00142 short *s, *dy, *du, *dv;
00143 int line, col;
00144
00145 s = (short *)src;
00146 dy = (short *)dsty;
00147 du = (short *)dstu;
00148 dv = (short *)dstv;
00149 for (line = 0; line < height; line++) {
00150 for (col = 0; col < width; col += 4) {
00151 *dy++ = *s++;
00152 *dy++ = *s++;
00153 if (line & 1)
00154 *dv++ = *s++;
00155 else
00156 *du++ = *s++;
00157 } /* ..for col */
00158 } /* ..for line */
00159 }
00160
00161 void ccvt_420i_yuyv(int width, int height, void *src, void *dst)
00162 {
00163 int line, col, linewidth;
00164 unsigned char *py, *pu, *pv, *d;
00165
00166 linewidth = width + (width >> 1);
00167 py = (unsigned char *)src;
00168 pu = src + 4;
00169 pv = pu + linewidth;
00170 d = (unsigned char *)dst;
00171
00172 for (line = 0; line < height; line++) {
00173 for (col = 0; col < width; col += 4) {
00174 /* four pixels in one go */
00175 *d++ = *py++;
00176 *d++ = *pu++;
00177 *d++ = *py++;
00178 *d++ = *pv++;
00179
00180 *d++ = *py++;
00181 *d++ = *pu++;
00182 *d++ = *py++;
00183 *d++ = *pv++;
00184
00185 py += 2;
00186 pu += 4;
00187 pv += 4;
00188 } /* ..for col */
00189 if (line & 1) { // odd line: go to next band
00190 pu += linewidth;
00191 pv += linewidth;
00192 }
00193 else { // rewind u/v pointers
00194 pu -= linewidth;
00195 pv -= linewidth;
00196 }
00197 } /* ..for line */
00198 }
00199
1.2.8.1 written by Dimitri van Heesch,
© 1997-2001