videoeditorengine/avcedit/src/bitbuffer.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 <string.h>
#include "globals.h"
#include "nrctyp32.h"
#include "bitbuffer.h"

#include "parameterset.h"


/*
 * Static functions
 */

static int removeStartCodeEmulationBytes(bitbuffer_s *bitbuf);
static int addStartCodeEmulationBytes(bitbuffer_s *bitbuf);


/*
 *
 * bibOpen:
 *
 * Parameters:
 *
 * Function:
 *      Open bitbuffer
 *
 * Returns:
 *      Pointer to bitbuffer object or NULL for allocation failure.
 *
 */
bitbuffer_s *bibOpen()
{
  bitbuffer_s *bitbuf;

  bitbuf = (bitbuffer_s *)User::Alloc(sizeof(bitbuffer_s));

  if (bitbuf != NULL)
    memset(bitbuf, 0, sizeof(bitbuffer_s));

  return bitbuf;
}


/*
 *
 * bibInit:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *      streamBytes           Pointer to data
 *      length                Data length in bytes
 *
 * Function:
 *      Initialize bitbuffer
 *
 * Returns:
 *      BIB_ok for ok, BIB_ERROR for error
 *
 */
int bibInit(bitbuffer_s *bitbuf, u_int8 *streamBytes, int length)
{
  bitbuf->data           = streamBytes;
  bitbuf->dataLen        = length;
  bitbuf->bytePos        = 0;
  bitbuf->bitpos         = 0;
  bitbuf->errorStatus    = BIB_OK;

#if ENCAPSULATED_NAL_PAYLOAD
  if (removeStartCodeEmulationBytes(bitbuf) < 0)
    return BIB_ERROR;
#endif

  return BIB_OK;
}


/*
 *
 * bibClose:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *
 * Function:
 *      Close bitbuffer
 *
 * Returns:
 *      -
 *
 */
void bibClose(bitbuffer_s *bitbuf)
{
  User::Free(bitbuf);
}


/*
 *
 * removeStartCodeEmulationBytes:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *
 * Function:
 *      Remove start code emulation bytes from the bitbuffer
 *
 * Returns:
 *      -
 *
 */
static int removeStartCodeEmulationBytes(bitbuffer_s *bitbuf)
{
  	TInt i;
  	TInt j;
  	TInt numZero;
  	TInt32 lastBytes;


  	// Skip the start code if it exists
  	numZero = 0;
  	i = 0;
  	while (i < bitbuf->dataLen) 
  	{
    	if (bitbuf->data[i] == 0)
      		numZero++;
    	else if (numZero > 1 && bitbuf->data[i] == 1) 
    	{
      		// Start code found
      		i++;
      		break;
    	}
    	else 
    	{
      		// No start code found 
      		i = 0;
      		break;
    	}
    	i++;
  	}

  	// Convert EBSP to RBSP. Note that the nal head byte is kept within the buffer
  	lastBytes = 0xffffffff;
  	j = 0;
  	while (i < bitbuf->dataLen) 
  	{
    	lastBytes = (lastBytes << 8) | bitbuf->data[i];
    	if ((lastBytes & 0xffffff) != 0x000003) 
    	{
	      	bitbuf->data[j] = bitbuf->data[i];
	      	j++;
    	}
    	i++;
  	}

  	// If bytes were removed, set as many bytes zero at the end of the buffer
  	if (j < bitbuf->dataLen)
  	{
  		// Prevention bytes have been removed, set the last bytes to zero
  		TInt removedBytes = bitbuf->dataLen - j;
  		for (i=0; i<removedBytes; i++)
  		{
  			bitbuf->data[bitbuf->dataLen-1-i] = 0;
  		}
	}
  	
  	// Adjust the bitbuffer dataLen
  	bitbuf->dataLen = j;

  	return BIB_OK;
}


/*
 *
 * bibGetBitFunc:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *
 * Function:
 *      Get next bit from bitbuffer.
 *
 * Returns:
 *      Next bit in bitbuffer or BIB_ERR_NO_BITS if no bits left.
 *
 */
int bibGetBitFunc(bitbuffer_s *bitbuf)
{
  /* If there are no bits left in buffer return an error */
  if (bitbuf->bitpos == 0 && bitbuf->bytePos >= bitbuf->dataLen) {
    bitbuf->errorStatus = BIB_ERR_NO_BITS;
    return 0;
  }

  /* Fill bitbuf->currentBits with bits */
  while (bitbuf->bitpos <= 24 && bitbuf->bytePos < bitbuf->dataLen) {
    bitbuf->currentBits = (bitbuf->currentBits << 8) | bitbuf->data[bitbuf->bytePos++];
    bitbuf->bitpos += 8;
  }

  /* Return bit */
  bitbuf->bitpos--;
  return (bitbuf->currentBits >> bitbuf->bitpos) & 1;
}


/*
 *
 * bibGetBitsFunc:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *      n                     Number of bits requested
 *
 * Function:
 *      Get next n bits from bitbuffer.
 *
 *      NOTE: maximum of 24 bits can be fetched
 *
 * Returns:
 *      Next n bits from bitbuffer
 *
 */
int32 bibGetBitsFunc(bitbuffer_s *bitbuf, int n)
{
  /* Fill bitbuf->currentBits with bits */
  while (n > bitbuf->bitpos && bitbuf->bytePos < bitbuf->dataLen) {
    bitbuf->currentBits = (bitbuf->currentBits << 8) | bitbuf->data[bitbuf->bytePos++];
    bitbuf->bitpos += 8;
  }

  /* If there are not enought bits there was an error */
  if (n > bitbuf->bitpos) {
    bitbuf->errorStatus = BIB_ERR_NO_BITS;
    return 0;
  }

  /* Return bits */
  bitbuf->bitpos -= n;
  return (bitbuf->currentBits >> (bitbuf->bitpos)) & ~(((u_int32)-1)<<n);
}


/*
 *
 * bibShowBitsFunc:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *      n                     Number of bits requested
 *
 * Function:
 *      Get next n bits from bitbuffer without advancing bitbuffer pointer.
 *      This function will not failt even if there are not enough bits in
 *      the bitbuffer.
 *
 *      NOTE: maximum of 24 bits can be fetched
 *
 * Returns:
 *      Next n bits of bitbuffer
 *
 */
int32 bibShowBitsFunc(bitbuffer_s *bitbuf, int n)
{
  /* Fill bitbuf->currentBits with bits */
  while (n > bitbuf->bitpos && bitbuf->bytePos < bitbuf->dataLen) {
    bitbuf->currentBits = (bitbuf->currentBits << 8) | bitbuf->data[bitbuf->bytePos++];
    bitbuf->bitpos += 8;
  }

  /* Check if there are enought bits in currentBits */
  if (n <= bitbuf->bitpos)
    /* Return bits normally */
    return (bitbuf->currentBits >> (bitbuf->bitpos-n)) & ~(((u_int32)-1)<<n);
  else
    /* Return bits padded with zero bits */
    return (bitbuf->currentBits << (n-bitbuf->bitpos)) & ~(((u_int32)-1)<<n);
}


/*
 *
 * bibSkipBitsFunc:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *      n                     Number of bits to skip
 *
 * Function:
 *      Skip next n bits in the bitbuffer
 *
 * Returns:
 *      BIB_OK for no error and BIB_ERR_NO_BITS for end of buffer.
 *
 */
int bibSkipBitsFunc(bitbuffer_s *bitbuf, int n)
{
  /* Fill bitbuf->currentBits with bits */
  while (n > bitbuf->bitpos && bitbuf->bytePos < bitbuf->dataLen) {
    bitbuf->currentBits = (bitbuf->currentBits << 8) | bitbuf->data[bitbuf->bytePos++];
    bitbuf->bitpos += 8;
  }

  bitbuf->bitpos -= n;

  /* Check for buffer underrun */
  if (bitbuf->bitpos < 0) {
    bitbuf->errorStatus = BIB_ERR_NO_BITS;
    return BIB_ERR_NO_BITS;
  }

  return BIB_OK;
}


/*
 *
 * bibGetByte:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *      byteRet               Return pointer for byte
 *
 * Function:
 *      Get next byte aligned byte from bitbuffer.
 *
 * Returns:
 *      1 for End Of Stream, 0 otherwise
 *
 */
int bibGetByte(bitbuffer_s *bitbuf, int *byteRet)
{
  if (bitbuf->bitpos >= 8) {
    bitbuf->bitpos = bitbuf->bitpos & ~7;
    *byteRet = (bitbuf->currentBits >> (bitbuf->bitpos - 8)) & 0xff;
    bitbuf->bitpos -= 8;
  }
  else {
    bitbuf->bitpos = 0;

    if (bitbuf->bytePos >= bitbuf->dataLen) {
      return 1;
    }

    *byteRet = bitbuf->data[bitbuf->bytePos++];
  }

  return 0;
}


/*
 *
 * bibByteAlign:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *
 * Function:
 *      Set bitbuffer pointer to next byte aligned position.
 *
 * Returns:
 *      Number of bits skipped as a result of aligning.
 *
 */
int bibByteAlign(bitbuffer_s *bitbuf)
{
  int bitpos = bitbuf->bitpos;

  bitbuf->bitpos = bitbuf->bitpos & ~7;

  return (bitpos - bitbuf->bitpos);
}


/*
 * bibSkipTrailingBits:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *
 * Function:
 *      Skip the trailing bits at the end of a NAL unit
 *
 * Returns:
 *      The number of bits being skipped or <0 for error.
 */
int bibSkipTrailingBits(bitbuffer_s *bitbuf)
{
  int ret;
  int len = 0;
  int bit = 0;

  bit = bibGetBitFunc(bitbuf);
  len++;

  ret = bibGetStatus(bitbuf);
  if (ret < 0)
    return ret;

  /* First we expect to receive 1 bit */
  if (bit != 1) {
    bibRaiseError(bitbuf, BIB_INCORRECT_TRAILING_BIT);
    return BIB_INCORRECT_TRAILING_BIT;
  }

  /* Remaining bits in current byte should be zero */
  while ( bitbuf->bitpos % 8 != 0 ) {  
    bibGetBit(bitbuf, &bit);
    len++;
    if (bit != 0) {
      bibRaiseError(bitbuf, BIB_INCORRECT_TRAILING_BIT);
      return BIB_INCORRECT_TRAILING_BIT;
    }
  }

  ret = bibGetStatus(bitbuf);
  if (ret < 0)
    return ret;

  return len;
}


/*
 * bibMoreRbspData:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *
 * Function:
 *      Check if there is more RBSP data in the bitbuffer.
 *
 * Returns:
 *      0: no more rbsp data
 *      1: more rbsp data
 */
int bibMoreRbspData(bitbuffer_s *bitbuf)
{
  int numBytesLeft;
  u_int32 lastBits;

  numBytesLeft = bitbuf->dataLen - bitbuf->bytePos;

  if (numBytesLeft >= 2 || (numBytesLeft*8 + bitbuf->bitpos >= 9))
    /* If there are at least 9 bits left, it is certain to have more rbsp data */
    return 1;

  if (numBytesLeft == 0 && bitbuf->bitpos == 0)
    /* Something may be wrong. Normally, there should be at least one bit left */
    return 0;

  if (numBytesLeft == 1) {
    /* Insert last byte to currentBits */
    bitbuf->currentBits = (bitbuf->currentBits << 8) | bitbuf->data[bitbuf->bytePos++];
    bitbuf->bitpos += 8;
  }

  /* Copy the last bits into "lastBits", then compare it with 0x1..00 */
  lastBits = bitbuf->currentBits & ~(((u_int32)-1)<<bitbuf->bitpos);

  if (lastBits == ((u_int32)1 << (bitbuf->bitpos-1)))
    return 0;
  else
    return 1;
}


/*
 * bibGetNumOfRemainingBits:
 *
 * Parameters:
 *      bitbuf                Bitbuffer object
 *
 * Function:
 *      Return number of bits in bitbuffer.
 *
 * Returns:
 *      Number of bits
 */
int32 bibGetNumRemainingBits(bitbuffer_s *bitbuf)
{
  return bitbuf->bitpos + 8*(bitbuf->dataLen - bitbuf->bytePos);
}


// syncBitBufferBitpos
// Synchronizes the input bit buffer's bit position to be between one and eight, 
// modifies the byte position and current bits if required.
void syncBitBufferBitpos(bitbuffer_s *bitbuf)
{
	// To be able to edit the bitbuffer, reset the bit position to be eight at the maximum
	while (bitbuf->bitpos > 8)
	{
		// If bit position is modified, then modify byte position and current bits accordingly
		bitbuf->bitpos -= 8;
		bitbuf->bytePos--;
		bitbuf->currentBits >>= 8;
	}
}


// addStartCodeEmulationBytes
// Adds start code emulation bytes to the input bit buffer.
static int addStartCodeEmulationBytes(bitbuffer_s *bitbuf)
{
  	TInt i = 0;
  	TInt32 lastBytes;


  	// Add prevention bytes that were removed for processing
  	lastBytes = 0xffffffff;
  	while (i < bitbuf->dataLen) 
  	{
    	lastBytes = (lastBytes << 8) | bitbuf->data[i];
    	
    	if(((lastBytes & 0xffff) == 0x0000) && ((i+1) < bitbuf->dataLen) && (bitbuf->data[i+1] < 4))
    	{
			// Add byte(s) to the bit buffer
			TInt error = AddBytesToBuffer(bitbuf, 1);

			if (error != 0)
				return error;

    		// Adjust data length
    		bitbuf->dataLen++;

    		// Make room for the emulation prevention byte 0x03 to the buffer
    		for (TInt k=bitbuf->dataLen; k>i; k--)
    		{
    			bitbuf->data[k] = bitbuf->data[k-1];
    		}
    		
    		// Add the emulation prevention byte to the buffer
      		bitbuf->data[i+1] = 0x03;
    	}
    	
    	i++;
  	}
	return KErrNone;
}


// bibEnd
// Takes care of the bit buffer after the frame has been processed.
int bibEnd(bitbuffer_s *bitbuf)
{
#if ENCAPSULATED_NAL_PAYLOAD
  	return addStartCodeEmulationBytes(bitbuf);
#endif
}


// addStartCodeEmulationBytesSlice
// Adds start code emulation bytes to the input bit buffer.
static void addStartCodeEmulationBytesSlice(bitbuffer_s *bitbuf)
{
  	TInt i = 0;
  	TInt32 lastBytes;


  	// Add prevention bytes that were removed for processing
  	lastBytes = 0xffffffff;
  	while (i < bitbuf->dataLen) 
  	{
    	lastBytes = (lastBytes << 8) | bitbuf->data[i];
    	
    	if(((lastBytes & 0xffff) == 0x0000) && ((i+1) < bitbuf->dataLen) && (bitbuf->data[i+1] < 4))
    	{
    		// Make room for the emulation prevention byte 0x03 to the buffer
    		for (TInt k=bitbuf->dataLen; k>i; k--)
    		{
    			bitbuf->data[k] = bitbuf->data[k-1];
    		}
    		// Adjust data length
    		bitbuf->dataLen++;
    		
    		// Add the emulation prevention byte to the buffer
      		bitbuf->data[i+1] = 0x03;
    	}
    	
    	i++;
  	}
}


// bibEndSlice
// Takes care of the bit buffer after the frame has been processed.
void bibEndSlice(bitbuffer_s *bitbuf)
{
#if ENCAPSULATED_NAL_PAYLOAD
  	addStartCodeEmulationBytesSlice(bitbuf);
#endif
}