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
viddec_mpeg2_append_workitem(void * parent,viddec_workload_item_t * wi,uint8_t next_wl)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
viddec_mpeg2_get_header(void * parent,uint8_t next_wl)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. */
viddec_mpeg2_set_seq_ext_defaults(struct viddec_mpeg2_parser * parser)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. */
viddec_mpeg2_set_pic_cod_ext_defaults(struct viddec_mpeg2_parser * parser)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
viddec_mpeg2_pack_qmat(struct viddec_mpeg2_parser * parser)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
viddec_mpeg2_pack_qmat(struct viddec_mpeg2_parser * parser)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 */
viddec_mpeg2_trans_metadata_workitems(void * ctxt)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. */
mpeg2_emit_frameid(void * parent,int32_t wl_type,uint8_t flag)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 */
mpeg2_send_ref_reorder(void * parent,uint8_t flag)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. */
viddec_mpeg2_manage_ref(void * parent,void * ctxt)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 */
viddec_mpeg2_check_unsupported(void * parent,void * ctxt)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. */
viddec_mpeg2_append_metadata(void * parent,void * ctxt)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. */
viddec_mpeg2_append_workitems(void * parent,uint32_t * address,int workitem_type,int num_items,uint8_t flag)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 */
viddec_mpeg2_emit_workload(void * parent,void * ctxt)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