• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &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. */
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