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