videoeditorengine/avcedit/src/macroblock.cpp
author Mikael Laine <mikael.laine@ixonos.com>
Fri, 29 Jan 2010 14:08:33 +0200
changeset 0 951a5db380a0
permissions -rw-r--r--
Committing the Video Editor package under the Eclipse Public License

/*
* Copyright (c) 2010 Ixonos Plc.
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - Initial contribution
*
* Contributors:
* Ixonos Plc
*
* Description:
*
*/


#include "globals.h"
#include "bitbuffer.h"
#include "macroblock.h"
#include "motcomp.h"
#include "framebuffer.h"
#include "vld.h"
#include "parameterset.h"

#ifdef USE_CLIPBUF
#include "clipbuf.h"
#endif

/*
 * Static functions
 */

static int getMacroblock(macroblock_s *mb, int numRefFrames,
                         int8 *ipTab, int8 **numCoefUpPred, int diffVecs[][2],
                         int picType, int chromaQpIdx, bitbuffer_s *bitbuf);

static int getMbAvailability(macroblock_s *mb, mbAttributes_s *mbData,
                             int picWidth, int constrainedIntra);


#ifdef USE_CLIPBUF
const u_int8 *mcpGetClip8Buf()
{
  return clip8Buf;
}
#endif

/*
 *
 * getMacroblock:
 *
 * Parameters:
 *      mb                    Macroblock parameters
 *      multRef               1 -> multiple reference frames used
 *      ipTab                 Macroblock intra pred. modes
 *      numCoefUpPred         Block coefficient counts of upper MBs
 *      diffVecs              Macroblock delta motion vectors
 *      picType               Picture type (intra/inter)
 *      chromaQpIdx           Chroma QP index relative to luma QP
 *      bitbuf                Bitbuffer handle
 *
 * Function:
 *      Get macroblock parameters from bitbuffer
 *      
 * Returns:
 *      MBK_OK for no error, MBK_ERROR for error
 *
 */
static int getMacroblock(macroblock_s *mb, int numRefFrames,
                         int8 *ipTab, int8 **numCoefUpPred, int diffVecs[][2],
                         int picType, int chromaQpIdx, bitbuffer_s *bitbuf)
{
  vldMBtype_s hdr;
  int numVecs;
  int delta_qp;
  int i;
  int8 *numCoefPtrY, *numCoefPtrU, *numCoefPtrV;
  int retCode;


  numCoefPtrY = &numCoefUpPred[0][mb->blkX];
  numCoefPtrU = &numCoefUpPred[1][mb->blkX>>1];
  numCoefPtrV = &numCoefUpPred[2][mb->blkX>>1];

  /*
   * Get Macroblock type
   */

  /* Check if we have to fetch run indicator */
  if (IS_SLICE_P(picType) && mb->numSkipped < 0) {

    mb->numSkipped = vldGetRunIndicator(bitbuf);

    if (bibGetStatus(bitbuf) < 0)
      return MBK_ERROR;
  }

  if (IS_SLICE_P(picType) && mb->numSkipped > 0) {

    /* If skipped MBs, set MB to COPY */
    mb->type = MBK_INTER;
    mb->interMode = MOT_COPY;
    mb->refNum[0] = 0;
    mb->cbpY = mb->cbpChromaDC = mb->cbpC = 0;
    mb->numSkipped -= 1;

    vldGetZeroLumaCoeffs(numCoefPtrY, mb->numCoefLeftPred);
    vldGetZeroChromaCoeffs(numCoefPtrU, numCoefPtrV, mb->numCoefLeftPredC);

    return MBK_OK;
  }
  else {

    if (vldGetMBtype(bitbuf, &hdr, picType) < 0) {
      PRINT((_L("Error: illegal MB type\n")));     
      return MBK_ERROR;
    }

    mb->type        = hdr.type;
    mb->intraType   = hdr.intraType;
    mb->intraMode   = hdr.intraMode;
    mb->interMode   = hdr.interMode;

    for (i = 0; i < 4; i++)
      mb->inter8x8modes[i] = hdr.inter8x8modes[i];

    mb->cbpY        = hdr.cbpY;
    mb->cbpChromaDC = hdr.cbpChromaDC;
    mb->cbpC        = hdr.cbpC;

    mb->numSkipped -= 1;
  }

  if (mb->type == MBK_INTRA && mb->intraType == MBK_INTRA_TYPE_PCM) {
    vldGetAllCoeffs(numCoefPtrY, numCoefPtrU, numCoefPtrV,
                    mb->numCoefLeftPred, mb->numCoefLeftPredC);
    return MBK_OK;
  }

  /*
   * 4x4 intra prediction modes 
   */
  if (mb->type == MBK_INTRA && mb->intraType == MBK_INTRA_TYPE1) {

    if (vldGetIntraPred(bitbuf, ipTab) < 0) {
      PRINT((_L("Error: illegal intra pred\n")));     
      return MBK_ERROR;
    }
  }

  /*
   * 8x8 chroma intra prediction mode
   */
  if (mb->type == MBK_INTRA) {

    mb->intraModeChroma = vldGetChromaIntraPred(bitbuf);

    if (mb->intraModeChroma < 0) {
      PRINT((_L("Error: illegal chroma intra pred\n")));     
      return MBK_ERROR;
    }
  }

  /*
   * Reference frame number and motion vectors
   */
  if (mb->type == MBK_INTER) {

    numVecs = mcpGetNumMotVecs(mb->interMode, mb->inter8x8modes);
    mb->numMotVecs = numVecs;

    retCode = vldGetMotVecs(bitbuf, mb->interMode, numRefFrames,
                            mb->refNum, diffVecs, numVecs);

    if (retCode < 0) {
      PRINT((_L("Error: illegal motion vectors\n")));     
      return MBK_ERROR;
    }
  }

  /*
   * Coded block pattern
   */
  if (!(mb->type == MBK_INTRA && mb->intraType == MBK_INTRA_TYPE2)) {

    retCode = vldGetCBP(bitbuf, mb->type, &mb->cbpY, &mb->cbpChromaDC, &mb->cbpC);

    if (retCode < 0) {
      PRINT((_L("Error: illegal CBP\n")));     
      return MBK_ERROR;
    }
  }


  /* Delta QP */
  if ((mb->type == MBK_INTRA && mb->intraType == MBK_INTRA_TYPE2) || 
      (mb->cbpY | mb->cbpChromaDC | mb->cbpC) != 0)
  {
    retCode = vldGetDeltaqp(bitbuf, &delta_qp);

    if (retCode < 0 || delta_qp < -(MAX_QP-MIN_QP+1)/2 || delta_qp >= (MAX_QP-MIN_QP+1)/2) {
      PRINT((_L("Error: illegal delta qp\n")));     
      return MBK_ERROR;
    }

    if (delta_qp != 0) {
      int qp = mb->qp + delta_qp;
      if (qp < MIN_QP)
        qp += (MAX_QP-MIN_QP+1);
      if (qp > MAX_QP)
        qp -= (MAX_QP-MIN_QP+1);
      mb->qp = qp;
      mb->qpC = qpChroma[clip(MIN_QP, MAX_QP, mb->qp + chromaQpIdx)];
    }
  }


  /*
   * Get transform coefficients
   */

  /*
   * Luma DC coefficients (if 16x16 intra)
   */
  if (mb->type == MBK_INTRA && mb->intraType == MBK_INTRA_TYPE2) {

    retCode = vldGetLumaDCcoeffs(bitbuf, mb->dcCoefY, numCoefPtrY,
                             mb->numCoefLeftPred, mb->mbAvailBits);
    if (retCode < 0) {
      PRINT((_L("Error: illegal luma DC coefficient\n")));     
      return MBK_ERROR;
    }
  }

  /*
   * Luma AC coefficients
   */
  if (mb->cbpY != 0) {

    retCode = vldGetLumaCoeffs(bitbuf, mb->type, mb->intraType, &mb->cbpY,
                               mb->coefY, numCoefPtrY, mb->numCoefLeftPred,
                               mb->mbAvailBits);
    if (retCode < 0) {
      PRINT((_L("Error: illegal luma AC coefficient\n")));     
      return MBK_ERROR;
    } 
  }
  else
    vldGetZeroLumaCoeffs(numCoefPtrY, mb->numCoefLeftPred);

  /*
   * Chroma DC coefficients
   */
  if (mb->cbpChromaDC != 0) {

    retCode = vldGetChromaDCcoeffs(bitbuf, mb->dcCoefC, &mb->cbpChromaDC);

    if (retCode < 0) {
      PRINT((_L("Error: illegal chroma DC coefficient\n")));     
      return MBK_ERROR;
    }
  }

  /*
   * Chroma AC coefficients
   */
  if (mb->cbpC != 0) {

    retCode = vldGetChromaCoeffs(bitbuf, mb->coefC, &mb->cbpC, numCoefPtrU, numCoefPtrV,
                             mb->numCoefLeftPredC[0], mb->numCoefLeftPredC[1], mb->mbAvailBits);
    if (retCode < 0) {
      PRINT((_L("Error: illegal chroma AC coefficient\n")));     
      return MBK_ERROR;
    }
  }
  else {
    vldGetZeroChromaCoeffs(numCoefPtrU, numCoefPtrV, mb->numCoefLeftPredC);
  }

  return MBK_OK;
}


/*
 *
 * mbkSetInitialQP:
 *
 * Parameters:
 *      mb                    Macroblock object
 *      qp                    Quantization parameter
 *      chromaQpIdx           Chroma QP index relative to luma QP
 *
 * Function:
 *      Set macroblock qp.
 *      
 * Returns:
 *      -
 *
 */
void mbkSetInitialQP(macroblock_s *mb, int qp, int chromaQpIdx)
{
  mb->qp  = qp;
  mb->qpC = qpChroma[clip(MIN_QP, MAX_QP, qp + chromaQpIdx)];

  mb->numSkipped = -1;
}


/*
 *
 * getMbAvailability:
 *
 * Parameters:
 *      mb                    Macroblock object
 *      mbData                Buffers for for macroblock attributes
 *      picWidth              Picture width
 *      constrainedIntra      Constrained intra prediction flag
 *
 * Function:
 *      Get neighboring macroblock availability info
 *      
 * Returns:
 *      Macroblock availability bits:
 *        bit 0 : left macroblock
 *        bit 1 : upper macroblock
 *        bit 2 : upper-right macroblock
 *        bit 3 : upper-left macroblock
 *        bit 4 : left macroblock (intra)
 *        bit 5 : upper macroblock (intra)
 *        bit 6 : upper-right macroblock (intra)
 *        bit 7 : upper-left macroblock (intra)
 */
static int getMbAvailability(macroblock_s *mb, mbAttributes_s *mbData,
                             int picWidth, int constrainedIntra)
{
  int mbsPerLine;
  int mbAddr;
  int currSliceIdx;
  int *sliceMap;
  int8 *mbTypeTable;
  int mbAvailBits;

  mbsPerLine = picWidth/MBK_SIZE;
  mbAddr = mb->idxY*mbsPerLine+mb->idxX;

  sliceMap = & mbData->sliceMap[mbAddr];
  currSliceIdx = sliceMap[0];

  mbAvailBits = 0;

  /* Check availability of left macroblock */
  if (mb->idxX > 0 && sliceMap[-1] == currSliceIdx)
    mbAvailBits |= 0x11;

  /* Check availability of upper, upper-left and upper-right macroblocks */

  if (mb->idxY > 0) {

    sliceMap -= mbsPerLine;

    /* Check availability of upper macroblock */
    if (sliceMap[0] == currSliceIdx)
      mbAvailBits |= 0x22;

    /* Check availability of upper-right macroblock */
    if (mb->idxX+1 < mbsPerLine && sliceMap[1] == currSliceIdx)
      mbAvailBits |= 0x44;

    /* Check availability of upper-left macroblock */
    if (mb->idxX > 0 && sliceMap[-1] == currSliceIdx)
      mbAvailBits |= 0x88;
  }


  /*
   * Check availability of intra MB if constrained intra is enabled
   */

  if (constrainedIntra) {

     mbTypeTable = & mbData->mbTypeTable[mbAddr];

    /* Check availability of left intra macroblock */
    if ((mbAvailBits & 0x10) && mbTypeTable[-1] != MBK_INTRA)
      mbAvailBits &= ~0x10;

    /* Check availability of upper, upper-left and upper-right intra macroblocks */

    if (mbAvailBits & (0x20|0x40|0x80)) {

      mbTypeTable -= mbsPerLine;

      /* Check availability of upper intra macroblock */
      if ((mbAvailBits & 0x20) && mbTypeTable[0] != MBK_INTRA)
        mbAvailBits &= ~0x20;

      /* Check availability of upper-right intra macroblock */
      if ((mbAvailBits & 0x40) && mbTypeTable[1] != MBK_INTRA)
        mbAvailBits &= ~0x40;

      /* Check availability of upper-left intra macroblock */
      if ((mbAvailBits & 0x80) && mbTypeTable[-1] != MBK_INTRA)
        mbAvailBits &= ~0x80;
    }
  }

  return mbAvailBits;
}


// mbkParse
// Parses the input macroblock. If PCM coding is used then re-aligns the byte 
// alignment if previous (slice header) modifications have broken the alignment.
TInt mbkParse(macroblock_s *mb, TInt numRefFrames, mbAttributes_s *mbData, 
			  TInt picWidth, TInt picType, TInt constIpred, TInt chromaQpIdx,
              TInt mbIdxX, TInt mbIdxY, void *streamBuf, TInt aBitOffset)
{
  	TInt8 ipTab[BLK_PER_MB*BLK_PER_MB];
  	TInt diffVecs[BLK_PER_MB*BLK_PER_MB][2];
//  	TInt hasDc;
//  	TInt pixOffset;
  	TInt constrainedIntra;
  	TInt copyMbFlag;
  	TInt mbAddr;
  	TInt pcmMbFlag;
  	TInt retCode;

  	mb->idxX = mbIdxX;
  	mb->idxY = mbIdxY;

  	mb->blkX = mbIdxX*BLK_PER_MB;
  	mb->blkY = mbIdxY*BLK_PER_MB;

  	mb->pixX = mbIdxX*MBK_SIZE;
  	mb->pixY = mbIdxY*MBK_SIZE;

  	mbAddr = mb->idxY*(picWidth/MBK_SIZE)+mb->idxX;

  	copyMbFlag = pcmMbFlag = 0;

  	constrainedIntra = constIpred && !(IS_SLICE_I(picType));

  	mb->mbAvailBits = getMbAvailability(mb, mbData, picWidth, constrainedIntra);

  	// Read macroblock bits
    retCode = getMacroblock(mb, numRefFrames, ipTab, mbData->numCoefUpPred, diffVecs,
                            picType, chromaQpIdx, (bitbuffer_s *)streamBuf);

  	if (retCode < 0)
	    return retCode;

  	// Set PCM flag 
  	if (mb->type == MBK_INTRA && mb->intraType == MBK_INTRA_TYPE_PCM)
	    pcmMbFlag = 1;


  	// Get intra/inter prediction
  	if (mb->type == MBK_INTRA) 
  	{
    	mbData->mbTypeTable[mbAddr] = MBK_INTRA;

    	if (pcmMbFlag) 
    	{
    		bitbuffer_s* tempBitBuffer = (bitbuffer_s *)streamBuf;
    		
    		// Synchronize bitbuffer bit position to get it between 1 and 8
			syncBitBufferBitpos(tempBitBuffer);
	
   			// To find out how much we have to shift to reach the byte alignment again,
   			// we have to first find out the old alignment
   			// oldAlignment is the place of the bitpos before the aBitOffset, i.e. it is
   			// the amount of zero alignment bits plus one
   			TInt oldAlignmentBits = tempBitBuffer->bitpos + aBitOffset - 1;
   			TInt shiftAmount;
	   			
   		
   			// If Bit-wise shift, i.e. aBitOffset is zero, do nothing
    		// Fix the possible bit buffer byte alignment
    		if (aBitOffset > 0)
    		{
    		
    			// aBitOffset > 0 indicates a bitshift to the right
    			
    			// To counter the shift to right we have to shift left by the same amount 
    			// unless shift is larger than the number of original alignment bits in 
    			// which case we have to shift more to the right 
     			
	   			// If the computed old alignment bits value is larger than eight, 
	   			//the correct value is (computed value) % 8
	   			oldAlignmentBits = oldAlignmentBits % 8;

    			if ( oldAlignmentBits < aBitOffset )
    			{
    				// When the amount of shift is larger than the number of original alignment bits,
    				// shift right to fill up the rest of the current byte with zeros
    				shiftAmount = 8 - aBitOffset;

   					// Here we can't shift back left since there were not enough alignment bits originally, 
   					// thus we have to shift right by new bit position - tempBitBuffer->bitpos

   					// E.g. original alignment bits 2, right shift by 4 bits:
   					/////////////////////////////////////////////////////////////////
					// original             after bit shift      byte alignment reset
					// 1. byte: 2. byte:    1. byte: 2. byte:    1. byte: 2. byte: 3. byte:
					// xxxxxx00 yyyyyyyy -> xxxxxxxx xx00yyyy -> xxxxxxxx xx000000 yyyyyyyy
   					/////////////////////////////////////////////////////////////////
   					ShiftBitBufferBitsRight(tempBitBuffer, shiftAmount);
    			}
    			else
    			{
   					// In this case, the old alignment bits are more than enough 
   					// to shift back left by the aBitOffset amount
   					
   					// E.g. original alignment bits 4, right shift by 2 bits:
   					/////////////////////////////////////////////////////////////////
					// original             after bit shift      byte alignment reset
   					// 1. byte: 2. byte:    1. byte: 2. byte:    1. byte: 2. byte:
   					// xxxx0000 yyyyyyyy -> xxxxxx00 00yyyyyy -> xxxxxx00 yyyyyyyy
   					/////////////////////////////////////////////////////////////////
   					ShiftBitBufferBitsLeft(tempBitBuffer, aBitOffset);
    			}
    		}
    		else if(aBitOffset < 0)
    		{
    			// There was a bit shift to left
    			// Change the aBitOffset sign to positive
    			aBitOffset = -aBitOffset;
    		
				// If the computed alignment bits is negative the correct value is -(computed value)
				if ( oldAlignmentBits < 0 )
				{
					oldAlignmentBits = -oldAlignmentBits;
				}
    			
    			if ( oldAlignmentBits + aBitOffset >= 8 )
    			{
					// When old alignment bits plus the shift are at least 8, then 
					// we have to shift left by the 8 - shift to reach byte alignment. 
	    			shiftAmount = 8 - aBitOffset;

   					// E.g. original alignment bits 6, left shift by 4 bits:
   					/////////////////////////////////////////////////////////////////
					// original             after bit shift      byte alignment reset
					// 1. byte: 2. byte:    1. byte: 2. byte:    1. byte: 2. byte: 
					// xx000000 yyyyyyyy -> xxxxxx00 0000yyyy -> xxxxxx00 yyyyyyyy 
   					/////////////////////////////////////////////////////////////////
   					ShiftBitBufferBitsLeft(tempBitBuffer, shiftAmount);
    			}
    			else
    			{

   					// Here we can just shift right by the amount of bits shifted left to reach 
   					// the byte alignment

   					// E.g. original alignment bits 2, left shift by 4 bits:
   					/////////////////////////////////////////////////////////////////
					// original             after bit shift      byte alignment reset
					// 1. byte: 2. byte:    1. byte: 2. byte:    1. byte: 2. byte: 
					// xxxxxx00 yyyyyyyy -> xx00yyyy yyyyyyyy -> xx000000 yyyyyyyy 
   					/////////////////////////////////////////////////////////////////
   					ShiftBitBufferBitsRight(tempBitBuffer, aBitOffset);
    			}
    		}
    	
    		return MBK_PCM_FOUND;
    	
    	}
  	}
  	else 
  	{

    	mbData->mbTypeTable[mbAddr] = (TInt8)(mb->interMode+1);

    	// If COPY MB, put skip motion vectors 
    	if (mb->interMode == MOT_COPY) 
    	{
      		mb->interMode = MOT_16x16;
    	}

  	}


  	// Decode prediction error & reconstruct MB
  	if (!copyMbFlag && !pcmMbFlag) 
  	{

    	// If 4x4 intra mode, luma prediction error is already transformed 
    	if (!(mb->type == MBK_INTRA && mb->intraType == MBK_INTRA_TYPE1)) 
    	{

//      		hasDc = (mb->type == MBK_INTRA && mb->intraType == MBK_INTRA_TYPE2) ? 1 : 0;

    	}

//    	pixOffset = ((mb->pixY*picWidth)>>2)+(mb->pixX>>1);
  	}


  	// Store qp and coded block pattern for current macroblock
	if (pcmMbFlag)
	    mbData->qpTable[mbAddr] = 0;
  	else
    	mbData->qpTable[mbAddr] = (TInt8)mb->qp;

  	mbData->cbpTable[mbAddr] = mb->cbpY;

  	return MBK_OK;
}