1#include "viddec_fw_debug.h"
2#include "viddec_parser_ops.h"
3#include "viddec_mp4_parse.h"
4#include "viddec_mp4_decodevideoobjectplane.h"
5#include "viddec_mp4_shortheader.h"
6#include "viddec_mp4_videoobjectlayer.h"
7#include "viddec_mp4_videoobjectplane.h"
8#include "viddec_mp4_visualobject.h"
9
10extern uint32_t viddec_parse_sc_mp4(void *in, void *pcxt, void *sc_state);
11
12void viddec_mp4_get_context_size(viddec_parser_memory_sizes_t *size)
13{
14    /* Should return size of my structure */
15    size->context_size = sizeof(viddec_mp4_parser_t);
16    size->persist_size = 0;
17    return;
18} // viddec_mp4_get_context_size
19
20uint32_t viddec_mp4_wkld_done(void *parent, void *ctxt, uint32_t next_sc, uint32_t *codec_specific_errors)
21{
22    viddec_mp4_parser_t *parser = (viddec_mp4_parser_t *) ctxt;
23    int result = VIDDEC_PARSE_SUCESS;
24    uint8_t frame_boundary = false;
25    uint8_t force_frame_complete = false;
26
27    //DEB("entering is_wkld_done: next_sc: 0x%x, sc_seen: %d\n", next_sc, parser->sc_seen);
28
29    parent = parent;
30
31    // VS, VO, VOL, VOP or GVOP start codes indicate frame boundary.
32    frame_boundary = (  (MP4_SC_VISUAL_OBJECT_SEQUENCE == next_sc) ||
33                        (MP4_SC_VISUAL_OBJECT == next_sc) ||
34                        ((MP4_SC_VIDEO_OBJECT_LAYER_MIN <= next_sc) && (next_sc <= MP4_SC_VIDEO_OBJECT_LAYER_MAX)) ||
35                        (next_sc <= MP4_SC_VIDEO_OBJECT_MAX) ||
36                        (MP4_SC_VIDEO_OBJECT_PLANE == next_sc) ||
37                        ((SHORT_THIRD_STARTCODE_BYTE & 0xFC) == (next_sc & 0xFC)) ||
38                        (MP4_SC_GROUP_OF_VOP == next_sc)    );
39
40    // EOS and discontinuity should force workload completion.
41    force_frame_complete = ((VIDDEC_PARSE_EOS == next_sc) || (VIDDEC_PARSE_DISCONTINUITY == next_sc));
42
43    if(frame_boundary | force_frame_complete)
44    {
45        *codec_specific_errors = 0;
46
47        // Frame is considered complete and without errors, if a VOL was received since startup and
48        // if a VOP was received for this workload.
49        if (!((parser->sc_seen & MP4_SC_SEEN_VOL) && (parser->sc_seen & MP4_SC_SEEN_VOP)) && !(parser->sc_seen & MP4_SC_SEEN_SVH))
50            *codec_specific_errors |= VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE;
51
52        /*
53        This is the strategy for error detection.
54        Errors in any field needed by the firmware (parser/decoder) are treated as non-decodable.
55        Errors in other fields will be considered decodable.
56        Defaults/alternate strategies will be considered on a case-by-case basis as customer content is seen.
57
58        ERROR_TYPE      |       PARSING         |   INVALID/UNSUPPORTED |       BS = Bitstream error
59        -----------------------------------------------------------------       UNSUP = Un-supported
60        DFLT_PRESENT    |       YES |   NO      |       YES |   NO      |       ND = Non-decodable
61        COMPONENT USED  |           |           |           |           |       DFLT = Populate defaults
62        -----------------------------------------------------------------
63        FIRMWARE        | BS+ND     | BS+ND     | UNSUP+ND  | UNSUP+ND  |
64        DRIVER/USER     | BS+DFLT   | BS        | UNSUP     | UNSUP     |
65        NONE            | BS        | BS        | UNSUP     | UNSUP     |
66                        |           |           | Continue Parsing      |
67        */
68        if((parser->bitstream_error & MP4_BS_ERROR_HDR_NONDEC) || (parser->bitstream_error & MP4_BS_ERROR_FRM_NONDEC))
69            *codec_specific_errors |= (VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE | VIDDEC_FW_WORKLOAD_ERR_MISSING_DMEM);
70
71        if((parser->bitstream_error & MP4_BS_ERROR_HDR_UNSUP) || (parser->bitstream_error & MP4_BS_ERROR_FRM_UNSUP))
72            *codec_specific_errors |= VIDDEC_FW_WORKLOAD_ERR_UNSUPPORTED;
73
74        if((parser->bitstream_error & MP4_BS_ERROR_HDR_PARSE) || (parser->bitstream_error & MP4_BS_ERROR_FRM_PARSE))
75            *codec_specific_errors |= VIDDEC_FW_WORKLOAD_ERR_BITSTREAM_ERROR;
76
77        parser->bitstream_error &= MP4_HDR_ERROR_MASK;
78        parser->sc_seen &= MP4_SC_SEEN_VOL;
79        result = VIDDEC_PARSE_FRMDONE;
80    }
81    //DEB("exiting is_wkld_done: next_sc: 0x%x, sc_seen: %d, err: %d, fr_bnd:%d, force:%d\n",
82    //        next_sc, parser->sc_seen, *codec_specific_errors, frame_boundary, force_frame_complete);
83
84    return result;
85} // viddec_mp4_wkld_done
86
87void viddec_mp4_init(void *ctxt, uint32_t *persist_mem, uint32_t preserve)
88{
89    viddec_mp4_parser_t *parser = (viddec_mp4_parser_t *) ctxt;
90
91    persist_mem = persist_mem;
92    parser->is_frame_start = false;
93    parser->prev_sc = MP4_SC_INVALID;
94    parser->current_sc = MP4_SC_INVALID;
95    parser->cur_sc_prefix = false;
96    parser->next_sc_prefix = false;
97    parser->ignore_scs = false;
98
99    if(preserve)
100    {
101        // Need to maintain information till VOL
102        parser->sc_seen &= MP4_SC_SEEN_VOL;
103        parser->bitstream_error &= MP4_HDR_ERROR_MASK;
104
105        // Reset only frame related data
106        memset(&(parser->info.VisualObject.VideoObject.VideoObjectPlane), 0, sizeof(mp4_VideoObjectPlane_t));
107        memset(&(parser->info.VisualObject.VideoObject.VideoObjectPlaneH263), 0, sizeof(mp4_VideoObjectPlaneH263));
108    }
109    else
110    {
111        parser->sc_seen = MP4_SC_SEEN_INVALID;
112        parser->bitstream_error = MP4_BS_ERROR_NONE;
113        memset(&(parser->info), 0, sizeof(mp4_Info_t));
114    }
115
116    return;
117} // viddec_mp4_init
118
119static uint32_t viddec_mp4_decodevop_and_emitwkld(void *parent, void *ctxt)
120{
121    int status = MP4_STATUS_OK;
122    viddec_mp4_parser_t *cxt = (viddec_mp4_parser_t *)ctxt;
123
124    status = mp4_DecodeVideoObjectPlane(&(cxt->info));
125
126#ifndef VBP
127    status = viddec_fw_mp4_emit_workload(parent, ctxt);
128#endif
129
130    return status;
131} // viddec_mp4_decodevop_and_emitwkld
132
133uint32_t viddec_mp4_parse(void *parent, void *ctxt)
134{
135    uint32_t sc=0;
136    viddec_mp4_parser_t *cxt;
137    uint8_t is_svh=0;
138    int32_t getbits=0;
139    int32_t status = 0;
140
141    cxt = (viddec_mp4_parser_t *)ctxt;
142    is_svh = (cxt->cur_sc_prefix) ? false: true;
143    if((getbits = viddec_pm_peek_bits(parent, &sc, 32)) == -1)
144    {
145        DEB("Start code not found\n");
146        return VIDDEC_PARSE_ERROR;
147    }
148
149    if(!is_svh)
150    {
151        viddec_pm_get_bits(parent, &sc, 32);
152        sc = sc & 0xFF;
153        cxt->current_sc = sc;
154        cxt->current_sc |= 0x100;
155        DEB("current_sc=0x%.8X, prev_sc=0x%x\n", sc, cxt->prev_sc);
156
157        switch(sc)
158        {
159            case MP4_SC_VISUAL_OBJECT_SEQUENCE:
160            {
161                status = mp4_Parse_VisualSequence(parent, cxt);
162                cxt->prev_sc = MP4_SC_VISUAL_OBJECT_SEQUENCE;
163                DEB("MP4_VISUAL_OBJECT_SEQUENCE_SC: \n");
164                break;
165            }
166            case MP4_SC_VISUAL_OBJECT_SEQUENCE_EC:
167            {/* Not required to do anything */
168                break;
169            }
170            case MP4_SC_USER_DATA:
171            {   /* Copy userdata to user-visible buffer (EMIT) */
172                status = mp4_Parse_UserData(parent, cxt);
173                DEB("MP4_USER_DATA_SC: \n");
174                break;
175            }
176            case MP4_SC_GROUP_OF_VOP:
177            {
178                status = mp4_Parse_GroupOfVideoObjectPlane(parent, cxt);
179                cxt->prev_sc = MP4_SC_GROUP_OF_VOP;
180                DEB("MP4_GROUP_OF_VOP_SC:0x%.8X\n", status);
181                break;
182            }
183            case MP4_SC_VIDEO_SESSION_ERROR:
184            {/* Not required to do anything?? */
185                break;
186            }
187            case MP4_SC_VISUAL_OBJECT:
188            {
189                status = mp4_Parse_VisualObject(parent, cxt);
190                cxt->prev_sc = MP4_SC_VISUAL_OBJECT;
191                DEB("MP4_VISUAL_OBJECT_SC: status=%.8X\n", status);
192                break;
193            }
194            case MP4_SC_VIDEO_OBJECT_PLANE:
195            {
196                /* We must decode the VOP Header information, it does not end  on a byte boundary, so we need to emit
197                   a starting bit offset after parsing the header. */
198                status = mp4_Parse_VideoObjectPlane(parent, cxt);
199                status = viddec_mp4_decodevop_and_emitwkld(parent, cxt);
200                // TODO: Fix this for interlaced
201                cxt->is_frame_start = true;
202                cxt->sc_seen |= MP4_SC_SEEN_VOP;
203
204                DEB("MP4_VIDEO_OBJECT_PLANE_SC: status=0x%.8X\n", status);
205                break;
206            }
207            case MP4_SC_STUFFING:
208            {
209                break;
210            }
211            default:
212            {
213                if( (sc >=  MP4_SC_VIDEO_OBJECT_LAYER_MIN) && (sc <=  MP4_SC_VIDEO_OBJECT_LAYER_MAX) )
214                {
215                    status = mp4_Parse_VideoObjectLayer(parent, cxt);
216                    cxt->sc_seen = MP4_SC_SEEN_VOL;
217                    cxt->prev_sc = MP4_SC_VIDEO_OBJECT_LAYER_MIN;
218                    DEB("MP4_VIDEO_OBJECT_LAYER_MIN_SC:status=0x%.8X\n", status);
219                    sc = MP4_SC_VIDEO_OBJECT_LAYER_MIN;
220                }
221                // sc is unsigned and will be >= 0, so no check needed for sc >= MP4_SC_VIDEO_OBJECT_MIN
222                else if(sc <= MP4_SC_VIDEO_OBJECT_MAX)
223                {
224                     // If there is more data, it is short video header, else the next start code is expected to be VideoObjectLayer
225                     getbits = viddec_pm_get_bits(parent, &sc, 22);
226                     if(getbits != -1)
227                     {
228                        cxt->current_sc = sc;
229                        status = mp4_Parse_VideoObject_svh(parent, cxt);
230                        status = viddec_mp4_decodevop_and_emitwkld(parent, cxt);
231                        cxt->sc_seen = MP4_SC_SEEN_SVH;
232                        cxt->is_frame_start = true;
233                        DEB("MP4_SCS_SVH: status=0x%.8X 0x%.8X %.8X\n", status, cxt->current_sc, sc);
234                        DEB("MP4_VIDEO_OBJECT_MIN_SC:status=0x%.8X\n", status);
235                     }
236                }
237                else
238                {
239                    DEB("UNKWON Cod:0x%08X\n", sc);
240                }
241            }
242            break;
243        }
244    }
245    else
246    {
247        viddec_pm_get_bits(parent, &sc, 22);
248        cxt->current_sc = sc;
249        DEB("current_sc=0x%.8X, prev_sc=0x%x\n", sc, cxt->prev_sc);
250        status = mp4_Parse_VideoObject_svh(parent, cxt);
251        status = viddec_mp4_decodevop_and_emitwkld(parent, cxt);
252        cxt->sc_seen = MP4_SC_SEEN_SVH;
253        cxt->is_frame_start = true;
254        DEB("SVH: MP4_SCS_SVH: status=0x%.8X 0x%.8X %.8X\n", status, cxt->current_sc, sc);
255    }
256
257    // Current sc becomes the previous sc
258    cxt->prev_sc = sc;
259
260    return VIDDEC_PARSE_SUCESS;
261} // viddec_mp4_parse
262
263uint32_t viddec_mp4_is_frame_start(void *ctxt)
264{
265    viddec_mp4_parser_t *parser = (viddec_mp4_parser_t *)ctxt;
266    return parser->is_frame_start;
267} // viddec_mp4_is_frame_start
268
269void viddec_mp4_get_ops(viddec_parser_ops_t *ops)
270{
271    ops->parse_syntax = viddec_mp4_parse;
272    ops->get_cxt_size = viddec_mp4_get_context_size;
273    ops->is_wkld_done = viddec_mp4_wkld_done;
274    ops->parse_sc = viddec_parse_sc_mp4;
275    ops->is_frame_start = viddec_mp4_is_frame_start;
276    ops->init = viddec_mp4_init;
277    return;
278} // viddec_mp4_get_ops
279