blob: ad83a1843f781268e576e7464abff9c9338baa14 [file] [log] [blame]
#include "viddec_parser_ops.h" // For parser helper functions
#include "vc1.h" // For the parser structure
#include "vc1parse.h" // For vc1 parser helper functions
#ifdef VBP
#include "viddec_pm.h"
#endif
#define vc1_is_frame_start_code( ch ) \
(( vc1_SCField == ch ||vc1_SCSlice == ch || vc1_SCFrameHeader == ch ) ? 1 : 0)
/* init function */
#ifdef VBP
void viddec_vc1_init(void *ctxt, uint32_t *persist_mem, uint32_t preserve)
#else
static void viddec_vc1_init(void *ctxt, uint32_t *persist_mem, uint32_t preserve)
#endif
{
vc1_viddec_parser_t *parser = ctxt;
int i;
persist_mem = persist_mem;
for (i=0; i<VC1_NUM_REFERENCE_FRAMES; i++)
{
parser->ref_frame[i].id = -1; /* first I frame checks that value */
parser->ref_frame[i].anchor[0] = 1;
parser->ref_frame[i].anchor[1] = 1;
parser->ref_frame[i].intcomp_top = 0;
parser->ref_frame[i].intcomp_bot = 0;
parser->ref_frame[i].tff=0;
}
parser->intcomp_top[0] = 0;
parser->intcomp_bot[0] = 0;
parser->intcomp_top[1] = 0;
parser->intcomp_bot[1] = 0;
parser->is_reference_picture = false;
memset(&parser->info.picLayerHeader, 0, sizeof(vc1_PictureLayerHeader));
if (preserve)
{
parser->sc_seen &= VC1_EP_MASK;
parser->sc_seen_since_last_wkld &= VC1_EP_MASK;
}
else
{
parser->sc_seen = VC1_SC_INVALID;
parser->sc_seen_since_last_wkld = VC1_SC_INVALID;
memset(&parser->info.metadata, 0, sizeof(parser->info.metadata));
}
return;
} // viddec_vc1_init
static void vc1_swap_intcomp(vc1_viddec_parser_t *parser)
{
parser->intcomp_top[1] = parser->intcomp_top[0];
parser->intcomp_bot[1] = parser->intcomp_bot[0];
parser->intcomp_top[0] = 0;
parser->intcomp_bot[0] = 0;
return;
} // vc1_swap_intcomp
#ifdef VBP
uint32_t viddec_vc1_parse(void *parent, void *ctxt)
#else
static uint32_t viddec_vc1_parse(void *parent, void *ctxt)
#endif
{
vc1_viddec_parser_t *parser = ctxt;
uint32_t sc=0x0;
int32_t ret=0, status=0;
#ifdef VBP
/* This works only if there is one slice and no start codes */
/* A better fix would be to insert start codes it there aren't any. */
ret = viddec_pm_peek_bits(parent, &sc, 32);
if ((sc > 0x0100) && (sc < 0x0200)) /* a Start code will be in this range. */
{
ret = viddec_pm_get_bits(parent, &sc, 32);
}
else
{
/* In cases where we get a buffer with no start codes, we assume */
/* that this is a frame of data. We may have to fix this later. */
sc = vc1_SCFrameHeader;
}
#else
ret = viddec_pm_get_bits(parent, &sc, 32);
#endif
sc = sc & 0xFF;
parser->is_frame_start = 0;
parser->is_second_start = 0;
DEB("START_CODE = %02x\n", sc);
switch ( sc )
{
case vc1_SCSequenceHeader:
{
uint32_t data;
parser->ref_frame[0].anchor[0] = 1;
parser->ref_frame[0].anchor[1] = 1;
parser->ref_frame[1].anchor[0] = 1;
parser->ref_frame[1].anchor[1] = 1;
memset( &parser->info.metadata, 0, sizeof(parser->info.metadata));
/* look if we have a rcv header for main or simple profile */
ret = viddec_pm_peek_bits(parent,&data ,2);
if (data == 3)
{
status = vc1_ParseSequenceLayer(parent, &parser->info);
}
else
{
status = vc1_ParseRCVSequenceLayer(parent, &parser->info);
}
parser->sc_seen = VC1_SC_SEQ;
parser->sc_seen_since_last_wkld |= VC1_SC_SEQ;
#ifdef VBP
parser->start_code = VC1_SC_SEQ;
if (parser->info.metadata.HRD_NUM_LEAKY_BUCKETS == 0)
{
if (parser->info.metadata.PROFILE == VC1_PROFILE_SIMPLE)
{
switch(parser->info.metadata.LEVEL)
{
case 0:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 96000;
break;
case 1:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 384000;
break;
}
}
else if (parser->info.metadata.PROFILE == VC1_PROFILE_MAIN)
{
switch(parser->info.metadata.LEVEL)
{
case 0:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 2000000;
break;
case 1:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 10000000;
break;
case 2:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 20000000;
break;
}
}
else if (parser->info.metadata.PROFILE == VC1_PROFILE_ADVANCED)
{
switch(parser->info.metadata.LEVEL)
{
case 0:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 2000000;
break;
case 1:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 10000000;
break;
case 2:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 20000000;
break;
case 3:
parser->info.metadata.hrd_initial_state.sLeakyBucket[0].HRD_RATE = 45000000;
break;
}
}
}
#endif
break;
}
case vc1_SCEntryPointHeader:
{
status = vc1_ParseEntryPointLayer(parent, &parser->info);
parser->sc_seen |= VC1_SC_EP;
// Clear all bits indicating data below ep header
parser->sc_seen &= VC1_EP_MASK;
parser->sc_seen_since_last_wkld |= VC1_SC_EP;
#ifdef VBP
parser->start_code = VC1_SC_EP;
#endif
break;
}
case vc1_SCFrameHeader:
{
memset(&parser->info.picLayerHeader, 0, sizeof(vc1_PictureLayerHeader));
status = vc1_ParsePictureLayer(parent, &parser->info);
if ((parser->info.picLayerHeader.PTypeField1 == VC1_I_FRAME) ||
(parser->info.picLayerHeader.PTypeField1 == VC1_P_FRAME) ||
(parser->info.picLayerHeader.PTYPE == VC1_I_FRAME) ||
(parser->info.picLayerHeader.PTYPE == VC1_P_FRAME))
{
vc1_swap_intcomp(parser);
}
parser->sc_seen |= VC1_SC_FRM;
// Clear all bits indicating data below frm header
parser->sc_seen &= VC1_FRM_MASK;
parser->sc_seen_since_last_wkld |= VC1_SC_FRM;
//vc1_start_new_frame ( parent, parser );
parser->is_frame_start = 1;
vc1_parse_emit_frame_start( parent, parser );
#ifdef VBP
parser->start_code = VC1_SC_FRM;
#endif
break;
}
case vc1_SCSlice:
{
status = vc1_ParseSliceLayer(parent, &parser->info);
parser->sc_seen_since_last_wkld |= VC1_SC_SLC;
vc1_parse_emit_current_slice( parent, parser );
#ifdef VBP
parser->start_code = VC1_SC_SLC;
#endif
break;
}
case vc1_SCField:
{
parser->info.picLayerHeader.SLICE_ADDR = 0;
parser->info.picLayerHeader.CurrField = 1;
parser->info.picLayerHeader.REFFIELD = 0;
parser->info.picLayerHeader.NUMREF = 0;
parser->info.picLayerHeader.MBMODETAB = 0;
parser->info.picLayerHeader.MV4SWITCH = 0;
parser->info.picLayerHeader.DMVRANGE = 0;
parser->info.picLayerHeader.MVTAB = 0;
parser->info.picLayerHeader.MVMODE = 0;
parser->info.picLayerHeader.MVRANGE = 0;
#ifdef VBP
parser->info.picLayerHeader.raw_MVTYPEMB = 0;
parser->info.picLayerHeader.raw_DIRECTMB = 0;
parser->info.picLayerHeader.raw_SKIPMB = 0;
parser->info.picLayerHeader.raw_ACPRED = 0;
parser->info.picLayerHeader.raw_FIELDTX = 0;
parser->info.picLayerHeader.raw_OVERFLAGS = 0;
parser->info.picLayerHeader.raw_FORWARDMB = 0;
memset(&(parser->info.picLayerHeader.MVTYPEMB), 0, sizeof(vc1_Bitplane));
memset(&(parser->info.picLayerHeader.DIRECTMB), 0, sizeof(vc1_Bitplane));
memset(&(parser->info.picLayerHeader.SKIPMB), 0, sizeof(vc1_Bitplane));
memset(&(parser->info.picLayerHeader.ACPRED), 0, sizeof(vc1_Bitplane));
memset(&(parser->info.picLayerHeader.FIELDTX), 0, sizeof(vc1_Bitplane));
memset(&(parser->info.picLayerHeader.OVERFLAGS), 0, sizeof(vc1_Bitplane));
memset(&(parser->info.picLayerHeader.FORWARDMB), 0, sizeof(vc1_Bitplane));
parser->info.picLayerHeader.ALTPQUANT = 0;
parser->info.picLayerHeader.DQDBEDGE = 0;
#endif
status = vc1_ParseFieldLayer(parent, &parser->info);
if ((parser->info.picLayerHeader.PTypeField2 == VC1_I_FRAME) ||
(parser->info.picLayerHeader.PTypeField2 == VC1_P_FRAME))
{
//vc1_swap_intcomp(parser);
}
parser->sc_seen |= VC1_SC_FLD;
parser->sc_seen_since_last_wkld |= VC1_SC_FLD;
parser->is_second_start = 1;
vc1_parse_emit_second_field_start( parent, parser );
#ifdef VBP
parser->start_code = VC1_SC_FLD;
#endif
break;
}
case vc1_SCSequenceUser:
case vc1_SCEntryPointUser:
case vc1_SCFrameUser:
case vc1_SCSliceUser:
case vc1_SCFieldUser:
{/* Handle user data */
parser->sc_seen_since_last_wkld |= VC1_SC_UD;
#ifdef VBP
parser->start_code = VC1_SC_UD;
#endif
break;
}
case vc1_SCEndOfSequence:
{
parser->sc_seen = VC1_SC_INVALID;
parser->sc_seen_since_last_wkld |= VC1_SC_INVALID;
#ifdef VBP
parser->start_code = VC1_SC_INVALID;
#endif
break;
}
default: /* Any other SC that is not handled */
{
DEB("SC = %02x - unhandled\n", sc );
#ifdef VBP
parser->start_code = VC1_SC_INVALID;
#endif
break;
}
}
return VIDDEC_PARSE_SUCESS;
} // viddec_vc1_parse
/**
If a picture header was seen and the next start code is a sequence header, entrypoint header,
end of sequence or another frame header, this api returns frame done.
If a sequence header and a frame header was not seen before this point, all the
information needed for decode is not present and parser errors are reported.
*/
#ifdef VBP
uint32_t viddec_vc1_wkld_done(void *parent, void *ctxt, unsigned int next_sc, uint32_t *codec_specific_errors)
#else
static uint32_t viddec_vc1_wkld_done(void *parent, void *ctxt, unsigned int next_sc, uint32_t *codec_specific_errors)
#endif
{
vc1_viddec_parser_t *parser = ctxt;
int ret = VIDDEC_PARSE_SUCESS;
parent = parent;
switch (next_sc)
{
case vc1_SCFrameHeader:
if (((parser->sc_seen_since_last_wkld & VC1_SC_EP) ||
(parser->sc_seen_since_last_wkld & VC1_SC_SEQ)) &&
(!(parser->sc_seen_since_last_wkld & VC1_SC_FRM)))
{
break;
}
// Deliberate fall-thru case
case vc1_SCEntryPointHeader:
if ((next_sc == vc1_SCEntryPointHeader) &&
(parser->sc_seen_since_last_wkld & VC1_SC_SEQ) &&
(!(parser->sc_seen_since_last_wkld & VC1_SC_EP)))
{
break;
}
// Deliberate fall-thru case
case vc1_SCSequenceHeader:
case vc1_SCEndOfSequence:
case VIDDEC_PARSE_EOS:
case VIDDEC_PARSE_DISCONTINUITY:
ret = VIDDEC_PARSE_FRMDONE;
// Set errors for progressive
if ((parser->sc_seen & VC1_SC_SEQ) && (parser->sc_seen & VC1_SC_FRM))
*codec_specific_errors = 0;
else
*codec_specific_errors |= VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE;
vc1_end_frame(parser);
parser->sc_seen_since_last_wkld = VC1_SC_INVALID;
// TODO: Need to check for interlaced
break;
default:
ret = VIDDEC_PARSE_SUCESS;
break;
} //switch
DEB("sc: 0x%x, sc_seen: 0x%x, sc_since_last_wkld:%d, error:%d, ret: %d\n",
next_sc, parser->sc_seen, parser->sc_seen_since_last_wkld,
*codec_specific_errors, ret);
return ret;
} // viddec_vc1_wkld_done
#ifdef VBP
void viddec_vc1_get_context_size(viddec_parser_memory_sizes_t *size)
#else
static void viddec_vc1_get_context_size(viddec_parser_memory_sizes_t *size)
#endif
{
size->context_size = sizeof(vc1_viddec_parser_t);
size->persist_size = 0;
return;
} // viddec_vc1_get_context_size
#ifdef VBP
uint32_t viddec_vc1_is_start_frame(void *ctxt)
#else
static uint32_t viddec_vc1_is_start_frame(void *ctxt)
#endif
{
vc1_viddec_parser_t *parser = (vc1_viddec_parser_t *) ctxt;
return parser->is_frame_start;
} // viddec_vc1_is_start_frame
void viddec_vc1_get_ops(viddec_parser_ops_t *ops)
{
ops->init = viddec_vc1_init;
ops->parse_syntax = viddec_vc1_parse;
ops->get_cxt_size = viddec_vc1_get_context_size;
ops->is_wkld_done = viddec_vc1_wkld_done;
ops->is_frame_start = viddec_vc1_is_start_frame;
return;
} // viddec_vc1_get_ops