summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/codecs/avc/enc/src/slice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/codecs/avc/enc/src/slice.cpp')
-rw-r--r--media/libstagefright/codecs/avc/enc/src/slice.cpp1025
1 files changed, 1025 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/avc/enc/src/slice.cpp b/media/libstagefright/codecs/avc/enc/src/slice.cpp
new file mode 100644
index 0000000..f6d066e
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/slice.cpp
@@ -0,0 +1,1025 @@
+/* ------------------------------------------------------------------
+ * 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 "avcenc_lib.h"
+
+
+AVCEnc_Status AVCEncodeSlice(AVCEncObject *encvid)
+{
+ AVCEnc_Status status = AVCENC_SUCCESS;
+ AVCCommonObj *video = encvid->common;
+ AVCPicParamSet *pps = video->currPicParams;
+ AVCSliceHeader *sliceHdr = video->sliceHdr;
+ AVCMacroblock *currMB ;
+ AVCEncBitstream *stream = encvid->bitstream;
+ uint slice_group_id;
+ int CurrMbAddr, slice_type;
+
+ slice_type = video->slice_type;
+
+ /* set the first mb in slice */
+ video->mbNum = CurrMbAddr = sliceHdr->first_mb_in_slice;// * (1+video->MbaffFrameFlag);
+ slice_group_id = video->MbToSliceGroupMap[CurrMbAddr];
+
+ video->mb_skip_run = 0;
+
+ /* while loop , see subclause 7.3.4 */
+ while (1)
+ {
+ video->mbNum = CurrMbAddr;
+ currMB = video->currMB = &(video->mblock[CurrMbAddr]);
+ currMB->slice_id = video->slice_id; // for deblocking
+
+ video->mb_x = CurrMbAddr % video->PicWidthInMbs;
+ video->mb_y = CurrMbAddr / video->PicWidthInMbs;
+
+ /* initialize QP for this MB here*/
+ /* calculate currMB->QPy */
+ RCInitMBQP(encvid);
+
+ /* check the availability of neighboring macroblocks */
+ InitNeighborAvailability(video, CurrMbAddr);
+
+ /* Assuming that InitNeighborAvailability has been called prior to this function */
+ video->intraAvailA = video->intraAvailB = video->intraAvailC = video->intraAvailD = 0;
+ /* this is necessary for all subsequent intra search */
+
+ if (!video->currPicParams->constrained_intra_pred_flag)
+ {
+ video->intraAvailA = video->mbAvailA;
+ video->intraAvailB = video->mbAvailB;
+ video->intraAvailC = video->mbAvailC;
+ video->intraAvailD = video->mbAvailD;
+ }
+ else
+ {
+ if (video->mbAvailA)
+ {
+ video->intraAvailA = video->mblock[video->mbAddrA].mb_intra;
+ }
+ if (video->mbAvailB)
+ {
+ video->intraAvailB = video->mblock[video->mbAddrB].mb_intra ;
+ }
+ if (video->mbAvailC)
+ {
+ video->intraAvailC = video->mblock[video->mbAddrC].mb_intra;
+ }
+ if (video->mbAvailD)
+ {
+ video->intraAvailD = video->mblock[video->mbAddrD].mb_intra;
+ }
+ }
+
+ /* encode_one_macroblock() */
+ status = EncodeMB(encvid);
+ if (status != AVCENC_SUCCESS)
+ {
+ break;
+ }
+
+ /* go to next MB */
+ CurrMbAddr++;
+
+ while ((uint)video->MbToSliceGroupMap[CurrMbAddr] != slice_group_id &&
+ (uint)CurrMbAddr < video->PicSizeInMbs)
+ {
+ CurrMbAddr++;
+ }
+
+ if ((uint)CurrMbAddr >= video->PicSizeInMbs)
+ {
+ /* end of slice, return, but before that check to see if there are other slices
+ to be encoded. */
+ encvid->currSliceGroup++;
+ if (encvid->currSliceGroup > (int)pps->num_slice_groups_minus1) /* no more slice group */
+ {
+ status = AVCENC_PICTURE_READY;
+ break;
+ }
+ else
+ {
+ /* find first_mb_num for the next slice */
+ CurrMbAddr = 0;
+ while (video->MbToSliceGroupMap[CurrMbAddr] != encvid->currSliceGroup &&
+ (uint)CurrMbAddr < video->PicSizeInMbs)
+ {
+ CurrMbAddr++;
+ }
+ if ((uint)CurrMbAddr >= video->PicSizeInMbs)
+ {
+ status = AVCENC_SLICE_EMPTY; /* error, one slice group has no MBs in it */
+ }
+
+ video->mbNum = CurrMbAddr;
+ status = AVCENC_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ if (video->mb_skip_run > 0)
+ {
+ /* write skip_run */
+ if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
+ {
+ ue_v(stream, video->mb_skip_run);
+ video->mb_skip_run = 0;
+ }
+ else /* shouldn't happen */
+ {
+ status = AVCENC_FAIL;
+ }
+ }
+
+ return status;
+}
+
+
+AVCEnc_Status EncodeMB(AVCEncObject *encvid)
+{
+ AVCEnc_Status status = AVCENC_SUCCESS;
+ AVCCommonObj *video = encvid->common;
+ AVCPictureData *currPic = video->currPic;
+ AVCFrameIO *currInput = encvid->currInput;
+ AVCMacroblock *currMB = video->currMB;
+ AVCMacroblock *MB_A, *MB_B;
+ AVCEncBitstream *stream = encvid->bitstream;
+ AVCRateControl *rateCtrl = encvid->rateCtrl;
+ uint8 *cur, *curL, *curCb, *curCr;
+ uint8 *orgL, *orgCb, *orgCr, *org4;
+ int CurrMbAddr = video->mbNum;
+ int picPitch = currPic->pitch;
+ int orgPitch = currInput->pitch;
+ int x_position = (video->mb_x << 4);
+ int y_position = (video->mb_y << 4);
+ int offset;
+ int b8, b4, blkidx;
+ AVCResidualType resType;
+ int slice_type;
+ int numcoeff; /* output from residual_block_cavlc */
+ int cost16, cost8;
+
+ int num_bits, start_mb_bits, start_text_bits;
+
+ slice_type = video->slice_type;
+
+ /* now, point to the reconstructed frame */
+ offset = y_position * picPitch + x_position;
+ curL = currPic->Sl + offset;
+ orgL = currInput->YCbCr[0] + offset;
+ offset = (offset + x_position) >> 2;
+ curCb = currPic->Scb + offset;
+ curCr = currPic->Scr + offset;
+ orgCb = currInput->YCbCr[1] + offset;
+ orgCr = currInput->YCbCr[2] + offset;
+
+ if (orgPitch != picPitch)
+ {
+ offset = y_position * (orgPitch - picPitch);
+ orgL += offset;
+ offset >>= 2;
+ orgCb += offset;
+ orgCr += offset;
+ }
+
+ /******* determine MB prediction mode *******/
+ if (encvid->intraSearch[CurrMbAddr])
+ {
+ MBIntraSearch(encvid, CurrMbAddr, curL, picPitch);
+ }
+ /******* This part should be determined somehow ***************/
+ if (currMB->mbMode == AVC_I_PCM)
+ {
+ /* write down mb_type and PCM data */
+ /* and copy from currInput to currPic */
+ status = EncodeIntraPCM(encvid);
+
+
+ return status;
+ }
+
+ /****** for intra prediction, pred is already done *******/
+ /****** for I4, the recon is ready and Xfrm coefs are ready to be encoded *****/
+
+ //RCCalculateMAD(encvid,currMB,orgL,orgPitch); // no need to re-calculate MAD for Intra
+ // not used since totalSAD is used instead
+
+ /* compute the prediction */
+ /* output is video->pred_block */
+ if (!currMB->mb_intra)
+ {
+ AVCMBMotionComp(encvid, video); /* perform prediction and residue calculation */
+ /* we can do the loop here and call dct_luma */
+ video->pred_pitch = picPitch;
+ currMB->CBP = 0;
+ cost16 = 0;
+ cur = curL;
+ org4 = orgL;
+
+ for (b8 = 0; b8 < 4; b8++)
+ {
+ cost8 = 0;
+
+ for (b4 = 0; b4 < 4; b4++)
+ {
+ blkidx = blkIdx2blkXY[b8][b4];
+ video->pred_block = cur;
+ numcoeff = dct_luma(encvid, blkidx, cur, org4, &cost8);
+ currMB->nz_coeff[blkidx] = numcoeff;
+ if (numcoeff)
+ {
+ video->cbp4x4 |= (1 << blkidx);
+ currMB->CBP |= (1 << b8);
+ }
+
+ if (b4&1)
+ {
+ cur += ((picPitch << 2) - 4);
+ org4 += ((orgPitch << 2) - 4);
+ }
+ else
+ {
+ cur += 4;
+ org4 += 4;
+ }
+ }
+
+ /* move the IDCT part out of dct_luma to accommodate the check
+ for coeff_cost. */
+
+ if ((currMB->CBP&(1 << b8)) && (cost8 <= _LUMA_COEFF_COST_))
+ {
+ cost8 = 0; // reset it
+
+ currMB->CBP ^= (1 << b8);
+ blkidx = blkIdx2blkXY[b8][0];
+
+ currMB->nz_coeff[blkidx] = 0;
+ currMB->nz_coeff[blkidx+1] = 0;
+ currMB->nz_coeff[blkidx+4] = 0;
+ currMB->nz_coeff[blkidx+5] = 0;
+ }
+
+ cost16 += cost8;
+
+ if (b8&1)
+ {
+ cur -= 8;
+ org4 -= 8;
+ }
+ else
+ {
+ cur += (8 - (picPitch << 3));
+ org4 += (8 - (orgPitch << 3));
+ }
+ }
+
+ /* after the whole MB, we do another check for coeff_cost */
+ if ((currMB->CBP&0xF) && (cost16 <= _LUMA_MB_COEFF_COST_))
+ {
+ currMB->CBP = 0; // reset it to zero
+ memset(currMB->nz_coeff, 0, sizeof(uint8)*16);
+ }
+
+ // now we do IDCT
+ MBInterIdct(video, curL, currMB, picPitch);
+
+// video->pred_block = video->pred + 256;
+ }
+ else /* Intra prediction */
+ {
+ encvid->numIntraMB++;
+
+ if (currMB->mbMode == AVC_I16) /* do prediction for the whole macroblock */
+ {
+ currMB->CBP = 0;
+ /* get the prediction from encvid->pred_i16 */
+ dct_luma_16x16(encvid, curL, orgL);
+ }
+ video->pred_block = encvid->pred_ic[currMB->intra_chroma_pred_mode];
+ }
+
+ /* chrominance */
+ /* not need to do anything, the result is in encvid->pred_ic
+ chroma dct must be aware that prediction block can come from either intra or inter. */
+
+ dct_chroma(encvid, curCb, orgCb, 0);
+
+ dct_chroma(encvid, curCr, orgCr, 1);
+
+
+ /* 4.1 if there's nothing in there, video->mb_skip_run++ */
+ /* 4.2 if coded, check if there is a run of skipped MB, encodes it,
+ set video->QPyprev = currMB->QPy; */
+
+ /* 5. vlc encode */
+
+ /* check for skipped macroblock, INTER only */
+ if (!currMB->mb_intra)
+ {
+ /* decide whether this MB (for inter MB) should be skipped if there's nothing left. */
+ if (!currMB->CBP && currMB->NumMbPart == 1 && currMB->QPy == video->QPy)
+ {
+ if (currMB->MBPartPredMode[0][0] == AVC_Pred_L0 && currMB->ref_idx_L0[0] == 0)
+ {
+ MB_A = &video->mblock[video->mbAddrA];
+ MB_B = &video->mblock[video->mbAddrB];
+
+ if (!video->mbAvailA || !video->mbAvailB)
+ {
+ if (currMB->mvL0[0] == 0) /* both mv components are zeros.*/
+ {
+ currMB->mbMode = AVC_SKIP;
+ video->mvd_l0[0][0][0] = 0;
+ video->mvd_l0[0][0][1] = 0;
+ }
+ }
+ else
+ {
+ 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))
+ {
+ if (currMB->mvL0[0] == 0) /* both mv components are zeros.*/
+ {
+ currMB->mbMode = AVC_SKIP;
+ video->mvd_l0[0][0][0] = 0;
+ video->mvd_l0[0][0][1] = 0;
+ }
+ }
+ else if (video->mvd_l0[0][0][0] == 0 && video->mvd_l0[0][0][1] == 0)
+ {
+ currMB->mbMode = AVC_SKIP;
+ }
+ }
+ }
+
+ if (currMB->mbMode == AVC_SKIP)
+ {
+ video->mb_skip_run++;
+
+ /* set parameters */
+ /* not sure whether we need the followings */
+ if (slice_type == AVC_P_SLICE)
+ {
+ currMB->mbMode = AVC_SKIP;
+ currMB->MbPartWidth = currMB->MbPartHeight = 16;
+ currMB->MBPartPredMode[0][0] = AVC_Pred_L0;
+ currMB->NumMbPart = 1;
+ currMB->NumSubMbPart[0] = currMB->NumSubMbPart[1] =
+ currMB->NumSubMbPart[2] = currMB->NumSubMbPart[3] = 1;
+ currMB->SubMbPartWidth[0] = currMB->SubMbPartWidth[1] =
+ currMB->SubMbPartWidth[2] = currMB->SubMbPartWidth[3] = currMB->MbPartWidth;
+ currMB->SubMbPartHeight[0] = currMB->SubMbPartHeight[1] =
+ currMB->SubMbPartHeight[2] = currMB->SubMbPartHeight[3] = currMB->MbPartHeight;
+
+ }
+ else if (slice_type == AVC_B_SLICE)
+ {
+ currMB->mbMode = AVC_SKIP;
+ currMB->MbPartWidth = currMB->MbPartHeight = 8;
+ currMB->MBPartPredMode[0][0] = AVC_Direct;
+ currMB->NumMbPart = -1;
+ }
+
+ /* for skipped MB, always look at the first entry in RefPicList */
+ currMB->RefIdx[0] = currMB->RefIdx[1] =
+ currMB->RefIdx[2] = currMB->RefIdx[3] = video->RefPicList0[0]->RefIdx;
+
+ /* do not return yet, need to do some copies */
+ }
+ }
+ }
+ /* non-skipped MB */
+
+
+ /************* START ENTROPY CODING *************************/
+
+ start_mb_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+ /* encode mb_type, mb_pred, sub_mb_pred, CBP */
+ if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE && currMB->mbMode != AVC_SKIP)
+ {
+ //if(!pps->entropy_coding_mode_flag) ALWAYS true
+ {
+ ue_v(stream, video->mb_skip_run);
+ video->mb_skip_run = 0;
+ }
+ }
+
+ if (currMB->mbMode != AVC_SKIP)
+ {
+ status = EncodeMBHeader(currMB, encvid);
+ if (status != AVCENC_SUCCESS)
+ {
+ return status;
+ }
+ }
+
+ start_text_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+ /**** now decoding part *******/
+ resType = AVC_Luma;
+
+ /* DC transform for luma I16 mode */
+ if (currMB->mbMode == AVC_I16)
+ {
+ /* vlc encode level/run */
+ status = enc_residual_block(encvid, AVC_Intra16DC, encvid->numcoefdc, currMB);
+ if (status != AVCENC_SUCCESS)
+ {
+ return status;
+ }
+ resType = AVC_Intra16AC;
+ }
+
+ /* VLC encoding for luma */
+ for (b8 = 0; b8 < 4; b8++)
+ {
+ if (currMB->CBP&(1 << b8))
+ {
+ for (b4 = 0; b4 < 4; b4++)
+ {
+ /* vlc encode level/run */
+ status = enc_residual_block(encvid, resType, (b8 << 2) + b4, currMB);
+ if (status != AVCENC_SUCCESS)
+ {
+ return status;
+ }
+ }
+ }
+ }
+
+ /* chroma */
+ if (currMB->CBP & (3 << 4)) /* chroma DC residual present */
+ {
+ for (b8 = 0; b8 < 2; b8++) /* for iCbCr */
+ {
+ /* vlc encode level/run */
+ status = enc_residual_block(encvid, AVC_ChromaDC, encvid->numcoefcdc[b8] + (b8 << 3), currMB);
+ if (status != AVCENC_SUCCESS)
+ {
+ return status;
+ }
+ }
+ }
+
+ if (currMB->CBP & (2 << 4))
+ {
+ /* AC part */
+ for (b8 = 0; b8 < 2; b8++) /* for iCbCr */
+ {
+ for (b4 = 0; b4 < 4; b4++) /* for each block inside Cb or Cr */
+ {
+ /* vlc encode level/run */
+ status = enc_residual_block(encvid, AVC_ChromaAC, 16 + (b8 << 2) + b4, currMB);
+ if (status != AVCENC_SUCCESS)
+ {
+ return status;
+ }
+ }
+ }
+ }
+
+
+ num_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+ RCPostMB(video, rateCtrl, start_text_bits - start_mb_bits,
+ num_bits - start_text_bits);
+
+// num_bits -= start_mb_bits;
+// fprintf(fdebug,"MB #%d: %d bits\n",CurrMbAddr,num_bits);
+// fclose(fdebug);
+ return status;
+}
+
+/* copy the content from predBlock back to the reconstructed YUV frame */
+void Copy_MB(uint8 *curL, uint8 *curCb, uint8 *curCr, uint8 *predBlock, int picPitch)
+{
+ int j, offset;
+ uint32 *dst, *dst2, *src;
+
+ dst = (uint32*)curL;
+ src = (uint32*)predBlock;
+
+ offset = (picPitch - 16) >> 2;
+
+ for (j = 0; j < 16; j++)
+ {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+
+ dst += offset;
+ }
+
+ dst = (uint32*)curCb;
+ dst2 = (uint32*)curCr;
+ offset >>= 1;
+
+ for (j = 0; j < 8; j++)
+ {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst2++ = *src++;
+ *dst2++ = *src++;
+
+ dst += offset;
+ dst2 += offset;
+ }
+ return ;
+}
+
+/* encode mb_type, mb_pred, sub_mb_pred, CBP */
+/* decide whether this MB (for inter MB) should be skipped */
+AVCEnc_Status EncodeMBHeader(AVCMacroblock *currMB, AVCEncObject *encvid)
+{
+ AVCEnc_Status status = AVCENC_SUCCESS;
+ uint mb_type;
+ AVCCommonObj *video = encvid->common;
+ AVCEncBitstream *stream = encvid->bitstream;
+
+ if (currMB->CBP > 47) /* chroma CBP is 11 */
+ {
+ currMB->CBP -= 16; /* remove the 5th bit from the right */
+ }
+
+ mb_type = InterpretMBType(currMB, video->slice_type);
+
+ status = ue_v(stream, mb_type);
+
+ if (currMB->mbMode == AVC_P8 || currMB->mbMode == AVC_P8ref0)
+ {
+ status = sub_mb_pred(video, currMB, stream);
+ }
+ else
+ {
+ status = mb_pred(video, currMB, stream) ;
+ }
+
+ if (currMB->mbMode != AVC_I16)
+ {
+ /* decode coded_block_pattern */
+ status = EncodeCBP(currMB, stream);
+ }
+
+ /* calculate currMB->mb_qp_delta = currMB->QPy - video->QPyprev */
+ if (currMB->CBP > 0 || currMB->mbMode == AVC_I16)
+ {
+ status = se_v(stream, currMB->QPy - video->QPy);
+ video->QPy = currMB->QPy; /* = (video->QPyprev + currMB->mb_qp_delta + 52)%52; */
+ // no need video->QPc = currMB->QPc;
+ }
+ else
+ {
+ if (currMB->QPy != video->QPy) // current QP is not the same as previous QP
+ {
+ /* restore these values */
+ RCRestoreQP(currMB, video, encvid);
+ }
+ }
+
+ return status;
+}
+
+
+/* inputs are mbMode, mb_intra, i16Mode, CBP, NumMbPart, MbPartWidth, MbPartHeight */
+uint InterpretMBType(AVCMacroblock *currMB, int slice_type)
+{
+ int CBP_chrom;
+ int mb_type;// part1, part2, part3;
+// const static int MapParts2Type[2][3][3]={{{4,8,12},{10,6,14},{16,18,20}},
+// {{5,9,13},{11,7,15},{17,19,21}}};
+
+ if (currMB->mb_intra)
+ {
+ if (currMB->mbMode == AVC_I4)
+ {
+ mb_type = 0;
+ }
+ else if (currMB->mbMode == AVC_I16)
+ {
+ CBP_chrom = (currMB->CBP & 0x30);
+ if (currMB->CBP&0xF)
+ {
+ currMB->CBP |= 0xF; /* either 0x0 or 0xF */
+ mb_type = 13;
+ }
+ else
+ {
+ mb_type = 1;
+ }
+ mb_type += (CBP_chrom >> 2) + currMB->i16Mode;
+ }
+ else /* if(currMB->mbMode == AVC_I_PCM) */
+ {
+ mb_type = 25;
+ }
+ }
+ else
+ { /* P-MB *//* note that the order of the enum AVCMBMode cannot be changed
+ since we use it here. */
+ mb_type = currMB->mbMode - AVC_P16;
+ }
+
+ if (slice_type == AVC_P_SLICE)
+ {
+ if (currMB->mb_intra)
+ {
+ mb_type += 5;
+ }
+ }
+ // following codes have not been tested yet, not needed.
+ /* else if(slice_type == AVC_B_SLICE)
+ {
+ if(currMB->mbMode == AVC_BDirect16)
+ {
+ mb_type = 0;
+ }
+ else if(currMB->mbMode == AVC_P16)
+ {
+ mb_type = currMB->MBPartPredMode[0][0] + 1; // 1 or 2
+ }
+ else if(currMB->mbMode == AVC_P8)
+ {
+ mb_type = 26;
+ }
+ else if(currMB->mbMode == AVC_P8ref0)
+ {
+ mb_type = 27;
+ }
+ else
+ {
+ part1 = currMB->mbMode - AVC_P16x8;
+ part2 = currMB->MBPartPredMode[0][0];
+ part3 = currMB->MBPartPredMode[1][0];
+ mb_type = MapParts2Type[part1][part2][part3];
+ }
+ }
+
+ if(slice_type == AVC_SI_SLICE)
+ {
+ mb_type++;
+ }
+ */
+ return (uint)mb_type;
+}
+
+//const static int mbPart2raster[3][4] = {{0,0,0,0},{1,1,0,0},{1,0,1,0}};
+
+/* see subclause 7.3.5.1 */
+AVCEnc_Status mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+ AVCEnc_Status status = AVCENC_SUCCESS;
+ int mbPartIdx;
+ AVCSliceHeader *sliceHdr = video->sliceHdr;
+ int max_ref_idx;
+ uint code;
+
+ if (currMB->mbMode == AVC_I4 || currMB->mbMode == AVC_I16)
+ {
+ if (currMB->mbMode == AVC_I4)
+ {
+ /* perform prediction to get the actual intra 4x4 pred mode */
+ EncodeIntra4x4Mode(video, currMB, stream);
+ /* output will be in currMB->i4Mode[4][4] */
+ }
+
+ /* assume already set from MBPrediction() */
+ status = ue_v(stream, currMB->intra_chroma_pred_mode);
+ }
+ else if (currMB->MBPartPredMode[0][0] != AVC_Direct)
+ {
+
+ memset(currMB->ref_idx_L0, 0, sizeof(int16)*4);
+
+ /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+ max_ref_idx = sliceHdr->num_ref_idx_l0_active_minus1;
+ /* if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+ max_ref_idx = 2*sliceHdr->num_ref_idx_l0_active_minus1 + 1;
+ */
+ /* decode ref index for L0 */
+ if (sliceHdr->num_ref_idx_l0_active_minus1 > 0)
+ {
+ for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+ {
+ if (/*(sliceHdr->num_ref_idx_l0_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+ currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+ {
+ code = currMB->ref_idx_L0[mbPartIdx];
+ status = te_v(stream, code, max_ref_idx);
+ }
+ }
+ }
+
+ /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+ max_ref_idx = sliceHdr->num_ref_idx_l1_active_minus1;
+ /* if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+ max_ref_idx = 2*sliceHdr->num_ref_idx_l1_active_minus1 + 1;
+ */
+ /* decode ref index for L1 */
+ if (sliceHdr->num_ref_idx_l1_active_minus1 > 0)
+ {
+ for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+ {
+ if (/*(sliceHdr->num_ref_idx_l1_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+ currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+ {
+ status = te_v(stream, currMB->ref_idx_L1[mbPartIdx], max_ref_idx);
+ }
+ }
+ }
+
+ /* encode mvd_l0 */
+ for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+ {
+ if (currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+ {
+ status = se_v(stream, video->mvd_l0[mbPartIdx][0][0]);
+ status = se_v(stream, video->mvd_l0[mbPartIdx][0][1]);
+ }
+ }
+ /* encode mvd_l1 */
+ for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+ {
+ if (currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+ {
+ status = se_v(stream, video->mvd_l1[mbPartIdx][0][0]);
+ status = se_v(stream, video->mvd_l1[mbPartIdx][0][1]);
+ }
+ }
+ }
+
+ return status;
+}
+
+/* see subclause 7.3.5.2 */
+AVCEnc_Status sub_mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+ AVCEnc_Status status = AVCENC_SUCCESS;
+ int mbPartIdx, subMbPartIdx;
+ AVCSliceHeader *sliceHdr = video->sliceHdr;
+ uint max_ref_idx;
+ uint slice_type = video->slice_type;
+ uint sub_mb_type[4];
+
+ /* this should move somewhere else where we don't have to make this check */
+ if (currMB->mbMode == AVC_P8ref0)
+ {
+ memset(currMB->ref_idx_L0, 0, sizeof(int16)*4);
+ }
+
+ /* we have to check the values to make sure they are valid */
+ /* assign values to currMB->sub_mb_type[] */
+ if (slice_type == AVC_P_SLICE)
+ {
+ InterpretSubMBTypeP(currMB, sub_mb_type);
+ }
+ /* no need to check for B-slice
+ else if(slice_type == AVC_B_SLICE)
+ {
+ InterpretSubMBTypeB(currMB,sub_mb_type);
+ }*/
+
+ for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+ {
+ status = ue_v(stream, sub_mb_type[mbPartIdx]);
+ }
+
+ /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+ max_ref_idx = sliceHdr->num_ref_idx_l0_active_minus1;
+ /* if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+ max_ref_idx = 2*sliceHdr->num_ref_idx_l0_active_minus1 + 1; */
+
+ for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+ {
+ if ((sliceHdr->num_ref_idx_l0_active_minus1 > 0 /*|| currMB->mb_field_decoding_flag*/) &&
+ currMB->mbMode != AVC_P8ref0 && /*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+ currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+ {
+ status = te_v(stream, currMB->ref_idx_L0[mbPartIdx], max_ref_idx);
+ }
+ /* used in deblocking */
+ currMB->RefIdx[mbPartIdx] = video->RefPicList0[currMB->ref_idx_L0[mbPartIdx]]->RefIdx;
+ }
+ /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+ max_ref_idx = sliceHdr->num_ref_idx_l1_active_minus1;
+ /* if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+ max_ref_idx = 2*sliceHdr->num_ref_idx_l1_active_minus1 + 1;*/
+
+ if (sliceHdr->num_ref_idx_l1_active_minus1 > 0)
+ {
+ for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+ {
+ if (/*(sliceHdr->num_ref_idx_l1_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+ /*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+ currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+ {
+ status = te_v(stream, currMB->ref_idx_L1[mbPartIdx], max_ref_idx);
+ }
+ }
+ }
+
+ for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+ {
+ if (/*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+ currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+ {
+ for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
+ {
+ status = se_v(stream, video->mvd_l0[mbPartIdx][subMbPartIdx][0]);
+ status = se_v(stream, video->mvd_l0[mbPartIdx][subMbPartIdx][1]);
+ }
+ }
+ }
+
+ for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+ {
+ if (/*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+ currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+ {
+ for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
+ {
+ status = se_v(stream, video->mvd_l1[mbPartIdx][subMbPartIdx][0]);
+ status = se_v(stream, video->mvd_l1[mbPartIdx][subMbPartIdx][1]);
+ }
+ }
+ }
+
+ return status;
+}
+
+/* input is mblock->sub_mb_type[] */
+void InterpretSubMBTypeP(AVCMacroblock *mblock, uint *sub_mb_type)
+{
+ int i;
+ /* see enum AVCMBType declaration */
+ /*const static AVCSubMBMode map2subMbMode[4] = {AVC_8x8,AVC_8x4,AVC_4x8,AVC_4x4};
+ const static int map2subPartWidth[4] = {8,8,4,4};
+ const static int map2subPartHeight[4] = {8,4,8,4};
+ const static int map2numSubPart[4] = {1,2,2,4};*/
+
+ for (i = 0; i < 4 ; i++)
+ {
+ sub_mb_type[i] = mblock->subMbMode[i] - AVC_8x8;
+ }
+
+ return ;
+}
+
+void InterpretSubMBTypeB(AVCMacroblock *mblock, uint *sub_mb_type)
+{
+ int i;
+ /* see enum AVCMBType declaration */
+ /* const static AVCSubMBMode map2subMbMode[13] = {AVC_BDirect8,AVC_8x8,AVC_8x8,
+ AVC_8x8,AVC_8x4,AVC_4x8,AVC_8x4,AVC_4x8,AVC_8x4,AVC_4x8,AVC_4x4,AVC_4x4,AVC_4x4};
+ const static int map2subPartWidth[13] = {4,8,8,8,8,4,8,4,8,4,4,4,4};
+ const static int map2subPartHeight[13] = {4,8,8,8,4,8,4,8,4,8,4,4,4};
+ const static int map2numSubPart[13] = {4,1,1,1,2,2,2,2,2,2,4,4,4};
+ const static int map2predMode[13] = {3,0,1,2,0,0,1,1,2,2,0,1,2};*/
+
+ for (i = 0; i < 4 ; i++)
+ {
+ if (mblock->subMbMode[i] == AVC_BDirect8)
+ {
+ sub_mb_type[i] = 0;
+ }
+ else if (mblock->subMbMode[i] == AVC_8x8)
+ {
+ sub_mb_type[i] = 1 + mblock->MBPartPredMode[i][0];
+ }
+ else if (mblock->subMbMode[i] == AVC_4x4)
+ {
+ sub_mb_type[i] = 10 + mblock->MBPartPredMode[i][0];
+ }
+ else
+ {
+ sub_mb_type[i] = 4 + (mblock->MBPartPredMode[i][0] << 1) + (mblock->subMbMode[i] - AVC_8x4);
+ }
+ }
+
+ return ;
+}
+
+/* see subclause 8.3.1 */
+AVCEnc_Status EncodeIntra4x4Mode(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+ int intra4x4PredModeA = 0;
+ int intra4x4PredModeB, predIntra4x4PredMode;
+ int component, SubBlock_indx, block_x, block_y;
+ int dcOnlyPredictionFlag;
+ uint flag;
+ int rem = 0;
+ int mode;
+ int bindx = 0;
+
+ for (component = 0; component < 4; component++) /* partition index */
+ {
+ block_x = ((component & 1) << 1);
+ block_y = ((component >> 1) << 1);
+
+ for (SubBlock_indx = 0; SubBlock_indx < 4; SubBlock_indx++) /* sub-partition index */
+ {
+ dcOnlyPredictionFlag = 0;
+ if (block_x > 0)
+ {
+ intra4x4PredModeA = currMB->i4Mode[(block_y << 2) + block_x - 1 ];
+ }
+ else
+ {
+ if (video->intraAvailA)
+ {
+ if (video->mblock[video->mbAddrA].mbMode == AVC_I4)
+ {
+ intra4x4PredModeA = video->mblock[video->mbAddrA].i4Mode[(block_y << 2) + 3];
+ }
+ else
+ {
+ intra4x4PredModeA = AVC_I4_DC;
+ }
+ }
+ else
+ {
+ dcOnlyPredictionFlag = 1;
+ }
+ }
+
+ if (block_y > 0)
+ {
+ intra4x4PredModeB = currMB->i4Mode[((block_y-1) << 2) + block_x];
+ }
+ else
+ {
+ if (video->intraAvailB)
+ {
+ if (video->mblock[video->mbAddrB].mbMode == AVC_I4)
+ {
+ intra4x4PredModeB = video->mblock[video->mbAddrB].i4Mode[(3 << 2) + block_x];
+ }
+ else
+ {
+ intra4x4PredModeB = AVC_I4_DC;
+ }
+ }
+ else
+ {
+ dcOnlyPredictionFlag = 1;
+ }
+ }
+
+ if (dcOnlyPredictionFlag)
+ {
+ intra4x4PredModeA = intra4x4PredModeB = AVC_I4_DC;
+ }
+
+ predIntra4x4PredMode = AVC_MIN(intra4x4PredModeA, intra4x4PredModeB);
+
+ flag = 0;
+ mode = currMB->i4Mode[(block_y<<2)+block_x];
+
+ if (mode == (AVCIntra4x4PredMode)predIntra4x4PredMode)
+ {
+ flag = 1;
+ }
+ else if (mode < predIntra4x4PredMode)
+ {
+ rem = mode;
+ }
+ else
+ {
+ rem = mode - 1;
+ }
+
+ BitstreamWrite1Bit(stream, flag);
+
+ if (!flag)
+ {
+ BitstreamWriteBits(stream, 3, rem);
+ }
+
+ bindx++;
+ block_y += (SubBlock_indx & 1) ;
+ block_x += (1 - 2 * (SubBlock_indx & 1)) ;
+ }
+ }
+
+ return AVCENC_SUCCESS;
+}
+
+
+