• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
10 extern uint32_t viddec_parse_sc_mp4(void *in, void *pcxt, void *sc_state);
11 
viddec_mp4_get_context_size(viddec_parser_memory_sizes_t * size)12 void 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 
viddec_mp4_wkld_done(void * parent,void * ctxt,uint32_t next_sc,uint32_t * codec_specific_errors)20 uint32_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 
viddec_mp4_init(void * ctxt,uint32_t * persist_mem,uint32_t preserve)87 void 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 
viddec_mp4_decodevop_and_emitwkld(void * parent,void * ctxt)119 static 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 
viddec_mp4_parse(void * parent,void * ctxt)133 uint32_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 
viddec_mp4_is_frame_start(void * ctxt)263 uint32_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 
viddec_mp4_get_ops(viddec_parser_ops_t * ops)269 void 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