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. */
viddec_mpeg2_parser_init(void * ctxt,uint32_t * persist_mem,uint32_t preserve)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. */
viddec_mpeg2_get_context_size(viddec_parser_memory_sizes_t * size)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. */
viddec_mpeg2_get_error_code(struct viddec_mpeg2_parser * parser,viddec_workload_t * wl,uint32_t * error_code)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. */
viddec_mpeg2_is_start_frame(void * ctxt)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. */
viddec_mpeg2_is_workload_done(void * parent,void * ctxt,unsigned int next_sc,uint32_t * codec_specific_errors)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. */
viddec_mpeg2_parse(void * parent,void * ctxt)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, ¤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. */
viddec_mpeg2_get_ops(viddec_parser_ops_t * ops)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