// VirtualDub - Video processing and capture application // Graphics support library // Copyright (C) 1998-2009 Avery Lee // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include #include #include #include #include uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y) { if (x >= px.w) x = px.w - 1; if (y >= px.h) y = px.h - 1; if (x < 0) x = 0; if (y < 0) y = 0; switch(px.format) { case nsVDPixmap::kPixFormat_Pal1: { uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 3]; return px.palette[(idx >> (7 - (x & 7))) & 1]; } case nsVDPixmap::kPixFormat_Pal2: { uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 2]; return px.palette[(idx >> (6 - (x & 3)*2)) & 3]; } case nsVDPixmap::kPixFormat_Pal4: { uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 1]; if (!(x & 1)) idx >>= 4; return px.palette[idx & 15]; } case nsVDPixmap::kPixFormat_Pal8: { uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x]; return px.palette[idx]; } case nsVDPixmap::kPixFormat_XRGB1555: { uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; uint32 r = c & 0x7c00; uint32 g = c & 0x03e0; uint32 b = c & 0x001f; uint32 rgb = (r << 9) + (g << 6) + (b << 3); return rgb + ((rgb >> 5) & 0x070707); } break; case nsVDPixmap::kPixFormat_RGB565: { uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; uint32 r = c & 0xf800; uint32 g = c & 0x07e0; uint32 b = c & 0x001f; uint32 rb = (r << 8) + (b << 3); return rb + ((rb >> 5) & 0x070007) + (g << 5) + ((g >> 1) & 0x0300); } break; case nsVDPixmap::kPixFormat_RGB888: { const uint8 *src = (const uint8 *)px.data + px.pitch*y + 3*x; uint32 b = src[0]; uint32 g = src[1]; uint32 r = src[2]; return (r << 16) + (g << 8) + b; } break; case nsVDPixmap::kPixFormat_XRGB8888: return ((const uint32 *)((const uint8 *)px.data + px.pitch*y))[x]; case nsVDPixmap::kPixFormat_Y8: { uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; return ((luma - 16)*255/219) * 0x010101; } break; case nsVDPixmap::kPixFormat_Y8_FR: { uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; return (uint32)luma * 0x010101; } break; case nsVDPixmap::kPixFormat_YUV444_Planar: return VDConvertYCbCrToRGB(VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapSample8(px.data2, px.pitch2, x, y), VDPixmapSample8(px.data3, px.pitch3, x, y), false, false); case nsVDPixmap::kPixFormat_YUV422_Planar: { sint32 u = (x << 7) + 128; sint32 v = (y << 8); uint32 w2 = px.w >> 1; uint32 h2 = px.h; return VDConvertYCbCrToRGB( VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), false, false); } case nsVDPixmap::kPixFormat_YUV420_Planar: { sint32 u = (x << 7) + 128; sint32 v = (y << 7); uint32 w2 = px.w >> 1; uint32 h2 = px.h >> 1; return VDConvertYCbCrToRGB( VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), false, false); } case nsVDPixmap::kPixFormat_YUV411_Planar: { sint32 u = (x << 6) + 128; sint32 v = (y << 8); uint32 w2 = px.w >> 2; uint32 h2 = px.h; return VDConvertYCbCrToRGB( VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), false, false); } case nsVDPixmap::kPixFormat_YUV410_Planar: { sint32 u = (x << 6) + 128; sint32 v = (y << 6); uint32 w2 = px.w >> 2; uint32 h2 = px.h >> 2; return VDConvertYCbCrToRGB( VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), false, false); } default: return VDPixmapInterpolateSampleRGB24(px, (x << 8) + 128, (y << 8) + 128); } } uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { // bias coordinates to integer x_256 -= 128; y_256 -= 128; // clamp coordinates x_256 &= ~(x_256 >> 31); y_256 &= ~(y_256 >> 31); uint32 w_256 = (w - 1) << 8; uint32 h_256 = (h - 1) << 8; x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8); const uint8 *row1 = row0; if ((uint32)y_256 < h_256) row1 += pitch; ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; sint32 xoffset = x_256 & 255; sint32 yoffset = y_256 & 255; sint32 p00 = row0[0]; sint32 p10 = row0[xstep]; sint32 p01 = row1[0]; sint32 p11 = row1[xstep]; sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; sint32 p = ((p0 << 8) + (p1 - p0)*yoffset + 0x8000) >> 16; return (uint8)p; } uint32 VDPixmapInterpolateSample8To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { // bias coordinates to integer x_256 -= 128; y_256 -= 128; // clamp coordinates x_256 &= ~(x_256 >> 31); y_256 &= ~(y_256 >> 31); sint32 w_256 = (w - 1) << 8; sint32 h_256 = (h - 1) << 8; x_256 += (w_256 - x_256) & ((w_256 - x_256) >> 31); y_256 += (h_256 - y_256) & ((h_256 - y_256) >> 31); const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8); const uint8 *row1 = row0; if (y_256 < h_256) row1 += pitch; ptrdiff_t xstep = x_256 < w_256 ? 1 : 0; sint32 xoffset = x_256 & 255; sint32 yoffset = y_256 & 255; sint32 p00 = row0[0]; sint32 p10 = row0[xstep]; sint32 p01 = row1[0]; sint32 p11 = row1[xstep]; sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; sint32 p = (p0 << 8) + (p1 - p0)*yoffset; return p; } uint32 VDPixmapInterpolateSample8x2To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { // bias coordinates to integer x_256 -= 128; y_256 -= 128; // clamp coordinates x_256 &= ~(x_256 >> 31); y_256 &= ~(y_256 >> 31); uint32 w_256 = (w - 1) << 8; uint32 h_256 = (h - 1) << 8; x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2; const uint8 *row1 = row0; if ((uint32)y_256 < h_256) row1 += pitch; ptrdiff_t xstep = (uint32)x_256 < w_256 ? 2 : 0; sint32 xoffset = x_256 & 255; sint32 yoffset = y_256 & 255; sint32 p00 = row0[0]; sint32 p10 = row0[xstep]; sint32 p01 = row1[0]; sint32 p11 = row1[xstep]; sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; sint32 p = (p0 << 8) + (p1 - p0)*yoffset; return p; } uint32 VDPixmapInterpolateSample8x4To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { // bias coordinates to integer x_256 -= 128; y_256 -= 128; // clamp coordinates x_256 &= ~(x_256 >> 31); y_256 &= ~(y_256 >> 31); uint32 w_256 = (w - 1) << 8; uint32 h_256 = (h - 1) << 8; x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*4; const uint8 *row1 = row0; if ((uint32)y_256 < h_256) row1 += pitch; ptrdiff_t xstep = (uint32)x_256 < w_256 ? 4 : 0; sint32 xoffset = x_256 & 255; sint32 yoffset = y_256 & 255; sint32 p00 = row0[0]; sint32 p10 = row0[xstep]; sint32 p01 = row1[0]; sint32 p11 = row1[xstep]; sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; sint32 p = (p0 << 8) + (p1 - p0)*yoffset; return p; } float VDPixmapInterpolateSample16F(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { // bias coordinates to integer x_256 -= 128; y_256 -= 128; // clamp coordinates x_256 &= ~(x_256 >> 31); y_256 &= ~(y_256 >> 31); uint32 w_256 = (w - 1) << 8; uint32 h_256 = (h - 1) << 8; x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); const uint16 *row0 = (const uint16 *)((const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2); const uint16 *row1 = row0; if ((uint32)y_256 < h_256) row1 = (const uint16 *)((const char *)row1 + pitch); ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; float xoffset = (float)(x_256 & 255) * (1.0f / 255.0f); float yoffset = (float)(y_256 & 255) * (1.0f / 255.0f); float p00; float p10; float p01; float p11; VDConvertHalfToFloat(row0[0], &p00); VDConvertHalfToFloat(row0[xstep], &p10); VDConvertHalfToFloat(row1[0], &p01); VDConvertHalfToFloat(row1[xstep], &p11); float p0 = p00 + (p10 - p00)*xoffset; float p1 = p01 + (p11 - p01)*xoffset; return p0 + (p1 - p0)*yoffset; } namespace { uint32 Lerp8888(uint32 p0, uint32 p1, uint32 p2, uint32 p3, uint32 xf, uint32 yf) { uint32 rb0 = p0 & 0x00ff00ff; uint32 ag0 = p0 & 0xff00ff00; uint32 rb1 = p1 & 0x00ff00ff; uint32 ag1 = p1 & 0xff00ff00; uint32 rb2 = p2 & 0x00ff00ff; uint32 ag2 = p2 & 0xff00ff00; uint32 rb3 = p3 & 0x00ff00ff; uint32 ag3 = p3 & 0xff00ff00; uint32 rbt = (rb0 + ((( rb1 - rb0 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; uint32 agt = (ag0 + ((((ag1 >> 8) - (ag0 >> 8))*xf + 0x00800080) )) & 0xff00ff00; uint32 rbb = (rb2 + ((( rb3 - rb2 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; uint32 agb = (ag2 + ((((ag3 >> 8) - (ag2 >> 8))*xf + 0x00800080) )) & 0xff00ff00; uint32 rb = (rbt + ((( rbb - rbt )*yf + 0x00800080) >> 8)) & 0x00ff00ff; uint32 ag = (agt + ((((agb >> 8) - (agt >> 8))*yf + 0x00800080) )) & 0xff00ff00; return rb + ag; } uint32 InterpPlanarY8(const VDPixmap& px, sint32 x1, sint32 y1) { sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); return VDClampedRoundFixedToUint8Fast((float)(y-0x100000) * (1.1643836f/65536.0f/255.0f))*0x010101; } uint32 ConvertYCC72ToRGB24(sint32 iy, sint32 icb, sint32 icr) { float y = (float)iy; float cb = (float)icb; float cr = (float)icr; // ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! // ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! // ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.5960268f/65536.0f/255.0f)*cr - (222.92157f / 255.0f)); uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.3917623f/65536.0f/255.0f)*cb - (0.8129676f/65536.0f/255.0f)*cr + (135.57529f / 255.0f)); uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.0172321f/65536.0f/255.0f)*cb - (276.83585f / 255.0f)); return (ir << 16) + (ig << 8) + ib; } uint32 ConvertYCC72ToRGB24_FR(sint32 iy, sint32 icb, sint32 icr) { float y = (float)iy; float cb = (float)icb; float cr = (float)icr; // 1. 0. 1.402 - 179.456 // 1. - 0.3441363 - 0.7141363 135.45889 // 1. 1.772 - 2.220D-16 - 226.816 uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.4020000f/65536.0f/255.0f)*cr - (179.456f / 255.0f)); uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.3441363f/65536.0f/255.0f)*cb - (0.7141363f/65536.0f/255.0f)*cr + (135.45889f / 255.0f)); uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.7720000f/65536.0f/255.0f)*cb - (226.816f / 255.0f)); return (ir << 16) + (ig << 8) + ib; } uint32 ConvertYCC72ToRGB24_709(sint32 iy, sint32 icb, sint32 icr) { float y = (float)iy; float cb = (float)icb; float cr = (float)icr; // ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! // ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! // ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.7927411f/65536.0f/255.0f)*cr - (248.10099f / 255.0f)); uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.2132486f/65536.0f/255.0f)*cb - (0.5329093f/65536.0f/255.0f)*cr + (76.87808f / 255.0f)); uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.1124018f/65536.0f/255.0f)*cb - (289.01757f / 255.0f)); return (ir << 16) + (ig << 8) + ib; } uint32 ConvertYCC72ToRGB24_709_FR(sint32 iy, sint32 icb, sint32 icr) { float y = (float)iy; float cb = (float)icb; float cr = (float)icr; // 1. 0. 1.5748 - 201.5744 // 1. - 0.1873243 - 0.4681243 83.897414 // 1. 1.8556 0. - 237.5168 uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.5748f/65536.0f/255.0f)*cr - (201.5744f / 255.0f)); uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.1873243f/65536.0f/255.0f)*cb - (0.4681243f/65536.0f/255.0f)*cr + (83.897414f / 255.0f)); uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.8556f/65536.0f/255.0f)*cb - (237.5168f / 255.0f)); return (ir << 16) + (ig << 8) + ib; } uint32 InterpPlanarYCC888(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); return ConvertYCC72ToRGB24(y, cb, cr); } uint32 InterpPlanarYCC888_709(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); return ConvertYCC72ToRGB24_709(y, cb, cr); } uint32 InterpPlanarYCC888_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); return ConvertYCC72ToRGB24_FR(y, cb, cr); } uint32 InterpPlanarYCC888_709_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); return ConvertYCC72ToRGB24_709_FR(y, cb, cr); } template uint32 InterpPlanarYCC888_420i(const VDPixmap& px, sint32 x1, sint32 y1) { sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); sint32 cb; sint32 cr; const uint8 *src2 = (const uint8 *)px.data2; const uint8 *src3 = (const uint8 *)px.data3; const ptrdiff_t pitch2 = px.pitch2 + px.pitch2; const ptrdiff_t pitch3 = px.pitch3 + px.pitch3; const uint32 w23 = (px.w + 1) >> 1; const uint32 h23 = (px.h + 1) >> 1; const sint32 xc = (x1 >> 1) + 64; sint32 yc = (y1 >> 1) + 64; if (y1 & 1) { yc -= 256; cb = VDPixmapInterpolateSample8To24(src2, pitch2, w23, h23 >> 1, xc, yc); cr = VDPixmapInterpolateSample8To24(src3, pitch3, w23, h23 >> 1, xc, yc); } else { cb = VDPixmapInterpolateSample8To24(src2 + px.pitch2, pitch2, w23, (h23 + 1) >> 1, xc, yc); cr = VDPixmapInterpolateSample8To24(src3 + px.pitch3, pitch3, w23, (h23 + 1) >> 1, xc, yc); } return ConvFn(y, cb, cr); } uint32 SampleV210_Y(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { if (x < 0) x = 0; if ((uint32)x >= w) x = w - 1; if (y < 0) y = 0; if ((uint32)y >= h) y = h - 1; const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 6)*4; switch((uint32)x % 6) { default: case 0: return (p[0] >> 10) & 0x3ff; case 1: return (p[1] >> 0) & 0x3ff; case 2: return (p[1] >> 20) & 0x3ff; case 3: return (p[2] >> 10) & 0x3ff; case 4: return (p[3] >> 0) & 0x3ff; case 5: return (p[3] >> 20) & 0x3ff; } } uint32 SampleV210_Cb(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { if (x < 0) x = 0; if ((uint32)x >= w) x = w - 1; if (y < 0) y = 0; if ((uint32)y >= h) y = h - 1; const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; switch((uint32)x % 3) { default: case 0: return (p[0] >> 0) & 0x3ff; case 1: return (p[1] >> 10) & 0x3ff; case 2: return (p[2] >> 20) & 0x3ff; } } uint32 SampleV210_Cr(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { if (x < 0) x = 0; if ((uint32)x >= w) x = w - 1; if (y < 0) y = 0; if ((uint32)y >= h) y = h - 1; const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; switch((uint32)x % 3) { default: case 0: return (p[0] >> 20) & 0x3ff; case 1: return (p[2] >> 0) & 0x3ff; case 2: return (p[3] >> 10) & 0x3ff; } } } uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x_256, sint32 y_256) { switch(px.format) { case nsVDPixmap::kPixFormat_Pal1: case nsVDPixmap::kPixFormat_Pal2: case nsVDPixmap::kPixFormat_Pal4: case nsVDPixmap::kPixFormat_Pal8: case nsVDPixmap::kPixFormat_RGB565: case nsVDPixmap::kPixFormat_RGB888: case nsVDPixmap::kPixFormat_XRGB1555: case nsVDPixmap::kPixFormat_XRGB8888: { x_256 -= 128; y_256 -= 128; int ix = x_256 >> 8; int iy = y_256 >> 8; uint32 p0 = VDPixmapSample(px, ix, iy); uint32 p1 = VDPixmapSample(px, ix+1, iy); uint32 p2 = VDPixmapSample(px, ix, iy+1); uint32 p3 = VDPixmapSample(px, ix+1, iy+1); return Lerp8888(p0, p1, p2, p3, x_256 & 255, y_256 & 255); } break; case nsVDPixmap::kPixFormat_Y8: return InterpPlanarY8(px, x_256, y_256); case nsVDPixmap::kPixFormat_YUV422_UYVY: return ConvertYCC72ToRGB24( VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) ); case nsVDPixmap::kPixFormat_YUV422_YUYV: return ConvertYCC72ToRGB24( VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) ); case nsVDPixmap::kPixFormat_YUV422_UYVY_FR: return ConvertYCC72ToRGB24_FR( VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) ); case nsVDPixmap::kPixFormat_YUV422_YUYV_FR: return ConvertYCC72ToRGB24_FR( VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) ); case nsVDPixmap::kPixFormat_YUV444_XVYU: return ConvertYCC72ToRGB24( VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, px.w, px.h, x_256, y_256) ); case nsVDPixmap::kPixFormat_YUV422_UYVY_709: return ConvertYCC72ToRGB24_709( VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) ); case nsVDPixmap::kPixFormat_YUV422_YUYV_709: return ConvertYCC72ToRGB24_709( VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) ); case nsVDPixmap::kPixFormat_YUV422_UYVY_709_FR: return ConvertYCC72ToRGB24_709_FR( VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) ); case nsVDPixmap::kPixFormat_YUV422_YUYV_709_FR: return ConvertYCC72ToRGB24_709_FR( VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) ); case nsVDPixmap::kPixFormat_YUV420_NV12: return ConvertYCC72ToRGB24( VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x_256, y_256), VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 0, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1), VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 1, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1) ); case nsVDPixmap::kPixFormat_YUV444_Planar: return InterpPlanarYCC888(px, x_256, y_256, x_256, y_256, px.w, px.h); case nsVDPixmap::kPixFormat_YUV422_Planar: return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); case nsVDPixmap::kPixFormat_YUV411_Planar: return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); case nsVDPixmap::kPixFormat_YUV420_Planar: return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV420it_Planar: return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV420ib_Planar: return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV410_Planar: return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256, (px.w + 1) >> 1, px.h); case nsVDPixmap::kPixFormat_YUV444_Planar_709: return InterpPlanarYCC888_709(px, x_256, y_256, x_256, y_256, px.w, px.h); case nsVDPixmap::kPixFormat_YUV422_Planar_709: return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); case nsVDPixmap::kPixFormat_YUV411_Planar_709: return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); case nsVDPixmap::kPixFormat_YUV420_Planar_709: return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV420it_Planar_709: return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV420ib_Planar_709: return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV410_Planar_709: return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); case nsVDPixmap::kPixFormat_YUV444_Planar_FR: return InterpPlanarYCC888_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); case nsVDPixmap::kPixFormat_YUV422_Planar_FR: return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); case nsVDPixmap::kPixFormat_YUV411_Planar_FR: return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); case nsVDPixmap::kPixFormat_YUV420_Planar_FR: return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV420it_Planar_FR: return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV420ib_Planar_FR: return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV410_Planar_FR: return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: return InterpPlanarYCC888_709_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR: return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR: return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); case nsVDPixmap::kPixFormat_YUV420i_Planar: return InterpPlanarYCC888_420i(px, x_256, y_256); case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: return InterpPlanarYCC888_420i(px, x_256, y_256); case nsVDPixmap::kPixFormat_YUV420i_Planar_709: return InterpPlanarYCC888_420i(px, x_256, y_256); case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: return InterpPlanarYCC888_420i(px, x_256, y_256); case nsVDPixmap::kPixFormat_YUV422_Planar_16F: { float y = VDPixmapInterpolateSample16F(px.data, px.pitch, px.w, px.h, x_256, y_256); float cb = VDPixmapInterpolateSample16F(px.data2, px.pitch2, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); float cr = VDPixmapInterpolateSample16F(px.data3, px.pitch3, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 1.5960268f*cr - (222.92157f / 255.0f)); uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*y - 0.3917623f*cb - 0.8129676f*cr + (135.57529f / 255.0f)); uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 2.0172321f*cb - (276.83585f / 255.0f)); return (ir << 16) + (ig << 8) + ib; } case nsVDPixmap::kPixFormat_YUV422_V210: { sint32 luma_x = x_256 - 128; sint32 luma_y = y_256 - 128; if (luma_x < 0) luma_x = 0; if (luma_y < 0) luma_y = 0; if (luma_x > (sint32)((px.w - 1) << 8)) luma_x = (sint32)((px.w - 1) << 8); if (luma_y > (sint32)((px.h - 1) << 8)) luma_y = (sint32)((px.h - 1) << 8); sint32 luma_ix = luma_x >> 8; sint32 luma_iy = luma_y >> 8; float luma_fx = (float)(luma_x & 255) * (1.0f / 255.0f); float luma_fy = (float)(luma_y & 255) * (1.0f / 255.0f); float y0 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); float y1 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); float y2 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); float y3 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); float yt = y0 + (y1 - y0)*luma_fx; float yb = y2 + (y3 - y2)*luma_fx; float yr = yt + (yb - yt)*luma_fy; uint32 chroma_w = (px.w + 1) >> 1; uint32 chroma_h = px.h; sint32 chroma_x = x_256 >> 1; sint32 chroma_y = y_256 - 128; if (chroma_x < 0) chroma_x = 0; if (chroma_y < 0) chroma_y = 0; if (chroma_x > (sint32)((chroma_w - 1) << 8)) chroma_x = (sint32)((chroma_w - 1) << 8); if (chroma_y > (sint32)((chroma_h - 1) << 8)) chroma_y = (sint32)((chroma_h - 1) << 8); sint32 chroma_ix = chroma_x >> 8; sint32 chroma_iy = chroma_y >> 8; float chroma_fx = (float)(chroma_x & 255) * (1.0f / 255.0f); float chroma_fy = (float)(chroma_y & 255) * (1.0f / 255.0f); float cb0 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); float cb1 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); float cb2 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); float cb3 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); float cbt = cb0 + (cb1 - cb0)*chroma_fx; float cbb = cb2 + (cb3 - cb2)*chroma_fx; float cbr = cbt + (cbb - cbt)*chroma_fy; float cr0 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); float cr1 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); float cr2 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); float cr3 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); float crt = cr0 + (cr1 - cr0)*chroma_fx; float crb = cr2 + (cr3 - cr2)*chroma_fx; float crr = crt + (crb - crt)*chroma_fy; uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 1.5960268f*crr - (222.92157f / 255.0f)); uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*yr - 0.3917623f*cbr - 0.8129676f*crr + (135.57529f / 255.0f)); uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 2.0172321f*cbr - (276.83585f / 255.0f)); return (ir << 16) + (ig << 8) + ib; } break; default: return 0; } } uint32 VDConvertYCbCrToRGB(uint8 y0, uint8 cb0, uint8 cr0, bool use709, bool useFullRange) { sint32 y = y0; sint32 cb = cb0 - 128; sint32 cr = cr0 - 128; sint32 r; sint32 g; sint32 b; if (use709) { if (useFullRange) { sint32 y2 = (y << 16) + 0x8000; r = y2 + cr * 103206; g = y2 + cr * -30679 + cb * -12276; b = y2 + cb * 121609; } else { sint32 y2 = (y - 16) * 76309 + 0x8000; r = y2 + cr * 117489; g = y2 + cr * -34925 + cb * -13975; b = y2 + cb * 138438; } } else { if (useFullRange) { sint32 y2 = (y << 16) + 0x8000; r = y2 + cr * 91181; g = y2 + cr * -46802 + cb * -22554; b = y2 + cb * 166130; } else { sint32 y2 = (y - 16) * 76309 + 0x8000; r = y2 + cr * 104597; g = y2 + cr * -53279 + cb * -25674; b = y2 + cb * 132201; } } r &= ~(r >> 31); g &= ~(g >> 31); b &= ~(b >> 31); r += (0xffffff - r) & ((0xffffff - r) >> 31); g += (0xffffff - g) & ((0xffffff - g) >> 31); b += (0xffffff - b) & ((0xffffff - b) >> 31); return (r & 0xff0000) + ((g & 0xff0000) >> 8) + (b >> 16); } uint32 VDConvertRGBToYCbCr(uint32 c) { return VDConvertRGBToYCbCr((uint8)(c >> 16), (uint8)(c >> 8), (uint8)c, false, false); } uint32 VDConvertRGBToYCbCr(uint8 r8, uint8 g8, uint8 b8, bool use709, bool useFullRange) { sint32 r = r8; sint32 g = g8; sint32 b = b8; sint32 y; sint32 cb; sint32 cr; if (use709) { if (useFullRange) { y = ( 13933*r + 46871*g + 4732*b + 0x8000) >> 8; cb = ( -7509*r - 25259*g + 32768*b + 0x808000) >> 16; cr = ( 32768*r - 29763*g - 3005*b + 0x808000); } else { y = ( 11966*r + 40254*g + 4064*b + 0x108000) >> 8; cb = ( -6596*r - 22189*g + 28784*b + 0x808000) >> 16; cr = ( 28784*r - 26145*g - 2639*b + 0x808000); } } else { if (useFullRange) { y = ( 19595*r + 38470*g + 7471*b + 0x8000) >> 8; cb = (-11058*r - 21710*g + 32768*b + 0x808000) >> 16; cr = ( 32768*r - 27439*g - 5329*b + 0x808000); } else { y = ( 16829*r + 33039*g + 6416*b + 0x108000) >> 8; cb = ( -9714*r - 19071*g + 28784*b + 0x808000) >> 16; cr = ( 28784*r - 24103*g - 4681*b + 0x808000); } } return (uint8)cb + (y & 0xff00) + (cr&0xff0000); }