blob: 414b8f7bc480373e954c62824d1745ada415cdc9 [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 <string.h>
#include "avclib_common.h"
OSCL_EXPORT_REF void InitNeighborAvailability(AVCCommonObj *video, int mbNum)
{
int PicWidthInMbs = video->PicWidthInMbs;
// do frame-only and postpone intraAvail calculattion
video->mbAddrA = mbNum - 1;
video->mbAddrB = mbNum - PicWidthInMbs;
video->mbAddrC = mbNum - PicWidthInMbs + 1;
video->mbAddrD = mbNum - PicWidthInMbs - 1;
video->mbAvailA = video->mbAvailB = video->mbAvailC = video->mbAvailD = 0;
if (video->mb_x)
{
video->mbAvailA = (video->mblock[video->mbAddrA].slice_id == video->currMB->slice_id);
if (video->mb_y)
{
video->mbAvailD = (video->mblock[video->mbAddrD].slice_id == video->currMB->slice_id);
}
}
if (video->mb_y)
{
video->mbAvailB = (video->mblock[video->mbAddrB].slice_id == video->currMB->slice_id);
if (video->mb_x < (PicWidthInMbs - 1))
{
video->mbAvailC = (video->mblock[video->mbAddrC].slice_id == video->currMB->slice_id);
}
}
return ;
}
bool mb_is_available(AVCMacroblock *mblock, uint PicSizeInMbs, int mbAddr, int currMbAddr)
{
if (mbAddr < 0 || mbAddr >= (int)PicSizeInMbs)
{
return FALSE;
}
if (mblock[mbAddr].slice_id != mblock[currMbAddr].slice_id)
{
return FALSE;
}
return TRUE;
}
OSCL_EXPORT_REF int predict_nnz(AVCCommonObj *video, int i, int j)
{
int pred_nnz = 0;
int cnt = 1;
AVCMacroblock *tempMB;
/* left block */
/*getLuma4x4Neighbour(video, mb_nr, i, j, -1, 0, &pix);
leftMB = video->mblock + pix.mb_addr; */
/* replace the above with below (won't work for field decoding), 1/19/04 */
if (i)
{
pred_nnz = video->currMB->nz_coeff[(j<<2)+i-1];
}
else
{
if (video->mbAvailA)
{
tempMB = video->mblock + video->mbAddrA;
pred_nnz = tempMB->nz_coeff[(j<<2)+3];
}
else
{
cnt = 0;
}
}
/* top block */
/*getLuma4x4Neighbour(video, mb_nr, i, j, 0, -1, &pix);
topMB = video->mblock + pix.mb_addr;*/
/* replace the above with below (won't work for field decoding), 1/19/04 */
if (j)
{
pred_nnz += video->currMB->nz_coeff[((j-1)<<2)+i];
cnt++;
}
else
{
if (video->mbAvailB)
{
tempMB = video->mblock + video->mbAddrB;
pred_nnz += tempMB->nz_coeff[12+i];
cnt++;
}
}
if (cnt == 2)
{
pred_nnz = (pred_nnz + 1) >> 1;
}
return pred_nnz;
}
OSCL_EXPORT_REF int predict_nnz_chroma(AVCCommonObj *video, int i, int j)
{
int pred_nnz = 0;
int cnt = 1;
AVCMacroblock *tempMB;
/* left block */
/*getChroma4x4Neighbour(video, mb_nr, i%2, j-4, -1, 0, &pix);
leftMB = video->mblock + pix.mb_addr;*/
/* replace the above with below (won't work for field decoding), 1/19/04 */
if (i&1)
{
pred_nnz = video->currMB->nz_coeff[(j<<2)+i-1];
}
else
{
if (video->mbAvailA)
{
tempMB = video->mblock + video->mbAddrA;
pred_nnz = tempMB->nz_coeff[(j<<2)+i+1];
}
else
{
cnt = 0;
}
}
/* top block */
/*getChroma4x4Neighbour(video, mb_nr, i%2, j-4, 0, -1, &pix);
topMB = video->mblock + pix.mb_addr;*/
/* replace the above with below (won't work for field decoding), 1/19/04 */
if (j&1)
{
pred_nnz += video->currMB->nz_coeff[((j-1)<<2)+i];
cnt++;
}
else
{
if (video->mbAvailB)
{
tempMB = video->mblock + video->mbAddrB;
pred_nnz += tempMB->nz_coeff[20+i];
cnt++;
}
}
if (cnt == 2)
{
pred_nnz = (pred_nnz + 1) >> 1;
}
return pred_nnz;
}
OSCL_EXPORT_REF void GetMotionVectorPredictor(AVCCommonObj *video, int encFlag)
{
AVCMacroblock *currMB = video->currMB;
AVCMacroblock *MB_A, *MB_B, *MB_C, *MB_D;
int block_x, block_y, block_x_1, block_y_1, new_block_x;
int mbPartIdx, subMbPartIdx, offset_indx;
int16 *mv, pmv_x, pmv_y;
int nmSubMbHeight, nmSubMbWidth, mbPartIdx_X, mbPartIdx_Y;
int avail_a, avail_b, avail_c;
const static uint32 C = 0x5750;
int i, j, offset_MbPart_indx, refIdxLXA, refIdxLXB, refIdxLXC = 0, curr_ref_idx;
int pmv_A_x, pmv_B_x, pmv_C_x = 0, pmv_A_y, pmv_B_y, pmv_C_y = 0;
/* we have to take care of Intra/skip blocks somewhere, i.e. set MV to 0 and set ref to -1! */
/* we have to populate refIdx as well */
MB_A = &video->mblock[video->mbAddrA];
MB_B = &video->mblock[video->mbAddrB];
if (currMB->mbMode == AVC_SKIP /* && !encFlag */) /* only for decoder */
{
currMB->ref_idx_L0[0] = currMB->ref_idx_L0[1] = currMB->ref_idx_L0[2] = currMB->ref_idx_L0[3] = 0;
if (video->mbAvailA && video->mbAvailB)
{
if ((MB_A->ref_idx_L0[1] == 0 && MB_A->mvL0[3] == 0) ||
(MB_B->ref_idx_L0[2] == 0 && MB_B->mvL0[12] == 0))
{
memset(currMB->mvL0, 0, sizeof(int32)*16);
return;
}
}
else
{
memset(currMB->mvL0, 0, sizeof(int32)*16);
return;
}
video->mvd_l0[0][0][0] = 0;
video->mvd_l0[0][0][1] = 0;
}
MB_C = &video->mblock[video->mbAddrC];
MB_D = &video->mblock[video->mbAddrD];
offset_MbPart_indx = 0;
for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
{
offset_indx = 0;
nmSubMbHeight = currMB->SubMbPartHeight[mbPartIdx] >> 2;
nmSubMbWidth = currMB->SubMbPartWidth[mbPartIdx] >> 2;
mbPartIdx_X = ((mbPartIdx + offset_MbPart_indx) & 1) << 1;
mbPartIdx_Y = (mbPartIdx + offset_MbPart_indx) & 2;
for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
{
block_x = mbPartIdx_X + ((subMbPartIdx + offset_indx) & 1);
block_y = mbPartIdx_Y + (((subMbPartIdx + offset_indx) >> 1) & 1);
block_x_1 = block_x - 1;
block_y_1 = block_y - 1;
refIdxLXA = refIdxLXB = refIdxLXC = -1;
pmv_A_x = pmv_A_y = pmv_B_x = pmv_B_y = pmv_C_x = pmv_C_y = 0;
if (block_x)
{
avail_a = 1;
refIdxLXA = currMB->ref_idx_L0[(block_y & 2) + (block_x_1 >> 1)];
mv = (int16*)(currMB->mvL0 + (block_y << 2) + block_x_1);
pmv_A_x = *mv++;
pmv_A_y = *mv;
}
else
{
avail_a = video->mbAvailA;
if (avail_a)
{
refIdxLXA = MB_A->ref_idx_L0[(block_y & 2) + 1];
mv = (int16*)(MB_A->mvL0 + (block_y << 2) + 3);
pmv_A_x = *mv++;
pmv_A_y = *mv;
}
}
if (block_y)
{
avail_b = 1;
refIdxLXB = currMB->ref_idx_L0[(block_y_1 & 2) + (block_x >> 1)];
mv = (int16*)(currMB->mvL0 + (block_y_1 << 2) + block_x);
pmv_B_x = *mv++;
pmv_B_y = *mv;
}
else
{
avail_b = video->mbAvailB;
if (avail_b)
{
refIdxLXB = MB_B->ref_idx_L0[2 + (block_x >> 1)];
mv = (int16*)(MB_B->mvL0 + 12 + block_x);
pmv_B_x = *mv++;
pmv_B_y = *mv;
}
}
new_block_x = block_x + (currMB->SubMbPartWidth[mbPartIdx] >> 2) - 1;
avail_c = (C >> ((block_y << 2) + new_block_x)) & 0x1;
if (avail_c)
{
/* it guaranteed that block_y > 0 && new_block_x<3 ) */
refIdxLXC = currMB->ref_idx_L0[(block_y_1 & 2) + ((new_block_x+1) >> 1)];
mv = (int16*)(currMB->mvL0 + (block_y_1 << 2) + (new_block_x + 1));
pmv_C_x = *mv++;
pmv_C_y = *mv;
}
else
{
if (block_y == 0 && new_block_x < 3)
{
avail_c = video->mbAvailB;
if (avail_c)
{
refIdxLXC = MB_B->ref_idx_L0[2 + ((new_block_x+1)>>1)];
mv = (int16*)(MB_B->mvL0 + 12 + (new_block_x + 1));
pmv_C_x = *mv++;
pmv_C_y = *mv;
}
}
else if (block_y == 0 && new_block_x == 3)
{
avail_c = video->mbAvailC;
if (avail_c)
{
refIdxLXC = MB_C->ref_idx_L0[2];
mv = (int16*)(MB_C->mvL0 + 12);
pmv_C_x = *mv++;
pmv_C_y = *mv;
}
}
if (avail_c == 0)
{ /* check D */
if (block_x && block_y)
{
avail_c = 1;
refIdxLXC = currMB->ref_idx_L0[(block_y_1 & 2) + (block_x_1 >> 1)];
mv = (int16*)(currMB->mvL0 + (block_y_1 << 2) + block_x_1);
pmv_C_x = *mv++;
pmv_C_y = *mv;
}
else if (block_y)
{
avail_c = video->mbAvailA;
if (avail_c)
{
refIdxLXC = MB_A->ref_idx_L0[(block_y_1 & 2) + 1];
mv = (int16*)(MB_A->mvL0 + (block_y_1 << 2) + 3);
pmv_C_x = *mv++;
pmv_C_y = *mv;
}
}
else if (block_x)
{
avail_c = video->mbAvailB;
if (avail_c)
{
refIdxLXC = MB_B->ref_idx_L0[2 + (block_x_1 >> 1)];
mv = (int16*)(MB_B->mvL0 + 12 + block_x_1);
pmv_C_x = *mv++;
pmv_C_y = *mv;
}
}
else
{
avail_c = video->mbAvailD;
if (avail_c)
{
refIdxLXC = MB_D->ref_idx_L0[3];
mv = (int16*)(MB_D->mvL0 + 15);
pmv_C_x = *mv++;
pmv_C_y = *mv;
}
}
}
}
offset_indx = currMB->SubMbPartWidth[mbPartIdx] >> 3;
curr_ref_idx = currMB->ref_idx_L0[(block_y & 2) + (block_x >> 1)];
if (avail_a && !(avail_b || avail_c))
{
pmv_x = pmv_A_x;
pmv_y = pmv_A_y;
}
else if (((curr_ref_idx == refIdxLXA) + (curr_ref_idx == refIdxLXB) + (curr_ref_idx == refIdxLXC)) == 1)
{
if (curr_ref_idx == refIdxLXA)
{
pmv_x = pmv_A_x;
pmv_y = pmv_A_y;
}
else if (curr_ref_idx == refIdxLXB)
{
pmv_x = pmv_B_x;
pmv_y = pmv_B_y;
}
else
{
pmv_x = pmv_C_x;
pmv_y = pmv_C_y;
}
}
else
{
pmv_x = AVC_MEDIAN(pmv_A_x, pmv_B_x, pmv_C_x);
pmv_y = AVC_MEDIAN(pmv_A_y, pmv_B_y, pmv_C_y);
}
/* overwrite if special case */
if (currMB->NumMbPart == 2)
{
if (currMB->MbPartWidth == 16)
{
if (mbPartIdx == 0)
{
if (refIdxLXB == curr_ref_idx)
{
pmv_x = pmv_B_x;
pmv_y = pmv_B_y;
}
}
else if (refIdxLXA == curr_ref_idx)
{
pmv_x = pmv_A_x;
pmv_y = pmv_A_y;
}
}
else
{
if (mbPartIdx == 0)
{
if (refIdxLXA == curr_ref_idx)
{
pmv_x = pmv_A_x;
pmv_y = pmv_A_y;
}
}
else if (refIdxLXC == curr_ref_idx)
{
pmv_x = pmv_C_x;
pmv_y = pmv_C_y;
}
}
}
mv = (int16*)(currMB->mvL0 + block_x + (block_y << 2));
if (encFlag) /* calculate residual MV video->mvd_l0 */
{
video->mvd_l0[mbPartIdx][subMbPartIdx][0] = *mv++ - pmv_x;
video->mvd_l0[mbPartIdx][subMbPartIdx][1] = *mv++ - pmv_y;
}
else /* calculate original MV currMB->mvL0 */
{
pmv_x += video->mvd_l0[mbPartIdx][subMbPartIdx][0];
pmv_y += video->mvd_l0[mbPartIdx][subMbPartIdx][1];
for (i = 0; i < nmSubMbHeight; i++)
{
for (j = 0; j < nmSubMbWidth; j++)
{
*mv++ = pmv_x;
*mv++ = pmv_y;
}
mv += (8 - (j << 1));
}
}
}
offset_MbPart_indx = currMB->MbPartWidth >> 4;
}
}