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. */ 12static 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. */ 65static 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. */ 77static 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. */ 191static 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. */ 202static 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. */ 252static 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, ¤t_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. */ 368void 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