Home | History | Annotate | Download | only in parser
      1 /**
      2  * viddec_mpeg2_parse.c
      3  * --------------------
      4  * This file acts as the main interface between the parser manager and MPEG2
      5  * parser. All the operations done by the MPEG2 parser are defined here and
      6  * functions pointers for each operation is returned to the parser manager.
      7  */
      8 
      9 #include "viddec_mpeg2.h"
     10 
     11 /* viddec_mpeg2_parser_init() - Initializes parser context. */
     12 static void viddec_mpeg2_parser_init
     13 (
     14     void        *ctxt,
     15     uint32_t    *persist_mem,
     16     uint32_t     preserve
     17 )
     18 {
     19     struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
     20 
     21     /* Avoid compiler warning */
     22     persist_mem = persist_mem;
     23 
     24     /* Initialize state variables */
     25     parser->mpeg2_pic_metadata_complete         =  false;
     26     parser->mpeg2_picture_interlaced            =  false;
     27     parser->mpeg2_first_field                   =  false;
     28     parser->mpeg2_frame_start                   =  false;
     29     parser->mpeg2_ref_table_updated             =  false;
     30     parser->mpeg2_use_next_workload             =  false;
     31     parser->mpeg2_first_slice_flag              =  false;
     32     parser->mpeg2_curr_frame_headers            =  MPEG2_HEADER_NONE;
     33     parser->mpeg2_last_parsed_sc                =  MPEG2_SC_ALL;
     34     parser->mpeg2_last_parsed_slice_sc          =  MPEG2_SC_SLICE_MAX;
     35     parser->mpeg2_wl_status                     =  MPEG2_WL_EMPTY;
     36     parser->mpeg2_prev_picture_structure        =  MPEG2_PIC_STRUCT_FRAME;
     37     parser->mpeg2_prev_temp_ref                 =  0;
     38     parser->mpeg2_num_pan_scan_offsets          =  0;
     39 
     40     if(preserve)
     41     {
     42     	/* Init all picture level header info */
     43     	memset(&parser->info.pic_hdr, 0, sizeof(struct mpeg2_picture_hdr_info));
     44     	memset(&parser->info.pic_cod_ext, 0, sizeof(struct mpeg2_picture_coding_ext_info));
     45     	memset(&parser->info.pic_disp_ext, 0, sizeof(struct mpeg2_picture_disp_ext_info));
     46     }
     47     else
     48     {
     49     	/* Init all header info */
     50     	memset(&parser->info, 0, sizeof(struct mpeg2_info));
     51 
     52     	parser->mpeg2_stream                        =  false;
     53     	parser->mpeg2_custom_qmat_parsed            =  false;
     54     	parser->mpeg2_valid_seq_hdr_parsed          =  false;
     55     	parser->mpeg2_curr_seq_headers              =  MPEG2_HEADER_NONE;
     56 	}
     57 
     58     MPEG2_DEB("MPEG2 Parser: Context Initialized.\n");
     59 
     60     return;
     61 }
     62 
     63 /* viddec_mpeg2_get_context_size() - Returns the memory size required by the */
     64 /* MPEG2 parser. */
     65 static void viddec_mpeg2_get_context_size
     66 (
     67     viddec_parser_memory_sizes_t    *size
     68 )
     69 {
     70     /* Should return size of my structure */
     71     size->context_size = sizeof(struct viddec_mpeg2_parser);
     72     size->persist_size = 0;
     73 }
     74 
     75 /* viddec_mpeg2_get_error_code() - Returns the error code for the current */
     76 /* workload. */
     77 static void viddec_mpeg2_get_error_code
     78 (
     79     struct viddec_mpeg2_parser  *parser,
     80     viddec_workload_t           *wl,
     81     uint32_t                    *error_code
     82 )
     83 {
     84     *error_code = 0;
     85 
     86     /* Dangling field error */
     87     if (parser->mpeg2_wl_status & MPEG2_WL_DANGLING_FIELD)
     88     {
     89         *error_code |= VIDDEC_FW_WORKLOAD_ERR_DANGLING_FLD;
     90         if (parser->mpeg2_wl_status & MPEG2_WL_DANGLING_FIELD_TOP)
     91         {
     92             *error_code |= VIDDEC_FW_WORKLOAD_ERR_TOPFIELD;
     93         }
     94         else
     95         {
     96             *error_code |= VIDDEC_FW_WORKLOAD_ERR_BOTTOMFIELD;
     97         }
     98     }
     99 
    100     /* Repeated same field */
    101     if (parser->mpeg2_wl_status & MPEG2_WL_REPEAT_FIELD)
    102     {
    103         *error_code |= (VIDDEC_FW_WORKLOAD_ERR_DANGLING_FLD
    104                         | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE);
    105     }
    106 
    107     /* If workload is not complete, set non-decodeable flag */
    108     if (!(parser->mpeg2_wl_status & MPEG2_WL_COMPLETE))
    109     {
    110         *error_code |= VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE;
    111     }
    112 
    113     /* If reference info is not updated, set missing reference flag */
    114     if (!(parser->mpeg2_wl_status & MPEG2_WL_REF_INFO))
    115     {
    116         *error_code |= VIDDEC_FW_WORKLOAD_ERR_MISSING_REFERENCE;
    117     }
    118 
    119     /* Missing DMEM data flag and irrecoverable flag is set */
    120     if (!(parser->mpeg2_wl_status & MPEG2_WL_DMEM_DATA))
    121     {
    122         *error_code |= ( VIDDEC_FW_WORKLOAD_ERR_MISSING_DMEM
    123                          | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE ) ;
    124     }
    125 
    126     /* Missing sequence header and irrecoverable flag is set */
    127     if ((!(parser->mpeg2_curr_seq_headers & MPEG2_HEADER_SEQ))
    128     		&& (!parser->mpeg2_valid_seq_hdr_parsed))
    129     {
    130         *error_code |= ( VIDDEC_FW_WORKLOAD_ERR_MISSING_SEQ_INFO
    131                          | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE ) ;
    132     }
    133 
    134     /* Unsupported features found in stream */
    135     if (parser->mpeg2_wl_status & MPEG2_WL_UNSUPPORTED)
    136     {
    137         *error_code |= ( VIDDEC_FW_WORKLOAD_ERR_UNSUPPORTED
    138                          | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE ) ;
    139     }
    140 
    141     /* If frame type is unknown, default to I frame. */
    142     if ((wl->attrs.frame_type != VIDDEC_FRAME_TYPE_I)
    143             && (wl->attrs.frame_type != VIDDEC_FRAME_TYPE_P)
    144             && (wl->attrs.frame_type != VIDDEC_FRAME_TYPE_B))
    145     {
    146         wl->attrs.frame_type = VIDDEC_FRAME_TYPE_I;
    147     }
    148 
    149     /* If there is a mismatch between the frame type and reference information */
    150     /* then mark the workload as not decodable */
    151     if (wl->attrs.frame_type == VIDDEC_FRAME_TYPE_B)
    152     {
    153         if (wl->is_reference_frame != 0) *error_code |= VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE;
    154     }
    155     else
    156     {
    157         if (wl->is_reference_frame == 0) *error_code |= VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE;
    158     }
    159 
    160     /* For non-decodable frames, do not set reference info so that the workload */
    161     /* manager does not increment ref count. */
    162     if (*error_code & VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE)
    163     {
    164         wl->is_reference_frame = 0;
    165     }
    166 
    167     /* Corrupted header notification */
    168     if (parser->mpeg2_wl_status & MPEG2_WL_CORRUPTED_SEQ_HDR)
    169         *error_code |= VIDDEC_FW_MPEG2_ERR_CORRUPTED_SEQ_HDR;
    170     if (parser->mpeg2_wl_status & MPEG2_WL_CORRUPTED_SEQ_EXT)
    171         *error_code |= VIDDEC_FW_MPEG2_ERR_CORRUPTED_SEQ_EXT;
    172     if (parser->mpeg2_wl_status & MPEG2_WL_CORRUPTED_SEQ_DISP_EXT)
    173         *error_code |= VIDDEC_FW_MPEG2_ERR_CORRUPTED_SEQ_DISP_EXT;
    174     if (parser->mpeg2_wl_status & MPEG2_WL_CORRUPTED_GOP_HDR)
    175         *error_code |= VIDDEC_FW_MPEG2_ERR_CORRUPTED_GOP_HDR;
    176     if (parser->mpeg2_wl_status & MPEG2_WL_CORRUPTED_PIC_HDR)
    177         *error_code |= VIDDEC_FW_MPEG2_ERR_CORRUPTED_PIC_HDR;
    178     if (parser->mpeg2_wl_status & MPEG2_WL_CORRUPTED_PIC_COD_EXT)
    179         *error_code |= VIDDEC_FW_MPEG2_ERR_CORRUPTED_PIC_COD_EXT;
    180     if (parser->mpeg2_wl_status & MPEG2_WL_CORRUPTED_PIC_DISP_EXT)
    181         *error_code |= VIDDEC_FW_MPEG2_ERR_CORRUPTED_PIC_DISP_EXT;
    182     if (parser->mpeg2_wl_status & MPEG2_WL_CORRUPTED_QMAT_EXT)
    183         *error_code |= VIDDEC_FW_MPEG2_ERR_CORRUPTED_QMAT_EXT;
    184 
    185     MPEG2_DEB("Workload error code: 0x%8X.\n", *error_code);
    186     return;
    187 }
    188 
    189 /* viddec_mpeg2_is_start_frame() - Returns if the current chunk of parsed */
    190 /* data has start of a frame. */
    191 static uint32_t viddec_mpeg2_is_start_frame
    192 (
    193     void    *ctxt
    194 )
    195 {
    196     struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
    197     return (parser->mpeg2_frame_start);
    198 }
    199 
    200 /* viddec_mpeg2_is_workload_done() - Returns current frame parsing status */
    201 /* to the parser manager. */
    202 static uint32_t viddec_mpeg2_is_workload_done
    203 (
    204     void            *parent,
    205     void            *ctxt,
    206     unsigned int    next_sc,
    207     uint32_t        *codec_specific_errors
    208 )
    209 {
    210     struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
    211     viddec_workload_t *wl = viddec_pm_get_header(parent);
    212     uint32_t ret = VIDDEC_PARSE_SUCESS;
    213     uint32_t frame_boundary = 0;
    214 	uint8_t force_frame_complete = 0;
    215     parent = parent;
    216 
    217     /* Detect Frame Boundary */
    218     frame_boundary = ((MPEG2_SC_PICTURE == next_sc) || (MPEG2_SC_SEQ_HDR == next_sc) || (MPEG2_SC_GROUP == next_sc));
    219     if (frame_boundary)
    220     {
    221         parser->mpeg2_first_slice_flag = false;
    222     }
    223 
    224 	force_frame_complete = ((VIDDEC_PARSE_EOS == next_sc) || (VIDDEC_PARSE_DISCONTINUITY == next_sc));
    225 
    226     if (force_frame_complete || (frame_boundary && (parser->mpeg2_pic_metadata_complete)))
    227     {
    228 		if(!force_frame_complete)
    229         {
    230             parser->mpeg2_wl_status            |= MPEG2_WL_COMPLETE;
    231             parser->mpeg2_last_parsed_slice_sc  =  MPEG2_SC_SLICE_MAX;
    232             parser->mpeg2_pic_metadata_complete = false;
    233             parser->mpeg2_first_slice_flag = false;
    234         }
    235 
    236         viddec_mpeg2_get_error_code(parser, wl, codec_specific_errors);
    237         parser->mpeg2_wl_status          = MPEG2_WL_EMPTY;
    238         parser->mpeg2_curr_frame_headers = MPEG2_HEADER_NONE;
    239         /* Reset mpeg2_use_next_workload flag if it is set */
    240         if (parser->mpeg2_use_next_workload)
    241         {
    242             viddec_pm_set_late_frame_detect(parent);
    243             parser->mpeg2_use_next_workload  = false;
    244         }
    245         ret = VIDDEC_PARSE_FRMDONE;
    246     }
    247     return ret;
    248 }
    249 
    250 /* viddec_mpeg2_parse() - Parse metadata info from the buffer for the prev */
    251 /* start code found. */
    252 static mpeg2_status viddec_mpeg2_parse
    253 (
    254     void    *parent,
    255     void    *ctxt
    256 )
    257 {
    258     uint32_t current_sc = 0, sc_bits = MPEG2_SC_AND_PREFIX_SIZE;
    259     int32_t  ret = MPEG2_SUCCESS;
    260     struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt;
    261 
    262     /* Reset frame start flag. For Mpeg1 we want to set frame start after
    263      we parsed pich header, since there is no extension*/
    264     parser->mpeg2_frame_start =  (!parser->mpeg2_stream) && (parser->mpeg2_last_parsed_sc == MPEG2_SC_PICTURE);
    265 
    266     /* Peak current start code - First 32 bits of the stream */
    267     ret = viddec_pm_peek_bits(parent, &current_sc, sc_bits);
    268     if (ret == -1)
    269     {
    270         MPEG2_DEB("Unable to get start code.\n");
    271         return MPEG2_PARSE_ERROR;
    272     }
    273     current_sc &= MPEG2_BIT_MASK_8;
    274     MPEG2_DEB("Start Code found = 0x%.8X\n", current_sc);
    275 
    276     /* Get rid of the start code prefix for all start codes except slice */
    277     /* start codes. */
    278     if ((current_sc < MPEG2_SC_SLICE_MIN) || (current_sc > MPEG2_SC_SLICE_MAX))
    279     {
    280         viddec_pm_skip_bits(parent, sc_bits);
    281     }
    282 
    283     /* Parse Metadata based on the start code found */
    284     switch( current_sc )
    285     {
    286         /* Sequence Start Code */
    287         case MPEG2_SC_SEQ_HDR:
    288         {
    289             parser->mpeg2_curr_seq_headers = MPEG2_HEADER_NONE;
    290             viddec_mpeg2_parse_seq_hdr(parent, ctxt);
    291         }
    292         break;
    293 
    294         /* Picture Start Code */
    295         case MPEG2_SC_PICTURE:
    296         {
    297             viddec_mpeg2_parse_pic_hdr(parent, ctxt);
    298         }
    299         break;
    300 
    301         /* Extension Code */
    302         case MPEG2_SC_EXT:
    303         {
    304             viddec_mpeg2_parse_ext(parent, ctxt);
    305         }
    306         break;
    307 
    308         /* Group of Pictures Header */
    309         case MPEG2_SC_GROUP:
    310         {
    311             viddec_mpeg2_parse_gop_hdr(parent, ctxt);
    312         }
    313         break;
    314 
    315         /* Unused Start Code */
    316         case MPEG2_SC_SEQ_END:
    317         case MPEG2_SC_SEQ_ERR:
    318             break;
    319 
    320         /* User Data */
    321         case MPEG2_SC_USER_DATA:
    322         {
    323             viddec_mpeg2_parse_and_append_user_data(parent, ctxt);
    324         }
    325         break;
    326 
    327         default:
    328         {
    329             /* Slice Data - Append slice data to the workload */
    330             if ((current_sc >= MPEG2_SC_SLICE_MIN) &&
    331                 (current_sc <= MPEG2_SC_SLICE_MAX))
    332             {
    333                 if (!parser->mpeg2_first_slice_flag)
    334                 {
    335                     /* At this point, all the metadata required by the MPEG2 */
    336                     /* hardware for decoding is extracted and stored. So the */
    337                     /* metadata can be packed into workitems and emitted out.*/
    338                     viddec_mpeg2_emit_workload(parent, ctxt);
    339 
    340                     /* If the current picture is progressive or it is the */
    341                     /* second field of interlaced field picture then, set */
    342                     /* the workload done flag. */
    343                     if ((!parser->mpeg2_picture_interlaced)
    344                         || ((parser->mpeg2_picture_interlaced) && (!parser->mpeg2_first_field)))
    345                     {
    346                         parser->mpeg2_pic_metadata_complete = true;
    347                     }
    348                     else if ((parser->mpeg2_picture_interlaced) && (parser->mpeg2_first_field))
    349                     {
    350                         parser->mpeg2_curr_frame_headers = MPEG2_HEADER_NONE;
    351                     }
    352 
    353                     parser->mpeg2_first_slice_flag = true;
    354                 }
    355                 parser->mpeg2_last_parsed_slice_sc = current_sc;
    356                 viddec_mpeg2_parse_and_append_slice_data(parent, ctxt);
    357                 parser->mpeg2_wl_status |= MPEG2_WL_PARTIAL_SLICE;
    358             }
    359         }
    360     } /* Switch */
    361 
    362     /* Save last parsed start code */
    363     parser->mpeg2_last_parsed_sc = current_sc;
    364     return ret;
    365 }
    366 
    367 /* viddec_mpeg2_get_ops() - Register parser ops with the parser manager. */
    368 void viddec_mpeg2_get_ops
    369 (
    370     viddec_parser_ops_t     *ops
    371 )
    372 {
    373     ops->init         = viddec_mpeg2_parser_init;
    374     ops->parse_syntax = viddec_mpeg2_parse;
    375     ops->get_cxt_size = viddec_mpeg2_get_context_size;
    376     ops->is_wkld_done = viddec_mpeg2_is_workload_done;
    377     ops->is_frame_start = viddec_mpeg2_is_start_frame;
    378     return;
    379 }
    380 
    381