1 /** 2 * viddec_mpeg2_workload.c 3 * ----------------------- 4 * This file packs the data parsed and stored in the context into workload and 5 * emits it out. The current list of workitems emitter into the workload 6 * include: 7 * 8 * - DMEM - Register Data 9 * - Past and Future picture references 10 * - Quantization matrix data 11 * 12 * Slice data gets appended into the workload in viddec_mpeg2_parse.c 13 * 14 * Also, the frame attributes are updated in the workload. 15 */ 16 17 #include "viddec_mpeg2.h" 18 #include "viddec_fw_item_types.h" 19 20 void viddec_mpeg2_append_workitem(void *parent, viddec_workload_item_t *wi, uint8_t next_wl) 21 { 22 if (next_wl) 23 { 24 viddec_pm_append_workitem_next(parent, wi); 25 } 26 else 27 { 28 viddec_pm_append_workitem(parent, wi); 29 } 30 return; 31 } 32 33 viddec_workload_t* viddec_mpeg2_get_header(void *parent, uint8_t next_wl) 34 { 35 viddec_workload_t *ret; 36 if (next_wl) 37 { 38 ret = viddec_pm_get_next_header(parent); 39 } 40 else 41 { 42 ret = viddec_pm_get_header(parent); 43 } 44 return ret; 45 } 46 47 /* viddec_mpeg2_set_seq_ext_defaults() - Sets non-zero default values for */ 48 /* sequence extension items in case sequence extension is not present. */ 49 static void viddec_mpeg2_set_seq_ext_defaults(struct viddec_mpeg2_parser *parser) 50 { 51 parser->info.seq_ext.progressive_sequence = true; 52 parser->info.seq_ext.chroma_format = MPEG2_CF_420; 53 } 54 55 /* viddec_mpeg2_set_pic_cod_ext_defaults() - Sets non-zero default values for*/ 56 /* picture coding extension items in case picture coding extension is not */ 57 /* present. */ 58 static void viddec_mpeg2_set_pic_cod_ext_defaults(struct viddec_mpeg2_parser *parser) 59 { 60 parser->info.pic_cod_ext.picture_structure = MPEG2_PIC_STRUCT_FRAME; 61 parser->info.pic_cod_ext.frame_pred_frame_dct = true; 62 parser->info.pic_cod_ext.progressive_frame = true; 63 } 64 65 /* viddec_mpeg2_pack_qmat() - Packs the 256 byte quantization matrix data */ 66 /* 64 32-bit values. */ 67 #ifdef MFDBIGENDIAN 68 static void viddec_mpeg2_pack_qmat(struct viddec_mpeg2_parser *parser) 69 { 70 /* Quantization Matrix Support */ 71 /* Populate Quantization Matrices */ 72 uint32_t index = 0; 73 uint32_t *qmat_packed, *qmat_unpacked; 74 75 /* When transferring the quantization matrix data from the parser */ 76 /* context into workload items, we are packing four 8 bit */ 77 /* quantization values into one DWORD (32 bits). To do this, the */ 78 /* array of values of type uint8_t, is typecast as uint32 * and */ 79 /* read. */ 80 qmat_packed = (uint32_t *) parser->wi.qmat; 81 qmat_unpacked = (uint32_t *) &parser->info.qnt_mat; 82 83 for (index=0; index<MPEG2_QUANT_MAT_SIZE; index++) 84 { 85 qmat_packed[index] = qmat_unpacked[index]; 86 } 87 return; 88 } 89 #else 90 static void viddec_mpeg2_pack_qmat(struct viddec_mpeg2_parser *parser) 91 { 92 /* Quantization Matrix Support */ 93 /* Populate Quantization Matrices */ 94 uint32_t index = 0; 95 uint32_t *qmat_packed; 96 uint8_t *qmat_unpacked; 97 98 /* When transferring the quantization matrix data from the parser */ 99 /* context into workload items, we are packing four 8 bit */ 100 /* quantization values into one DWORD (32 bits). To do this, the */ 101 /* array of values of type uint8_t, is typecast as uint32 * and */ 102 /* read. */ 103 qmat_packed = (uint32_t *) parser->wi.qmat; 104 qmat_unpacked = (uint8_t *) &parser->info.qnt_mat; 105 106 for (index=0; index<MPEG2_QUANT_MAT_SIZE; index++) 107 { 108 qmat_packed[index] = 109 (((uint32_t)qmat_unpacked[(index<<2)+0])<< 24) | 110 (((uint32_t)qmat_unpacked[(index<<2)+1])<< 16) | 111 (((uint32_t)qmat_unpacked[(index<<2)+2])<< 8) | 112 (((uint32_t)qmat_unpacked[(index<<2)+3])<< 0) ; 113 } 114 return; 115 } 116 #endif 117 118 /* viddec_mpeg2_trans_metadata_workitems() - Transfers the metadata stored */ 119 /* in parser context into workitems by bit masking. These workitems are then */ 120 /* sent through emitter */ 121 static void viddec_mpeg2_trans_metadata_workitems(void *ctxt) 122 { 123 struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt; 124 125 /* Reset register values */ 126 parser->wi.csi1 = 0x0; 127 parser->wi.csi2 = 0x0; 128 parser->wi.cpi1 = 0x0; 129 parser->wi.cpce1 = 0x0; 130 131 /* Set defaults for missing fields */ 132 if (!(parser->mpeg2_curr_seq_headers & MPEG2_HEADER_SEQ_EXT)) 133 { 134 viddec_mpeg2_set_seq_ext_defaults(parser); 135 } 136 if (!(parser->mpeg2_curr_frame_headers & MPEG2_HEADER_PIC_COD_EXT)) 137 { 138 viddec_mpeg2_set_pic_cod_ext_defaults(parser); 139 } 140 141 /* Populate Core Sequence Info 1 */ 142 parser->wi.csi1 |= (parser->mpeg2_stream) << 1; 143 parser->wi.csi1 |= (parser->info.seq_hdr.constrained_parameters_flag) << 2; 144 parser->wi.csi1 |= (parser->info.seq_ext.progressive_sequence) << 3; 145 parser->wi.csi1 |= (parser->info.seq_ext.chroma_format) << 16; 146 parser->wi.csi1 |= (parser->info.qnt_ext.load_intra_quantiser_matrix) << 19; 147 parser->wi.csi1 |= (parser->info.qnt_ext.load_non_intra_quantiser_matrix) << 20; 148 parser->wi.csi1 |= (parser->info.qnt_ext.load_chroma_intra_quantiser_matrix) << 21; 149 parser->wi.csi1 |= (parser->info.qnt_ext.load_chroma_non_intra_quantiser_matrix) << 22; 150 MPEG2_DEB("Core Sequence Info 1: 0x%.8X\n", parser->wi.csi1); 151 152 /* Populate Core Sequence Info 2 */ 153 parser->wi.csi2 |= (parser->info.seq_hdr.horizontal_size_value & MPEG2_BIT_MASK_11); 154 parser->wi.csi2 |= (parser->info.seq_hdr.vertical_size_value & MPEG2_BIT_MASK_11) << 14; 155 MPEG2_DEB("Core Sequence Info 2: 0x%.8X\n", parser->wi.csi2); 156 157 /* Populate Core Picture Info */ 158 parser->wi.cpi1 |= (parser->info.pic_hdr.full_pel_forward_vect); 159 parser->wi.cpi1 |= (parser->info.pic_hdr.forward_f_code) << 1; 160 parser->wi.cpi1 |= (parser->info.pic_hdr.full_pel_backward_vect) << 4; 161 parser->wi.cpi1 |= (parser->info.pic_hdr.backward_f_code) << 5; 162 parser->wi.cpi1 |= (parser->info.pic_cod_ext.fcode00) << 8; 163 parser->wi.cpi1 |= (parser->info.pic_cod_ext.fcode01) << 12; 164 parser->wi.cpi1 |= (parser->info.pic_cod_ext.fcode10) << 16; 165 parser->wi.cpi1 |= (parser->info.pic_cod_ext.fcode11) << 20; 166 parser->wi.cpi1 |= (parser->info.pic_cod_ext.intra_dc_precision) << 24; 167 parser->wi.cpi1 |= (parser->info.pic_hdr.picture_coding_type-1) << 26; 168 MPEG2_DEB("Core Picture Info 1: 0x%.8X\n", parser->wi.cpi1); 169 170 /* Populate Core Picture Extension Info */ 171 parser->wi.cpce1 |= (parser->info.pic_cod_ext.composite_display_flag); 172 parser->wi.cpce1 |= (parser->info.pic_cod_ext.progressive_frame) << 1; 173 parser->wi.cpce1 |= (parser->info.pic_cod_ext.chroma_420_type) << 2; 174 parser->wi.cpce1 |= (parser->info.pic_cod_ext.repeat_first_field) << 3; 175 parser->wi.cpce1 |= (parser->info.pic_cod_ext.alternate_scan) << 4; 176 parser->wi.cpce1 |= (parser->info.pic_cod_ext.intra_vlc_format) << 5; 177 parser->wi.cpce1 |= (parser->info.pic_cod_ext.q_scale_type) << 6; 178 parser->wi.cpce1 |= (parser->info.pic_cod_ext.concealment_motion_vectors) << 7; 179 parser->wi.cpce1 |= (parser->info.pic_cod_ext.frame_pred_frame_dct) << 8; 180 parser->wi.cpce1 |= (parser->info.pic_cod_ext.top_field_first) << 9; 181 parser->wi.cpce1 |= (parser->info.pic_cod_ext.picture_structure) << 10; 182 MPEG2_DEB("Core Picture Ext Info 1: 0x%.8X\n", parser->wi.cpce1); 183 184 return; 185 } 186 187 /* mpeg2_emit_display_frame() - Sends the frame id as a workload item. */ 188 static inline void mpeg2_emit_frameid(void *parent, int32_t wl_type, uint8_t flag) 189 { 190 viddec_workload_item_t wi; 191 wi.vwi_type = wl_type; 192 193 wi.ref_frame.reference_id = 0; 194 wi.ref_frame.luma_phys_addr = 0; 195 wi.ref_frame.chroma_phys_addr = 0; 196 viddec_mpeg2_append_workitem( parent, &wi, flag ); 197 } 198 199 /* mpeg2_send_ref_reorder() - Reorders reference frames */ 200 static inline void mpeg2_send_ref_reorder(void *parent, uint8_t flag) 201 { 202 viddec_workload_item_t wi; 203 204 wi.vwi_type = VIDDEC_WORKLOAD_REFERENCE_FRAME_REORDER; 205 wi.ref_reorder.ref_table_offset = 0; 206 /* Reorder index 1 to index 0 only */ 207 wi.ref_reorder.ref_reorder_00010203 = 0x01010203; 208 wi.ref_reorder.ref_reorder_04050607 = 0x04050607; 209 viddec_mpeg2_append_workitem( parent, &wi, flag ); 210 } 211 212 /* viddec_mpeg2_manage_ref() - Manages frame references by inserting the */ 213 /* past and future references (if any) for every frame inserted in the */ 214 /* workload. */ 215 static void viddec_mpeg2_manage_ref(void *parent, void *ctxt) 216 { 217 int32_t frame_id = 1; 218 int32_t frame_type; 219 220 /* Get MPEG2 Parser context */ 221 struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt; 222 viddec_workload_t *wl = viddec_mpeg2_get_header( parent, parser->mpeg2_use_next_workload ); 223 wl->is_reference_frame = 0; 224 225 /* Identify the frame type (I, P or B) */ 226 frame_type = parser->info.pic_hdr.picture_coding_type; 227 228 /* Send reference frame information based on whether the picture is a */ 229 /* frame picture or field picture. */ 230 if ((!parser->mpeg2_picture_interlaced) 231 || ((parser->mpeg2_picture_interlaced) && (parser->mpeg2_first_field))) 232 { 233 /* Check if we need to reorder frame references/send frame for display */ 234 /* in case of I or P type */ 235 if (frame_type != MPEG2_PC_TYPE_B) 236 { 237 /* Checking reorder */ 238 if (parser->mpeg2_ref_table_updated) 239 { 240 mpeg2_send_ref_reorder(parent, parser->mpeg2_use_next_workload); 241 } 242 } 243 244 /* Send reference frame workitems */ 245 switch(frame_type) 246 { 247 case MPEG2_PC_TYPE_I: 248 { 249 break; 250 } 251 case MPEG2_PC_TYPE_P: 252 { 253 mpeg2_emit_frameid(parent, VIDDEC_WORKLOAD_MPEG2_REF_PAST, parser->mpeg2_use_next_workload); 254 break; 255 } 256 case MPEG2_PC_TYPE_B: 257 { 258 mpeg2_emit_frameid(parent, VIDDEC_WORKLOAD_MPEG2_REF_PAST, parser->mpeg2_use_next_workload); 259 mpeg2_emit_frameid(parent, VIDDEC_WORKLOAD_MPEG2_REF_FUTURE, parser->mpeg2_use_next_workload); 260 } 261 } 262 263 /* Set reference information updated flag */ 264 if (!parser->mpeg2_picture_interlaced) 265 { 266 parser->mpeg2_wl_status |= MPEG2_WL_REF_INFO; 267 } 268 } 269 else 270 { 271 /* Set reference information updated flag for second fiel */ 272 parser->mpeg2_wl_status |= MPEG2_WL_REF_INFO; 273 } 274 275 /* Set the reference frame flags for I and P types */ 276 if (frame_type != MPEG2_PC_TYPE_B) 277 { 278 wl->is_reference_frame |= WORKLOAD_REFERENCE_FRAME | (frame_id & WORKLOAD_REFERENCE_FRAME_BMASK); 279 parser->mpeg2_ref_table_updated = true; 280 } 281 282 return; 283 } 284 285 /* viddec_mpeg2_check_unsupported() - Check for unsupported feature in the stream */ 286 static void viddec_mpeg2_check_unsupported(void *parent, void *ctxt) 287 { 288 unsigned int unsupported_feature_found = 0; 289 290 /* Get MPEG2 Parser context */ 291 struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt; 292 293 /* Get workload */ 294 viddec_workload_t *wl = viddec_mpeg2_get_header( parent, parser->mpeg2_use_next_workload ); 295 296 /* Get attributes in workload */ 297 viddec_frame_attributes_t *attrs = &wl->attrs; 298 299 /* Check for unsupported content size */ 300 unsupported_feature_found |= (attrs->cont_size.height > MPEG2_MAX_CONTENT_HEIGHT); 301 unsupported_feature_found |= (attrs->cont_size.width > MPEG2_MAX_CONTENT_WIDTH); 302 303 /* Update parser status, if found */ 304 if (unsupported_feature_found) 305 { 306 parser->mpeg2_wl_status |= MPEG2_WL_UNSUPPORTED; 307 } 308 309 return; 310 } 311 312 /* viddec_mpeg2_append_metadata() - Appends meta data from the stream. */ 313 void viddec_mpeg2_append_metadata(void *parent, void *ctxt) 314 { 315 /* Get MPEG2 Parser context */ 316 struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt; 317 318 viddec_workload_item_t wi; 319 320 /* Append sequence info, if found with current frame */ 321 if (parser->mpeg2_curr_frame_headers & MPEG2_HEADER_SEQ) 322 { 323 memset(&wi, 0, sizeof(viddec_workload_item_t)); 324 wi.vwi_type = VIDDEC_WORKLOAD_SEQUENCE_INFO; 325 326 viddec_fw_mp2_sh_set_horizontal_size_value ( &(wi.mp2_sh) , parser->info.seq_hdr.horizontal_size_value); 327 viddec_fw_mp2_sh_set_vertical_size_value ( &(wi.mp2_sh) , parser->info.seq_hdr.vertical_size_value); 328 viddec_fw_mp2_sh_set_aspect_ratio_information ( &(wi.mp2_sh) , parser->info.seq_hdr.aspect_ratio_information); 329 viddec_fw_mp2_sh_set_frame_rate_code ( &(wi.mp2_sh) , parser->info.seq_hdr.frame_rate_code); 330 viddec_fw_mp2_sh_set_bit_rate_value ( &(wi.mp2_sh) , parser->info.seq_hdr.bit_rate_value); 331 viddec_fw_mp2_sh_set_vbv_buffer_size_value ( &(wi.mp2_sh) , parser->info.seq_hdr.vbv_buffer_size_value); 332 333 viddec_mpeg2_append_workitem(parent, &wi, parser->mpeg2_use_next_workload); 334 } 335 336 /* Append sequence extension info, if found with current frame */ 337 if (parser->mpeg2_curr_frame_headers & MPEG2_HEADER_SEQ_EXT) 338 { 339 memset(&wi, 0, sizeof(viddec_workload_item_t)); 340 wi.vwi_type = VIDDEC_WORKLOAD_MPEG2_SEQ_EXT; 341 342 viddec_fw_mp2_se_set_profile_and_level_indication( &(wi.mp2_se) , parser->info.seq_ext.profile_and_level_indication); 343 viddec_fw_mp2_se_set_progressive_sequence ( &(wi.mp2_se) , parser->info.seq_ext.progressive_sequence); 344 viddec_fw_mp2_se_set_chroma_format ( &(wi.mp2_se) , parser->info.seq_ext.chroma_format); 345 viddec_fw_mp2_se_set_horizontal_size_extension ( &(wi.mp2_se) , parser->info.seq_ext.horizontal_size_extension); 346 viddec_fw_mp2_se_set_vertical_size_extension ( &(wi.mp2_se) , parser->info.seq_ext.vertical_size_extension); 347 viddec_fw_mp2_se_set_bit_rate_extension ( &(wi.mp2_se) , parser->info.seq_ext.bit_rate_extension); 348 viddec_fw_mp2_se_set_vbv_buffer_size_extension ( &(wi.mp2_se) , parser->info.seq_ext.vbv_buffer_size_extension); 349 viddec_fw_mp2_se_set_frame_rate_extension_n ( &(wi.mp2_se) , parser->info.seq_ext.frame_rate_extension_n); 350 viddec_fw_mp2_se_set_frame_rate_extension_d ( &(wi.mp2_se) , parser->info.seq_ext.frame_rate_extension_d); 351 352 viddec_mpeg2_append_workitem(parent, &wi, parser->mpeg2_use_next_workload); 353 } 354 355 /* Append Display info, if present */ 356 if (parser->mpeg2_curr_frame_headers & MPEG2_HEADER_SEQ_DISP_EXT) 357 { 358 memset(&wi, 0, sizeof(viddec_workload_item_t)); 359 wi.vwi_type = VIDDEC_WORKLOAD_DISPLAY_INFO; 360 361 viddec_fw_mp2_sde_set_video_format ( &(wi.mp2_sde) , parser->info.seq_disp_ext.video_format); 362 viddec_fw_mp2_sde_set_color_description ( &(wi.mp2_sde) , parser->info.seq_disp_ext.colour_description); 363 viddec_fw_mp2_sde_set_color_primaries ( &(wi.mp2_sde) , parser->info.seq_disp_ext.colour_primaries); 364 viddec_fw_mp2_sde_set_transfer_characteristics( &(wi.mp2_sde) , parser->info.seq_disp_ext.transfer_characteristics); 365 viddec_fw_mp2_sde_set_display_horizontal_size ( &(wi.mp2_sde) , parser->info.seq_disp_ext.display_horizontal_size); 366 viddec_fw_mp2_sde_set_display_vertical_size ( &(wi.mp2_sde) , parser->info.seq_disp_ext.display_vertical_size); 367 368 viddec_mpeg2_append_workitem(parent, &wi, parser->mpeg2_use_next_workload); 369 } 370 371 /* Append GOP info, if present */ 372 if (parser->mpeg2_curr_frame_headers & MPEG2_HEADER_GOP) 373 { 374 memset(&wi, 0, sizeof(viddec_workload_item_t)); 375 wi.vwi_type = VIDDEC_WORKLOAD_GOP_INFO; 376 377 viddec_fw_mp2_gop_set_closed_gop ( &(wi.mp2_gop) , parser->info.gop_hdr.closed_gop); 378 viddec_fw_mp2_gop_set_broken_link( &(wi.mp2_gop) , parser->info.gop_hdr.broken_link); 379 380 viddec_mpeg2_append_workitem(parent, &wi, parser->mpeg2_use_next_workload); 381 } 382 383 return; 384 } 385 386 /* viddec_mpeg2_append_workitems() - Appends decoder specific workitems */ 387 /* to the workload starting at the address and length specified. */ 388 static void viddec_mpeg2_append_workitems 389 ( 390 void *parent, 391 uint32_t* address, 392 int workitem_type, 393 int num_items, 394 uint8_t flag 395 ) 396 { 397 int32_t index=0; 398 const uint32_t* initial_address = address; 399 viddec_workload_item_t wi; 400 401 for (index=0; index < num_items; index++) 402 { 403 wi.vwi_type = workitem_type; 404 wi.data.data_offset = (char *) address - (const char *) initial_address; 405 wi.data.data_payload[0] = address[0]; 406 wi.data.data_payload[1] = address[1]; 407 address += 2; 408 409 viddec_mpeg2_append_workitem(parent, &wi, flag); 410 } 411 412 return; 413 } 414 415 /* viddec_mpeg2_emit_workload() - Emits MPEG2 parser generated work load */ 416 /* items. */ 417 /* Items include: MPEG2 DMEM Data, Quantization Matrices. */ 418 /* Pixel ES data sent separately whenever parser sees slice data */ 419 void viddec_mpeg2_emit_workload(void *parent, void *ctxt) 420 { 421 MPEG2_DEB("Emitting workloads.\n"); 422 423 /* Get MPEG2 Parser context */ 424 struct viddec_mpeg2_parser *parser = (struct viddec_mpeg2_parser *) ctxt; 425 426 /* Append meta data workitems */ 427 viddec_mpeg2_append_metadata(parent, ctxt); 428 429 /* Transfer metadata into attributes */ 430 viddec_mpeg2_translate_attr(parent, ctxt); 431 432 /* Check for unsupported features in the stream and update parser status */ 433 viddec_mpeg2_check_unsupported(parent, ctxt); 434 435 /* Transfer all stored metadata into MPEG2 Hardware Info */ 436 viddec_mpeg2_trans_metadata_workitems(parser); 437 438 /* Send MPEG2 DMEM workitems */ 439 viddec_mpeg2_append_workitems(parent, 440 (uint32_t *) &parser->wi, 441 VIDDEC_WORKLOAD_MPEG2_DMEM, 442 MPEG2_NUM_DMEM_WL_ITEMS, 443 parser->mpeg2_use_next_workload); 444 parser->mpeg2_wl_status |= MPEG2_WL_DMEM_DATA; 445 MPEG2_DEB("Adding %d items as DMEM Data.\n", MPEG2_NUM_DMEM_WL_ITEMS); 446 447 /* Send MPEG2 Quantization Matrix workitems, if updated */ 448 viddec_mpeg2_pack_qmat(parser); 449 viddec_mpeg2_append_workitems(parent, 450 (uint32_t *) parser->wi.qmat, 451 VIDDEC_WORKLOAD_MPEG2_QMAT, 452 MPEG2_NUM_QMAT_WL_ITEMS, 453 parser->mpeg2_use_next_workload); 454 MPEG2_DEB("Adding %d items as QMAT Data.\n", MPEG2_NUM_QMAT_WL_ITEMS); 455 456 /* Manage reference frames */ 457 viddec_mpeg2_manage_ref(parent, ctxt); 458 459 return; 460 } 461 462