blob: 6dab31a29ed50f53652f886f376b09de8e679f34 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "mp4def.h"
#include "mp4enc_lib.h"
#include "mp4lib_int.h"
#include "m4venc_oscl.h"
#define VOP_OFFSET ((lx<<4)+16) /* for offset to image area */
#define CVOP_OFFSET ((lx<<2)+8)
#define PREF_INTRA 512 /* bias for INTRA coding */
/*===============================================================
Function: ChooseMode
Date: 09/21/2000
Purpose: Choosing between INTRA or INTER
Input/Output: Pointer to the starting point of the macroblock.
Note:
===============================================================*/
void ChooseMode_C(UChar *Mode, UChar *cur, Int lx, Int min_SAD)
{
Int i, j;
Int MB_mean, A, tmp, Th;
Int offset = (lx >> 2) - 4;
UChar *p = cur;
Int *pint = (Int *) cur, temp = 0;
MB_mean = 0;
A = 0;
Th = (min_SAD - PREF_INTRA) >> 1;
for (j = 0; j < 8; j++)
{
/* Odd Rows */
temp += (*pint++) & 0x00FF00FF;
temp += (*pint++) & 0x00FF00FF;
temp += (*pint++) & 0x00FF00FF;
temp += (*pint++) & 0x00FF00FF;
pint += offset;
/* Even Rows */
temp += (*pint++ >> 8) & 0x00FF00FF;
temp += (*pint++ >> 8) & 0x00FF00FF;
temp += (*pint++ >> 8) & 0x00FF00FF;
temp += (*pint++ >> 8) & 0x00FF00FF;
pint += offset;
}
MB_mean = (((temp & 0x0000FFFF)) + ((temp & 0xFFFF0000) >> 16)) >> 7;
p = cur;
offset = lx - 16;
for (j = 0; j < 16; j++)
{
temp = (j & 1);
p += temp;
i = 8;
while (i--)
{
tmp = *p - MB_mean;
p += 2;
if (tmp > 0) A += tmp;
else A -= tmp;
}
if (A >= Th)
{
*Mode = MODE_INTER;
return ;
}
p += (offset - temp);
}
if (A < Th)
*Mode = MODE_INTRA;
else
*Mode = MODE_INTER;
return ;
}
/*===============================================================
Function: GetHalfPelMBRegion
Date: 09/17/2000
Purpose: Interpolate the search region for half-pel search
Input/Output: Center of the search, Half-pel memory, width
Note: rounding type should be parameterized.
Now fixed it to zero!!!!!!
===============================================================*/
void GetHalfPelMBRegion_C(UChar *cand, UChar *hmem, Int lx)
{
Int i, j;
UChar *p1, *p2, *p3, *p4;
UChar *hmem1 = hmem;
UChar *hmem2 = hmem1 + 33;
Int offset = lx - 17;
p1 = cand - lx - 1;
p2 = cand - lx;
p3 = cand - 1;
p4 = cand;
for (j = 0; j < 16; j++)
{
for (i = 0; i < 16; i++)
{
*hmem1++ = ((*p1++) + *p2 + *p3 + *p4 + 2) >> 2;
*hmem1++ = ((*p2++) + *p4 + 1) >> 1;
*hmem2++ = ((*p3++) + *p4 + 1) >> 1;
*hmem2++ = *p4++;
}
/* last pixel */
*hmem1++ = ((*p1++) + (*p2++) + *p3 + *p4 + 2) >> 2;
*hmem2++ = ((*p3++) + (*p4++) + 1) >> 1;
hmem1 += 33;
hmem2 += 33;
p1 += offset;
p2 += offset;
p3 += offset;
p4 += offset;
}
/* last row */
for (i = 0; i < 16; i++)
{
*hmem1++ = ((*p1++) + *p2 + (*p3++) + *p4 + 2) >> 2;
*hmem1++ = ((*p2++) + (*p4++) + 1) >> 1;
}
*hmem1 = (*p1 + *p2 + *p3 + *p4 + 2) >> 2;
return ;
}
/*===============================================================
Function: GetHalfPelBlkRegion
Date: 09/20/2000
Purpose: Interpolate the search region for half-pel search
in 4MV mode.
Input/Output: Center of the search, Half-pel memory, width
Note: rounding type should be parameterized.
Now fixed it to zero!!!!!!
===============================================================*/
void GetHalfPelBlkRegion(UChar *cand, UChar *hmem, Int lx)
{
Int i, j;
UChar *p1, *p2, *p3, *p4;
UChar *hmem1 = hmem;
UChar *hmem2 = hmem1 + 17;
Int offset = lx - 9;
p1 = cand - lx - 1;
p2 = cand - lx;
p3 = cand - 1;
p4 = cand;
for (j = 0; j < 8; j++)
{
for (i = 0; i < 8; i++)
{
*hmem1++ = ((*p1++) + *p2 + *p3 + *p4 + 2) >> 2;
*hmem1++ = ((*p2++) + *p4 + 1) >> 1;
*hmem2++ = ((*p3++) + *p4 + 1) >> 1;
*hmem2++ = *p4++;
}
/* last pixel */
*hmem1++ = ((*p1++) + (*p2++) + *p3 + *p4 + 2) >> 2;
*hmem2++ = ((*p3++) + (*p4++) + 1) >> 1;
hmem1 += 17;
hmem2 += 17;
p1 += offset;
p2 += offset;
p3 += offset;
p4 += offset;
}
/* last row */
for (i = 0; i < 8; i++)
{
*hmem1++ = ((*p1++) + *p2 + (*p3++) + *p4 + 2) >> 2;
*hmem1++ = ((*p2++) + (*p4++) + 1) >> 1;
}
*hmem1 = (*p1 + *p2 + *p3 + *p4 + 2) >> 2;
return ;
}
/*=====================================================================
Function: PaddingEdge
Date: 09/16/2000
Purpose: Pad edge of a Vop
Modification: 09/20/05.
=====================================================================*/
void PaddingEdge(Vop *refVop)
{
UChar *src, *dst;
Int i;
Int pitch, width, height;
ULong temp1, temp2;
width = refVop->width;
height = refVop->height;
pitch = refVop->pitch;
/* pad top */
src = refVop->yChan;
temp1 = *src; /* top-left corner */
temp2 = src[width-1]; /* top-right corner */
temp1 |= (temp1 << 8);
temp1 |= (temp1 << 16);
temp2 |= (temp2 << 8);
temp2 |= (temp2 << 16);
dst = src - (pitch << 4);
*((ULong*)(dst - 16)) = temp1;
*((ULong*)(dst - 12)) = temp1;
*((ULong*)(dst - 8)) = temp1;
*((ULong*)(dst - 4)) = temp1;
M4VENC_MEMCPY(dst, src, width);
*((ULong*)(dst += width)) = temp2;
*((ULong*)(dst + 4)) = temp2;
*((ULong*)(dst + 8)) = temp2;
*((ULong*)(dst + 12)) = temp2;
dst = dst - width - 16;
i = 15;
while (i--)
{
M4VENC_MEMCPY(dst + pitch, dst, pitch);
dst += pitch;
}
/* pad sides */
dst += (pitch + 16);
src = dst;
i = height;
while (i--)
{
temp1 = *src;
temp2 = src[width-1];
temp1 |= (temp1 << 8);
temp1 |= (temp1 << 16);
temp2 |= (temp2 << 8);
temp2 |= (temp2 << 16);
*((ULong*)(dst - 16)) = temp1;
*((ULong*)(dst - 12)) = temp1;
*((ULong*)(dst - 8)) = temp1;
*((ULong*)(dst - 4)) = temp1;
*((ULong*)(dst += width)) = temp2;
*((ULong*)(dst + 4)) = temp2;
*((ULong*)(dst + 8)) = temp2;
*((ULong*)(dst + 12)) = temp2;
src += pitch;
dst = src;
}
/* pad bottom */
dst -= 16;
i = 16;
while (i--)
{
M4VENC_MEMCPY(dst, dst - pitch, pitch);
dst += pitch;
}
return ;
}
/*===================================================================
Function: ComputeMBSum
Date: 10/28/2000
Purpose: Compute sum of absolute value (SAV) of blocks in a macroblock
in INTRA mode needed for rate control. Thus, instead of
computing the SAV, we can compute first order moment or
variance .
11/28/00: add MMX
9/3/01: do parallel comp for C function.
===================================================================*/
void ComputeMBSum_C(UChar *cur, Int lx, MOT *mot_mb)
{
Int j;
Int *cInt, *cInt2;
Int sad1 = 0, sad2 = 0, sad3 = 0, sad4 = 0;
Int tmp, tmp2, mask = 0x00FF00FF;
cInt = (Int*)cur; /* make sure this is word-align */
cInt2 = (Int*)(cur + (lx << 3));
j = 8;
while (j--)
{
tmp = cInt[3]; /* load 4 pixels at a time */
tmp2 = tmp & mask;
tmp = (tmp >> 8) & mask;
tmp += tmp2;
sad2 += tmp;
tmp = cInt[2];
tmp2 = tmp & mask;
tmp = (tmp >> 8) & mask;
tmp += tmp2;
sad2 += tmp;
tmp = cInt[1];
tmp2 = tmp & mask;
tmp = (tmp >> 8) & mask;
tmp += tmp2;
sad1 += tmp;
tmp = *cInt;
cInt += (lx >> 2);
tmp2 = tmp & mask;
tmp = (tmp >> 8) & mask;
tmp += tmp2;
sad1 += tmp;
tmp = cInt2[3];
tmp2 = tmp & mask;
tmp = (tmp >> 8) & mask;
tmp += tmp2;
sad4 += tmp;
tmp = cInt2[2];
tmp2 = tmp & mask;
tmp = (tmp >> 8) & mask;
tmp += tmp2;
sad4 += tmp;
tmp = cInt2[1];
tmp2 = tmp & mask;
tmp = (tmp >> 8) & mask;
tmp += tmp2;
sad3 += tmp;
tmp = *cInt2;
cInt2 += (lx >> 2);
tmp2 = tmp & mask;
tmp = (tmp >> 8) & mask;
tmp += tmp2;
sad3 += tmp;
}
sad1 += (sad1 << 16);
sad2 += (sad2 << 16);
sad3 += (sad3 << 16);
sad4 += (sad4 << 16);
sad1 >>= 16;
sad2 >>= 16;
sad3 >>= 16;
sad4 >>= 16;
mot_mb[1].sad = sad1;
mot_mb[2].sad = sad2;
mot_mb[3].sad = sad3;
mot_mb[4].sad = sad4;
mot_mb[0].sad = sad1 + sad2 + sad3 + sad4;
return ;
}