videoeditorengine/avcedit/src/bitbuffer.cpp
changeset 0 951a5db380a0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/videoeditorengine/avcedit/src/bitbuffer.cpp	Fri Jan 29 14:08:33 2010 +0200
@@ -0,0 +1,613 @@
+/*
+* 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
+}
+