4439 lines
142 KiB
C++

/*
* 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 <string.h> // memcpy(), memset()
#include <assert.h>
#include <stdlib.h> // abs
//#define SCALEOPT //Currently for windows only. June 2010
#ifdef SCALEOPT
#include <emmintrin.h>
#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
}