videoeditorengine/h263decoder/src/sync_mpeg.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:  
* MPEG-4 sync code functions.
*
*/


#include "h263dConfig.h"

#include "sync.h"
#include "errcodes.h"
#include "debug.h"
#include "mpegcons.h"
#include "biblin.h"


/*
 * Global functions
 */

/* {{-output"sncCheckMpegVOP.txt"}} */
/*
 *
 * sncCheckMpegVOP
 *
 * Parameters:
 *    buffer                     a pointer to a bit buffer structure
 *    error                      error code
 *
 * Function:
 *    This function checks if the GOV, VOP start codes
 *    are the next codes in the bit buffer.
 *    NO stuffing is allowed before the code, the routine checks from the
 *    current position in the buffer-
 *    The code is not flushed from the buffer.
 *
 * Returns:
 *    SNC_NO_SYNC                if no sync code is found
 *    SNC_PSC                    if GOV or VOP start code is found
 *
 * Error codes:
 *    Error codes returned by bibFlushBits/bibGetBits/bibShowBits.
 *
 *    
 *    
 */

int sncCheckMpegVOP(bibBuffer_t *buffer, int16 *error)
/* {{-output"sncCheckMpegVOP.txt"}} */
{
   u_int32 bits;
   int16 newError = 0;
   int numBitsGot, bitErrorIndication = 0;

   bits = bibShowBits(32, buffer, &numBitsGot, &bitErrorIndication, &newError);
   
   if ((newError == ERR_BIB_NOT_ENOUGH_DATA) && (numBitsGot > 0 )) {
       /* Still bits in the buffer */
       deb("sncCheckSync: bibShowReturned not enough data but there are "
           "still bits in the buffer --> error cleared.\n");
       return SNC_NO_SYNC;
   } else if (newError) {
       *error = newError;
       return SNC_NO_SYNC;
   }

   if (bits == MP4_GROUP_START_CODE || bits == MP4_VOP_START_CODE || bits == MP4_EOB_CODE)
        return SNC_PSC;
   else 
        return SNC_NO_SYNC;
}

/* {{-output"sncCheckMpegSync.txt"}} */
/*
 *
 * sncCheckMpegSync
 *
 * Parameters:
 *    buffer                     a pointer to a bit buffer structure
 *    f_code                     f_code of the last P-vop
 *    error                      error code
 *
 * Function:
 *    This function checks if the GOV, VOP or Video Pcaket start codes
 *    are the next codes in the bit buffer.
 *    Stuffing is needed before the code and the number of stuffing bits
 *    is returned in numStuffBits parameter.
 *    The code is not flushed from the buffer.
 *
 * Returns:
 *    SNC_NO_SYNC                if no sync code is found
 *    SNC_GOV                    if GOV start code is found
 *    SNC_VOP                    if VOP start code is found
 *    SNC_VOS                    if VOS start code is found
 *    SNC_VIDPACK                if Video Packet start code is found
 *    SNC_STUFFING               if there is a bit with the value zero 
 *                               followed by less than 7 bits with the 
 *                               value one starting from the current position 
 *                               and after them the buffer (picture segment) ends
 *
 * Error codes:
 *    Error codes returned by bibFlushBits/bibGetBits/bibShowBits.
 *
 *    
 *    
 *    
 *    
 *    
 */

int sncCheckMpegSync(bibBuffer_t *buffer, int f_code, int16 *error)
/* {{-output"sncCheckMpegSync.txt"}} */
{
   u_int32 result, bits, start_code_val;
   int numBitsGot, i, shift_bits;
   int16 newError = 0;
   int bitErrorIndication = 0;

   shift_bits = 32-(16+f_code);

   bits = bibShowBits(32, buffer, &numBitsGot, &bitErrorIndication, &newError);
   
   if ( buffer->error )
      {
      // out of bits
      *error = (int16)buffer->error;
      return SNC_NO_SYNC;
      }


   for(i = 0; i <= 8; i++) {

       /* if stuffing is correct */
       if ( (i==0) || ((bits >> (32-i)) == (u_int32) ((1 << (i-1))-1)) ) {

           result = bits << i;

           if ((result >> 8) == 1) {

               /* Stuff start code */
               if (i != 0) {
                   bibFlushBits(i, buffer, &numBitsGot, &bitErrorIndication, &newError);
                   if (newError) {
                       *error = newError;
                       return SNC_NO_SYNC;
                   }
               }

               /* Check start code */
               start_code_val = 
                   bibShowBits(32, buffer, &numBitsGot, &bitErrorIndication, &newError);
               if ((newError == ERR_BIB_NOT_ENOUGH_DATA) && (numBitsGot > 0 )) {
                       /* Still bits in the buffer */
                       deb("sncCheckSync: bibShowReturned not enough data but there are "
                           "still bits in the buffer --> error cleared.\n");
                       if (i) bibRewindBits(i, buffer, &newError);
                       return SNC_NO_SYNC;
               } else if (newError) {
                   *error = newError;
                   if (i) bibRewindBits(i, buffer, &newError);
                   return SNC_NO_SYNC;
               }

               if (start_code_val == MP4_VOP_START_CODE) {
                   return SNC_VOP;
               } else if (start_code_val == MP4_VOS_START_CODE) {
                   return SNC_VOS;
               } else if (start_code_val == MP4_GROUP_START_CODE) {
                   return SNC_GOV;
               } else if (start_code_val == MP4_USER_DATA_START_CODE) {
                   return SNC_USERDATA;
               } else if (start_code_val == MP4_EOB_CODE) {
                   return SNC_EOB;
               } else if (((start_code_val >> (32-MP4_VID_START_CODE_LENGTH)) == MP4_VID_START_CODE) ||
                          ((start_code_val >> (32-MP4_VOL_START_CODE_LENGTH)) == MP4_VOL_START_CODE)) {
                   return SNC_VID;
               } else {
                   if (i) bibRewindBits(i, buffer, &newError);
                   continue;               
               }

           } else if (f_code && ((result >> shift_bits) == 1)) {
               if (i != 0) {
                   /* Stuff start code */
                   bibFlushBits(i, buffer, &numBitsGot, &bitErrorIndication, &newError);
                   if (newError) {
                       *error = newError;
                       return SNC_NO_SYNC;
                   }
               }
               return SNC_VIDPACK;
           }
       }
   }

   return SNC_NO_SYNC;
}


/* {{-output"sncRewindAndSeekNewMPEGSync.txt"}} */
/*
 * sncRewindAndSeekNewMPEGSync
 *    
 *
 * Parameters:
 *    numBitsToRewind            the number of bits to rewind before seeking
 *                               the synchronization code,
 *                               if negative, a default number of bits is
 *                               rewinded. It is recommended to use 
 *                               the SNC_DEFAULT_REWIND definition to represent
 *                               negative values in order to increase code 
 *                               readability.
 *    buffer                     a pointer to a bit buffer structure
 *    f_code                     f_code of the last P-vop
 *    error                      error code
 *
 * Function:
 *    This function is intended to be called after bit error detection.
 *    It rewinds some (already read) bits in order not to miss any sync code.
 *    Then, this function finds the next GOV, VOP or Video Packet start code
 *    which is not within the rewinded bits. The function discards the bits 
 *    before the synchronization code but does not remove the found code from 
 *    the buffer.
 *
 *
 * Returns:
 *    SNC_NO_SYNC                if no sync code was found and 
 *                               no more bits are available
 *    SNC_GOV                    if GOV start code is found
 *    SNC_VOP                    if VOP start code is found
 *    SNC_VIDPACK                if Video Packet start code is found
 *
 * Error codes:
 *    Error codes returned by bibFlushBits/bibGetBits/bibShowBits.
 *
 *    
 *    
 */

int sncRewindAndSeekNewMPEGSync(int numBitsToRewind, bibBuffer_t *buffer,
                                int f_code, int16 *error)
/* {{-output"sncRewindAndSeekNewMPEGSync.txt"}} */
{
   int sncCode;                     /* found sync code */
   u_int32 numRewindableBits;       /* number of bits which can be rewinded */
   u_int32 bitPosBeforeRewinding;   /* initial buffer bit index */
   u_int32 syncStartBitPos;         /* 1st bit index in found sync code */
   u_int32 syncEndBitPos;
    int nb = 0;
    int bei = 0;

   *error = 0;

   /* If default number of rewinded bits requested */
   if (numBitsToRewind < 0)
      /* 32 bits is considered to be enough */
      numBitsToRewind = 32;

   numRewindableBits = bibNumberOfRewBits(buffer);

   if (numRewindableBits < (u_int32) numBitsToRewind)
      numBitsToRewind = (int) numRewindableBits;

   bitPosBeforeRewinding = bibNumberOfFlushedBits(buffer);

   if (numBitsToRewind) bibRewindBits(numBitsToRewind, buffer, error);
   if (*error)
      return SNC_NO_SYNC;

   /* Loop */
   do {

      /* Seek the next synchronization code */
      sncCode = sncSeekMPEGStartCode (buffer, f_code, 0 /* this method used with DP and VP => VP resync is relevant */, 0, error);
      if (*error)
         return sncCode;

      syncStartBitPos = bibNumberOfFlushedBits(buffer);

      syncEndBitPos = syncStartBitPos + 
                      (u_int32) ((sncCode == SNC_VIDPACK) ? (16 + f_code) : 32);

      if (syncEndBitPos <= bitPosBeforeRewinding)
          bibFlushBits( 1, buffer, &nb, &bei, error );

   /* While the found sync code has been previously read */
   } while (syncEndBitPos <= bitPosBeforeRewinding);

   return sncCode;
}

/* {{-output"sncSeekMPEGSync.txt"}} */
/*
 * sncSeekMPEGSync
 *    
 *
 * Parameters:
 *    buffer                     a pointer to a bit buffer structure
 *    f_code                     f_code of the last P-vop
 *    error                      error code
 *
 * Function:
 *    Then, this function finds the next GOV, VOP or Video Packet start code
 *    from the buffer. The function discards the bits before the sync code
 *    but does not remove the found code from the buffer.
 *
 * Returns:
 *    SNC_NO_SYNC                if no sync code was found and 
 *                               no more bits are available
 *    SNC_GOV                    if GOV start code is found
 *    SNC_VOP                    if VOP start code is found
 *    SNC_VOS                    if VOS start code is found
 *    SNC_VIDPACK                if Video Packet start code is found
 *
 * Error codes:
 *    Error codes returned by bibFlushBits/bibGetBits/bibShowBits.
 *
 *    
 */

int sncSeekMPEGSync(bibBuffer_t *buffer, int f_code, int16 *error)
/* {{-output"sncSeekMPEGSync.txt"}} */
{
   u_int32 result;
   int numBitsGot, shift_bits;
   int16 newError = 0;
   int bitErrorIndication = 0;

   shift_bits = 32-(16+f_code);

   for (;;) {
       
       bitErrorIndication = 0;

       result = bibShowBits(32, buffer, &numBitsGot, &bitErrorIndication, &newError);

      
       if (newError == ERR_BIB_NOT_ENOUGH_DATA && numBitsGot) {
           /* Use the available bits */
           result <<= (32 - numBitsGot);
           newError = 0;
       } else if (newError) {
           deb("sncSeekSync: ERROR - bibShowBits failed.\n");
           *error = newError;
           return SNC_NO_SYNC;
       }

       if (result == MP4_GROUP_START_CODE)
           return SNC_GOV;
       else if (result == MP4_VOP_START_CODE)
           return SNC_VOP;
       else if (result == MP4_VOS_START_CODE)
           return SNC_VOS;
       else if (result == MP4_EOB_CODE)
           return SNC_EOB;
       else if (f_code && ((result >> shift_bits) == 1))
           return SNC_VIDPACK;
       else if ( buffer->error )
          {
          // out of bits
          *error = (int16)buffer->error;
          return SNC_NO_SYNC;
          }

       
       bibFlushBits(1, buffer, &numBitsGot, &bitErrorIndication, error);
   }
}

   /* {{-output"sncSeekMPEGStartCode.txt"}} */
/*
 * sncSeekMPEGStartCode
 *    
 *
 * Parameters:
 *    buffer                     a pointer to a bit buffer structure
 *    f_code                     f_code of the last P-vop
 *    skipVPSync                 nonzero if Video Packet sync codes can be skipped
 *    error                      error code
 *
 * Function:
 *    This function finds the next GOV, VOP or Video Packet start code
 *    from the buffer in byte-aligned positions. The function discards the bits before the sync code
 *    but does not remove the found code from the buffer.
 *
 * Returns:
 *    SNC_NO_SYNC                if no sync code was found and 
 *                               no more bits are available
 *    SNC_GOV                    if GOV start code is found
 *    SNC_VOP                    if VOP start code is found
 *    SNC_VOS                    if VOS start code is found
 *    SNC_VIDPACK                if Video Packet start code is found
 *
 * Error codes:
 *    Error codes returned by bibFlushBits/bibGetBits/bibShowBits.
 *
 *    
 */

int sncSeekMPEGStartCode(bibBuffer_t *buffer, int f_code, int skipVPSync, int checkUD, int16 *error)
/* {{-output"sncSeekMPEGSync.txt"}} */
{
  u_int32 result;
  int numBitsGot, shift_bits;
  int16 newError = 0;
  int bitErrorIndication = 0;
  int flush = 8;
  const u_int32 MAX_MPEG4_START_CODE = 0x000001ff;
  shift_bits = 32-(16+f_code);
  
  /* start codes are always byte aligned */
  /* move to the next byte aligned position, if not already there */
  if (buffer->bitIndex != 7)
  {
    bibForwardBits(buffer->bitIndex + 1, buffer); 
  }
  
  for (;;) 
  {
    bitErrorIndication = 0;
    result = bibShowBits(32, buffer, &numBitsGot, &bitErrorIndication, &newError);
    

    if ( buffer->error )
      {
      // out of bits
      *error = (int16)buffer->error;
      return SNC_NO_SYNC;
      }

    /* don't check all start codes, if it is not one of them */
    if (result <= MAX_MPEG4_START_CODE)
    {
      if (result == MP4_GROUP_START_CODE)
        return SNC_GOV;
      else if (result == MP4_VOP_START_CODE)
        return SNC_VOP;
      else if (result == MP4_VOS_START_CODE)
        return SNC_VOS;
      else if (result == MP4_EOB_CODE)
        return SNC_EOB;
      else if ( checkUD && (result == MP4_USER_DATA_START_CODE) )
      	return SNC_USERDATA;
      
    }
    else if (!skipVPSync && f_code && ((result >> shift_bits) == 1))
        {
        return SNC_VIDPACK;
        }

    // we continue here after either if all the if-else's inside the if above are false or if the last else-if is false

    // Note! the following optimization is based on MPEG-4 sync code prefix 0x000001. It doesn't work with any other prefixes.
    if ( !skipVPSync )
        {
        flush = 8;
        // a small optimization could be reached also with video packet sync markers, but is probably not worth the effort since 
        // it seems that it could be used to shift at most 16 bits at least in cases with typical f_code values
        // idea:
        //  at least if fcode == 15, possible vp resync markers are in the form
        //  00008xxx, 00009xxx, 0000axxx, 0000bxxx, 0000cxxx, 0000dxxx, 0000exxx, 0000fxxx
        //  the shifting above already removes the 15 lowest bits => 16th bit must be 1 and 16 highest bits
        //  should be 0
        //  in the old way, the sync code from 00008xxx is found in the following steps
        //  8xxxyyyy, 008xxxyy, => match
        //  hence we can skip 16 bits (or f-code dependent nr of bits) if 
        //    a) 32nd bit is 1
        //  If 32nd bit is 0, we can skip the 16-(nr of successive 0-MSB bits)
        }
        
    // then check for the other sync codes
    
    // the 1st check here is needed to optimize the checking: in hopeless cases only a single check is needed
    else if ( (result & 0x000000ff) <= 1 )
        {
        // the 1st check is needed to optimize the checking: in hopeless cases only a single check is needed
        if ( ((result & 0x000000ff ) == 1) && ((result & 0x00ffff00 ) > 0))
            {
            // yyxxxx01, where one of the x != 0 => hopeless
            flush = 32;
            }
        else if ( (result & 0x0000ffff ) == 0 )
            {
            // xxxx0000 => could be the 1st 2 bytes of sync code
            flush = 16;
            }
        else if ( (result & 0x000000ff) == 0 )
            {
            // yyyyxx00, where xx != 00 (checked above), could be the 1st byte of sync code
            flush = 24;
            }
        else if ( (result & 0x00ffffff) == 1 )
            {
            // xx000001 => shift 1 byte
            flush = 8;
            }
        else
            {
            // this looks duplicate to the 1st one, but is kept here for simplicity. The 1st one is there since it is the most probable and
            // hence most cases fall under it. If it was not there, then in most cases all the if's were evaluated and that means extra processing
            flush = 32;
            }
        }
    else
        {
        // hopeless
        flush = 32;
        }

    // flush bits
    bibFlushBits(flush, buffer, &numBitsGot, &bitErrorIndication, error);
    }
}


/* {{-output"sncSeekBitPattern.txt"}} */
/*
 * sncSeekBitPattern
 *    
 *
 * Parameters:
 *    buffer                     a pointer to a bit buffer structure
 *    error                      error code
 *    BitPattern                 to bit pattern to be found
 *    BitPatternLength           length of the bit pattern to be found
 *
 * Function:
 *    This function finds the next occurance of the given BitPattern 
 *    from the buffer. The function discards the bits before the BitPattern
 *    but does not remove the found code from the buffer.
 *
 * Returns:
 *    SNC_NO_SYNC                if the bit pattern was not found and 
 *                               no more bits are available
 *    SNC_PATTERN                if the BitPattern is found
 *
 * Error codes:
 *    Error codes returned by bibFlushBits/bibGetBits/bibShowBits.
 *
 *    
 */

int sncSeekBitPattern(bibBuffer_t *buffer, u_int32 BitPattern, int BitPatternLength, int16 *error)
/* {{-output"sncSeekBitPattern.txt"}} */
{
   u_int32 result;
   int numBitsGot;
   int16 newError = 0;
   int bitErrorIndication = 0;

   for (;;) {
       
       bitErrorIndication = 0;

       result = bibShowBits(32, buffer, &numBitsGot, &bitErrorIndication, &newError);

       if (newError == ERR_BIB_NOT_ENOUGH_DATA && numBitsGot >= BitPatternLength) {
           /* Use the available bits */
           result <<= (32 - numBitsGot);
           newError = 0;
       } else if (newError) {
           deb("sncSeekBitPattern: ERROR - bibShowBits failed.\n");
           *error = newError;
           return SNC_NO_SYNC;
       }

       if ((result >> (32 - BitPatternLength)) == BitPattern)
           return SNC_PATTERN;
       else if (result == MP4_GROUP_START_CODE)
           return SNC_GOV;
       else if (result == MP4_VOP_START_CODE)
           return SNC_VOP;
       else if (result == MP4_EOB_CODE)
           return SNC_EOB;
       else if ( buffer->error )
          {
          // out of bits
          *error = (int16)buffer->error;
          return SNC_NO_SYNC;
          }
       
       bibFlushBits(1, buffer, &numBitsGot, &bitErrorIndication, error);
   }
}

/* {{-output"sncRewindStuffing.txt"}} */
/*
 * sncRewindStuffing
 *    
 *
 * Parameters:
 *    buffer                     a pointer to a bit buffer structure
 *    error                      error code
 *
 * Function:
 *    This function recognizes and rewinds the stuffing bits (1..8) from
 *    the current position of the buffer.
 *
 * Returns:
 *    SNC_NO_SYNC                if the stuffing was not found
 *    SNC_PATTERN                if the stuffing has been rewinded successfully
 *
 * Error codes:
 *    Error codes returned by bibFlushBits/bibGetBits/bibShowBits.
 *
 *    
 */

int sncRewindStuffing(bibBuffer_t *buffer, int16 *error)
/* {{-output"sncRewindStuffing.txt"}} */
{
   u_int32 result;
   int numBitsGot, i;
   int16 newError = 0;
   int bitErrorIndication = 0;

   bibRewindBits(8, buffer, &newError);
   result = bibGetBits(8, buffer, &numBitsGot, &bitErrorIndication, &newError);
   if (newError) {
       deb("sncRewindStuffing: ERROR - bibShowBits failed.\n");
       *error = newError;
       return SNC_NO_SYNC;
   }

   for(i = 1; i <= 8; i++) {       
       /* if stuffing is correct */
       if ((result & (1 << (i-1))) == 0) {
           bibRewindBits(i, buffer, &newError);
           return SNC_PATTERN;
       }
   }

   return SNC_NO_SYNC;
}
// End of File