diff options
Diffstat (limited to 'media/libstagefright/codecs/avc/enc/src/residual.cpp')
-rw-r--r-- | media/libstagefright/codecs/avc/enc/src/residual.cpp | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/avc/enc/src/residual.cpp b/media/libstagefright/codecs/avc/enc/src/residual.cpp new file mode 100644 index 0000000..42eb910 --- /dev/null +++ b/media/libstagefright/codecs/avc/enc/src/residual.cpp @@ -0,0 +1,389 @@ +/* ------------------------------------------------------------------ + * 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 EncodeIntraPCM(AVCEncObject *encvid) +{ + AVCEnc_Status status = AVCENC_SUCCESS; + AVCCommonObj *video = encvid->common; + AVCFrameIO *currInput = encvid->currInput; + AVCEncBitstream *stream = encvid->bitstream; + int x_position = (video->mb_x << 4); + int y_position = (video->mb_y << 4); + int orgPitch = currInput->pitch; + int offset1 = y_position * orgPitch + x_position; + int i, j; + int offset; + uint8 *pDst, *pSrc; + uint code; + + ue_v(stream, 25); + + i = stream->bit_left & 0x7; + if (i) /* not byte-aligned */ + { + BitstreamWriteBits(stream, 0, i); + } + + pSrc = currInput->YCbCr[0] + offset1; + pDst = video->currPic->Sl + offset1; + offset = video->PicWidthInSamplesL - 16; + + /* at this point bitstream is byte-aligned */ + j = 16; + while (j > 0) + { +#if (WORD_SIZE==32) + for (i = 0; i < 4; i++) + { + code = *((uint*)pSrc); + pSrc += 4; + *((uint*)pDst) = code; + pDst += 4; + status = BitstreamWriteBits(stream, 32, code); + } +#else + for (i = 0; i < 8; i++) + { + code = *((uint*)pSrc); + pSrc += 2; + *((uint*)pDst) = code; + pDst += 2; + status = BitstreamWriteBits(stream, 16, code); + } +#endif + pDst += offset; + pSrc += offset; + j--; + } + if (status != AVCENC_SUCCESS) /* check only once per line */ + return status; + + pDst = video->currPic->Scb + ((offset1 + x_position) >> 2); + pSrc = currInput->YCbCr[1] + ((offset1 + x_position) >> 2); + offset >>= 1; + + j = 8; + while (j > 0) + { +#if (WORD_SIZE==32) + for (i = 0; i < 2; i++) + { + code = *((uint*)pSrc); + pSrc += 4; + *((uint*)pDst) = code; + pDst += 4; + status = BitstreamWriteBits(stream, 32, code); + } +#else + for (i = 0; i < 4; i++) + { + code = *((uint*)pSrc); + pSrc += 2; + *((uint*)pDst) = code; + pDst += 2; + status = BitstreamWriteBits(stream, 16, code); + } +#endif + pDst += offset; + pSrc += offset; + j--; + } + + if (status != AVCENC_SUCCESS) /* check only once per line */ + return status; + + pDst = video->currPic->Scr + ((offset1 + x_position) >> 2); + pSrc = currInput->YCbCr[2] + ((offset1 + x_position) >> 2); + + j = 8; + while (j > 0) + { +#if (WORD_SIZE==32) + for (i = 0; i < 2; i++) + { + code = *((uint*)pSrc); + pSrc += 4; + *((uint*)pDst) = code; + pDst += 4; + status = BitstreamWriteBits(stream, 32, code); + } +#else + for (i = 0; i < 4; i++) + { + code = *((uint*)pSrc); + pSrc += 2; + *((uint*)pDst) = code; + pDst += 2; + status = BitstreamWriteBits(stream, 16, code); + } +#endif + pDst += offset; + pSrc += offset; + j--; + } + + return status; +} + + +AVCEnc_Status enc_residual_block(AVCEncObject *encvid, AVCResidualType type, int cindx, AVCMacroblock *currMB) +{ + AVCEnc_Status status = AVCENC_SUCCESS; + AVCCommonObj *video = encvid->common; + int i, maxNumCoeff, nC; + int cdc = 0, cac = 0; + int TrailingOnes; + AVCEncBitstream *stream = encvid->bitstream; + uint trailing_ones_sign_flag; + int zerosLeft; + int *level, *run; + int TotalCoeff; + const static int incVlc[] = {0, 3, 6, 12, 24, 48, 32768}; // maximum vlc = 6 + int escape, numPrefix, sufmask, suffix, shift, sign, value, absvalue, vlcnum, level_two_or_higher; + int bindx = blkIdx2blkXY[cindx>>2][cindx&3] ; // raster scan index + + switch (type) + { + case AVC_Luma: + maxNumCoeff = 16; + level = encvid->level[cindx]; + run = encvid->run[cindx]; + TotalCoeff = currMB->nz_coeff[bindx]; + break; + case AVC_Intra16DC: + maxNumCoeff = 16; + level = encvid->leveldc; + run = encvid->rundc; + TotalCoeff = cindx; /* special case */ + bindx = 0; + cindx = 0; + break; + case AVC_Intra16AC: + maxNumCoeff = 15; + level = encvid->level[cindx]; + run = encvid->run[cindx]; + TotalCoeff = currMB->nz_coeff[bindx]; + break; + case AVC_ChromaDC: /* how to differentiate Cb from Cr */ + maxNumCoeff = 4; + cdc = 1; + if (cindx >= 8) + { + level = encvid->levelcdc + 4; + run = encvid->runcdc + 4; + TotalCoeff = cindx - 8; /* special case */ + } + else + { + level = encvid->levelcdc; + run = encvid->runcdc; + TotalCoeff = cindx; /* special case */ + } + break; + case AVC_ChromaAC: + maxNumCoeff = 15; + cac = 1; + level = encvid->level[cindx]; + run = encvid->run[cindx]; + cindx -= 16; + bindx = 16 + blkIdx2blkXY[cindx>>2][cindx&3]; + cindx += 16; + TotalCoeff = currMB->nz_coeff[bindx]; + break; + default: + return AVCENC_FAIL; + } + + + /* find TrailingOnes */ + TrailingOnes = 0; + zerosLeft = 0; + i = TotalCoeff - 1; + nC = 1; + while (i >= 0) + { + zerosLeft += run[i]; + if (nC && (level[i] == 1 || level[i] == -1)) + { + TrailingOnes++; + } + else + { + nC = 0; + } + i--; + } + if (TrailingOnes > 3) + { + TrailingOnes = 3; /* clip it */ + } + + if (!cdc) + { + if (!cac) /* not chroma */ + { + nC = predict_nnz(video, bindx & 3, bindx >> 2); + } + else /* chroma ac but not chroma dc */ + { + nC = predict_nnz_chroma(video, bindx & 3, bindx >> 2); + } + + status = ce_TotalCoeffTrailingOnes(stream, TrailingOnes, TotalCoeff, nC); + } + else + { + nC = -1; /* Chroma DC level */ + status = ce_TotalCoeffTrailingOnesChromaDC(stream, TrailingOnes, TotalCoeff); + } + + /* This part is done quite differently in ReadCoef4x4_CAVLC() */ + if (TotalCoeff > 0) + { + + i = TotalCoeff - 1; + + if (TrailingOnes) /* keep reading the sign of those trailing ones */ + { + nC = TrailingOnes; + trailing_ones_sign_flag = 0; + while (nC) + { + trailing_ones_sign_flag <<= 1; + trailing_ones_sign_flag |= ((uint32)level[i--] >> 31); /* 0 or positive, 1 for negative */ + nC--; + } + + /* instead of writing one bit at a time, read the whole thing at once */ + status = BitstreamWriteBits(stream, TrailingOnes, trailing_ones_sign_flag); + } + + level_two_or_higher = 1; + if (TotalCoeff > 3 && TrailingOnes == 3) + { + level_two_or_higher = 0; + } + + if (TotalCoeff > 10 && TrailingOnes < 3) + { + vlcnum = 1; + } + else + { + vlcnum = 0; + } + + /* then do this TotalCoeff-TrailingOnes times */ + for (i = TotalCoeff - TrailingOnes - 1; i >= 0; i--) + { + value = level[i]; + absvalue = (value >= 0) ? value : -value; + + if (level_two_or_higher) + { + if (value > 0) value--; + else value++; + level_two_or_higher = 0; + } + + if (value >= 0) + { + sign = 0; + } + else + { + sign = 1; + value = -value; + } + + if (vlcnum == 0) // VLC1 + { + if (value < 8) + { + status = BitstreamWriteBits(stream, value * 2 + sign - 1, 1); + } + else if (value < 8 + 8) + { + status = BitstreamWriteBits(stream, 14 + 1 + 4, (1 << 4) | ((value - 8) << 1) | sign); + } + else + { + status = BitstreamWriteBits(stream, 14 + 2 + 12, (1 << 12) | ((value - 16) << 1) | sign) ; + } + } + else // VLCN + { + shift = vlcnum - 1; + escape = (15 << shift) + 1; + numPrefix = (value - 1) >> shift; + sufmask = ~((0xffffffff) << shift); + suffix = (value - 1) & sufmask; + if (value < escape) + { + status = BitstreamWriteBits(stream, numPrefix + vlcnum + 1, (1 << (shift + 1)) | (suffix << 1) | sign); + } + else + { + status = BitstreamWriteBits(stream, 28, (1 << 12) | ((value - escape) << 1) | sign); + } + + } + + if (absvalue > incVlc[vlcnum]) + vlcnum++; + + if (i == TotalCoeff - TrailingOnes - 1 && absvalue > 3) + vlcnum = 2; + } + + if (status != AVCENC_SUCCESS) /* occasionally check the bitstream */ + { + return status; + } + if (TotalCoeff < maxNumCoeff) + { + if (!cdc) + { + ce_TotalZeros(stream, zerosLeft, TotalCoeff); + } + else + { + ce_TotalZerosChromaDC(stream, zerosLeft, TotalCoeff); + } + } + else + { + zerosLeft = 0; + } + + i = TotalCoeff - 1; + while (i > 0) /* don't do the last one */ + { + if (zerosLeft > 0) + { + ce_RunBefore(stream, run[i], zerosLeft); + } + + zerosLeft = zerosLeft - run[i]; + i--; + } + } + + return status; +} |