4439 lines
142 KiB
C++
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
|
|
|
|
}
|