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, &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. */
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