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