blob: 70f74540eb8d77ce4aaafa85c3c8ba767021b4df [file] [log] [blame]
#include "viddec_pm_parse.h"
#include "viddec_fw_debug.h"
#include "viddec_mp4_parse.h"
/* Parse for Sc code of pattern 0x00 0x00 0xXX in the current buffer. Returns either sc found or success.
The conext is updated with current phase and sc_code position in the buffer.
What is phase?: phase is a value between [0-4], we keep track of consecutive '0's with this.
Any time a '0' is found its incremented by 1(uptp 2) and reset to '0' if a zero not found.
if 0xXX code is found and current phase is 2, its changed to 3 which means we found the pattern
we are looking for. Its incremented to 4 once we see a byte after this pattern.
For MP4 there are two startcode patterns LVH & SVH. LVH is same as other codecs (00 00 01), SVH
A.K.A H263 is (00 00 8X). So we have to look for both kind of start codes. The spec doesn't
explicitly say if both of them can exist in a stream? So current implemenation will assume
that only one of them is present in a given stream to simplify implementation. The reason it can
get complicated is resync marker in LVH can potentially be (00 00 8) which will cause false detect
of SVH start code.
*/
#ifndef VBP
uint32_t viddec_parse_sc_mp4(void *in, void *pcxt, void *sc_state)
{
uint8_t *ptr;
uint32_t size;
uint32_t data_left=0, phase = 0, ret = 0;
viddec_sc_parse_cubby_cxt_t *cxt;
viddec_mp4_parser_t *p_info;
cxt = ( viddec_sc_parse_cubby_cxt_t *)in;
viddec_sc_prefix_state_t *state = (viddec_sc_prefix_state_t *)sc_state;
size = 0;
data_left = cxt->size;
ptr = cxt->buf;
phase = cxt->phase;
cxt->sc_end_pos = -1;
p_info = (viddec_mp4_parser_t *)pcxt;
/* parse until there is more data and start code not found */
while ((data_left > 0) &&(phase < 3))
{
/* Check if we are byte aligned & phase=0, if thats the case we can check
work at a time instead of byte*/
if (((((uint32_t)ptr) & 0x3) == 0) && (phase == 0))
{
while (data_left > 3)
{
uint32_t data;
char mask1 = 0, mask2=0;
data = *((uint32_t *)ptr);
#ifndef MFDBIGENDIAN
data = SWAP_WORD(data);
#endif
mask1 = (FIRST_STARTCODE_BYTE != (data & SC_BYTE_MASK0));
mask2 = (FIRST_STARTCODE_BYTE != (data & SC_BYTE_MASK1));
/* If second byte and fourth byte are not zero's then we cannot have a start code here as we need
two consecutive zero bytes for a start code pattern */
if (mask1 && mask2)
{/* Success so skip 4 bytes and start over */
ptr+=4;
size+=4;
data_left-=4;
continue;
}
else
{
break;
}
}
}
/* At this point either data is not on a word boundary or phase > 0 or On a word boundary but we detected
two zero bytes in the word so we look one byte at a time*/
if (data_left > 0)
{
if (*ptr == FIRST_STARTCODE_BYTE)
{/* Phase can be 3 only if third start code byte is found */
phase++;
ptr++;
size++;
data_left--;
if (phase > 2)
{
phase = 2;
if ( (((uint32_t)ptr) & 0x3) == 0 )
{
while ( data_left > 3 )
{
if (*((uint32_t *)ptr) != 0)
{
break;
}
ptr+=4;
size+=4;
data_left-=4;
}
}
}
}
else
{
uint8_t normal_sc=0, short_sc=0;
if (phase == 2)
{
normal_sc = (*ptr == THIRD_STARTCODE_BYTE);
short_sc = (p_info->ignore_scs == 0) && (SHORT_THIRD_STARTCODE_BYTE == ( *ptr & 0xFC));
}
if (!(normal_sc | short_sc))
{
phase = 0;
}
else
{/* Match for start code so update context with byte position */
cxt->sc_end_pos = size;
phase = 3;
p_info->cur_sc_prefix = p_info->next_sc_prefix;
p_info->next_sc_prefix = (normal_sc) ? 1: 0;
if (normal_sc)
{
p_info->ignore_scs=1;
}
else
{
/* For short start code since start code is in one nibble just return at this point */
phase += 1;
state->next_sc = *ptr;
state->second_scprfx_length = 2;
ret=1;
break;
}
}
ptr++;
size++;
data_left--;
}
}
}
if ((data_left > 0) && (phase == 3))
{
cxt->sc_end_pos++;
state->next_sc = cxt->buf[cxt->sc_end_pos];
state->second_scprfx_length = 3;
phase++;
ret = 1;
}
cxt->phase = phase;
/* Return SC found only if phase is 4, else always success */
return ret;
}
#endif