| /* ------------------------------------------------------------------ |
| * 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; |
| |
| } |
| } |
| |
| |