/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "vplib.h" #include // memcpy(), memset() #include #include // abs //#define SCALEOPT //Currently for windows only. June 2010 #ifdef SCALEOPT #include #endif // webrtc includes #include "conversion_tables.h" namespace webrtc { //Verify and allocate buffer static WebRtc_Word32 VerifyAndAllocate(WebRtc_UWord8*& buffer, WebRtc_UWord32 currentSize, WebRtc_UWord32 newSize); // clip value to [0,255] inline WebRtc_UWord8 Clip(WebRtc_Word32 val); #ifdef SCALEOPT void *memcpy_16(void * dest, const void * src, size_t n); void *memcpy_8(void * dest, const void * src, size_t n); #endif WebRtc_UWord32 CalcBufferSize(VideoType type, WebRtc_UWord32 width, WebRtc_UWord32 height) { WebRtc_UWord32 bitsPerPixel = 32; switch(type) { case kI420: bitsPerPixel = 12; break; case kNV12: bitsPerPixel = 12; break; case kNV21: bitsPerPixel = 12; break; case kIYUV: bitsPerPixel = 12; break; case kYV12: bitsPerPixel = 12; break; case kRGB24: bitsPerPixel = 24; break; case kARGB: bitsPerPixel = 32; break; case kARGB4444: bitsPerPixel = 16; break; case kRGB565: bitsPerPixel = 16; break; case kARGB1555: bitsPerPixel = 16; break; case kYUY2: bitsPerPixel = 16; break; case kUYVY: bitsPerPixel = 16; break; default: assert(false); break; } return (width * height * bitsPerPixel) >> 3; // bytes } WebRtc_UWord32 CalcBufferSize(VideoType incomingVideoType, VideoType convertedVideoType, WebRtc_UWord32 length) { WebRtc_UWord32 incomingBitsPerPixel = 32; switch(incomingVideoType) { case kI420: incomingBitsPerPixel = 12; break; case kNV12: incomingBitsPerPixel = 12; break; case kNV21: incomingBitsPerPixel = 12; break; case kIYUV: incomingBitsPerPixel = 12; break; case kYV12: incomingBitsPerPixel = 12; break; case kRGB24: incomingBitsPerPixel = 24; break; case kARGB: incomingBitsPerPixel = 32; break; case kARGB4444: incomingBitsPerPixel = 16; break; case kRGB565: incomingBitsPerPixel = 16; break; case kARGB1555: incomingBitsPerPixel = 16; break; case kYUY2: incomingBitsPerPixel = 16; break; case kUYVY: incomingBitsPerPixel = 16; break; default: assert(false); break; } WebRtc_Word32 convertedBitsPerPixel = 32; switch(convertedVideoType) { case kI420: convertedBitsPerPixel = 12; break; case kIYUV: convertedBitsPerPixel = 12; break; case kYV12: convertedBitsPerPixel = 12; break; case kRGB24: convertedBitsPerPixel = 24; break; case kARGB: convertedBitsPerPixel = 32; break; case kARGB4444: convertedBitsPerPixel = 16; break; case kRGB565: convertedBitsPerPixel = 16; break; case kARGB1555: convertedBitsPerPixel = 16; break; case kYUY2: convertedBitsPerPixel = 16; break; case kUYVY: convertedBitsPerPixel = 16; break; default: assert(false); break; } return (length * convertedBitsPerPixel) / incomingBitsPerPixel; } WebRtc_Word32 ConvertI420ToRGB24(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } // RGB orientation - bottom up WebRtc_UWord8* out = outFrame + width * height * 3 - width * 3; WebRtc_UWord8* out2 = out - width * 3; WebRtc_UWord32 h, w; WebRtc_Word32 tmpR, tmpG, tmpB; const WebRtc_UWord8 *y1, *y2 ,*u, *v; y1 = inFrame; y2 = y1 + width; u = y1 + width * height; v = u + ((width * height) >> 2); for (h = (height >> 1); h > 0; h--) { // 2 rows at a time, 2 y's at a time for (w = 0; w < (width >> 1); w++) {// vertical and horizontal sub-sampling tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8); out[2] = Clip(tmpR); out[1] = Clip(tmpG); out[0] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8); out2[2] = Clip(tmpR); out2[1] = Clip(tmpG); out2[0] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8); out[5] = Clip(tmpR); out[4] = Clip(tmpG); out[3] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8); out2[5] = Clip(tmpR); out2[4] = Clip(tmpG); out2[3] = Clip(tmpB); out += 6; out2 += 6; y1 += 2; y2 += 2; u++; v++; } y1 += width; y2 += width; out -= width * 9; out2 -= width * 9; } // end height for return width * height * 3; } WebRtc_Word32 ConvertI420ToARGB(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (width < 1 || height < 1) { return -1; } if (strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } WebRtc_Word32 diff = strideOut - width; WebRtc_UWord8* out1 = outFrame; WebRtc_UWord8* out2 = out1 + strideOut * 4; const WebRtc_UWord8 *y1,*y2, *u, *v; y1 = inFrame; y2 = y1 + width; u = y1 + width * height; v = u + (( width * height ) >> 2 ); WebRtc_UWord32 h, w; WebRtc_Word32 tmpR, tmpG, tmpB; for (h = (height >> 1); h > 0; h--) { //do 2 rows at the time for (w = 0; w < (width >> 1); w++) { // vertical and horizontal sub-sampling tmpR = (WebRtc_UWord32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_UWord32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] +128) >> 8); tmpB = (WebRtc_UWord32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8); out1[3] = 0xff; out1[2] = Clip(tmpR); out1[1] = Clip(tmpG); out1[0] = Clip(tmpB); tmpR = (WebRtc_UWord32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_UWord32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_UWord32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8); out2[3] = 0xff; out2[2] = Clip(tmpR); out2[1] = Clip(tmpG); out2[0] = Clip(tmpB); tmpR = (WebRtc_UWord32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_UWord32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_UWord32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8); out1[7] = 0xff; out1[6] = Clip(tmpR); out1[5] = Clip(tmpG); out1[4] = Clip(tmpB); tmpR = (WebRtc_UWord32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_UWord32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_UWord32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8); out2[7] = 0xff; out2[6] = Clip(tmpR); out2[5] = Clip(tmpG); out2[4] = Clip(tmpB); out1 += 8; out2 += 8; y1 += 2; y2 += 2; u++; v++; } y1 += width; y2 += width; out1 += (strideOut + diff) * 4; out2 += (strideOut + diff) * 4; } // end height for return strideOut * height * 4; } WebRtc_Word32 ConvertI420ToRGBAMac(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (height < 1 || width < 1) { return -1; } if (strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } WebRtc_Word32 diff = strideOut - width; WebRtc_UWord8 * out = outFrame; WebRtc_UWord8 * out2 = out + strideOut * 4; const WebRtc_UWord8 *y1,*y2, *u, *v; WebRtc_Word32 tmpG, tmpB, tmpR; WebRtc_UWord32 h, w; y1 = inFrame; y2 = y1 + width; v = y1 + width * height; u = v + ((width * height) >> 2); for (h = (height >> 1); h > 0; h--) { //do 2 rows at the time for (w = 0; w < (width >> 1); w++) { tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128 ) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128 ) >> 8); out[1] = Clip(tmpR); out[2] = Clip(tmpG); out[3] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8); out2[1] = Clip(tmpR); out2[2] = Clip(tmpG); out2[3] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8); out[5] = Clip(tmpR); out[6] = Clip(tmpG); out[7] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8); out2[5] = Clip(tmpR); out2[6] = Clip(tmpG); out2[7] = Clip(tmpB); out[0] = 0xff; out[4] = 0xff; out += 8; out2[0] = 0xff; out2[4] = 0xff; out2 += 8; y1 += 2; y2 += 2; u++; v++; } y1 += width; y2 += width; out += (width + diff * 2) * 4; out2 += (width + diff * 2) * 4; } return strideOut * height * 4; } // Little Endian... WebRtc_Word32 ConvertI420ToARGB4444(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (width < 1 || height < 1) { return -1; } if (strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } // RGB orientation - bottom up WebRtc_UWord8* out = outFrame + strideOut * (height - 1) * 2; WebRtc_UWord8* out2 = out - 2 * strideOut; WebRtc_Word32 tmpR, tmpG, tmpB; const WebRtc_UWord8 *y1,*y2, *u, *v; y1 = inFrame; y2 = y1 + width; u = y1 + width * height; v = u + ((width * height) >> 2); WebRtc_UWord32 h, w; for (h = (height >> 1); h > 0; h--) { // 2 rows at a time, 2 y's at a time for (w = 0; w < (width >> 1); w++) { // vertical and horizontal sub-sampling // Convert to RGB888 and re-scale to 4 bits tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8); out[0] =(WebRtc_UWord8)((Clip(tmpG) & 0xf0) + (Clip(tmpB) >> 4)); out[1] = (WebRtc_UWord8)(0xf0 + (Clip(tmpR) >> 4)); tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8); out2[0] = (WebRtc_UWord8)((Clip(tmpG) & 0xf0 ) + (Clip(tmpB) >> 4)); out2[1] = (WebRtc_UWord8) (0xf0 + (Clip(tmpR) >> 4)); tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8); out[2] = (WebRtc_UWord8)((Clip(tmpG) & 0xf0 ) + (Clip(tmpB) >> 4)); out[3] = (WebRtc_UWord8)(0xf0 + (Clip(tmpR) >> 4)); tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8); out2[2] = (WebRtc_UWord8)((Clip(tmpG) & 0xf0 ) + (Clip(tmpB) >> 4)); out2[3] = (WebRtc_UWord8)(0xf0 + (Clip(tmpR) >> 4)); out += 4; out2 += 4; y1 += 2; y2 += 2; u++; v++; } y1 += width; y2 += width; out -= (2 * strideOut + width) * 2; out2 -= (2 * strideOut + width) * 2; } // end height for return strideOut * height * 2; } WebRtc_Word32 ConvertI420ToRGB565(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord16* out = (WebRtc_UWord16*)(outFrame) + width * (height - 1); WebRtc_UWord16* out2 = out - width ; WebRtc_Word32 tmpR, tmpG, tmpB; const WebRtc_UWord8 *y1,*y2, *u, *v; y1 = inFrame; y2 = y1 + width; u = y1 + width * height; v = u + (width * height >> 2); WebRtc_UWord32 h, w; for (h = (height >>1); h > 0; h--) { // 2 rows at a time, 2 y's at a time for (w = 0; w < (width >> 1); w++) { // vertical and horizontal sub-sampling // 1. Convert to RGB888 // 2. Shift to adequate location (in the 16 bit word) - RGB 565 tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8); out[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8); out2[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8); out[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB ) >> 3); tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8); out2[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); y1 += 2; y2 += 2; out += 2; out2 += 2; u++; v++; } y1 += width; y2 += width; out -= 3 * width; out2 -= 3 * width; } // end height for return width * height * 2; } //Same as ConvertI420ToRGB565 but doesn't flip vertically. WebRtc_Word32 ConvertI420ToRGB565Android(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord16* out = (WebRtc_UWord16*)(outFrame); WebRtc_UWord16* out2 = out + (width) ; WebRtc_Word32 tmpR, tmpG, tmpB; const WebRtc_UWord8 *y1,*y2, *u, *v; WebRtc_UWord32 h, w; y1 = inFrame; y2 = y1 + width; u = y1 + width * height; v = u + (width * height >> 2); for (h = (height >>1); h > 0; h--) { // 2 rows at a time, 2 y's at a time for (w = 0; w < (width >> 1); w++) { // vertical and horizontal sub-sampling // 1. Convert to RGB888 // 2. Shift to adequate location (in the 16 bit word) - RGB 565 tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8); out[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8); out2[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8); out[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB ) >> 3); tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8); out2[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); y1 += 2; y2 += 2; out += 2; out2 += 2; u++; v++; } y1 += width; y2 += width; out += width; out2 += width; } // end height for return width * height * 2; } WebRtc_Word32 ConvertI420ToARGB1555(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (width < 1 || height < 1) { return -1; } if (strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } WebRtc_UWord16* out = (WebRtc_UWord16*)(outFrame) + width * (height - 1); WebRtc_UWord16* out2 = out - width ; WebRtc_Word32 tmpR, tmpG, tmpB; const WebRtc_UWord8 *y1,*y2, *u, *v; WebRtc_UWord32 h, w; y1 = inFrame; y2 = y1 + width; u = y1 + width * height; v = u + (width * height >> 2); for (h = (height >> 1); h > 0; h--) { // 2 rows at a time, 2 y's at a time for (w = 0; w < (width >> 1); w++) { // vertical and horizontal sub-sampling // 1. Convert to RGB888 // 2. shift to adequate location (in the 16 bit word) - RGB 555 // 3. Add 1 for alpha value tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128) >> 8); out[0] = (WebRtc_UWord16)(0x8000 + ((Clip(tmpR) & 0xf8) << 10) + ((Clip(tmpG) & 0xf8) << 3) + (Clip(tmpB) >> 3)); tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8); out2[0] = (WebRtc_UWord16)(0x8000 + ((Clip(tmpR) & 0xf8) << 10) + ((Clip(tmpG) & 0xf8) << 3) + (Clip(tmpB) >> 3)); tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8); out[1] = (WebRtc_UWord16)(0x8000 + ((Clip(tmpR) & 0xf8) << 10) + ((Clip(tmpG) & 0xf8) << 3) + (Clip(tmpB) >> 3)); tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8); out2[1] = (WebRtc_UWord16)(0x8000 + ((Clip(tmpR) & 0xf8) << 10) + ((Clip(tmpG) & 0xf8) << 3) + (Clip(tmpB) >> 3)); y1 += 2; y2 += 2; out += 2; out2 += 2; u++; v++; } y1 += width; y2 += width; out -= 3 * width; out2 -= 3 * width; } // end height for return strideOut * height * 2; } WebRtc_Word32 ConvertI420ToYUY2(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (width < 1 || height < 1) { return -1; } if(strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } const WebRtc_UWord8* in1 = inFrame; const WebRtc_UWord8* in2 = inFrame + width ; const WebRtc_UWord8* inU = inFrame + width * height; const WebRtc_UWord8* inV = inU + width * (height >> 2); WebRtc_UWord8* out1 = outFrame; WebRtc_UWord8* out2 = outFrame + 2*strideOut; //YUY2 - Macro-pixel = 2 image pixels //Y0U0Y1V0....Y2U2Y3V2...Y4U4Y5V4.... #ifndef SCALEOPT for (WebRtc_UWord32 i = 0; i < (height >> 1);i++) { for (WebRtc_UWord32 j = 0; j < (width >> 1);j++) { out1[0] = in1[0]; out1[1] = *inU; out1[2] = in1[1]; out1[3] = *inV; out2[0] = in2[0]; out2[1] = *inU; out2[2] = in2[1]; out2[3] = *inV; out1 += 4; out2 += 4; inU++; inV++; in1 += 2; in2 += 2; } in1 += width; in2 += width; out1 += 2 * strideOut + 2 * (strideOut - width); out2 += 2 * strideOut + 2 * (strideOut - width); } #else for (WebRtc_UWord32 i = 0; i < (height >> 1);i++) { WebRtc_Word32 width__ = (width >> 4); _asm { ;pusha mov eax, DWORD PTR [in1] ;1939.33 mov ecx, DWORD PTR [in2] ;1939.33 mov ebx, DWORD PTR [inU] ;1939.33 mov edx, DWORD PTR [inV] ;1939.33 loop0: movq xmm6, QWORD PTR [ebx] ;inU movq xmm0, QWORD PTR [edx] ;inV punpcklbw xmm6, xmm0 ;inU, inV mix ;movdqa xmm1, xmm6 ;movdqa xmm2, xmm6 ;movdqa xmm4, xmm6 movdqu xmm3, XMMWORD PTR [eax] ;in1 movdqa xmm1, xmm3 punpcklbw xmm1, xmm6 ;in1, inU, in1, inV mov esi, DWORD PTR [out1] movdqu XMMWORD PTR [esi], xmm1 ;write to out1 movdqu xmm5, XMMWORD PTR [ecx] ;in2 movdqa xmm2, xmm5 punpcklbw xmm2, xmm6 ;in2, inU, in2, inV mov edi, DWORD PTR [out2] movdqu XMMWORD PTR [edi], xmm2 ;write to out2 punpckhbw xmm3, xmm6 ;in1, inU, in1, inV again movdqu XMMWORD PTR [esi+16], xmm3 ;write to out1 again add esi, 32 mov DWORD PTR [out1], esi punpckhbw xmm5, xmm6 ;inU, in2, inV again movdqu XMMWORD PTR [edi+16], xmm5 ;write to out2 again add edi, 32 mov DWORD PTR [out2], edi add ebx, 8 add edx, 8 add eax, 16 add ecx, 16 mov esi, DWORD PTR [width__] sub esi, 1 mov DWORD PTR [width__], esi jg loop0 mov DWORD PTR [in1], eax ;1939.33 mov DWORD PTR [in2], ecx ;1939.33 mov DWORD PTR [inU], ebx ;1939.33 mov DWORD PTR [inV], edx ;1939.33 ;popa emms } in1 += width; in2 += width; out1 += 2 * strideOut + 2 * (strideOut - width); out2 += 2 * strideOut + 2 * (strideOut - width); } #endif return strideOut * height * 2; } WebRtc_Word32 ConvertI420ToUYVY(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (width < 1 || height < 1) { return -1; } if(strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } WebRtc_UWord32 i = 0; const WebRtc_UWord8* in1 = inFrame; const WebRtc_UWord8* in2 = inFrame + width ; const WebRtc_UWord8* inU = inFrame + width * height; const WebRtc_UWord8* inV = inFrame + width * height + width * (height >> 2); WebRtc_UWord8* out1 = outFrame; WebRtc_UWord8* out2 = outFrame + 2 * strideOut; //Macro-pixel = 2 image pixels //U0Y0V0Y1....U2Y2V2Y3...U4Y4V4Y5..... #ifndef SCALEOPT for (; i < (height >> 1);i++) { for (WebRtc_UWord32 j = 0; j < (width >> 1) ;j++) { out1[0] = *inU; out1[1] = in1[0]; out1[2] = *inV; out1[3] = in1[1]; out2[0] = *inU; out2[1] = in2[0]; out2[2] = *inV; out2[3] = in2[1]; out1 += 4; out2 += 4; inU++; inV++; in1 += 2; in2 += 2; } in1 += width; in2 += width; out1 += 2 * (strideOut + (strideOut - width)); out2 += 2 * (strideOut + (strideOut - width)); } #else for (; i< (height >> 1);i++) { WebRtc_Word32 width__ = (width >> 4); _asm { ;pusha mov eax, DWORD PTR [in1] ;1939.33 mov ecx, DWORD PTR [in2] ;1939.33 mov ebx, DWORD PTR [inU] ;1939.33 mov edx, DWORD PTR [inV] ;1939.33 loop0: movq xmm6, QWORD PTR [ebx] ;inU movq xmm0, QWORD PTR [edx] ;inV punpcklbw xmm6, xmm0 ;inU, inV mix movdqa xmm1, xmm6 movdqa xmm2, xmm6 movdqa xmm4, xmm6 movdqu xmm3, XMMWORD PTR [eax] ;in1 punpcklbw xmm1, xmm3 ;inU, in1, inV mov esi, DWORD PTR [out1] movdqu XMMWORD PTR [esi], xmm1 ;write to out1 movdqu xmm5, XMMWORD PTR [ecx] ;in2 punpcklbw xmm2, xmm5 ;inU, in2, inV mov edi, DWORD PTR [out2] movdqu XMMWORD PTR [edi], xmm2 ;write to out2 punpckhbw xmm4, xmm3 ;inU, in1, inV again movdqu XMMWORD PTR [esi+16], xmm4 ;write to out1 again add esi, 32 mov DWORD PTR [out1], esi punpckhbw xmm6, xmm5 ;inU, in2, inV again movdqu XMMWORD PTR [edi+16], xmm6 ;write to out2 again add edi, 32 mov DWORD PTR [out2], edi add ebx, 8 add edx, 8 add eax, 16 add ecx, 16 mov esi, DWORD PTR [width__] sub esi, 1 mov DWORD PTR [width__], esi jg loop0 mov DWORD PTR [in1], eax ;1939.33 mov DWORD PTR [in2], ecx ;1939.33 mov DWORD PTR [inU], ebx ;1939.33 mov DWORD PTR [inV], edx ;1939.33 ;popa emms } in1 += width; in2 += width; out1 += 2 * (strideOut + (strideOut - width)); out2 += 2 * (strideOut + (strideOut - width)); } #endif return strideOut * height * 2; } WebRtc_Word32 ConvertI420ToYV12(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (height < 1 || width < 1 ) { return -1; } if (strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } // copy Y for (WebRtc_UWord32 i = 0; i < height; i++) { #ifndef SCALEOPT memcpy(outFrame, inFrame, width); #else memcpy_16(outFrame, inFrame, width); #endif inFrame += width; outFrame += strideOut; } // copy U outFrame += (strideOut >> 1) * height >> 1; for (WebRtc_UWord32 i = 0; i < height >>1; i++) { #ifndef SCALEOPT memcpy(outFrame, inFrame, width >> 1); #else memcpy_8(outFrame, inFrame, width >> 1); #endif inFrame += width >> 1; outFrame += strideOut >> 1; } outFrame -= strideOut*height >> 1; // copy V for (WebRtc_UWord32 i = 0; i < height >> 1; i++) { #ifndef SCALEOPT memcpy(outFrame, inFrame, width >> 1); #else memcpy_8(outFrame, inFrame, width >> 1); #endif inFrame += width >> 1; outFrame += strideOut >> 1; } return ((3 * strideOut * height) >> 1); } WebRtc_Word32 ConvertYV12ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* outFrame) { if (height < 1 || width <1) { return -1; } WebRtc_UWord8 *u, *v, *uo, *vo; WebRtc_Word32 lumlen = 0; WebRtc_Word32 crlen = 0; lumlen = height * width; crlen = (lumlen >> 2); v = (WebRtc_UWord8 *)inFrame + lumlen; uo = outFrame + lumlen; u = v + crlen; vo = uo + crlen; memcpy(outFrame, inFrame, lumlen); // copy luminance memcpy(vo, v, crlen); // copy V to V out memcpy(uo, u, crlen); // copy U to U out return (width * height * 3) >> 1; } WebRtc_Word32 ConvertNV12ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } // Bi-Planar: Y plane followed by an interlaced U and V plane WebRtc_UWord8* out = outFrame; // copying Y plane as is memcpy(out, inFrame, width * height); // de-interlacing U and V const WebRtc_UWord8 *interlacedSrc; WebRtc_UWord8 *u, *v; u = outFrame + width * height; v = u + (width * height >> 2); interlacedSrc = inFrame + width * height; for (WebRtc_UWord32 ind = 0; ind < (width * height >> 2); ind ++) { u[ind] = interlacedSrc[2 * ind]; v[ind] = interlacedSrc[2 * ind + 1]; } return (width * height * 3 >> 1); } WebRtc_Word32 ConvertNV12ToI420AndRotate180(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } // Bi-Planar: Y plane followed by an interlaced U and V plane WebRtc_UWord8* out = outFrame; for(WebRtc_UWord32 index = 0; index < width * height; index++) { out[index] = inFrame[width * height - index - 1]; } // de-interlacing U and V const WebRtc_UWord8 *interlacedSrc; WebRtc_UWord8 *u, *v; u = outFrame + width * height; v = u + (width * height >> 2); interlacedSrc = inFrame + width * height; // extracting and rotating 180 for (WebRtc_UWord32 index = 0; index < (width * height >> 2); index++) { u[(width * height >> 2) - index - 1] = interlacedSrc[2 * index]; v[(width * height >> 2) - index - 1] = interlacedSrc[2 * index + 1]; } return (width * height * 3 >> 1); } WebRtc_Word32 ConvertNV12ToI420AndRotateClockwise(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord8* targetBuffer = outFrame; const WebRtc_UWord8* sourcePtr = inFrame; const WebRtc_UWord8* interlacedSrc = inFrame + width * height; WebRtc_UWord32 index = 0; // Rotate Y for(WebRtc_UWord32 newRow = 0; newRow < width; ++newRow) { for(WebRtc_Word32 newColumn = height-1; newColumn >= 0; --newColumn) { targetBuffer[index++] = sourcePtr[newColumn * width + newRow]; } } // extracting and rotating U and V WebRtc_UWord8* u = targetBuffer + width * height; WebRtc_UWord8* v = u + (width * height >> 2); for (WebRtc_UWord32 colInd = 0; colInd < height >> 1; colInd ++) { for (WebRtc_UWord32 rowInd = 0; rowInd < width >> 1; rowInd ++) { u[rowInd * height / 2 + colInd] = interlacedSrc[(height / 2 - colInd - 1) * width + 2 * rowInd]; v[rowInd * height / 2 + colInd] = interlacedSrc[(height / 2 - colInd - 1) * width + 2 * rowInd + 1]; } } return (width * height * 3 >> 1); } WebRtc_Word32 ConvertNV12ToI420AndRotateAntiClockwise(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord8* targetBuffer = outFrame; const WebRtc_UWord8* sourcePtr = inFrame; const WebRtc_UWord8* interlacedSrc = inFrame + width * height; WebRtc_UWord32 index = 0; // Rotate Y for(WebRtc_Word32 newRow = width - 1; newRow >= 0; --newRow) { for(WebRtc_UWord32 newColumn = 0; newColumn < height; ++newColumn) { targetBuffer[index++] = sourcePtr[newColumn * width + newRow]; } } // extracting and rotating U and V WebRtc_UWord8* u = targetBuffer + width * height; WebRtc_UWord8* v = u + (width * height >> 2); index = 0; for(WebRtc_Word32 newRow = (width >> 1) - 1; newRow >= 0; --newRow) { for(WebRtc_UWord32 newColumn = 0; newColumn < (height >> 1); ++newColumn) { u[index] = interlacedSrc[2 * (newColumn * (width >> 1) + newRow)]; v[index] = interlacedSrc[2 * (newColumn * (width >> 1) + newRow) + 1]; index++; } } return (width * height * 3 >> 1); } WebRtc_Word32 ConvertNV12ToRGB565(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } // Bi-Planar: Y plane followed by an interlaced U and V plane const WebRtc_UWord8* interlacedSrc = inFrame + width * height; WebRtc_UWord16* out = (WebRtc_UWord16*)(outFrame) + width * (height - 1); WebRtc_UWord16* out2 = out - width; WebRtc_Word32 tmpR, tmpG, tmpB; const WebRtc_UWord8 *y1,*y2; y1 = inFrame; y2 = y1 + width; WebRtc_UWord32 h, w; for (h = (height >> 1); h > 0; h--) { // 2 rows at a time, 2 y's at a time for (w = 0; w < (width >> 1); w++) { // vertical and horizontal sub-sampling // 1. Convert to RGB888 // 2. Shift to adequate location (in the 16 bit word) - RGB 565 tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[interlacedSrc[1]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[interlacedSrc[0]] + mapVcg[interlacedSrc[1]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[interlacedSrc[0]] + 128) >> 8); out[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[interlacedSrc[1]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[interlacedSrc[0]] + mapVcg[interlacedSrc[1]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[interlacedSrc[0]] + 128) >> 8); out2[0] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[interlacedSrc[1]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[interlacedSrc[0]] + mapVcg[interlacedSrc[1]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[interlacedSrc[0]] + 128) >> 8); out[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB ) >> 3); tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[interlacedSrc[1]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[interlacedSrc[0]] + mapVcg[interlacedSrc[1]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[interlacedSrc[0]] + 128) >> 8); out2[1] = (WebRtc_UWord16)((Clip(tmpR) & 0xf8) << 8) + ((Clip(tmpG) & 0xfc) << 3) + (Clip(tmpB) >> 3); y1 += 2; y2 += 2; out += 2; out2 += 2; interlacedSrc += 2; } y1 += width; y2 += width; out -= 3 * width; out2 -= 3 * width; } // end height for return (width * height * 2); } //NV21 Android Functions WebRtc_Word32 ConvertNV21ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } // Bi-Planar: Y plane followed by an interlaced U and V plane WebRtc_UWord8* out = outFrame; // copying Y plane as is memcpy(out, inFrame, width * height); // de-interlacing U and V const WebRtc_UWord8 *interlacedSrc; WebRtc_UWord8 *u, *v; u = outFrame + width * height; v = u + (width * height >> 2); interlacedSrc = inFrame + width * height; for (WebRtc_UWord32 ind = 0; ind < (width * height >> 2); ind ++) { v[ind] = interlacedSrc[2 * ind]; u[ind] = interlacedSrc[2 * ind + 1]; } return (width * height * 3 >> 1); } WebRtc_Word32 ConvertNV21ToI420AndRotate180(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } // Bi-Planar: Y plane followed by an interlaced U and V plane WebRtc_UWord8* out = outFrame; for(WebRtc_UWord32 index = 0; index < width * height; index++) { out[index] = inFrame[width * height - index - 1]; } // de-interlacing U and V const WebRtc_UWord8 *interlacedSrc; WebRtc_UWord8 *u, *v; u = outFrame + width * height; v = u + (width * height >> 2); interlacedSrc = inFrame + width * height; // extracting and rotating 180 for (WebRtc_UWord32 index = 0; index < (width * height >> 2); index++) { v[(width * height >> 2) - index - 1] = interlacedSrc[2 * index]; u[(width * height >> 2) - index - 1] = interlacedSrc[2 * index + 1]; } return (width * height * 3 >> 1); } WebRtc_Word32 ConvertNV21ToI420AndRotateClockwise(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } // Paint the destination buffer black memset(outFrame,0,width * height); memset(outFrame + width * height,127,(width * height) / 2); const WebRtc_Word32 offset = (width - height) / 2; //Y WebRtc_UWord8* yn= outFrame; const WebRtc_UWord8* ys= inFrame; for (WebRtc_UWord32 m = 0; m < height; ++m)// New row { yn += offset; for (WebRtc_UWord32 n = 0; n < height; ++n) // new column { (*yn++) = ys[(height - 1 - n) * width + offset + m]; } yn += offset; } //U & V WebRtc_UWord8* un= outFrame + height * width; WebRtc_UWord8* vn= outFrame+height * width + height * width / 4; const WebRtc_UWord8* uvs= inFrame + height * width; for (WebRtc_UWord32 m = 0;m < height / 2; ++m)// New row { un += offset / 2; vn += offset / 2; for (WebRtc_UWord32 n = 0;n < height / 2; ++n) // new column { (*un++) = uvs[(height / 2 - 1 - n) * width + offset + 2 * m + 1]; (*vn++) = uvs[(height / 2 - 1 - n) * width + offset + 2 * m]; } un += offset / 2; vn += offset / 2; } return (width * height * 3 >> 1); } WebRtc_Word32 ConvertNV21ToI420AndRotateAntiClockwise(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } // Paint the destination buffer black memset(outFrame,0,width * height); memset(outFrame + width * height, 127, (width * height) / 2); const WebRtc_Word32 offset = (width - height) / 2; //Y WebRtc_UWord8* yn = outFrame; const WebRtc_UWord8* ys = inFrame; for (WebRtc_UWord32 m = 0;m < height; ++m)// New row { yn += offset; for (WebRtc_UWord32 n = 0;n < height; ++n) // new column { (*yn++) = ys[width * (n + 1) - 1 - offset - m]; } yn += offset; } //U & V WebRtc_UWord8* un= outFrame + height * width; WebRtc_UWord8* vn= outFrame + height * width + height * width / 4; const WebRtc_UWord8* uvs= inFrame + height * width; for (WebRtc_UWord32 m = 0;m < height / 2; ++m)// New row { un += offset / 2; vn += offset / 2; for (WebRtc_UWord32 n = 0;n < height / 2; ++n) // new column { (*un++) = uvs[width * (n + 1) - 1 - offset - 2 * m];; (*vn++) = uvs[width * (n + 1) - 1 - offset - 2 * m - 1];; } un += offset / 2; vn += offset / 2; } return (width * height * 3 >> 1); } WebRtc_Word32 ConvertI420ToRGBAIPhone(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (width < 1 || height < 1) { return -1; } if (strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } // RGB orientation - bottom up // same as ARGB but reverting RGB <-> BGR (same as previous version) WebRtc_UWord8* out = outFrame + strideOut * height * 4 - strideOut * 4; WebRtc_UWord8* out2 = out - strideOut * 4; WebRtc_Word32 tmpR, tmpG, tmpB; const WebRtc_UWord8 *y1,*y2, *u, *v; WebRtc_UWord32 h, w; y1 = inFrame; y2 = y1 + width; u = y1 + width * height; v = u + ((width * height) >> 2); for (h = (height >> 1); h > 0; h--) { // 2 rows at a time, 2 y's at a time for (w = 0; w < (width >> 1); w++) { // vertical and horizontal sub-sampling tmpR = (WebRtc_Word32)((298 * (y1[0] - 16) + 409 * (v[0] - 128) + 128) >> 8); tmpG = (WebRtc_Word32)((298 * (y1[0] - 16) - 100 * (u[0] - 128) - 208 * (v[0] - 128) + 128 ) >> 8); tmpB = (WebRtc_Word32)((298 * (y1[0] - 16) + 516 * (u[0] - 128) + 128 ) >> 8); out[3] = 0xff; out[0] = Clip(tmpR); out[1] = Clip(tmpG); out[2] = Clip(tmpB); tmpR = (WebRtc_Word32)((298 * (y2[0] - 16) + 409 * (v[0] - 128) + 128) >> 8); tmpG = (WebRtc_Word32)((298 * (y2[0] - 16) - 100 * (u[0] - 128) - 208 * (v[0] - 128) + 128) >> 8); tmpB = (WebRtc_Word32)((298 * (y2[0] - 16) + 516 * (u[0] - 128) + 128) >> 8); out2[3] = 0xff; out2[0] = Clip(tmpR); out2[1] = Clip(tmpG); out2[2] = Clip(tmpB); tmpR = (WebRtc_Word32)((298 * (y1[1] - 16) + 409 * (v[0] - 128) + 128 ) >> 8); tmpG = (WebRtc_Word32)((298 * (y1[1] - 16) - 100 * (u[0] - 128) - 208 * (v[0] - 128) + 128 ) >> 8); tmpB = (WebRtc_Word32)((298 * (y1[1] - 16) + 516 * (u[0] - 128) + 128) >> 8); out[7] = 0xff; out[4] = Clip(tmpR); out[5] = Clip(tmpG); out[6] = Clip(tmpB); tmpR = (WebRtc_Word32)((298 * (y2[1] - 16) + 409 * (v[0] - 128) + 128) >> 8); tmpG = (WebRtc_Word32)((298 * (y2[1] - 16) - 100 * (u[0] - 128) - 208 * (v[0] - 128) + 128) >> 8); tmpB = (WebRtc_Word32)((298 * (y2[1] - 16) + 516 * (u[0] - 128) + 128 ) >> 8); out2[7] = 0xff; out2[4] = Clip(tmpR); out2[5] = Clip(tmpG); out2[6] = Clip(tmpB); out += 8; out2 += 8; y1 += 2; y2 += 2; u++; v++; } y1 += width; y2 += width; out -= (2 * strideOut + width) * 4; out2 -= (2 * strideOut + width) * 4; } // end height for return strideOut * height * 4; } WebRtc_Word32 ConvertI420ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (strideOut == 0 || strideOut == width) { memcpy(outFrame, inFrame, 3 * width * (height >> 1)); strideOut = width; } else if (strideOut < width) { return -1; } else { WebRtc_UWord32 i = 0; for (; i < height; i++) { memcpy(outFrame,inFrame ,width); outFrame += strideOut; inFrame += width; } for (i = 0; i < (height >> 1);i++) { memcpy(outFrame, inFrame,width >> 1); outFrame += strideOut >> 1; inFrame += width >> 1; } for (i = 0; i< (height >> 1); i++) { memcpy(outFrame, inFrame,width >> 1); outFrame += strideOut >> 1; inFrame += width >> 1; } } return 3 * strideOut * (height >> 1); } WebRtc_Word32 ConvertUYVYToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight) { if (inWidth < 1 || inHeight < 1 || outHeight < 1 || outWidth < 1) { return -1; } WebRtc_UWord32 i = 0; WebRtc_UWord32 j = 0; WebRtc_Word32 cutDiff = 0; // in pixels WebRtc_Word32 padDiffLow = 0; // in pixels WebRtc_Word32 padDiffHigh = 0; // in pixels WebRtc_UWord8* outI = outFrame; WebRtc_UWord8* outCr = outFrame + outWidth * outHeight; WebRtc_UWord8* outCb = outFrame + outWidth * outHeight + outWidth * (outHeight >> 2); // cut height? if (inHeight > outHeight) { // parse away half of the lines inFrame += ((inHeight - outHeight) / 2) * inWidth * 2; } // cut width? if (inWidth > outWidth) { cutDiff = (inWidth - outWidth); // in pixels // start half of the width diff into the line inFrame += cutDiff; // each pixel is 2 bytes hence diff is the correct value in bytes } // pad height? if (inHeight < outHeight) { // pad top WebRtc_Word32 diff = (outHeight - inHeight) >> 1; memset(outI, 0, diff * outWidth); outI += diff * outWidth; WebRtc_Word32 colorLength = (diff >> 1) * (outWidth >> 1); memset(outCr, 127, colorLength); memset(outCb, 127, colorLength); outCr += colorLength; outCb += colorLength; // pad bottom memset(outI + outWidth * inHeight, 0, diff * outWidth); memset(outCr + (outWidth * inHeight >> 2), 127, colorLength); memset(outCb + (outWidth * inHeight >> 2), 127, colorLength); } // pad width? if (inWidth < outWidth) { padDiffLow = (outWidth - inWidth) >> 1; // in pixels padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels } WebRtc_UWord32 height = 0; if (inHeight > outHeight) height = outHeight; else height = inHeight; for (; i< (height >> 1); i++) // 2 rows per loop { // pad beginning of row? if (padDiffLow) { // pad row memset(outI,0,padDiffLow); memset(outCr,127,padDiffLow >> 1); memset(outCb,127,padDiffLow >> 1); outI += padDiffLow; outCr += padDiffLow >> 1; outCb += padDiffLow >> 1; } for (j = 0; j < (inWidth >> 1); j++) // 2 pixels per loop { outI[0] = inFrame[1]; *outCr = inFrame[0]; outI[1] = inFrame[3]; *outCb = inFrame[2]; inFrame += 4; outI += 2; outCr++; outCb++; } // pad end of row? if (padDiffHigh) { memset(outI,0,padDiffHigh); memset(outCr,127,padDiffHigh >> 1); memset(outCb,127,padDiffHigh >> 1); outI += padDiffHigh; outCr += padDiffHigh >> 1; outCb += padDiffHigh >> 1; } // next row // pad beginning of row? memset(outI,0,padDiffLow); outI += padDiffLow; for (j = 0; j < (inWidth >> 1);j++) { outI[0] = inFrame[1]; outI[1] = inFrame[3]; inFrame += 4; outI += 2; } // pad end of row? if (padDiffHigh) { memset(outI,0,padDiffHigh); outI += padDiffHigh; } else { // cut row for (j = 0; j < (outWidth >> 1); j++) // 2 pixels per loop { outI[0] = inFrame[1]; *outCr = inFrame[0]; outI[1] = inFrame[3]; *outCb = inFrame[2]; inFrame += 4; outI += 2; outCr++; outCb++; } inFrame += cutDiff * 2; // next row for (j = 0; j < (outWidth >> 1);j++) { outI[0] = inFrame[1]; outI[1] = inFrame[3]; inFrame += 4; outI += 2; } inFrame += cutDiff * 2; } } return outWidth * (outHeight >> 1) * 3; } WebRtc_Word32 ConvertUYVYToI420interlaced(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight) { if (inWidth < 1 || inHeight < 1 || outHeight < 1 || outWidth < 1) { return -1; } WebRtc_Word32 i = 0; WebRtc_UWord32 j = 0; WebRtc_Word32 cutDiff = 0; // in pixels WebRtc_Word32 padDiffLow = 0; // in pixels WebRtc_Word32 padDiffHigh = 0; // in pixels WebRtc_UWord8* outI = outFrame; WebRtc_UWord8* outCr = outFrame + outWidth * outHeight; WebRtc_UWord8* outCb = outFrame + outWidth * outHeight + outWidth * ( outHeight >> 2 ); // cut height? if (inHeight > outHeight) { // parse away half of the lines inFrame += (( inHeight - outHeight ) / 2) * inWidth * 2; } // cut width? if (inWidth > outWidth) { cutDiff = (inWidth - outWidth); // in pixels // start half of the width diff into the line inFrame += cutDiff; // each pixel is 2 bytes hence diff is the correct value in bytes } // pad height? if (inHeight < outHeight) { // pad top WebRtc_Word32 diff = (outHeight - inHeight) >> 1; memset(outI, 0, diff * outWidth); outI += diff * outWidth; WebRtc_Word32 colorLength =(diff >> 1) * (outWidth >> 1); memset(outCr, 127, colorLength); memset(outCb, 127, colorLength); outCr += colorLength; outCb += colorLength; // pad bottom memset(outI+outWidth * inHeight, 0, diff * outWidth); memset(outCr+(outWidth * inHeight >> 2), 127, colorLength); memset(outCb+(outWidth * inHeight >> 2), 127, colorLength); } // pad width? if (inWidth < outWidth) { padDiffLow = (outWidth - inWidth) >> 1; // in pixels padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels } WebRtc_Word32 height = 0; if (inHeight > outHeight) height = outHeight; else height = inHeight; for (; i < (height >> 1); i++) // 2 rows per loop { // pad beginning of row? if (padDiffLow) { // pad row memset(outI,0,padDiffLow); memset(outCr,127,padDiffLow >> 1); memset(outCb,127,padDiffLow >> 1); outI += padDiffLow; outCr += padDiffLow / 2; outCb += padDiffLow / 2; for (j = 0; j < (inWidth >> 1); j++) // 2 pixels per loop { outI[0] = inFrame[1]; *outCr = inFrame[0]; outI[1] = inFrame[3]; *outCb = inFrame[2]; inFrame += 4; outI += 2; outCr++; outCb++; } // pad end of row? if (padDiffHigh) { memset(outI,0,padDiffHigh); memset(outCr,127,padDiffHigh >> 1); memset(outCb,127,padDiffHigh >> 1); outI += padDiffHigh; outCr += padDiffHigh >> 1; outCb += padDiffHigh >> 1; } // next row // pad beginning of row? memset(outI,0,padDiffLow); outI += padDiffLow; for (j = 0; j < (inWidth >> 1); j++) { outI[0] = inFrame[1]; outI[1] = inFrame[3]; inFrame += 4; outI += 2; } // pad end of row? if (padDiffHigh) { memset(outI,0,padDiffHigh); outI += padDiffHigh; } } else { // cut row for (j = 0; j < (outWidth >> 1); j++) // 2 pixels per loop { outI[0] = inFrame[1]; *outCr = inFrame[0]; outI[1] = inFrame[3]; *outCb = inFrame[2]; inFrame += 4; outI += 2; outCr++; outCb++; } inFrame -= (outWidth * 2); const WebRtc_UWord8 *inFrame2 = inFrame + (inWidth * 2) * 2; if(i + 1 == (height >> 1)) { // last row for (j = 0; j < (outWidth >> 1); j++) { // copy last row outI[0] = inFrame[1]; outI[1] = inFrame[3]; inFrame += 4; inFrame2 += 4; outI += 2; } } else { // next row for (j = 0; j < (outWidth >> 1); j++) { outI[0] = (inFrame[1] + inFrame2[1]) >> 1; outI[1] = (inFrame[3] + inFrame2[1]) >> 1; inFrame += 4; inFrame2 += 4; outI += 2; } } inFrame += cutDiff * 2; inFrame += inWidth * 2; // skip next row } } return outWidth * (outHeight >> 1) * 3; } WebRtc_Word32 ConvertUYVYToI420(WebRtc_UWord32 width,WebRtc_UWord32 height, const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord32 i = 0; WebRtc_UWord32 j = 0; WebRtc_UWord8* outI = outFrame; WebRtc_UWord8* outCr = outFrame + width * height; WebRtc_UWord8* outCb = outFrame + width * height + width * (height >> 2); for (; i< (height >> 1);i++) { for (j = 0; j < (width >> 1); j++) { outI[0] = inFrame[1]; *outCr = inFrame[0]; outI[1] = inFrame[3]; *outCb = inFrame[2]; inFrame += 4; outI += 2; outCr++; outCb++; } for (j = 0; j < (width >> 1); j++) { outI[0] = inFrame[1]; outI[1] = inFrame[3]; inFrame += 4; outI += 2; } } return width * (height >> 1) * 3; } WebRtc_Word32 ConvertYUY2ToI420interlaced(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight) { if (inWidth < 1 || inHeight < 1 || outHeight < 1 || outWidth < 1) { return -1; } // use every other row and interpolate the removed row WebRtc_UWord32 i = 0; WebRtc_UWord32 j = 0; WebRtc_Word32 cutDiff = 0; // in pixels WebRtc_Word32 padDiffLow = 0; // in pixels WebRtc_Word32 padDiffHigh = 0; // in pixels WebRtc_UWord8* outI = outFrame; WebRtc_UWord8* inPtr3 = (WebRtc_UWord8*)inFrame + inWidth * 2 * 2; // ptr to third row WebRtc_UWord8* outCr = outFrame + outWidth * outHeight; WebRtc_UWord8* outCb = outFrame +outWidth * outHeight + outWidth * (outHeight >> 2); // cut height? if(inHeight > outHeight) { // parse away half of the lines inFrame += ((inHeight - outHeight) / 2) * inWidth * 2; inPtr3 += ((inHeight - outHeight) / 2) * inWidth * 2; } // cut width? if(inWidth > outWidth) { cutDiff = (inWidth - outWidth); // in pixels // start half of the width diff into the line inPtr3 += cutDiff; inFrame += cutDiff; // each pixel is 2 bytes hence diff is the correct value in bytes } // pad height? if(inHeight < outHeight) { // pad top WebRtc_Word32 diff = (outHeight - inHeight) / 2; memset(outI, 0, diff * outWidth); outI += diff * outWidth; WebRtc_Word32 colorLength =(diff / 2) * (outWidth / 2); memset(outCr, 127, colorLength); memset(outCb, 127, colorLength); outCr+= colorLength; outCb+= colorLength; // pad bottom memset(outI + outWidth * inHeight, 0, diff * outWidth); memset(outCr + (outWidth * inHeight / 4), 127, colorLength); memset(outCb + (outWidth * inHeight / 4), 127, colorLength); } // pad width? if(inWidth < outWidth) { padDiffLow = (outWidth - inWidth) / 2; // in pixels padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels } WebRtc_UWord32 height = 0; if(inHeight > outHeight) height = outHeight; else height = inHeight; for (; i< (height >> 1);i++) // 2 rows per loop { // pad beginning of row? if(padDiffLow) { // pad row memset(outI,0,padDiffLow); memset(outCr,127,padDiffLow / 2); memset(outCb,127,padDiffLow / 2); outI += padDiffLow; outCr += padDiffLow / 2; outCb += padDiffLow / 2; for (j = 0; j< (inWidth >> 1);j++) // 2 pixels per loop { outI[0] = inFrame[0]; *outCr = inFrame[1]; outI[1] = inFrame[2]; *outCb = inFrame[3]; inFrame +=4; outI += 2; outCr++; outCb++; } // pad end of row? if (padDiffHigh) { memset(outI,0,padDiffHigh); memset(outCr,127,padDiffHigh / 2); memset(outCb,127,padDiffHigh / 2); outI += padDiffHigh; outCr += padDiffHigh / 2; outCb += padDiffHigh / 2; } // next row // pad beginning of row? memset(outI,0,padDiffLow); outI += padDiffLow; inFrame -= inWidth * 2; if (i == (height >> 1) - 1) { // last loop // copy the last row for (j = 0; j< (inWidth >> 1); j++) { outI[0] = inFrame[0]; outI[1] = inFrame[2]; inFrame += 4; outI += 2; } } else { // turn back inFrame for (j = 0; j < (inWidth >> 1); j++) { outI[0] = (inFrame[0] + inPtr3[0]) >> 1; outI[1] = (inFrame[2] + inPtr3[2]) >> 1; inFrame += 4; inPtr3 += 4; outI += 2; } inFrame += inWidth * 2; inPtr3 += inWidth * 2; } // pad end of row? if (padDiffHigh) { memset(outI,0,padDiffHigh); outI += padDiffHigh; } } else { // cut row for (j = 0; j < (outWidth >> 1); j++) // 2 pixels per loop { outI[0] = inFrame[0]; *outCr = inFrame[1]; outI[1] = inFrame[2]; *outCb = inFrame[3]; inFrame += 4; outI += 2; outCr++; outCb++; } inFrame += cutDiff * 2; inFrame -= inWidth * 2; if (i == (height >> 1) -1) { // last loop // copy the last row for (j = 0; j < (outWidth >> 1);j++) { outI[0] = inFrame[0]; outI[1] = inFrame[2]; inFrame +=4; outI += 2; } } else { // next row for (j = 0; j< (outWidth >> 1);j++) { outI[0] = (inFrame[0] + inPtr3[0]) >> 1; outI[1] = (inFrame[2] + inPtr3[2]) >> 1; inPtr3 += 4; inFrame += 4; outI += 2; } inFrame += cutDiff * 2; inPtr3 += cutDiff * 2; } inFrame += inWidth * 2; inPtr3 += inWidth * 2; } } return outWidth * (outHeight >> 1) * 3; } WebRtc_Word32 ConvertYUY2ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight) { if (inWidth < 1 || inHeight < 1 || outHeight < 1 || outWidth < 1) { return -1; } WebRtc_UWord32 i = 0; WebRtc_UWord32 j = 0; WebRtc_Word32 cutDiff = 0; // in pixels WebRtc_Word32 padDiffLow = 0; // in pixels WebRtc_Word32 padDiffHigh = 0; // in pixels WebRtc_UWord8* outI = outFrame; WebRtc_UWord8* outCr = outFrame + outWidth * outHeight; WebRtc_UWord8* outCb = outFrame + outWidth * outHeight + outWidth * (outHeight >> 2); // cut height? if (inHeight > outHeight) { // parse away half of the lines inFrame += ((inHeight - outHeight) >> 1) * inWidth * 2; } // cut width? if (inWidth > outWidth) { cutDiff = (inWidth - outWidth); // in pixels // start half of the width diff into the line inFrame += cutDiff; // each pixel is 2 bytes hence diff is the correct value in bytes } // pad height? if (inHeight < outHeight) { // pad top WebRtc_Word32 diff = (outHeight - inHeight) >> 1; memset(outI, 0, diff * outWidth); outI += diff * outWidth; WebRtc_Word32 colorLength =(diff >> 1) * (outWidth >> 1); memset(outCr, 127, colorLength); memset(outCb, 127, colorLength); outCr += colorLength; outCb += colorLength; // pad bottom memset(outI + outWidth * inHeight, 0, diff * outWidth); memset(outCr + (outWidth * inHeight >> 2), 127, colorLength); memset(outCb + (outWidth * inHeight >> 2), 127, colorLength); } // pad width? if (inWidth < outWidth) { padDiffLow = (outWidth - inWidth) >> 1; // in pixels padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels } WebRtc_UWord32 height = 0; if (inHeight > outHeight) height = outHeight; else height = inHeight; for (; i< (height >> 1); i++) // 2 rows per loop { // pad beginning of row? if (padDiffLow) { // pad row memset(outI,0,padDiffLow); memset(outCr,127,padDiffLow >> 1); memset(outCb,127,padDiffLow >> 1); outI += padDiffLow; outCr += padDiffLow >> 1; outCb += padDiffLow >> 1; for (j = 0; j< (inWidth >> 1);j++) // 2 pixels per loop { outI[0] = inFrame[0]; *outCr = inFrame[1]; outI[1] = inFrame[2]; *outCb = inFrame[3]; inFrame += 4; outI += 2; outCr++; outCb++; } // pad end of row? if (padDiffHigh) { memset(outI,0,padDiffHigh); memset(outCr,127,padDiffHigh >> 1); memset(outCb,127,padDiffHigh >> 1); outI += padDiffHigh; outCr += padDiffHigh >> 1; outCb += padDiffHigh >> 1; } // next row // pad beginning of row? memset(outI,0,padDiffLow); outI += padDiffLow; for (j = 0; j< (inWidth >> 1); j++) { outI[0] = inFrame[0]; outI[1] = inFrame[2]; inFrame += 4; outI += 2; } // pad end of row? if (padDiffHigh) { memset(outI,0,padDiffHigh); outI += padDiffHigh; } } else { // cut row for (j = 0; j < (outWidth >> 1); j++) // 2 pixels per loop { outI[0] = inFrame[0]; *outCr = inFrame[1]; outI[1] = inFrame[2]; *outCb = inFrame[3]; inFrame += 4; outI += 2; outCr++; outCb++; } inFrame += cutDiff * 2; // next row for (j = 0; j < (outWidth >> 1); j++) { outI[0] = inFrame[0]; outI[1] = inFrame[2]; inFrame += 4; outI += 2; } inFrame += cutDiff * 2; } } return outWidth * (outHeight >> 1) * 3; } WebRtc_Word32 ConvertYUY2ToI420(WebRtc_UWord32 width, WebRtc_UWord32 height,const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame) { #ifndef SCALEOPT if (width < 1 || height < 1) { return -1; } WebRtc_UWord32 i =0; WebRtc_UWord32 j =0; WebRtc_UWord8* outI = outFrame; WebRtc_UWord8* outCr = outFrame + width * height; WebRtc_UWord8* outCb = outFrame +width * height + width * (height >> 2); for (; i < (height >> 1); i++) { for (j = 0; j < (width >> 1); j++) { outI[0] = inFrame[0]; *outCr = inFrame[1]; outI[1] = inFrame[2]; *outCb = inFrame[3]; inFrame += 4; outI += 2; outCr++; outCb++; } for (j = 0; j < (width >> 1); j++) { outI[0] = inFrame[0]; outI[1] = inFrame[2]; inFrame += 4; outI += 2; } } #else if (width < 1 || height < 1) { return -1; } WebRtc_Word32 i =0; WebRtc_Word32 j =0; WebRtc_UWord8* outI = outFrame; WebRtc_UWord8* outCr = outFrame + width * height; WebRtc_UWord8* outCb = outFrame + width * height + width * (height >> 2); WebRtc_Word32 height_half = height / 2; _asm{ mov esi, DWORD PTR [width] mov edx, DWORD PTR [height_half] ; prepare masks: pxor xmm0, xmm0 pcmpeqd xmm1, xmm1 punpcklbw xmm1, xmm0 pcmpeqd xmm2, xmm2 punpcklbw xmm0, xmm2 test edx, edx jle exit_ xor ebx, ebx mov edi, DWORD PTR [outFrame] sar esi, 4 test esi, esi jle exit_ loop0: add ebx, 1 mov DWORD PTR [i], ebx mov ebx, DWORD PTR [inFrame] mov edx, DWORD PTR [outCr] mov eax, DWORD PTR [outCb] xor ecx, ecx loop1: movdqa xmm5, xmm1 movdqa xmm2, xmm1 movdqu xmm4, XMMWORD PTR [ebx] movdqu xmm3, XMMWORD PTR [ebx+16] add ebx, 32 pand xmm5, xmm4 pand xmm4, xmm0 psrldq xmm4, 1 pand xmm2, xmm3 pand xmm3, xmm0 psrldq xmm3, 1 packuswb xmm5, xmm2 movdqu XMMWORD PTR [edi], xmm5 movdqa xmm2, xmm1 packuswb xmm4, xmm3 pand xmm2, xmm4 pand xmm4, xmm0 psrldq xmm4, 1 packuswb xmm2, xmm4 movq QWORD PTR [edx], xmm2 psrldq xmm2, 8 movq QWORD PTR [eax], xmm2 add edi, 16 add edx, 8 add eax, 8 add ecx, 1 cmp ecx, esi jl loop1 mov DWORD PTR [outCb], eax mov DWORD PTR [outCr], edx mov edx, DWORD PTR [height_half] mov DWORD PTR [inFrame], ebx mov ebx, DWORD PTR [i] test esi, esi jle exit_ mov eax, DWORD PTR [inFrame] //now becomes 00568FE8 xor ecx, ecx loop2: movdqu xmm3, XMMWORD PTR [eax] movdqu xmm2, XMMWORD PTR [eax+16] add eax, 32 pand xmm3, xmm1 pand xmm2, xmm1 packuswb xmm3, xmm2 movdqu XMMWORD PTR [edi], xmm3 add edi, 16 add ecx, 1 cmp ecx, esi jl loop2 mov DWORD PTR [inFrame], eax //now 005692A8 mov eax, DWORD PTR [width] cmp ebx, edx jl loop0 exit_: } #endif return width * (height >> 1) * 3; } // make a center cut WebRtc_Word32 CutI420Frame(WebRtc_UWord8* frame, WebRtc_UWord32 fromWidth, WebRtc_UWord32 fromHeight, WebRtc_UWord32 toWidth, WebRtc_UWord32 toHeight) { if (toWidth < 1 || fromWidth < 1 || toHeight < 1 || fromHeight < 1 ) { return -1; } if (toWidth == fromWidth && toHeight == fromHeight) { // nothing to do return 3 * toHeight * toWidth / 2; } if (toWidth > fromWidth || toHeight > fromHeight) { // error return -1; } WebRtc_UWord32 i = 0; WebRtc_Word32 m = 0; WebRtc_UWord32 loop = 0; WebRtc_UWord32 halfToWidth = toWidth / 2; WebRtc_UWord32 halfToHeight = toHeight / 2; WebRtc_UWord32 halfFromWidth = fromWidth / 2; WebRtc_UWord32 halfFromHeight= fromHeight / 2; WebRtc_UWord32 cutHeight = ( fromHeight - toHeight ) / 2; //12 WebRtc_UWord32 cutWidth = ( fromWidth - toWidth ) / 2; // 16 for (i = fromWidth * cutHeight + cutWidth; loop < toHeight ; loop++, i += fromWidth) { memcpy(&frame[m],&frame[i],toWidth); m += toWidth; } i = fromWidth * fromHeight; // ilum loop = 0; for ( i += (halfFromWidth * cutHeight / 2 + cutWidth / 2); loop < halfToHeight; loop++,i += halfFromWidth) { memcpy(&frame[m],&frame[i],halfToWidth); m += halfToWidth; } loop = 0; i = fromWidth * fromHeight + halfFromHeight * halfFromWidth; // ilum +Cr for( i += (halfFromWidth * cutHeight / 2 + cutWidth / 2); loop < halfToHeight; loop++, i += halfFromWidth) { memcpy(&frame[m],&frame[i],halfToWidth); m += halfToWidth; } return halfToWidth * toHeight * 3;// new size 64*96*3; // 128/2 == 64 } WebRtc_Word32 ConvertI420ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight) { if (inWidth < 1 || outWidth < 1 || inHeight < 1 || outHeight < 1 ) { return -1; } if (inWidth == outWidth && inHeight == outHeight) { memcpy(outFrame, inFrame, 3*outWidth*(outHeight>>1)); } else { if( inHeight < outHeight) { // pad height WebRtc_Word32 padH = outHeight - inHeight; WebRtc_UWord32 i =0; WebRtc_Word32 padW = 0; WebRtc_Word32 cutW = 0; WebRtc_Word32 width = inWidth; if (inWidth < outWidth) { // pad width padW = outWidth - inWidth; } else { // cut width cutW = inWidth - outWidth; width = outWidth; } if (padH) { memset(outFrame, 0, outWidth * (padH >> 1)); outFrame += outWidth * (padH >> 1); } for (i = 0; i < inHeight;i++) { if (padW) { memset(outFrame, 0, padW / 2); outFrame += padW / 2; } inFrame += cutW >> 1; // in case we have a cut memcpy(outFrame,inFrame ,width); inFrame += cutW >> 1; outFrame += width; inFrame += width; if (padW) { memset(outFrame, 0, padW / 2); outFrame += padW / 2; } } if (padH) { memset(outFrame, 0, outWidth * (padH >> 1)); outFrame += outWidth * (padH >> 1); } if (padH) { memset(outFrame, 127, (outWidth >> 2) * (padH >> 1)); outFrame += (outWidth >> 2) * (padH >> 1); } for (i = 0; i < (inHeight >> 1); i++) { if (padW) { memset(outFrame, 127, padW >> 2); outFrame += padW >> 2; } inFrame += cutW >> 2; // in case we have a cut memcpy(outFrame, inFrame,width >> 1); inFrame += cutW >> 2; outFrame += width >> 1; inFrame += width >> 1; if (padW) { memset(outFrame, 127, padW >> 2); outFrame += padW >> 2; } } if (padH) { memset(outFrame, 127, (outWidth >> 1) * (padH >> 1)); outFrame += (outWidth >> 1) * (padH >> 1); } for (i = 0; i < (inHeight >> 1); i++) { if (padW) { memset(outFrame, 127, padW >> 2); outFrame += padW >> 2; } inFrame += cutW >> 2; // in case we have a cut memcpy(outFrame, inFrame,width >> 1); inFrame += cutW >> 2; outFrame += width >> 1; inFrame += width >> 1; if (padW) { memset(outFrame, 127, padW >> 2); outFrame += padW >> 2; } } if (padH) { memset(outFrame, 127, (outWidth >> 2) * (padH >> 1)); outFrame += (outWidth >> 2) * (padH >> 1); } } else { // cut height WebRtc_UWord32 i =0; WebRtc_Word32 padW = 0; WebRtc_Word32 cutW = 0; WebRtc_Word32 width = inWidth; if (inWidth < outWidth) { // pad width padW = outWidth - inWidth; } else { // cut width cutW = inWidth - outWidth; width = outWidth; } WebRtc_Word32 diffH = inHeight - outHeight; inFrame += inWidth * (diffH >> 1); // skip top I for (i = 0; i < outHeight; i++) { if (padW) { memset(outFrame, 0, padW / 2); outFrame += padW / 2; } inFrame += cutW >> 1; // in case we have a cut memcpy(outFrame,inFrame ,width); inFrame += cutW >> 1; outFrame += width; inFrame += width; if (padW) { memset(outFrame, 0, padW / 2); outFrame += padW / 2; } } inFrame += inWidth * (diffH >> 1); // skip end I inFrame += (inWidth >> 2) * (diffH >> 1); // skip top of Cr for (i = 0; i < (outHeight >> 1); i++) { if (padW) { memset(outFrame, 127, padW >> 2); outFrame += padW >> 2; } inFrame += cutW >> 2; // in case we have a cut memcpy(outFrame, inFrame,width >> 1); inFrame += cutW >> 2; outFrame += width >> 1; inFrame += width >> 1; if (padW) { memset(outFrame, 127, padW >> 2); outFrame += padW >> 2; } } inFrame += (inWidth >> 2) * (diffH >> 1); // skip end of Cr inFrame += (inWidth >> 2) * (diffH >> 1); // skip top of Cb for (i = 0; i < (outHeight >> 1); i++) { if (padW) { memset(outFrame, 127, padW >> 2); outFrame += padW >> 2; } inFrame += cutW >> 2; // in case we have a cut memcpy(outFrame, inFrame, width >> 1); inFrame += cutW >> 2; outFrame += width >> 1; inFrame += width >> 1; if (padW) { memset(outFrame, 127, padW >> 2); outFrame += padW >> 2; } } } } return 3 * outWidth * (outHeight >> 1); } WebRtc_Word32 ConvertRGB24ToARGB(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (width < 1 || height < 1) { return -1; } if (strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } WebRtc_UWord32 i, j, offset; outFrame += strideOut * (height - 1) * 4; for(i = 0; i < height; i++) { for(j = 0; j < width; j++) { offset = j*4; outFrame[0 + offset] = inFrame[0]; outFrame[1 + offset] = inFrame[1]; outFrame[2 + offset] = inFrame[2]; outFrame[3 + offset] = 0xff; inFrame += 3; } outFrame -= 4 * (strideOut - width); } return strideOut * height * 4; } WebRtc_Word32 ConvertRGB24ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 inWidth, WebRtc_UWord32 inHeight, WebRtc_UWord8* outFrame, WebRtc_UWord32 outWidth, WebRtc_UWord32 outHeight) { if (inWidth < 1 || outWidth < 1 || inHeight < 1 || outHeight < 1 ) { return -1; } WebRtc_UWord32* yStartPtr = (WebRtc_UWord32*)(outFrame + (outWidth * outHeight)); WebRtc_UWord8* uStartPtr = outFrame + (outWidth * outHeight) + ((outWidth * outHeight) >> 2); WebRtc_UWord8* vStartPtr = outFrame + (outWidth * outHeight) +((outWidth * outHeight) >> 1); yStartPtr--; uStartPtr--; vStartPtr--; const WebRtc_UWord8* inpPtr; const WebRtc_UWord8* inFramePtr = inFrame; WebRtc_Word32 offset = 0; WebRtc_Word32 height = inHeight; WebRtc_Word32 cutDiff = 0; WebRtc_Word32 padDiffLow= 0; WebRtc_Word32 padDiffHigh = 0; if (inHeight > outHeight) { // cut height inFramePtr += inWidth*3 * ((inHeight - outHeight) >> 1); // skip the first diff/2 rows height = outHeight; } if (outHeight > inHeight) { // Pad height. WebRtc_UWord8* outI = outFrame; WebRtc_UWord8* outCr = outFrame + outWidth * outHeight; WebRtc_UWord8* outCb = outCr + ((outWidth * outHeight) >> 2); // -- I -- WebRtc_UWord32 padHeight = outHeight - inHeight; WebRtc_UWord32 padHeightT = padHeight >> 1; WebRtc_UWord32 padHeightB = padHeight - padHeightT; WebRtc_UWord32 padLength = padHeightT * outWidth; memset(outI, 0, padLength); // Pad the top. outI += padLength; outI += outWidth * inHeight; // Skip the image. padLength = padHeightB * outWidth; memset(outI, 0, padLength); // Pad the bottom. // Shift the out poWebRtc_Word32er. yStartPtr -= (padLength >> 2); // (>> 2) due to WebRtc_Word32 pointer. // -- Cr and Cb -- padHeight >>= 1; padHeightT >>= 1; padHeightB = padHeight - padHeightT; padLength = padHeightT * (outWidth >> 1); memset(outCr, 127, padLength); // Pad the top. memset(outCb, 127, padLength); outCr += padLength; outCb += padLength; padLength = (outWidth * inHeight) >> 2; outCr += padLength; // Skip the image. outCb += padLength; padLength = padHeightB * (outWidth >> 1); memset(outCr, 127, padLength); // Pad the bottom. memset(outCb, 127, padLength); // Shift the out pointers. uStartPtr -= padLength; vStartPtr -= padLength; } // cut width? if (inWidth > outWidth) { cutDiff = (inWidth - outWidth) >> 1; // in pixels } // pad width? if (inWidth < outWidth) { padDiffLow = (outWidth - inWidth) >> 1; // in pixels padDiffHigh = (outWidth - inWidth) - padDiffLow; // in pixels } for (WebRtc_Word32 y = 0; y < height; y++) { offset = y * inWidth * 3; inpPtr = &inFramePtr[offset + (inWidth - 4) * 3]; // right to left inpPtr -= 3*cutDiff; WebRtc_Word32 i = (inWidth - (cutDiff * 2)) >> 2; WebRtc_UWord32 tmp; if (padDiffLow) { yStartPtr -= padDiffLow >> 2; //div by 4 since its a WebRtc_Word32 ptr memset(yStartPtr + 1, 0, padDiffLow); } for (; i > 0; i--) // do 4 pixels wide in one loop { #ifdef WEBRTC_BIG_ENDIAN tmp = (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[8] + 129 * inpPtr[7] + 25 * inpPtr[6] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[11] + 129 * inpPtr[10] + 25 * inpPtr[9] + 128) >> 8) + 16; #else tmp = (WebRtc_UWord8)((66 * inpPtr[11] + 129 * inpPtr[10] + 25 * inpPtr[9] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[8] + 129 * inpPtr[7] + 25 * inpPtr[6] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128) >> 8) + 16; #endif *yStartPtr = tmp; yStartPtr--; inpPtr -= 12; } if (padDiffHigh) { yStartPtr -= padDiffHigh >> 2; //div by 4 since its a WebRtc_Word32 ptr memset(yStartPtr + 1, 0, padDiffHigh); } y++; // doing an ugly add to my loop variable offset = y * inWidth * 3; inpPtr = &inFramePtr[offset + (inWidth - 4) * 3]; inpPtr -= 3 * cutDiff; i = (inWidth - (cutDiff * 2)) >> 2; if (padDiffLow) { yStartPtr -= padDiffLow >> 2; //div by 4 since its a WebRtc_Word32 ptr uStartPtr -= padDiffLow >> 1; vStartPtr -= padDiffLow >> 1; memset(yStartPtr + 1, 0, padDiffLow); memset(uStartPtr + 1, 127, padDiffLow >> 1); memset(vStartPtr + 1, 127, padDiffLow >> 1); } for (; i > 0; i--) { *uStartPtr = (WebRtc_UWord8)((-38 * inpPtr[8] - 74 * inpPtr[7] + 112 * inpPtr[6] + 128) >> 8) + 128; uStartPtr--; *vStartPtr = (WebRtc_UWord8)((112 * inpPtr[8] - 94 * inpPtr[7] - 18 * inpPtr[6] + 128) >> 8) + 128; vStartPtr--; *uStartPtr = (WebRtc_UWord8)((-38 * inpPtr[2] - 74 * inpPtr[1] + 112 * inpPtr[0] + 128) >> 8) + 128; uStartPtr--; *vStartPtr = (WebRtc_UWord8)((112 * inpPtr[2] - 94 * inpPtr[1] - 18 * inpPtr[0] + 128) >> 8) + 128; vStartPtr--; #ifdef WEBRTC_BIG_ENDIAN tmp = (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128 ) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[8] + 129 * inpPtr[7] + 25 * inpPtr[6] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[11] + 129 * inpPtr[10] + 25 * inpPtr[9] + 128) >> 8) + 16; #else tmp = (WebRtc_UWord8)((66 * inpPtr[11] + 129 * inpPtr[10] + 25 * inpPtr[9]+ 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[8] + 129 * inpPtr[7] + 25 * inpPtr[6] + 128) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128 ) >> 8) + 16; tmp = tmp << 8; tmp += (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128) >> 8) + 16; #endif *yStartPtr = tmp; yStartPtr--; inpPtr -= 12; } if (padDiffHigh) { yStartPtr -= padDiffHigh >> 2; //div by 4 since its a WebRtc_Word32 ptr uStartPtr -= padDiffHigh >> 1; vStartPtr -= padDiffHigh >> 1; memset(yStartPtr + 1, 0, padDiffHigh); memset(uStartPtr + 1, 127, padDiffHigh >> 1); memset(vStartPtr + 1, 127, padDiffHigh >> 1); } } return (outWidth >> 1) * outHeight * 3; } WebRtc_Word32 ConvertRGB24ToI420(WebRtc_UWord32 width, WebRtc_UWord32 height, const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame) { if (height < 1 || width < 1) { return -1; } WebRtc_UWord8* yStartPtr; WebRtc_UWord8* yStartPtr2; WebRtc_UWord8* uStartPtr; WebRtc_UWord8* vStartPtr; const WebRtc_UWord8* inpPtr; const WebRtc_UWord8* inpPtr2; // assuming RGB in a bottom up orientation. yStartPtr = outFrame; yStartPtr2 = yStartPtr + width; uStartPtr = outFrame + (width * height); vStartPtr = uStartPtr + (width * height >> 2); inpPtr = inFrame + width * height * 3 - 3 * width; inpPtr2 = inpPtr - 3 * width; for (WebRtc_UWord32 h = 0; h < (height >> 1); h++ ) { for (WebRtc_UWord32 w = 0; w < (width >> 1); w++) { //Y yStartPtr[0] = (WebRtc_UWord8)((66 * inpPtr[2] + 129 * inpPtr[1] + 25 * inpPtr[0] + 128) >> 8) + 16; yStartPtr2[0] = (WebRtc_UWord8)((66 * inpPtr2[2] + 129 * inpPtr2[1] + 25 * inpPtr2[0] + 128) >> 8) + 16; // moving to next column yStartPtr[1] = (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[4] + 25 * inpPtr[3] + 128) >> 8) + 16; yStartPtr2[1] = (WebRtc_UWord8)((66 * inpPtr2[5] + 129 * inpPtr2[4] + 25 * inpPtr2[3] + 128) >> 8 ) + 16; //U uStartPtr[0] = (WebRtc_UWord8)((-38 * inpPtr[2] - 74 * inpPtr[1] + 112 * inpPtr[0] + 128) >> 8) + 128; //V vStartPtr[0] = (WebRtc_UWord8)((112 * inpPtr[2] -94 * inpPtr[1] -18 * inpPtr[0] + 128) >> 8) + 128; yStartPtr += 2; yStartPtr2 += 2; uStartPtr++; vStartPtr++; inpPtr += 6; inpPtr2 += 6; } // end for w yStartPtr += width; yStartPtr2 += width; inpPtr -= 9 * width; inpPtr2 -= 9 * width; } // end for h return (width >> 1) * height * 3; } WebRtc_Word32 ConvertI420ToARGBMac(const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord32 strideOut) { if (height < 1 || width < 1) { return -1; } if (strideOut == 0) { strideOut = width; } else if (strideOut < width) { return -1; } WebRtc_Word32 diff = strideOut - width; WebRtc_UWord8* out = outFrame; WebRtc_UWord8* out2 = out + strideOut * 4; const WebRtc_UWord8 *y1,*y2, *u, *v; WebRtc_UWord32 h, w; y1 = inFrame; y2 = y1 + width; v = y1 + width * height; u = v + ((width * height) >> 2); for (h = (height >> 1); h > 0; h--) { WebRtc_Word32 tmpG, tmpB, tmpR; //do 2 rows at the time for (w = 0; w < (width >> 1); w++) { tmpR = (WebRtc_Word32)((mapYc[y1[0]] + mapVcr[v[0]] + 128 )>> 8); tmpG = (WebRtc_Word32)((mapYc[y1[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[0]] + mapUcb[u[0]] + 128 )>> 8); out[2] = Clip(tmpR); out[1] = Clip(tmpG); out[0] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y2[0]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[0]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[0]] + mapUcb[u[0]] + 128) >> 8); out2[2] = Clip(tmpR); out2[1] = Clip(tmpG); out2[0] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y1[1]] + mapVcr[v[0]] + 128)>> 8); tmpG = (WebRtc_Word32)((mapYc[y1[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y1[1]] + mapUcb[u[0]] + 128) >> 8); out[6] = Clip(tmpR); out[5] = Clip(tmpG); out[4] = Clip(tmpB); tmpR = (WebRtc_Word32)((mapYc[y2[1]] + mapVcr[v[0]] + 128) >> 8); tmpG = (WebRtc_Word32)((mapYc[y2[1]] + mapUcg[u[0]] + mapVcg[v[0]] + 128) >> 8); tmpB = (WebRtc_Word32)((mapYc[y2[1]] + mapUcb[u[0]] + 128) >> 8); out2[6] = Clip(tmpR); out2[5] = Clip(tmpG); out2[4] = Clip(tmpB); out[3] = 0xff; out[7] = 0xff; out += 8; out2[3] = 0xff; out2[7] = 0xff; out2 += 8; y1 += 2; y2 += 2; u++; v++; } y1 += width; y2 += width; out += (width + diff * 2) * 4; out2 += (width + diff * 2) * 4; } return strideOut * height * 4; } WebRtc_Word32 ConvertRGB565ToI420(const WebRtc_UWord8* inFrame, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* outFrame) { if (width < 1 || height < 1 ) { return -1; } WebRtc_UWord8 tmpR, tmpG, tmpB; WebRtc_UWord8 tmpR2, tmpG2, tmpB2; WebRtc_UWord8* yStartPtr = outFrame; WebRtc_UWord8* yStartPtr2 = yStartPtr + width; WebRtc_UWord8* uStartPtr = outFrame + (width * height); WebRtc_UWord8* vStartPtr = uStartPtr + (width * height >> 2); const WebRtc_UWord16* inpPtr = (const WebRtc_UWord16*)inFrame; inpPtr += width * (height - 1); const WebRtc_UWord16* inpPtr2 = inpPtr - width; for (WebRtc_UWord32 h = 0; h < (height >> 1); h++ ) { for (WebRtc_UWord32 w = 0; w < (width >> 1); w++) { // calculating 8 bit values tmpB = (WebRtc_UWord8)((inpPtr[0] & 0x001F) << 3); tmpG = (WebRtc_UWord8)((inpPtr[0] & 0x07E0) >> 3); tmpR = (WebRtc_UWord8)((inpPtr[0] & 0xF800) >> 8); tmpB2 = (WebRtc_UWord8)((inpPtr2[0] & 0x001F) << 3); tmpG2 = (WebRtc_UWord8)((inpPtr2[0] & 0x07E0) >> 3); tmpR2 = (WebRtc_UWord8)((inpPtr2[0] & 0xF800) >> 8); //Y yStartPtr[0] = (WebRtc_UWord8)((66 * tmpR + 129 * tmpG + 25 * tmpB + 128) >> 8) + 16; //U uStartPtr[0] = (WebRtc_UWord8)((-38 * tmpR - 74 * tmpG + 112 * tmpB + 128) >> 8) + 128; //V vStartPtr[0] = (WebRtc_UWord8)((112 * tmpR - 94 * tmpG - 18 * tmpB + 128) >> 8) + 128; yStartPtr2[0] = (WebRtc_UWord8)((66 * tmpR2 + 129 * tmpG2 + 25 * tmpB2 + 128) >> 8) + 16; // moving to next column tmpB = (WebRtc_UWord8)((inpPtr[1] & 0x001F) << 3); tmpG = (WebRtc_UWord8)((inpPtr[1] & 0x07E0) >> 3); tmpR = (WebRtc_UWord8)((inpPtr[1] & 0xF800) >> 8); tmpB2 = (WebRtc_UWord8)((inpPtr2[1] & 0x001F) << 3); tmpG2 = (WebRtc_UWord8)((inpPtr2[1] & 0x07E0) >> 3); tmpR2 = (WebRtc_UWord8)((inpPtr2[1] & 0xF800) >> 8); yStartPtr[1] = (WebRtc_UWord8)((66 * tmpR + 129 * tmpG + 25 * tmpB + 128) >> 8) + 16; yStartPtr2[1] = (WebRtc_UWord8)((66 * tmpR2 +129 * tmpG2 + 25 * tmpB2 + 128) >> 8) + 16; yStartPtr += 2; yStartPtr2 += 2; uStartPtr++; vStartPtr++; inpPtr += 2; inpPtr2 += 2; } yStartPtr += width; yStartPtr2 += width; inpPtr -= 3 * width; inpPtr2 -= 3 * width; } return (width >> 1) * height * 3; } WebRtc_Word32 ConvertARGBMacToI420(WebRtc_UWord32 width, WebRtc_UWord32 height, const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame) { if (height < 1 || width < 1) { return -1; } WebRtc_UWord8* yStartPtr; WebRtc_UWord8* yStartPtr2; WebRtc_UWord8* uStartPtr; WebRtc_UWord8* vStartPtr; const WebRtc_UWord8* inpPtr; const WebRtc_UWord8* inpPtr2; yStartPtr = outFrame; yStartPtr2 = yStartPtr + width; uStartPtr = outFrame + (width * height); vStartPtr = uStartPtr + (width * height >> 2); inpPtr = inFrame; inpPtr2 = inpPtr + 4 * width; WebRtc_UWord32 h, w; for (h = 0; h < (height >> 1); h++) { for (w = 0; w < (width >> 1); w++) { //Y yStartPtr[0] = (WebRtc_UWord8)((66 * inpPtr[1] + 129 * inpPtr[2] + 25 * inpPtr[3] + 128) >> 8) + 16; yStartPtr2[0] = (WebRtc_UWord8)((66 * inpPtr2[1] + 129 * inpPtr2[2] + 25 * inpPtr2[3] + 128) >> 8) + 16; // moving to next column yStartPtr[1] = (WebRtc_UWord8)((66 * inpPtr[5] + 129 * inpPtr[6] + 25 * inpPtr[7] + 128) >> 8) + 16; yStartPtr2[1] = (WebRtc_UWord8)((66 * inpPtr2[5] + 129 * inpPtr2[6] + 25 * inpPtr2[7] + 128) >> 8) + 16; //U uStartPtr[0] = (WebRtc_UWord8)((-38 * inpPtr[1] - 74 * inpPtr[2] + 112 * inpPtr[3] + 128) >> 8) + 128; //V vStartPtr[0] = (WebRtc_UWord8)((112 * inpPtr[1] - 94 * inpPtr[2] - 18 * inpPtr[3] + 128) >> 8) + 128; yStartPtr += 2; yStartPtr2 += 2; uStartPtr++; vStartPtr++; inpPtr += 8; inpPtr2 += 8; } yStartPtr += width; yStartPtr2 += width; inpPtr += 4 * width; inpPtr2 += 4 * width; } return (width * height * 3 >> 1); } WebRtc_Word32 PadI420BottomRows(WebRtc_UWord8* inputVideoBuffer, WebRtc_UWord32 size, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_Word32 nrRows, WebRtc_UWord32& newLength) { // sanity WebRtc_UWord32 length = 3 * (width >> 1) * (height + nrRows); if (size < length) return -1; if (nrRows < 0) return -1; WebRtc_Word32 colorSize = (width * height) >> 2; WebRtc_Word32 padSize = width * nrRows; WebRtc_Word32 padSizeColor = (width * nrRows) >> 2; WebRtc_Word32 outColorSize = (width *(height + nrRows)) >> 2; WebRtc_Word32 j = width * (height + nrRows) + outColorSize; WebRtc_Word32 i = width*height + colorSize; // start of Cr memmove(&inputVideoBuffer[j], &inputVideoBuffer[i], colorSize); memset((&inputVideoBuffer[j])+colorSize,127,padSizeColor); i = width*height; // start of Cb j = width*(height+nrRows); memmove(&inputVideoBuffer[j], &inputVideoBuffer[i], colorSize); memset((&inputVideoBuffer[j])+colorSize,127,padSizeColor); memset(&inputVideoBuffer[i],0,padSize); newLength = length; return 0; } static WebRtc_UWord32 PadI420Component(const WebRtc_UWord8* inBuf, WebRtc_UWord8* outBuf, const WebRtc_UWord32 fromWidth, const WebRtc_UWord32 fromHeight, const WebRtc_UWord32 padWidth, const WebRtc_UWord32 padWidthL, const WebRtc_UWord32 padHeight, const WebRtc_UWord32 padHeightT, const WebRtc_UWord8 padValue) { const WebRtc_Word32 toWidth = fromWidth + padWidth; const WebRtc_Word32 padWidthR = padWidth - padWidthL; const WebRtc_Word32 padHeightB = padHeight - padHeightT; // Top border memset(outBuf, padValue, toWidth * padHeightT); WebRtc_UWord32 outIdx = toWidth * padHeightT; WebRtc_UWord32 inIdx = 0; for (WebRtc_UWord32 i = 0; i < fromHeight; i++) { // Left border memset(&outBuf[outIdx], padValue, padWidthL); outIdx += padWidthL; // Copy image memcpy(&outBuf[outIdx], &inBuf[inIdx], fromWidth); outIdx += fromWidth; inIdx += fromWidth; // Right border memset(&outBuf[outIdx], padValue, padWidthR); outIdx += padWidthR; } // Bottom border memset(&outBuf[outIdx], padValue, toWidth * padHeightB); outIdx += toWidth * padHeightB; return outIdx; } WebRtc_Word32 PadI420Frame(const WebRtc_UWord8* inBuffer, WebRtc_UWord8* outBuffer, WebRtc_UWord32 fromWidth, WebRtc_UWord32 fromHeight, WebRtc_UWord32 toWidth, WebRtc_UWord32 toHeight) { if (toWidth < 1 || fromWidth < 1 || toHeight < 1 || fromHeight < 1) { return -1; } if (toWidth == fromWidth && toHeight == fromHeight) { // nothing to do return (3 * toHeight * toWidth) >> 1; } if (inBuffer == NULL) { return -1; } if (outBuffer == NULL) { return -1; } if (fromWidth < 0 || fromHeight < 0) { return -1; } if (toWidth < 0 || toHeight < 0) { return -1; } if (toWidth < fromWidth || toHeight < fromHeight) { return -1; } WebRtc_UWord32 padWidth = toWidth - fromWidth; WebRtc_UWord32 padHeight = toHeight - fromHeight; WebRtc_UWord32 padWidthL = 0; WebRtc_UWord32 padHeightT = 0; // If one of the padded dimensions is a multiple of 16, we apply the padding in // blocks of 16. if (padHeight % 16 == 0) { WebRtc_UWord32 num16blocks = padHeight >> 4; padHeightT = ((num16blocks >> 1) << 4); // NOTE: not the same as // num16blocks << 3 } else { padHeightT = padHeight >> 1; } if (padWidth % 16 == 0) { WebRtc_UWord32 num16blocks = padWidth >> 4; padWidthL = ((num16blocks >> 1) << 4); } else { padWidthL = padWidth >> 1; } // -- I -- WebRtc_UWord32 inIdx = 0; WebRtc_UWord32 outIdx = 0; outIdx = PadI420Component(&inBuffer[inIdx], &outBuffer[outIdx], fromWidth, fromHeight, padWidth, padWidthL, padHeight, padHeightT, 0); // -- Cr -- inIdx = fromWidth * fromHeight; fromWidth >>= 1; fromHeight >>= 1; padWidth >>= 1; padWidthL >>= 1; padHeight >>= 1; padHeightT >>= 1; outIdx += PadI420Component(&inBuffer[inIdx], &outBuffer[outIdx], fromWidth, fromHeight, padWidth, padWidthL, padHeight, padHeightT, 127); // -- Cb -- inIdx += fromWidth * fromHeight; outIdx += PadI420Component(&inBuffer[inIdx], &outBuffer[outIdx], fromWidth, fromHeight, padWidth, padWidthL, padHeight, padHeightT, 127); return outIdx; } WebRtc_Word32 PadI420Frame(WebRtc_UWord32 size, const WebRtc_UWord8* inBuffer, WebRtc_UWord8* outBuffer, bool block16Bit) { if (size < 1) { return -1; } WebRtc_Word32 i = 0; WebRtc_Word32 m = 0; WebRtc_Word32 loop = 0; WebRtc_Word32 dropHeightBits = 0; // must be a factor of 4 WebRtc_Word32 halfToWidth; WebRtc_Word32 halfToHeight; WebRtc_Word32 halfFromWidth; WebRtc_Word32 halfFromHeight; WebRtc_Word32 padHeightT; WebRtc_Word32 padHeightB; WebRtc_Word32 padWidthL; WebRtc_Word32 padWidthR; WebRtc_Word32 toWidth; WebRtc_Word32 toHeight; WebRtc_Word32 fromWidth; WebRtc_Word32 fromHeight; if (block16Bit) { if (size == 115200) // to 152064 { toWidth = 352; toHeight = 288; fromWidth = 320; fromHeight =240; padHeightT = 16; padHeightB = 32; padWidthL = 16; padWidthR = 16; } else if (size == 28800) { fromWidth = 160; fromHeight =120; dropHeightBits = 8; // drop 8 bits toWidth = 176; toHeight = 144; padHeightT = 16; padHeightB = 16; padWidthL = 0; padWidthR = 16; } else { return -1; } } else { return -1; } halfFromWidth = fromWidth >> 1; halfFromHeight = fromHeight >> 1; halfToWidth = toWidth >> 1; halfToHeight = toHeight >> 1; //Ilum memset(outBuffer,0,toWidth * padHeightT + padWidthL); // black i = toWidth * padHeightT + padWidthL; m = (dropHeightBits >> 1) * fromWidth; for (loop = 0; loop < (fromHeight - dropHeightBits); loop++) { memcpy(&outBuffer[i], &inBuffer[m],fromWidth); i += fromWidth; m += fromWidth; memset(&outBuffer[i],0,padWidthL + padWidthR); // black i += padWidthL + padWidthR; } memset(&outBuffer[i],0,toWidth * padHeightB - padWidthL); // black m += (dropHeightBits >> 1) * fromWidth; i = toWidth * toHeight; // ilum end // Cr memset(&outBuffer[i],127,halfToWidth * (padHeightT >> 1) + (padWidthL >> 1) ); // black i += halfToWidth * (padHeightT >> 1) + (padWidthL >> 1); m += (dropHeightBits >> 2) * halfFromWidth; for(loop =0 ; loop < (halfFromHeight - (dropHeightBits >> 1)); loop++) { memcpy(&outBuffer[i],&inBuffer[m],halfFromWidth); m += halfFromWidth; i += halfFromWidth; memset(&outBuffer[i],127,(padWidthL + padWidthR) >> 1); // black i += (padWidthL + padWidthR) >> 1; } memset(&outBuffer[i],127,halfToWidth * (padHeightB >> 1) - (padWidthL >> 1) ); // black m += (dropHeightBits>>2) * halfFromWidth; i = toWidth * toHeight + halfToHeight * halfToWidth; // ilum +Cr // Cb memset(&outBuffer[i],127,halfToWidth * (padHeightT >> 1) + (padWidthL >> 2)); // black i += halfToWidth * (padHeightT >> 1) + (padWidthL >> 1); m += (dropHeightBits >> 2) * halfFromWidth; for(loop = 0; loop < (halfFromHeight - (dropHeightBits >> 1)); loop++) { memcpy(&outBuffer[i],&inBuffer[m],halfFromWidth); m += halfFromWidth; i += halfFromWidth; memset(&outBuffer[i],127,((padWidthL + padWidthR) >> 1)); // black i+=((padWidthL + padWidthR) >> 1); } memset(&outBuffer[i],127,halfToWidth * (padHeightB >> 1) - (padWidthL >> 1) ); // black return halfToWidth * toHeight * 3; } WebRtc_Word32 ScaleI420UpHalfFrame(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* inFrame) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord8* inPtr = inFrame + (width * height / 4 * 3) -1; WebRtc_UWord8* outPtr = inFrame + (width * height / 2 * 3) -1; for(WebRtc_Word32 i = (width * height / 4 * 3)-1; i > 0; i--) { *outPtr = *inPtr; outPtr--; inPtr--; *outPtr = ((inPtr[0] + inPtr[1]) / 2); outPtr--; } *outPtr = *inPtr; outPtr--; *outPtr = *inPtr; return 3 * width * height / 2; } WebRtc_Word32 ScaleI420DownHalfFrame(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* inFrame) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord8* inPtr1 = inFrame; WebRtc_UWord8* outPtr = inFrame; WebRtc_UWord32 y = 0; WebRtc_UWord32 x = 0; // ilum for(; y < (height); y++) { for(x = 0; x < (width >> 1); x++) { WebRtc_Word32 avg = inPtr1[0] + inPtr1[1]; avg = avg >>1; *outPtr= (WebRtc_UWord8)(avg); inPtr1 += 2; outPtr++; } } inPtr1 = inFrame + (width * height); // color for(y = 0; y < height; y++) { // 2 rows for(x = 0; x < (width >> 2); x++) { WebRtc_Word32 avg = inPtr1[0] + inPtr1[1] ; *outPtr = (WebRtc_UWord8)(avg >> 1); inPtr1 += 2; outPtr++; } } return height * (width >> 1) * 3; } WebRtc_Word32 ScaleI420FrameQuarter(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* inFrame) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord8* inPtr1 = inFrame; WebRtc_UWord8* inPtr2 = inFrame + width; WebRtc_UWord8* outPtr = inFrame; WebRtc_UWord32 y = 0; WebRtc_UWord32 x = 0; // ilum for(; y < (height >> 1); y++) { // 2 rows for(x = 0; x < (width >> 1); x++) { WebRtc_Word32 avg = inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1]; *outPtr= (WebRtc_UWord8)(avg >> 2); inPtr1 += 2; inPtr2 += 2; outPtr++; } inPtr1 +=width; inPtr2 +=width; } inPtr1 = inFrame + (width * height); inPtr2 = inPtr1 + (width>>1); // color for(y = 0; y < (height>>1); y++) { // 2 rows for(x = 0; x < (width>>2); x++) { WebRtc_Word32 avg = inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1]; *outPtr= (WebRtc_UWord8)(avg >> 2); inPtr1 += 2; inPtr2 += 2; outPtr++; } inPtr1 += (width >> 1); inPtr2 += (width >> 1); } return height * (width >> 1) * 3; } WebRtc_Word32 ScaleI420Up2(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8*& buffer, WebRtc_UWord32 size, WebRtc_UWord32 &scaledWidth, WebRtc_UWord32 &scaledHeight) { if (width <= 1 || height <= 1 || (width % 2) != 0 || (height % 2) != 0) { return -1; } if (size < (WebRtc_UWord32)(width * height * 3 / 2)) { return -1; } scaledWidth = (width << 1); scaledHeight = (height << 1); // Verify allocated size WebRtc_UWord32 scaledBufferSize = CalcBufferSize(kI420, scaledWidth, scaledHeight); VerifyAndAllocate(buffer, size, scaledBufferSize); WebRtc_UWord8* inPtr1 = buffer + (3 * width * (height >> 1)) - 1; WebRtc_UWord8* inPtr2 = buffer + (3 * width * (height >> 1)) - (width >> 1) - 1; WebRtc_UWord8* outPtr1 = buffer + (3 * scaledWidth * (scaledHeight >> 1)) - 1; WebRtc_UWord8* outPtr2 = buffer + (3 * scaledWidth * (scaledHeight >> 1)) - (scaledWidth >> 1) - 1; // Color for (WebRtc_Word32 i = 1; i <= 2; i++) { for (WebRtc_UWord32 y = 0; y < (height >> 1) - 1; y++) { for (WebRtc_UWord32 x = 0; x < (width >> 1) - 1; x++) { *outPtr1 = *inPtr1; *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1); inPtr1--; inPtr2--; outPtr1--; outPtr2--; *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1); *outPtr2 = ((inPtr1[0] + inPtr1[1] + inPtr2[0] + inPtr2[1]) >> 2); outPtr1--; outPtr2--; } *outPtr1 = *inPtr1; *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1); outPtr1--; outPtr2--; *outPtr1 = *inPtr1; *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1); outPtr1--; outPtr2--; inPtr1--; inPtr2--; outPtr1 -= width; outPtr2 -= width; } // First row for (WebRtc_UWord32 x = 0; x < (width >> 1) - 1; x++) { *outPtr1 = *inPtr1; *outPtr2 = *outPtr1; inPtr1--; inPtr2--; outPtr1--; outPtr2--; *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1); *outPtr2 = *outPtr1; outPtr1--; outPtr2--; } *outPtr1 = *inPtr1; *outPtr2 = *inPtr1; outPtr1--; outPtr2--; *outPtr1 = *inPtr1; *outPtr2 = *inPtr1; outPtr1--; outPtr2--; inPtr1--; inPtr2--; outPtr1 -= width; outPtr2 -= width; } inPtr2 -= (width >> 1); outPtr2 -= width; // illum for (WebRtc_UWord32 y = 0; y < height - 1; y++) { for (WebRtc_UWord32 x = 0; x < width - 1; x++) { *outPtr1 = *inPtr1; *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1); inPtr1--; inPtr2--; outPtr1--; outPtr2--; *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1); *outPtr2 = ((inPtr1[0] + inPtr1[1] + inPtr2[0] + inPtr2[1]) >> 2); outPtr1--; outPtr2--; } *outPtr1 = *inPtr1; *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1); outPtr1--; outPtr2--; *outPtr1 = *inPtr1; *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1); outPtr1--; outPtr2--; inPtr1--; inPtr2--; outPtr1 -= scaledWidth; outPtr2 -= scaledWidth; } // First row for (WebRtc_UWord32 x = 0; x < width - 1; x++) { *outPtr1 = *inPtr1; *outPtr2 = *outPtr1; inPtr1--; outPtr1--; outPtr2--; *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1); *outPtr2 = *outPtr1; outPtr1--; outPtr2--; } *outPtr1 = *inPtr1; *outPtr2 = *inPtr1; outPtr1--; outPtr2--; *outPtr1 = *inPtr1; *outPtr2 = *inPtr1; return scaledHeight * (scaledWidth >> 1) * 3; } WebRtc_Word32 ScaleI420Up3_2(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8*& buffer, WebRtc_UWord32 size, WebRtc_UWord32 &scaledWidth, WebRtc_UWord32 &scaledHeight) { if (width <= 1 || height <= 1) { return -1; } if ((width % 2) != 0 || (height % 2) != 0 || ((width >> 1) % 2) != 0 || ((height >> 1) % 2) != 0) { return -1; } if (size < (WebRtc_UWord32)(width * height * 3 / 2)) { return -1; } scaledWidth = 3 * (width >> 1); scaledHeight = 3 * (height >> 1); // Verify new buffer size WebRtc_UWord32 scaledBufferSize = webrtc::CalcBufferSize(kI420, scaledWidth, scaledHeight); VerifyAndAllocate(buffer, size, scaledBufferSize); WebRtc_UWord8* inPtr1 = buffer + (3 * width * (height >> 1)) - 1; WebRtc_UWord8* inPtr2 = buffer + (3 * width*(height >> 1)) - (width >> 1) - 1; WebRtc_UWord8* outPtr1 = buffer + (3 * scaledWidth * (scaledHeight >> 1)) - 1; WebRtc_UWord8* outPtr2 = buffer + (3 * scaledWidth * (scaledHeight >> 1)) - (scaledWidth >> 1) - 1; WebRtc_Word32 cy = 0; WebRtc_Word32 cx = 0; // Color for (WebRtc_UWord32 y = 0; y < (height); y++) { for (WebRtc_UWord32 x = 0; x < (width >> 1); x++) { *outPtr1 = *inPtr1; outPtr1--; cy = y % 2; cx = x % 2; if (cy == 0) { *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1); } outPtr2--; inPtr1--; inPtr2--; if (cx == 0 && cy == 0) { *outPtr2 = ((inPtr1[0] + inPtr1[1] + inPtr2[0] + inPtr2[1]) >> 2); } if (cx == 0) { *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1); outPtr1--; outPtr2--; } } if (cy == 0) { outPtr1 -= (scaledWidth >> 1); outPtr2 -= (scaledWidth >> 1); } } inPtr2 -= (width >> 1); outPtr2 -= (scaledWidth >> 1); // illum for (WebRtc_UWord32 y = 0; y < height; y++) { for (WebRtc_UWord32 x = 0; x < width; x++) { *outPtr1 = *inPtr1; outPtr1--; cy = y % 2; cx = x % 2; if (cy == 0) { *outPtr2 = ((inPtr1[0] + inPtr2[0]) >> 1); } outPtr2--; inPtr1--; inPtr2--; if (cx == 0 && cy == 0) { *outPtr2 = ((inPtr1[0] + inPtr1[1] + inPtr2[0] + inPtr2[1]) >> 2); } if (cx == 0) { *outPtr1 = ((inPtr1[0] + inPtr1[1]) >> 1); outPtr1--; outPtr2--; } } if (cy == 0) { outPtr1 -= scaledWidth; outPtr2 -= scaledWidth; } } return scaledHeight * (scaledWidth >> 1) * 3; } WebRtc_Word32 ScaleI420Down1_3(WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8*& buffer, WebRtc_UWord32 size, WebRtc_UWord32 &scaledWidth, WebRtc_UWord32 &scaledHeight) { if (width <= 5 || height <= 5) { return -1; } if ((width % 2) != 0 || (height % 2) != 0 || (((height / 3) % 2) != 0)) { return -1; } if (size < (WebRtc_UWord32)(width * height * 3 / 2)) { return -1; } scaledWidth = width / 3; scaledHeight = height / 3; WebRtc_Word32 scaledBufferSize = CalcBufferSize(kI420, scaledWidth, scaledHeight); VerifyAndAllocate(buffer, size, scaledBufferSize); WebRtc_UWord8* inPtr1 = buffer; WebRtc_UWord8* inPtr2 = buffer + width; WebRtc_UWord8* outPtr = buffer; WebRtc_Word32 remWidth = width - scaledWidth * 3; bool addWidth = false; if (scaledWidth % 2) { scaledWidth++; addWidth = true; } WebRtc_Word32 remWidthCol = (width >> 1) - WebRtc_Word32((scaledWidth >> 1) * 3.0); // illum for (WebRtc_UWord32 y = 0; y < height / 3; y++) { for (WebRtc_UWord32 x = 0; x < width / 3; x++) { *outPtr = ((inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1]) >> 2); inPtr1 += 3; inPtr2 += 3; outPtr++; } if (addWidth) { *outPtr = ((inPtr1[0] + inPtr2[0]) >> 1); outPtr++; } inPtr1 += (width << 1) + remWidth; inPtr2 += (width << 1) + remWidth; } inPtr1 = buffer + (width * height); inPtr2 = inPtr1 + (width >> 1); // Color for (WebRtc_UWord32 y = 0; y < (scaledHeight >> 1); y++) { for (WebRtc_UWord32 x = 0; x < (scaledWidth >> 1); x++) { *outPtr = ((inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1]) >> 2); inPtr1 += 3; inPtr2 += 3; outPtr++; } inPtr1 += width + (remWidthCol); inPtr2 += width + (remWidthCol); } inPtr1 = buffer + (width * height) + (width * height >> 2); inPtr2 = inPtr1 + (width >> 1); for (WebRtc_UWord32 y = 0; y < (scaledHeight >> 1); y++) { for (WebRtc_UWord32 x = 0; x < (scaledWidth >> 1); x++) { *outPtr = ((inPtr1[0] + inPtr2[0] + inPtr1[1] + inPtr2[1]) >> 2); inPtr1 += 3; inPtr2 += 3; outPtr++; } inPtr1 += width + (remWidthCol); inPtr2 += width + (remWidthCol); } return scaledHeight * (scaledWidth >> 1) * 3; } WebRtc_Word32 ConvertToI420(VideoType incomingVideoType, const WebRtc_UWord8* incomingBuffer, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* outgoingBuffer, bool interlaced /* =false */, VideoRotationMode rotate /* = kRotateNone */) { if (width < 1 || height < 1 ) { return -1; } WebRtc_Word32 outgoingLength = 0; WebRtc_Word32 length = 0; switch(incomingVideoType) { case kRGB24: outgoingLength = ConvertRGB24ToI420(width, height, incomingBuffer, outgoingBuffer); break; case kRGB565: outgoingLength = ConvertRGB565ToI420(incomingBuffer, width, height, outgoingBuffer); break; #ifdef WEBRTC_MAC case kARGB: outgoingLength = ConvertARGBMacToI420(width, height, incomingBuffer, outgoingBuffer); break; #endif case kI420: switch(rotate) { case kRotateNone: length = CalcBufferSize(kI420, width, height); outgoingLength = length; memcpy(outgoingBuffer, incomingBuffer, length); break; case kRotateClockwise: outgoingLength = ConvertToI420AndRotateClockwise(incomingBuffer, width, height, outgoingBuffer, height, width, kI420); break; case kRotateAntiClockwise: outgoingLength = ConvertToI420AndRotateAntiClockwise(incomingBuffer, width, height, outgoingBuffer, height, width, kI420); break; case kRotate180: outgoingLength = ConvertToI420AndMirrorUpDown(incomingBuffer,outgoingBuffer, width, height, kI420); break; default: assert(false); break; } break; case kYUY2: if (interlaced) { outgoingLength = ConvertYUY2ToI420interlaced(incomingBuffer, width, height, outgoingBuffer, width, height); } else { outgoingLength = ConvertYUY2ToI420(incomingBuffer, width, height, outgoingBuffer, width, height); } break; case kUYVY: if (interlaced) { outgoingLength = ConvertUYVYToI420interlaced(incomingBuffer, width, height, outgoingBuffer, width, height); } else { outgoingLength = ConvertUYVYToI420(width, height, incomingBuffer, outgoingBuffer); } break; case kYV12: switch(rotate) { case kRotateNone: outgoingLength = ConvertYV12ToI420(incomingBuffer, width, height, outgoingBuffer); break; case kRotateClockwise: outgoingLength = ConvertToI420AndRotateClockwise(incomingBuffer, width, height, outgoingBuffer, height,width, kYV12); break; case kRotateAntiClockwise: outgoingLength = ConvertToI420AndRotateAntiClockwise(incomingBuffer, width, height, outgoingBuffer, height, width, kYV12); break; case kRotate180: outgoingLength = ConvertToI420AndMirrorUpDown(incomingBuffer, outgoingBuffer, width, height, kYV12); break; default: assert(false); break; } break; case kNV12: switch(rotate) { case kRotateNone: outgoingLength = ConvertNV12ToI420(incomingBuffer, outgoingBuffer, width, height); break; case kRotateClockwise: outgoingLength = ConvertNV12ToI420AndRotateClockwise(incomingBuffer, outgoingBuffer, width, height); break; case kRotateAntiClockwise: outgoingLength = ConvertNV12ToI420AndRotateAntiClockwise(incomingBuffer, outgoingBuffer, width, height); break; case kRotate180: outgoingLength = ConvertNV12ToI420AndRotate180(incomingBuffer, outgoingBuffer, width, height); break; default: assert(false); break; } break; case kNV21: switch(rotate) { case kRotateNone: outgoingLength = ConvertNV21ToI420(incomingBuffer, outgoingBuffer, width, height); break; case kRotateClockwise: outgoingLength = ConvertNV21ToI420AndRotateClockwise(incomingBuffer, outgoingBuffer, width, height); break; case kRotateAntiClockwise: outgoingLength = ConvertNV21ToI420AndRotateAntiClockwise(incomingBuffer, outgoingBuffer, width, height); break; case kRotate180: outgoingLength = ConvertNV21ToI420AndRotate180(incomingBuffer, outgoingBuffer, width, height); break; default: assert(false); break; } break; default: assert(false); break; } return outgoingLength; } WebRtc_Word32 ConvertFromI420(VideoType outgoingVideoType, const WebRtc_UWord8* incomingBuffer, WebRtc_UWord32 width, WebRtc_UWord32 height, WebRtc_UWord8* outgoingBuffer, bool interlaced /* = false */, VideoRotationMode rotate /* = kRotateNone */) { if (width < 1 || height < 1) { return -1; } WebRtc_Word32 outgoingLength = 0; WebRtc_Word32 length = 0; switch(outgoingVideoType) { case kRGB24: outgoingLength = ConvertI420ToRGB24(incomingBuffer, outgoingBuffer, width, height); break; case kARGB: outgoingLength = ConvertI420ToARGB(incomingBuffer, outgoingBuffer, width, height, 0); break; case kARGB4444: outgoingLength = ConvertI420ToARGB4444(incomingBuffer, outgoingBuffer, width, height, 0); break; case kARGB1555: outgoingLength = ConvertI420ToARGB1555(incomingBuffer, outgoingBuffer, width, height,0); break; case kRGB565: outgoingLength = ConvertI420ToRGB565(incomingBuffer, outgoingBuffer, width, height); break; case kI420: length = CalcBufferSize(kI420, width, height); outgoingLength = length; memcpy(outgoingBuffer, incomingBuffer, length); break; case kUYVY: outgoingLength = ConvertI420ToUYVY(incomingBuffer, outgoingBuffer, width, height); break; case kYUY2: outgoingLength = ConvertI420ToYUY2(incomingBuffer, outgoingBuffer, width, height,0); break; case kYV12: outgoingLength = ConvertI420ToYV12(incomingBuffer, outgoingBuffer, width, height,0); break; #ifdef WEBRTC_MAC case kRGBAMac: outgoingLength = ConvertI420ToRGBAMac(incomingBuffer, outgoingBuffer, width, height,0); break; case kARGBMac: outgoingLength = ConvertI420ToARGBMac(incomingBuffer, outgoingBuffer, width, height,0); break; #endif default: assert(false); break; } return outgoingLength; } WebRtc_Word32 MirrorI420LeftRight( const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } WebRtc_Word32 indO = 0; WebRtc_Word32 indS = 0; WebRtc_UWord32 wind, hind; WebRtc_UWord8 tmpVal; // will swap two values per iteration const WebRtc_UWord32 halfW = width >> 1; // Y for (wind = 0; wind < halfW; wind++ ) { for (hind = 0; hind < height; hind++ ) { indO = hind * width + wind; indS = hind * width + (width - wind - 1); // swapping index tmpVal = inFrame[indO]; outFrame[indO] = inFrame[indS]; outFrame[indS] = tmpVal; } // end for (height) } // end for(width) const WebRtc_UWord32 lengthW = width >> 2; const WebRtc_UWord32 lengthH = height >> 1; // V WebRtc_Word32 zeroInd = width * height; for (wind = 0; wind < lengthW; wind++ ) { for (hind = 0; hind < lengthH; hind++ ) { indO = zeroInd + hind * halfW + wind; indS = zeroInd + hind * halfW + (halfW - wind - 1); // swapping index tmpVal = inFrame[indO]; outFrame[indO] = inFrame[indS]; outFrame[indS] = tmpVal; } // end for (height) } // end for(width) //U zeroInd += width * height >> 2; for (wind = 0; wind < lengthW; wind++ ) { for (hind = 0; hind < lengthH; hind++ ) { indO = zeroInd + hind * halfW + wind; indS = zeroInd + hind * halfW + (halfW - wind - 1); // swapping index tmpVal = inFrame[indO]; outFrame[indO] = inFrame[indS]; outFrame[indS] = tmpVal; } // end for (height) } // end for(width) return 0; } WebRtc_Word32 MirrorI420UpDown( const WebRtc_UWord8* inFrame, WebRtc_UWord8* outFrame, WebRtc_UWord32 width, WebRtc_UWord32 height) { if (width < 1 || height < 1) { return -1; } WebRtc_UWord32 indO = 0; WebRtc_UWord32 indS = 0; WebRtc_UWord32 wind, hind; WebRtc_UWord8 tmpVal; WebRtc_UWord32 halfH = height >> 1; WebRtc_UWord32 halfW = width >> 1; // Y for (hind = 0; hind < halfH; hind++ ) { for (wind = 0; wind < width; wind++ ) { indO = hind * width + wind; indS = (height - hind - 1) * width + wind; tmpVal = inFrame[indO]; outFrame[indO] = inFrame[indS]; outFrame[indS] = tmpVal; } } // V WebRtc_UWord32 lengthW = width >> 1; WebRtc_UWord32 lengthH = height >> 2; WebRtc_UWord32 zeroInd = width * height; for (hind = 0; hind < lengthH; hind++ ) { for (wind = 0; wind < lengthW; wind++ ) { indO = zeroInd + hind * halfW + wind; indS = zeroInd + (halfH - hind - 1) * halfW + wind; tmpVal = inFrame[indO]; outFrame[indO] = inFrame[indS]; outFrame[indS] = tmpVal; } } // U zeroInd += width * height >> 2; for (hind = 0; hind < lengthH; hind++ ) { for (wind = 0; wind < lengthW; wind++ ) { indO = zeroInd + hind * halfW + wind; indS = zeroInd + (halfH - hind - 1) * halfW + wind; tmpVal = inFrame[indO]; outFrame[indO] = inFrame[indS]; outFrame[indS] = tmpVal; } } return 0; } WebRtc_Word32 ConvertToI420AndMirrorUpDown(const WebRtc_UWord8* srcBuffer, WebRtc_UWord8* dstBuffer, WebRtc_UWord32 srcWidth, WebRtc_UWord32 srcHeight, VideoType colorSpaceIn) { if (colorSpaceIn != kI420 && colorSpaceIn != kYV12) { return -1; } const WebRtc_Word32 sourceHeight = srcHeight; const WebRtc_Word32 halfHeight = srcHeight >> 1; const WebRtc_Word32 sourceWidth = srcWidth; const WebRtc_Word32 halfWidth = sourceWidth >> 1; WebRtc_UWord8* targetBuffer = dstBuffer; const WebRtc_UWord8* sourcePtr = srcBuffer; //Mirror Y component for (WebRtc_UWord32 newRow = 0; newRow < srcHeight; ++newRow) { memcpy(targetBuffer, &sourcePtr[((srcHeight - newRow) - 1) * sourceWidth], sourceWidth); targetBuffer += sourceWidth; } //Mirror U component sourcePtr += sourceHeight * sourceWidth; if (colorSpaceIn == kYV12) { sourcePtr += (sourceHeight * sourceWidth) >> 2; } for (WebRtc_Word32 newRow = 0; newRow < halfHeight; ++newRow) { memcpy(targetBuffer, &sourcePtr[((halfHeight - newRow) - 1) * halfWidth], halfWidth); targetBuffer += halfWidth; } //Mirror V component if (colorSpaceIn != kYV12) { sourcePtr += (sourceHeight * sourceWidth) >> 2; } else { sourcePtr -= (sourceHeight * sourceWidth) >> 2; } for(WebRtc_Word32 newRow = 0; newRow < halfHeight; ++newRow) { memcpy(targetBuffer, &sourcePtr[((halfHeight - newRow) - 1) * halfWidth], halfWidth); targetBuffer += halfWidth; } return 0; } WebRtc_Word32 ConvertToI420AndRotateClockwise(const WebRtc_UWord8* srcBuffer, WebRtc_UWord32 srcWidth, WebRtc_UWord32 srcHeight, WebRtc_UWord8* dstBuffer, WebRtc_UWord32 dstWidth, WebRtc_UWord32 dstHeight, VideoType colorSpaceIn) { if (colorSpaceIn != kI420 && colorSpaceIn != kYV12) { return -1; } const WebRtc_Word32 targetHeight = dstHeight; const WebRtc_Word32 targetWidth = dstWidth; const WebRtc_Word32 sourceHeight = srcHeight; const WebRtc_Word32 sourceWidth = srcWidth; WebRtc_UWord8* targetBuffer=dstBuffer; const WebRtc_UWord8* sourcePtr=srcBuffer; // Paint the destination buffer black memset(dstBuffer,0,dstWidth * dstHeight); memset(dstBuffer + dstWidth * dstHeight,127,(dstWidth * dstHeight) / 2); const WebRtc_Word32 paddingWidth = (targetWidth - sourceHeight) / 2; const WebRtc_Word32 halfPaddingWidth = paddingWidth / 2; const WebRtc_Word32 paddingHeight = (targetHeight - sourceWidth) / 2; const WebRtc_Word32 halfPaddingHeight = paddingHeight / 2; //Rotate Y component targetBuffer += paddingHeight * targetWidth; for(WebRtc_Word32 newRow = 0; newRow < sourceWidth; ++newRow) { targetBuffer+=paddingWidth; for(WebRtc_Word32 newColumn = sourceHeight - 1;newColumn >= 0;--newColumn) { (*targetBuffer++) = sourcePtr[newColumn * sourceWidth + newRow]; } targetBuffer += paddingWidth; } targetBuffer += paddingHeight * targetWidth; //Rotate U component and store as kI420 sourcePtr += sourceHeight * sourceWidth; if (colorSpaceIn == kYV12) { sourcePtr += (sourceHeight * sourceWidth) >> 2; } targetBuffer += halfPaddingHeight * targetWidth / 2; for(WebRtc_Word32 newRow = 0;newRow < sourceWidth / 2; ++newRow) { targetBuffer += halfPaddingWidth; for(WebRtc_Word32 newColumn=sourceHeight / 2 - 1; newColumn >= 0; --newColumn) { (*targetBuffer++) = sourcePtr[(newColumn * sourceWidth >> 1) + newRow]; } targetBuffer += halfPaddingWidth; } targetBuffer += halfPaddingHeight * targetWidth / 2; //Rotate V component if (colorSpaceIn != kYV12) { sourcePtr += (sourceHeight * sourceWidth) >> 2; } else { sourcePtr -= (sourceHeight * sourceWidth) >> 2; } targetBuffer += halfPaddingHeight * targetWidth / 2; for(WebRtc_Word32 newRow = 0; newRow < sourceWidth / 2; ++newRow) { targetBuffer+=halfPaddingWidth; for(WebRtc_Word32 newColumn = sourceHeight / 2 - 1; newColumn >= 0; --newColumn) { (*targetBuffer++) = sourcePtr[(newColumn * sourceWidth >> 1) + newRow]; } targetBuffer += halfPaddingWidth; } targetBuffer += halfPaddingHeight * targetWidth / 2; return 0; } WebRtc_Word32 ConvertToI420AndRotateAntiClockwise(const WebRtc_UWord8* srcBuffer, WebRtc_UWord32 srcWidth, WebRtc_UWord32 srcHeight, WebRtc_UWord8* dstBuffer, WebRtc_UWord32 dstWidth, WebRtc_UWord32 dstHeight, VideoType colorSpaceIn) { if (colorSpaceIn != kI420 && colorSpaceIn != kYV12) { return -1; } if (dstWidth < srcHeight || dstHeight < srcWidth) { return -1; } const WebRtc_Word32 targetHeight = dstHeight; const WebRtc_Word32 targetWidth = dstWidth; const WebRtc_Word32 sourceHeight = srcHeight; const WebRtc_Word32 sourceWidth = srcWidth; WebRtc_UWord8* targetBuffer = dstBuffer; const WebRtc_UWord8* sourcePtr = srcBuffer; // Paint the destination buffer black memset(dstBuffer,0,dstWidth * dstHeight); memset(dstBuffer + dstWidth * dstHeight,127,(dstWidth * dstHeight) / 2); const WebRtc_Word32 paddingWidth = (targetWidth - sourceHeight) / 2; const WebRtc_Word32 halfPaddingWidth = paddingWidth / 2; const WebRtc_Word32 paddingHeight = (targetHeight - sourceWidth) / 2; const WebRtc_Word32 halfPaddingHeight = paddingHeight / 2; //Rotate Y component targetBuffer += paddingHeight*targetWidth; for(WebRtc_Word32 newRow = sourceWidth - 1; newRow >= 0; --newRow) { targetBuffer+=paddingWidth; for(WebRtc_Word32 newColumn = 0; newColumn < sourceHeight; ++newColumn) { (*targetBuffer++) = sourcePtr[newColumn * sourceWidth + newRow]; } targetBuffer += paddingWidth; } targetBuffer += paddingHeight * targetWidth; //Rotate U component and store as kI420 sourcePtr += sourceHeight * sourceWidth; if (colorSpaceIn == kYV12) { sourcePtr += (sourceHeight * sourceWidth) >> 2; } targetBuffer += halfPaddingHeight * targetWidth / 2; for(WebRtc_Word32 newRow = sourceWidth / 2 - 1; newRow >= 0;--newRow) { targetBuffer += halfPaddingWidth; for(WebRtc_Word32 newColumn = 0; newColumn < sourceHeight / 2; ++newColumn) { (*targetBuffer++) = sourcePtr[(newColumn*sourceWidth >> 1) + newRow]; } targetBuffer += halfPaddingWidth; } targetBuffer += halfPaddingHeight * targetWidth / 2; //Rotate V component if (colorSpaceIn != kYV12) { sourcePtr += (sourceHeight * sourceWidth) >> 2; } else { sourcePtr -= (sourceHeight * sourceWidth) >> 2; } targetBuffer += halfPaddingHeight * targetWidth / 2; for (WebRtc_Word32 newRow = sourceWidth / 2 - 1; newRow >= 0; --newRow) { targetBuffer += halfPaddingWidth; for (WebRtc_Word32 newColumn = 0; newColumn < sourceHeight / 2; ++newColumn) { (*targetBuffer++) = sourcePtr[(newColumn*sourceWidth >> 1) + newRow]; } targetBuffer += halfPaddingWidth; } targetBuffer += halfPaddingHeight * targetWidth / 2; return 0; } inline WebRtc_UWord8 Clip(WebRtc_Word32 val) { if (val < 0) { return (WebRtc_UWord8)0; } else if (val > 255) { return (WebRtc_UWord8)255; } return (WebRtc_UWord8)val; } WebRtc_Word32 VerifyAndAllocate(WebRtc_UWord8*& buffer, WebRtc_UWord32 currentSize, WebRtc_UWord32 newSize) { if (newSize > currentSize) { // make sure that our buffer is big enough WebRtc_UWord8* newBuffer = new WebRtc_UWord8[newSize]; if (buffer) { // copy old data memcpy(newBuffer, buffer, currentSize); delete [] buffer; } buffer = newBuffer; return newSize; } return currentSize; } #ifdef SCALEOPT //memcpy_16 assumes that width is an integer multiple of 16! void *memcpy_16(void * dest, const void * src, size_t n) { _asm { mov eax, dword ptr [src] mov ebx, dword ptr [dest] mov ecx, dword ptr [n] loop0: movdqu xmm0, XMMWORD PTR [eax] movdqu XMMWORD PTR [ebx], xmm0 add eax, 16 add ebx, 16 sub ecx, 16 jg loop0 } } //memcpy_8 assumes that width is an integer multiple of 8! void *memcpy_8(void * dest, const void * src, size_t n) { _asm { mov eax, dword ptr [src] mov ebx, dword ptr [dest] mov ecx, dword ptr [n] loop0: movq mm0, QWORD PTR [eax] movq QWORD PTR [ebx], mm0 add eax, 8 add ebx, 8 sub ecx, 8 jg loop0 emms } } #endif }