00001 #include "osdsurface.h"
00002 #include "dithertable.h"
00003 #include "mythcontext.h"
00004 #include "compat.h"
00005
00006 #include <algorithm>
00007 using namespace std;
00008
00009 #ifdef MMX
00010
00011 extern "C" {
00012 #include "config.h"
00013 #include "dsputil.h"
00014 #include "i386/mmx.h"
00015 }
00016
00017 #endif
00018
00019 OSDSurface::OSDSurface(int w, int h)
00020 {
00021 yuvbuffer = new unsigned char[w * (h + 2) * 3 / 2];
00022 y = yuvbuffer;
00023 u = yuvbuffer + w * h;
00024 v = u + w * h / 4;
00025 alpha = new unsigned char[w * (h + 2)];
00026
00027 width = w;
00028 height = h;
00029
00030 size = width * height;
00031
00032 for (int i = 0; i < 256; i++)
00033 {
00034 for (int j = 0; j < 256; j++)
00035 {
00036 int divisor = (i + (j * (255 - i)) / 255);
00037 if (divisor > 0)
00038 pow_lut[i][j] = (i * 255) / divisor;
00039 else
00040 pow_lut[i][j] = 0;
00041 }
00042 }
00043
00044 for (int i = 0; i < 256; i++)
00045 cropTbl[i + MAX_NEG_CROP] = i;
00046 for (int i = 0; i < MAX_NEG_CROP; i++)
00047 {
00048 cropTbl[i] = 0;
00049 cropTbl[i + MAX_NEG_CROP + 256] = 255;
00050 }
00051
00052 cm = cropTbl + MAX_NEG_CROP;
00053
00054 Clear();
00055
00056 usemmx = false;
00057
00058 blendregionfunc = &blendregion;
00059 blendcolumn2func = &blendcolumn2;
00060 blendcolumnfunc = &blendcolumn;
00061 blendcolorfunc = &blendcolor;
00062 blendconstfunc = &blendconst;
00063 #if defined(MMX)
00064 usemmx = (mm_support() & MM_MMX);
00065 if (usemmx)
00066 {
00067 rec_lut[0] = 0;
00068 for (int i = 1; i < 256; i++)
00069 rec_lut[i] = ((255 << 7) + (i >> 1)) / i;
00070 blendregionfunc = &blendregion_mmx;
00071 blendcolumn2func = &blendcolumn2_mmx;
00072 blendcolumnfunc = &blendcolumn_mmx;
00073 blendcolorfunc = &blendcolor_mmx;
00074 blendconstfunc = &blendconst_mmx;
00075 }
00076 #endif
00077 revision = 0;
00078 }
00079
00080 OSDSurface::~OSDSurface()
00081 {
00082 delete [] yuvbuffer;
00083 delete [] alpha;
00084 }
00085
00086 void OSDSurface::Clear(void)
00087 {
00088 QMutexLocker lock(&usedRegionsLock);
00089 memset(y, 0, size);
00090 memset(u, 127, size / 4);
00091 memset(v, 127, size / 4);
00092 memset(alpha, 0, size);
00093 usedRegions = QRegion();
00094 }
00095
00096 void OSDSurface::ClearUsed(void)
00097 {
00098 QMutexLocker lock(&usedRegionsLock);
00099 QMemArray<QRect> rects = usedRegions.rects();
00100 QMemArray<QRect>::Iterator it = rects.begin();
00101 QRect drawRect;
00102 int startcol, startline, endcol, endline, cwidth, uvcwidth;
00103 int yoffset;
00104
00105 for (; it != rects.end(); ++it)
00106 {
00107 drawRect = *it;
00108
00109 startcol = drawRect.left();
00110 startline = drawRect.top();
00111 endcol = drawRect.right();
00112 endline = drawRect.bottom();
00113
00114 cwidth = drawRect.width();
00115 uvcwidth = cwidth / 2;
00116
00117 if (startline < 0) startline = 0;
00118 if (endline >= height) endline = height - 1;
00119 if (startcol < 0) endcol = 0;
00120 if (endcol >= width) endcol = width - 1;
00121
00122 for (int line = startline; line <= endline; line++)
00123 {
00124 yoffset = line * width;
00125
00126 memset(y + yoffset + startcol, 0, cwidth);
00127 memset(alpha + yoffset + startcol, 0, cwidth);
00128
00129 {
00130 memset(u + yoffset / 4 + startcol / 2, 127, uvcwidth);
00131 memset(v + yoffset / 4 + startcol / 2, 127, uvcwidth);
00132 }
00133 }
00134 }
00135
00136 usedRegions = QRegion();
00137 }
00138
00139 bool OSDSurface::IsClear(void)
00140 {
00141 return (usedRegions == QRegion());
00142 }
00143
00144 bool OSDSurface::IntersectsDrawn(QRect &newrect)
00145 {
00146 QMutexLocker lock(&usedRegionsLock);
00147 QMemArray<QRect> rects = usedRegions.rects();
00148 QMemArray<QRect>::Iterator it = rects.begin();
00149 for (; it != rects.end(); ++it)
00150 if (newrect.intersects(*it))
00151 return true;
00152 return false;
00153 }
00154
00155 void OSDSurface::AddRect(QRect &newrect)
00156 {
00157 QMutexLocker lock(&usedRegionsLock);
00158 usedRegions = usedRegions.unite(newrect);
00159 }
00160
00162
00164
00165 static inline void blendalpha8_c(unsigned char *src, unsigned char *dest,
00166 unsigned char *alpha, bool uvplane)
00167 {
00168 int mult = uvplane ? 2 : 1;
00169
00170 for (int i = 0; i < 8; i++)
00171 dest[i] = blendColorsAlpha(src[i], dest[i], alpha[i * mult]);
00172 }
00173
00174 #ifdef MMX
00175
00176 static inline void blendalpha8_mmx(unsigned char *src, unsigned char *dest,
00177 unsigned char *alpha, bool uvplane)
00178 {
00179 static mmx_t mmx_80w = {0x0080008000800080LL};
00180 static mmx_t mmx_fs = {0xffffffffffffffffLL};
00181 static mmx_t mmx_ff00 = {0x00ff00ff00ff00ffLL};
00182
00183 movq_m2r(*dest, mm0);
00184 movq_r2r(mm0, mm1);
00185 movq_m2r(mmx_fs, mm2);
00186 movq_m2r(mmx_80w, mm4);
00187 pxor_r2r(mm7, mm7);
00188
00189 if (uvplane)
00190 {
00191 movq_m2r(*alpha, mm5);
00192 movq_m2r(*(alpha+8), mm6);
00193
00194 pand_m2r(mmx_ff00, mm5);
00195 pand_m2r(mmx_ff00, mm6);
00196
00197 packuswb_r2r(mm6, mm5);
00198 }
00199 else
00200 movq_m2r(*alpha, mm5);
00201
00202 psubw_r2r(mm5, mm2);
00203 punpcklbw_r2r(mm7, mm0);
00204 punpckhbw_r2r(mm7, mm1);
00205
00206 movq_r2r(mm2, mm3);
00207 punpcklbw_r2r(mm7, mm2);
00208 punpckhbw_r2r(mm7, mm3);
00209
00210 pmullw_r2r(mm2, mm0);
00211 pmullw_r2r(mm3, mm1);
00212
00213 paddw_r2r(mm4, mm0);
00214 paddw_r2r(mm4, mm1);
00215
00216 movq_r2r(mm0, mm2);
00217 movq_r2r(mm1, mm3);
00218
00219 psrlw_i2r(8, mm0);
00220 psrlw_i2r(8, mm1);
00221
00222 paddw_r2r(mm2, mm0);
00223 paddw_r2r(mm3, mm1);
00224
00225 psrlw_i2r(8, mm0);
00226 psrlw_i2r(8, mm1);
00227
00228 movq_m2r(*src, mm2);
00229 movq_r2r(mm2, mm3);
00230
00231 punpcklbw_r2r(mm7, mm2);
00232 punpckhbw_r2r(mm7, mm3);
00233
00234 movq_r2r(mm5, mm6);
00235
00236 punpcklbw_r2r(mm7, mm5);
00237 punpckhbw_r2r(mm7, mm6);
00238
00239 pmullw_r2r(mm5, mm2);
00240 pmullw_r2r(mm6, mm3);
00241
00242 paddw_r2r(mm4, mm2);
00243 paddw_r2r(mm4, mm3);
00244
00245 movq_r2r(mm2, mm4);
00246 movq_r2r(mm3, mm5);
00247
00248 psrlw_i2r(8, mm2);
00249 psrlw_i2r(8, mm3);
00250
00251 paddw_r2r(mm4, mm2);
00252 paddw_r2r(mm5, mm3);
00253
00254 psrlw_i2r(8, mm2);
00255 psrlw_i2r(8, mm3);
00256
00257 paddw_r2r(mm2, mm0);
00258 paddw_r2r(mm3, mm1);
00259
00260 packuswb_r2r(mm1, mm0);
00261
00262 movq_r2m(mm0, *dest);
00263
00264 emms();
00265 }
00266 #endif
00267
00268 blendtoyv12_8_fun blendtoyv12_8_init(const OSDSurface *surface)
00269 {
00270 (void)surface;
00271 #ifdef MMX
00272 if (surface->usemmx)
00273 return blendalpha8_mmx;
00274 #endif
00275 return blendalpha8_c;
00276 }
00277
00278 static inline void blendtoargb_8_c(const OSDSurface *surf, unsigned char *src,
00279 unsigned char *usrc, unsigned char *vsrc,
00280 unsigned char *alpha, unsigned char *dest)
00281 {
00282 int r, g, b, y0;
00283 int cb, cr, r_add, g_add, b_add;
00284 const unsigned char *cm = surf->cm;
00285
00286 int i, j;
00287
00288 for (i = 0, j = 0; i < 8; i++)
00289 {
00290 YUV_TO_RGB1(usrc[j], vsrc[j]);
00291 YUV_TO_RGB2(r, g, b, src[i]);
00292 RGBA_OUT(&(dest[i * 4]), r, g, b, alpha[i]);
00293 if (i % 2 == 0)
00294 j++;
00295 }
00296 }
00297
00298 #ifdef MMX
00299 #define movntq(src, dest) movq_r2m(src, dest);
00300 static inline void blendtoargb_8_mmx(const OSDSurface * , unsigned char *src,
00301 unsigned char *usrc, unsigned char *vsrc,
00302 unsigned char *alpha, unsigned char *dest)
00303 {
00304 static mmx_t mmx_80w = {0x0080008000800080LL};
00305 static mmx_t mmx_U_green = {0xf37df37df37df37dLL};
00306 static mmx_t mmx_U_blue = {0x4093409340934093LL};
00307 static mmx_t mmx_V_red = {0x3312331233123312LL};
00308 static mmx_t mmx_V_green = {0xe5fce5fce5fce5fcLL};
00309 static mmx_t mmx_10w = {0x1010101010101010LL};
00310 static mmx_t mmx_00ffw = {0x00ff00ff00ff00ffLL};
00311 static mmx_t mmx_Y_coeff = {0x253f253f253f253fLL};
00312
00313 movd_m2r(*usrc, mm0);
00314 movd_m2r(*vsrc, mm1);
00315 movq_m2r(*src, mm6);
00316 pxor_r2r(mm4, mm4);
00317
00318 punpcklbw_r2r(mm4, mm0);
00319 punpcklbw_r2r(mm4, mm1);
00320 psubsw_m2r(mmx_80w, mm0);
00321 psubsw_m2r(mmx_80w, mm1);
00322 psllw_i2r(3, mm0);
00323 psllw_i2r(3, mm1);
00324 movq_r2r(mm0, mm2);
00325 movq_r2r(mm1, mm3);
00326 pmulhw_m2r(mmx_U_green, mm2);
00327 pmulhw_m2r(mmx_V_green, mm3);
00328 pmulhw_m2r(mmx_U_blue, mm0);
00329 pmulhw_m2r(mmx_V_red, mm1);
00330 paddsw_r2r(mm3, mm2);
00331
00332 psubusb_m2r(mmx_10w, mm6);
00333 movq_r2r(mm6, mm7);
00334 pand_m2r(mmx_00ffw, mm6);
00335 psrlw_i2r(8, mm7);
00336 psllw_i2r(3, mm6);
00337 psllw_i2r(3, mm7);
00338 pmulhw_m2r(mmx_Y_coeff, mm6);
00339 pmulhw_m2r(mmx_Y_coeff, mm7);
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349 movq_r2r(mm0, mm3);
00350 movq_r2r(mm1, mm4);
00351 movq_r2r(mm2, mm5);
00352 paddsw_r2r(mm6, mm0);
00353 paddsw_r2r(mm7, mm3);
00354 paddsw_r2r(mm6, mm1);
00355 paddsw_r2r(mm7, mm4);
00356 paddsw_r2r(mm6, mm2);
00357 paddsw_r2r(mm7, mm5);
00358 packuswb_r2r(mm0, mm0);
00359 packuswb_r2r(mm1, mm1);
00360 packuswb_r2r(mm2, mm2);
00361 packuswb_r2r(mm3, mm3);
00362 packuswb_r2r(mm4, mm4);
00363 packuswb_r2r(mm5, mm5);
00364 punpcklbw_r2r(mm3, mm0);
00365 punpcklbw_r2r(mm4, mm1);
00366 punpcklbw_r2r(mm5, mm2);
00367
00368 movq_m2r(*alpha, mm3);
00369
00370 movq_r2r(mm0, mm6);
00371 movq_r2r(mm1, mm7);
00372 movq_r2r(mm0, mm4);
00373 movq_r2r(mm1, mm5);
00374 punpcklbw_r2r(mm2, mm6);
00375 punpcklbw_r2r(mm3, mm7);
00376 punpcklwd_r2r(mm7, mm6);
00377 movntq(mm6, *dest);
00378 movq_r2r(mm0, mm6);
00379 punpcklbw_r2r(mm2, mm6);
00380 punpckhwd_r2r(mm7, mm6);
00381 movntq(mm6, *(dest+8));
00382 punpckhbw_r2r(mm2, mm4);
00383 punpckhbw_r2r(mm3, mm5);
00384 punpcklwd_r2r(mm5, mm4);
00385 movntq(mm4, *(dest+16));
00386 movq_r2r(mm0, mm4);
00387 punpckhbw_r2r(mm2, mm4);
00388 punpckhwd_r2r(mm5, mm4);
00389 movntq(mm4, *(dest+24));
00390
00391 emms();
00392 }
00393 #endif
00394
00395 blendtoargb_8_fun blendtoargb_8_init(const OSDSurface *surface)
00396 {
00397 (void)surface;
00398 #ifdef MMX
00399 if (surface->usemmx)
00400 return blendtoargb_8_mmx;
00401 #endif
00402 return blendtoargb_8_c;
00403 }
00404
00405 struct dither8_context
00406 {
00407 int ashift;
00408 int amask;
00409 int ishift;
00410 int imask;
00411 #ifdef MMX
00412 mmx_t amask_mmx;
00413 mmx_t imask_mmx;
00414 #endif
00415 };
00416
00417 static inline void dithertoia44_8_c(unsigned char *src, unsigned char *dest,
00418 unsigned char *alpha,
00419 const unsigned char *dmp, int xpos,
00420 dither8_context *context)
00421 {
00422 int grey;
00423 for (int i = 0; i < 8; i++)
00424 {
00425 grey = src[i] + ((dmp[((xpos + i) & (DM_WIDTH - 1))] << 2) >> 4);
00426 grey = (grey - (grey >> 4)) >> 4;
00427
00428 dest[i] = (((alpha[i] >> 4) << context->ashift) & context->amask) |
00429 (((grey) << context->ishift) & context->imask);
00430 }
00431 }
00432
00433 #ifdef MMX
00434 static inline void dithertoia44_8_mmx(unsigned char *src, unsigned char *dest,
00435 unsigned char *alpha,
00436 const unsigned char *dmp, int xpos,
00437 dither8_context *context)
00438 {
00439 unsigned char tmp2[8];
00440
00441 dithertoia44_8_c(src, tmp2, alpha, dmp, xpos, context);
00442
00443 unsigned char tmp[8];
00444
00445 tmp[0] = dmp[((xpos+0) & (DM_WIDTH - 1))];
00446 tmp[1] = dmp[((xpos+1) & (DM_WIDTH - 1))];
00447 tmp[2] = dmp[((xpos+2) & (DM_WIDTH - 1))];
00448 tmp[3] = dmp[((xpos+3) & (DM_WIDTH - 1))];
00449 tmp[4] = dmp[((xpos+4) & (DM_WIDTH - 1))];
00450 tmp[5] = dmp[((xpos+5) & (DM_WIDTH - 1))];
00451 tmp[6] = dmp[((xpos+6) & (DM_WIDTH - 1))];
00452 tmp[7] = dmp[((xpos+7) & (DM_WIDTH - 1))];
00453
00454 movq_m2r(*src, mm0);
00455 movq_r2r(mm0, mm1);
00456 movq_m2r(*tmp, mm2);
00457 movq_r2r(mm2, mm3);
00458 movq_m2r(*alpha, mm4);
00459 movq_m2r(context->amask_mmx, mm5);
00460 movq_m2r(context->imask_mmx, mm6);
00461
00462 pxor_r2r(mm7, mm7);
00463
00464 punpcklbw_r2r(mm7, mm0);
00465 punpckhbw_r2r(mm7, mm1);
00466
00467 punpcklbw_r2r(mm7, mm2);
00468 punpckhbw_r2r(mm7, mm3);
00469
00470 psllw_i2r(2, mm2);
00471 psllw_i2r(2, mm3);
00472
00473 psrlw_i2r(4, mm2);
00474 psrlw_i2r(4, mm3);
00475
00476 paddw_r2r(mm0, mm2);
00477 paddw_r2r(mm1, mm3);
00478
00479 movq_r2r(mm2, mm0);
00480 movq_r2r(mm3, mm1);
00481
00482 psrlw_i2r(4, mm0);
00483 psrlw_i2r(4, mm1);
00484
00485 psubw_r2r(mm0, mm2);
00486 psubw_r2r(mm1, mm3);
00487
00488 psrlw_i2r(4, mm2);
00489 psrlw_i2r(4, mm3);
00490
00491 packuswb_r2r(mm3, mm2);
00492
00493 psllw_i2r(4, mm2);
00494
00495 pand_r2r(mm6, mm2);
00496
00497 psrlw_i2r(4, mm4);
00498
00499 psllw_i2r(0, mm4);
00500
00501 pand_r2r(mm5, mm4);
00502
00503 por_r2r(mm4, mm2);
00504
00505 movq_r2m(mm2, *dest);
00506
00507 emms();
00508 }
00509 #endif
00510
00511 dithertoia44_8_fun dithertoia44_8_init(const OSDSurface* )
00512 {
00513 #ifdef MMX
00514
00515
00516
00517 #endif
00518 return dithertoia44_8_c;
00519 }
00520
00521 #ifdef MMX
00522 static mmx_t mask_0f = {0x0f0f0f0f0f0f0f0fLL};
00523 static mmx_t mask_f0 = {0xf0f0f0f0f0f0f0f0LL};
00524 #endif
00525
00526 dither8_context *init_dithertoia44_8_context(bool first)
00527 {
00528 dither8_context *context = new dither8_context;
00529 if (first)
00530 {
00531 context->ashift = 0;
00532 context->amask = 0x0f;
00533 context->ishift = 4;
00534 context->imask = 0xf0;
00535 #ifdef MMX
00536 context->amask_mmx = mask_0f;
00537 context->imask_mmx = mask_f0;
00538 #endif
00539 }
00540 else
00541 {
00542 context->ashift = 4;
00543 context->amask = 0xf0;
00544 context->ishift = 0;
00545 context->imask = 0x0f;
00546 #ifdef MMX
00547 context->amask_mmx = mask_f0;
00548 context->imask_mmx = mask_0f;
00549 #endif
00550 }
00551
00552 return context;
00553 }
00554
00555 void delete_dithertoia44_8_context(dither8_context *context)
00556 {
00557 delete context;
00558 }
00559
00566 void OSDSurface::BlendToYV12(unsigned char *yptrdest,
00567 unsigned char *uptrdest,
00568 unsigned char *vptrdest,
00569 int ystride, int ustride, int vstride) const
00570 {
00571 QMutexLocker lock(&usedRegionsLock);
00572 const OSDSurface *surface = this;
00573 blendtoyv12_8_fun blender = blendtoyv12_8_init(surface);
00574
00575 QMemArray<QRect> rects = surface->usedRegions.rects();
00576 QMemArray<QRect>::Iterator it = rects.begin();
00577 for (; it != rects.end(); ++it)
00578 {
00579 int begx = max((*it).left(), 0);
00580 int begy = max((*it).top(), 0);
00581 int endx = min((*it).right(), width - 1);
00582 int endy = min((*it).bottom(), height - 1);
00583
00584 for (int y = begy; y <= endy; y++)
00585 {
00586 int ysrcoff = y * surface->width;
00587 int ydstoff = y * ystride;
00588
00589 unsigned char *src = surface->y + ysrcoff + begx;
00590 unsigned char *alpha = surface->alpha + ysrcoff + begx;
00591 unsigned char *dest = yptrdest + ydstoff + begx;
00592
00593 for (int x = begx; x <= endx;)
00594 {
00595 if (x + 8 >= endx)
00596 {
00597 if (*alpha != 0)
00598 *dest = blendColorsAlpha(*src, *dest, *alpha);
00599 src++;
00600 dest++;
00601 alpha++;
00602 x++;
00603 }
00604 else
00605 {
00606 blender(src, dest, alpha, false);
00607 src += 8;
00608 dest += 8;
00609 alpha += 8;
00610 x += 8;
00611 }
00612 }
00613
00614 if ((y & 1) == 1)
00615 continue;
00616
00617 int uvbegx = begx >> 1;
00618 int uvsrcoff = (y >> 1) * (surface->width >> 1);
00619 int udestoff = (y >> 1) * ustride;
00620 int vdestoff = (y >> 1) * vstride;
00621
00622 unsigned char *usrc = surface->u + uvsrcoff + uvbegx;
00623 unsigned char *udest = uptrdest + udestoff + uvbegx;
00624 unsigned char *vsrc = surface->v + uvsrcoff + uvbegx;
00625 unsigned char *vdest = vptrdest + vdestoff + uvbegx;
00626
00627 for (int x = begx; x <= endx;)
00628 {
00629 alpha = surface->alpha + ysrcoff + x;
00630 if (x + 16 >= endx)
00631 {
00632 if (*alpha != 0)
00633 {
00634 *udest = blendColorsAlpha(*usrc, *udest, *alpha);
00635 *vdest = blendColorsAlpha(*vsrc, *vdest, *alpha);
00636 }
00637
00638 usrc++;
00639 udest++;
00640 vsrc++;
00641 vdest++;
00642 x += 2;
00643 }
00644 else
00645 {
00646 blender(usrc, udest, alpha, true);
00647 blender(vsrc, vdest, alpha, true);
00648 usrc += 8;
00649 udest += 8;
00650 vsrc += 8;
00651 vdest += 8;
00652 x += 16;
00653 }
00654 }
00655 }
00656 }
00657 }
00658
00659 static void BlendToBlack(unsigned char *argbptr, uint width, uint outheight)
00660 {
00661 unsigned int i, argb, a, r, g, b;
00662 for (i = 0; i < width * outheight; i++)
00663 {
00664 argb = ((uint*)argbptr)[i];
00665 a = (argb >> 24);
00666 if (argb && a < 250)
00667 {
00668 r = (argb >> 16) & 0xff;
00669 g = (argb >> 8) & 0xff;
00670 b = (argb) & 0xff;
00671
00672 RGBA_OUT(&argbptr[i * 4], (a * r) >> 8, (a * g) >> 8,
00673 (a * b) >> 8, 128);
00674 }
00675 }
00676 }
00677
00690 void OSDSurface::BlendToARGB(unsigned char *argbptr, uint stride,
00691 uint outheight, bool blend_to_black,
00692 uint threshold) const
00693 {
00694 QMutexLocker lock(&usedRegionsLock);
00695 const OSDSurface *surface = this;
00696 blendtoargb_8_fun blender = blendtoargb_8_init(surface);
00697 const unsigned char *cm = surface->cm;
00698
00699 if (blend_to_black)
00700 bzero(argbptr, stride * outheight);
00701
00702 QMemArray<QRect> rects = surface->usedRegions.rects();
00703 QMemArray<QRect>::Iterator it = rects.begin();
00704 for (; it != rects.end(); ++it)
00705 {
00706 QRect drawRect = *it;
00707
00708 int startcol = std::max(drawRect.left(), 0);
00709 int startline = std::max(drawRect.top(), 0);
00710 int endcol = std::min(drawRect.right(), width - 1);
00711 int endline = std::min(drawRect.bottom(), height - 1);
00712
00713 unsigned char *src, *usrcbase, *vsrcbase, *usrc, *vsrc;
00714 unsigned char *dest;
00715 unsigned char *alpha;
00716
00717 int yoffset;
00718 int destyoffset;
00719
00720 int cb, cr, r_add, g_add, b_add;
00721 int r, g, b, y0;
00722
00723 for (int y = startline; y <= endline; y++)
00724 {
00725 yoffset = y * surface->width;
00726 destyoffset = y * stride;
00727
00728 src = surface->y + yoffset + startcol;
00729 dest = argbptr + destyoffset + startcol * 4;
00730 alpha = surface->alpha + yoffset + startcol;
00731
00732 usrcbase = surface->u + (y / 2) * (surface->width / 2);
00733 vsrcbase = surface->v + (y / 2) * (surface->width / 2);
00734
00735 for (int x = startcol; x <= endcol; x++)
00736 {
00737 usrc = usrcbase + x / 2;
00738 vsrc = vsrcbase + x / 2;
00739
00740 if (((x + 8) >= endcol) || threshold)
00741 {
00742 if (*alpha > threshold)
00743 {
00744 YUV_TO_RGB1(*usrc, *vsrc);
00745 YUV_TO_RGB2(r, g, b, *src);
00746 RGBA_OUT(dest, r, g, b, *alpha);
00747 }
00748 src++;
00749 alpha++;
00750 dest += 4;
00751 }
00752 else
00753 {
00754 blender(surface, src, usrc, vsrc, alpha, dest);
00755 src += 8;
00756 dest += 32;
00757 alpha += 8;
00758 x += 7;
00759 }
00760 }
00761 }
00762 }
00763 if (blend_to_black)
00764 BlendToBlack(argbptr, stride>>2, outheight);
00765 }
00766
00778 void OSDSurface::DitherToI44(unsigned char *outbuf, bool ifirst,
00779 uint stride, uint outheight) const
00780 {
00781 QMutexLocker lock(&usedRegionsLock);
00782 const OSDSurface *surface = this;
00783 int ashift = ifirst ? 0 : 4;
00784 int amask = ifirst ? 0x0f : 0xf0;
00785
00786 int ishift = ifirst ? 4 : 0;
00787 int imask = ifirst ? 0xf0 : 0x0f;
00788
00789 dithertoia44_8_fun ditherer = dithertoia44_8_init(surface);
00790 dither8_context *dcontext = init_dithertoia44_8_context(ifirst);
00791
00792 bzero(outbuf, stride * outheight);
00793
00794 QMemArray<QRect> rects = surface->usedRegions.rects();
00795 QMemArray<QRect>::Iterator it = rects.begin();
00796 for (; it != rects.end(); ++it)
00797 {
00798 QRect drawRect = *it;
00799
00800 int startcol, startline, endcol, endline;
00801 startcol = drawRect.left();
00802 startline = drawRect.top();
00803 endcol = drawRect.right();
00804 endline = drawRect.bottom();
00805
00806 if (startline < 0) startline = 0;
00807 if (endline >= height) endline = height - 1;
00808 if (startcol < 0) startcol = 0;
00809 if (endcol >= width) endcol = width - 1;
00810
00811 unsigned char *src;
00812 unsigned char *dest;
00813 unsigned char *alpha;
00814
00815 const unsigned char *dmp;
00816
00817 int yoffset;
00818 int destyoffset;
00819
00820 int grey;
00821
00822 for (int y = startline; y <= endline; y++)
00823 {
00824 yoffset = y * surface->width;
00825 destyoffset = y * stride;
00826
00827 src = surface->y + yoffset + startcol;
00828 dest = outbuf + destyoffset + startcol;
00829 alpha = surface->alpha + yoffset + startcol;
00830
00831 dmp = DM[(y) & (DM_HEIGHT - 1)];
00832
00833 for (int x = startcol; x <= endcol; x++)
00834 {
00835 if (x + 8 >= endcol)
00836 {
00837 if (*alpha != 0)
00838 {
00839 grey = *src + ((dmp[(x & (DM_WIDTH - 1))] << 2) >> 4);
00840 grey = (grey - (grey >> 4)) >> 4;
00841
00842 *dest = (((*alpha >> 4) << ashift) & amask) |
00843 (((grey) << ishift) & imask);
00844 }
00845 else
00846 *dest = 0;
00847
00848 src++;
00849 dest++;
00850 alpha++;
00851 }
00852 else
00853 {
00854 ditherer(src, dest, alpha, dmp, x, dcontext);
00855 src += 8;
00856 dest += 8;
00857 alpha += 8;
00858 x += 7;
00859 }
00860 }
00861 }
00862 }
00863
00864 delete_dithertoia44_8_context(dcontext);
00865 }
00866
00876 void OSDSurface::DitherToIA44(unsigned char* outbuf,
00877 uint stride, uint outheight) const
00878 {
00879 DitherToI44(outbuf, false, stride, outheight);
00880 }
00881
00891 void OSDSurface::DitherToAI44(unsigned char* outbuf,
00892 uint stride, uint outheight) const
00893 {
00894 DitherToI44(outbuf, true, stride, outheight);
00895 }