1 #include "viddec_pm.h"
2 #include "viddec_fw_debug.h"
3 #include "viddec_fw_common_defs.h"
4 #include "viddec_pm_tags.h"
5 #include "viddec_parser_ops.h"
6 #include "viddec_vc1_parse.h"
7 #include "viddec_mp4_parse.h"
8 #include "viddec_mpeg2_parse.h"
9 #include "viddec_h264_parse.h"
10 /*
11 Overview of Parser manager:
12 Parser manager is the glue between Kernel(main.c) and actual codecs. We abstract common functionality as much as we can
13 in this module. The parser Manager context allocates memory for Parsers. At any point in time there is only one active stream.
14 During open stream we setup all necessary initialisation for the codec we are handling. The parser manager context is
15 stored on DDR when the current stream gets swapped out by the kernel. When the next stream comes in it has it's own
16 version of parser manager.
17 Parser manager is reponsible for providing information on when its a good time to swap a stream.
18 High level algorithm of parser Manager once a stream is opened and active(RET's are returns to Kernel):
19
20 1. create a list data structure to hold any incoming ES descriptors.
21 2. Check to see if any of the ES buffers Desc in current list has data to be processed. If not request kernel(RET) for a buffer.
22 3. If data is present parse until a scprefix+sc is found. If not goto step2.
23 4. If startcode detected update list state to make ES data look like Linear buffer.
24 5. Setup required state to provide getbits interface for codecs to access bit stream maximum 32bits at a time.
25 6. Setup Current & Next workloads provided by Kernel.
26 7. Call the codec to parse the data we collected between start codes.
27 8. Query to see if we parsed frame worth of data.
28 9. Do necessary TAG association and remove used buffers from List.
29 10. Send information to kernel on whether workload is done or Not.(RET). When kernel reschedules start from step2.
30
31 Kernel can swap current stream at RET points described above.
32
33 Other additional things supported:
34 - Generic start code detect function which is same for most of codecs.
35 - Memory Management.
36 - Flush of stream.
37 - Emulation prevention.
38 - Interface to emit necessary tags for codec specific types.
39 */
40
41
42 /* check to see if codec needs emulation prevention */
43 #define EMUL_REQD(codec) ((codec == MFD_STREAM_FORMAT_VC1) || (codec_type == MFD_STREAM_FORMAT_H264) ? 1: 0)
44
45 #ifdef RTL_SIMULATION
46 extern void output_omar_wires( unsigned int value );
47 #else
48 #define output_omar_wires(x)
49 #endif
50
51 /* Place to store Function pointers for all supported interfaces for each codec */
52 viddec_parser_ops_t parser_ops[MFD_STREAM_FORMAT_MAX];
53
54
55
56 /* we need to define as external function so that for host mode we can use the same code without
57 modifications by overloading dma function with a copy function
58 */
59 extern uint32_t cp_using_dma(uint32_t ddr_addr, uint32_t local_addr, uint32_t size, char to_ddr, char swap);
60
viddec_pm_init_ops()61 void viddec_pm_init_ops()
62 {
63 viddec_vc1_get_ops(&parser_ops[MFD_STREAM_FORMAT_VC1]);
64 parser_ops[MFD_STREAM_FORMAT_VC1].parse_sc = viddec_parse_sc;
65 parser_ops[MFD_STREAM_FORMAT_VC1].gen_contrib_tags = viddec_pm_generic_generate_contribution_tags;
66 parser_ops[MFD_STREAM_FORMAT_VC1].gen_assoc_tags = viddec_generic_add_association_tags;
67
68 viddec_mpeg2_get_ops(&parser_ops[MFD_STREAM_FORMAT_MPEG]);
69 parser_ops[MFD_STREAM_FORMAT_MPEG].parse_sc = viddec_parse_sc;
70 parser_ops[MFD_STREAM_FORMAT_MPEG].gen_contrib_tags = viddec_pm_generic_generate_contribution_tags;
71 parser_ops[MFD_STREAM_FORMAT_MPEG].gen_assoc_tags = viddec_mpeg2_add_association_tags;
72
73 viddec_h264_get_ops(&parser_ops[MFD_STREAM_FORMAT_H264]);
74 parser_ops[MFD_STREAM_FORMAT_H264].parse_sc = viddec_parse_sc;
75 parser_ops[MFD_STREAM_FORMAT_H264].gen_contrib_tags = viddec_pm_lateframe_generate_contribution_tags;
76 parser_ops[MFD_STREAM_FORMAT_H264].gen_assoc_tags = viddec_h264_add_association_tags;
77
78 viddec_mp4_get_ops(&parser_ops[MFD_STREAM_FORMAT_MPEG42]);
79 parser_ops[MFD_STREAM_FORMAT_MPEG42].gen_contrib_tags = viddec_pm_generic_generate_contribution_tags;
80 parser_ops[MFD_STREAM_FORMAT_MPEG42].gen_assoc_tags = viddec_generic_add_association_tags;
81 }
82
83 /*
84 Returns size of persistent DDR memory required for the codec. If the required memory is less than max allocated
85 scratch memory in FW we always give the max scratch size.
86 */
viddec_pm_get_parser_sizes(uint32_t codec_type,viddec_parser_memory_sizes_t * size)87 uint32_t viddec_pm_get_parser_sizes(uint32_t codec_type, viddec_parser_memory_sizes_t *size)
88 {
89 parser_ops[codec_type].get_cxt_size(size);
90 if(size->context_size > MAX_CODEC_CXT_SIZE)
91 {
92 DEB("ERROR: size(%d) of context for codec=%d is greater than max=%d\n",size->context_size,codec_type,MAX_CODEC_CXT_SIZE);
93 }
94 size->context_size = sizeof(viddec_pm_cxt_t);
95 return 1;
96 }
97
98 /*
99 Initialize the scratch memory allocated to the stream based on clean. if clean is true initialize to
100 start state, if not then preserve stream information.
101 */
viddec_pm_init_context(viddec_pm_cxt_t * cxt,uint32_t codec_type,uint32_t * persist_mem,uint32_t clean)102 void viddec_pm_init_context(viddec_pm_cxt_t *cxt, uint32_t codec_type, uint32_t *persist_mem, uint32_t clean)
103 {
104 int i;
105
106 for(i=0; i<MAX_IBUFS_PER_SC; i++)
107 {
108 cxt->pending_tags.pending_tags[i] = INVALID_ENTRY;
109 }
110 cxt->frame_start_found = false;
111 cxt->found_fm_st_in_current_au = false;
112 cxt->late_frame_detect = (MFD_STREAM_FORMAT_H264 == codec_type) ? true:false;
113 cxt->pending_tags.first_buf_aligned = cxt->pending_tags.using_next = cxt->pending_tags.frame_done =false;
114 cxt->next_workload_error_eos = VIDDEC_FW_WORKLOAD_ERR_FLUSHED_FRAME | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE;
115 viddec_pm_utils_list_init(&(cxt->list));
116 cxt->cur_buf.list_index = -1;
117 cxt->parse_cubby.phase=0;
118 parser_ops[codec_type].init((void *)&(cxt->codec_data[0]), persist_mem, !clean);
119 if(clean)
120 {
121 cxt->pending_inband_tags = 0;
122 }
123 else
124 {
125 /* TODO: Enable this once codecs support this function */
126 //parser_ops[codec_type].flush_preserve((void *)&(cxt->codec_data[0]), persist_mem);
127 }
128
129 }
130
viddec_pm_update_time(viddec_pm_cxt_t * cxt,uint32_t time)131 void viddec_pm_update_time(viddec_pm_cxt_t *cxt, uint32_t time)
132 {
133 viddec_emit_time(&(cxt->emitter), time);
134 }
135
136 /* add an esbuffer to list */
viddec_pm_add_es_buf_to_list(viddec_pm_cxt_t * cxt,viddec_input_buffer_t * es_buf)137 static inline uint32_t viddec_pm_add_es_buf_to_list(viddec_pm_cxt_t *cxt, viddec_input_buffer_t *es_buf)
138 {
139 uint32_t val , ret = PM_OVERFLOW;
140
141 val = viddec_pm_utils_list_addbuf(&(cxt->list), es_buf);
142 if(val == 1) ret = PM_SUCCESS;
143 return ret;
144 }
145
viddec_pm_check_inband_messages(viddec_pm_sc_cur_buf_t * cur_buf,uint32_t * type)146 static inline uint32_t viddec_pm_check_inband_messages(viddec_pm_sc_cur_buf_t *cur_buf, uint32_t *type)
147 {
148 uint32_t ret=false;
149 if(cur_buf->cur_es->flags != 0)
150 {
151 /* update offset to point to next position for loading data */
152 cur_buf->cur_offset +=(cur_buf->cur_size);
153 cur_buf->cur_size = 0;
154 switch(cur_buf->cur_es->flags)
155 {
156 case VIDDEC_STREAM_EOS:
157 {
158 *type = PM_EOS;
159 }
160 break;
161 case VIDDEC_STREAM_DISCONTINUITY:
162 {
163 *type = PM_DISCONTINUITY;
164 }
165 default:
166 break;
167 }
168 ret =true;
169 }
170 return ret;
171 }
172
173 /* creates an ibuf from the current position in list. Fills sc_parse_cubby_cxt */
viddec_pm_create_ibuf(viddec_pm_cxt_t * cxt)174 uint32_t viddec_pm_create_ibuf(viddec_pm_cxt_t *cxt)
175 {
176 uint32_t ret = PM_NO_DATA;
177 #ifndef VBP
178 viddec_sc_parse_cubby_cxt_t *cubby = &(cxt->parse_cubby);
179 #endif
180 viddec_pm_sc_cur_buf_t *cur_buf = &(cxt->cur_buf);
181 viddec_pm_utils_list_t *list = &(cxt->list);
182
183 /* Step1: check if list is Empty, If yes return No data */
184 if(list->num_items > 0)
185 {
186 /* Step 2: Check to see If current index into list is empty & we have data in list,
187 if so increment index and initialise it*/
188 if(cur_buf->list_index == -1)
189 {
190 if(viddec_pm_utils_list_getbyte_position(list,
191 list->first_scprfx_length+1,
192 (uint32_t *)&(cur_buf->list_index),
193 &(cur_buf->cur_offset)) != 1)
194 {/* This return's offset and index from where we have to start for sc detect */
195 cur_buf->cur_size = 0;
196 cur_buf->cur_es = &(list->sc_ibuf[cur_buf->list_index]);
197 }
198 else
199 {
200 return PM_NO_DATA;
201 }
202 }
203
204 /* Step3: If we are done with current buffer then try to go to next item in list */
205 if((cur_buf->cur_offset + cur_buf->cur_size) >= cur_buf->cur_es->len)
206 {
207 /* Need to handle In band messages before going to next buffer */
208 //if(viddec_pm_check_inband_messages(cur_buf))
209 if(viddec_pm_check_inband_messages(cur_buf, &ret))
210 {
211 return ret;
212 }
213 /* If no items in list after the current buffer return no data */
214 if((uint32_t)(cur_buf->list_index + 1) >= list->num_items)
215 {
216 return PM_NO_DATA;
217 }
218 cur_buf->list_index++;
219 cur_buf->cur_es = &(list->sc_ibuf[cur_buf->list_index]);
220 cur_buf->cur_offset = cur_buf->cur_size = 0;
221 }
222 /* Step4: Fill the cubby with data to send to parser sc code function */
223 {
224 int32_t data_left;
225 /* data left is the leftout size in current ES buffer */
226 data_left = cur_buf->cur_es->len - (cur_buf->cur_offset + cur_buf->cur_size);
227
228 /* update offset to point to next position for loading data */
229 cur_buf->cur_offset +=(cur_buf->cur_size);
230
231 #ifndef VBP
232 /* Load maximum of array size */
233 if(data_left >= SC_DETECT_BUF_SIZE)
234 {
235 data_left = SC_DETECT_BUF_SIZE;
236 }
237 /* can be zero if we have zero sized buffers in our list.EX:NEW segment */
238 if(data_left > 0)
239 {/* do a copy using Linear Dma */
240 uint32_t size , ddr_addr = 0, ddr_mask=0;
241 /* get ddr adress of current offset in ES buffer */
242 #ifdef HOST_ONLY
243 ddr_addr = cur_buf->cur_offset + (uint32_t)cur_buf->cur_es->buf;
244 #else
245 ddr_addr = cur_buf->cur_offset + cur_buf->cur_es->phys;
246 #endif
247 ddr_mask = (ddr_addr & 3);
248 ddr_addr = ddr_addr & ~3;
249 /* return from this function can be more bytes based on input buf alignment.
250 The adress for local memory we are sending is on DWORD boundary so it should be safe.
251 */
252
253 size = cp_using_dma(ddr_addr, (uint32_t)&(cxt->scbuf[0]), data_left+ddr_mask, 0,1);//false, true);
254 cubby->size = data_left;
255
256 /* point to actual memory location which has the data(skip aligment bytes) */
257 cubby->buf = &(cxt->scbuf[ddr_mask]);
258 cur_buf->cur_size = data_left;
259 ret = PM_SUCCESS;
260 }
261 else
262 {
263 /* If we completely consumed this buffer or this is a zero sized buffer we want to check inband messages */
264 //if(viddec_pm_check_inband_messages(cur_buf))
265 if(viddec_pm_check_inband_messages(cur_buf, &ret))
266 {
267 return ret;
268 }
269 }
270 #else
271 ret = PM_SUCCESS;
272 #endif
273 }
274 }
275
276 return ret;
277 }
278
279 /*
280 Read data from esbuffer list and parse for start codes or EOS. If we consumed all the data we return no data left.
281 */
viddec_pm_parse_for_sccode(viddec_pm_cxt_t * cxt,viddec_parser_ops_t * func)282 static inline uint32_t viddec_pm_parse_for_sccode(viddec_pm_cxt_t *cxt, viddec_parser_ops_t *func)
283 {
284 uint32_t ret = PM_NO_DATA;
285 uint32_t sc_boundary_found = 0;
286
287 while(!sc_boundary_found)
288 {
289 /* Create an buffer from list to parse */
290 ret = viddec_pm_create_ibuf(cxt);
291 switch(ret)
292 {
293 case PM_NO_DATA:
294 {/* No data in esbuffer list for parsing sc */
295 sc_boundary_found = 1;
296 }
297 break;
298 case PM_EOS:
299 case PM_DISCONTINUITY:
300 {
301 sc_boundary_found = 1;
302 cxt->list.end_offset = cxt->cur_buf.cur_offset+1;
303 cxt->parse_cubby.phase = 0;
304 /* we didn't find a start code so second start code length would be 0 */
305 cxt->sc_prefix_info.second_scprfx_length = 0;
306 //cxt->sc_prefix_info.next_sc = VIDDEC_PARSE_EOS;
307 if(ret == PM_EOS)
308 {
309 cxt->sc_prefix_info.next_sc = VIDDEC_PARSE_EOS;
310 }
311 if(ret == PM_DISCONTINUITY)
312 {
313 cxt->sc_prefix_info.next_sc = VIDDEC_PARSE_DISCONTINUITY;
314 }
315 }
316 break;
317 case PM_SUCCESS:
318 default:
319 {
320 /* parse the created buffer for sc */
321 ret = func->parse_sc((void *)&(cxt->parse_cubby), (void *)&(cxt->codec_data[0]), &(cxt->sc_prefix_info));
322 if(ret == 1)
323 {
324 cxt->list.end_offset = cxt->parse_cubby.sc_end_pos + cxt->cur_buf.cur_offset;
325 cxt->parse_cubby.phase = 0;
326 cxt->list.total_bytes+=cxt->parse_cubby.sc_end_pos;
327 ret = PM_SC_FOUND;
328 sc_boundary_found = 1;
329 break;
330 }
331 else
332 {
333 cxt->list.total_bytes+=cxt->cur_buf.cur_size;
334 }
335 }
336 break;
337 }
338 }
339
340 return ret;
341 }
342
343 /*
344 Once we are ready to flush the current workload, we update current workload on DDR with our internal information
345 that was not written before like num of items in workload, errors in stream etc...
346 */
viddec_pm_finalize_workload(viddec_pm_cxt_t * cxt,uint32_t codec_type,uint32_t codec_errors)347 void viddec_pm_finalize_workload(viddec_pm_cxt_t *cxt, uint32_t codec_type, uint32_t codec_errors)
348 {
349 viddec_emit_set_codec(&(cxt->emitter), codec_type);
350 viddec_emit_set_codec_errors(&(cxt->emitter), codec_errors);
351 viddec_emit_flush_current_wkld(&(cxt->emitter));
352 output_omar_wires( 0x5 );
353 output_omar_wires( 0x1 );
354 }
355
356 /*
357 After parsing between start codes we cleanup our list so that it has only buffers that are not consumed yet.
358 */
viddec_pm_finalize_list(viddec_pm_cxt_t * cxt)359 uint32_t viddec_pm_finalize_list(viddec_pm_cxt_t *cxt)
360 {
361 uint32_t ret=1;
362
363 viddec_pm_utils_list_remove_used_entries(&(cxt->list), cxt->sc_prefix_info.second_scprfx_length);
364 cxt->cur_buf.list_index = -1;
365 cxt->list.first_scprfx_length = cxt->sc_prefix_info.second_scprfx_length;
366 return ret;
367 }
368
369 /* Case to handle if we encounter list overflow without seeing second start code */
viddec_pm_handle_buffer_overflow(viddec_pm_cxt_t * cxt,uint32_t codec_type,viddec_input_buffer_t * es_buf)370 void viddec_pm_handle_buffer_overflow(viddec_pm_cxt_t *cxt, uint32_t codec_type, viddec_input_buffer_t *es_buf)
371 {
372 uint32_t indx=0;
373 while(indx< (uint32_t)cxt->list.num_items)
374 {/* Dump tags for all entries in list to prevent buffer leak */
375 viddec_emit_contr_tag(&(cxt->emitter), &(cxt->list.sc_ibuf[indx]), false, true);
376 viddec_emit_assoc_tag(&(cxt->emitter), cxt->list.sc_ibuf[indx].id, true);
377 indx++;
378 }
379 /* Dump tags for the new buffer that was received */
380 viddec_emit_contr_tag(&(cxt->emitter), es_buf, 0, true);
381 viddec_emit_assoc_tag(&(cxt->emitter), es_buf->id, true);
382 /* Set errors on both current and next as both can be invalid */
383 viddec_emit_set_workload_error(&(cxt->emitter),
384 (VIDDEC_FW_WORKLOAD_ERR_BUFFERS_OVERFLOW | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE),
385 true);
386 viddec_emit_set_workload_error(&(cxt->emitter),
387 (VIDDEC_FW_WORKLOAD_ERR_BUFFERS_OVERFLOW | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE),
388 false);
389 /* cleanup the pending tags */
390 viddec_pm_generate_missed_association_tags(cxt, true);
391 viddec_pm_finalize_workload(cxt, codec_type, 0);
392 WRITE_SVEN(SVEN_MODULE_EVENT_GV_FW_FATAL_BUFFER_OVERLFOW, (int)es_buf->phys, (int)es_buf->len, 0, 0, 0, 0);
393 }
394
viddec_pm_handle_post_inband_messages(viddec_pm_cxt_t * cxt,uint32_t m_type)395 static inline void viddec_pm_handle_post_inband_messages(viddec_pm_cxt_t *cxt, uint32_t m_type)
396 {
397 if((m_type & ~(0xFF))== PM_INBAND_MESSAGES)
398 {
399 /* If EOS decide set error on next workload too */
400 viddec_emit_set_workload_error(&(cxt->emitter), cxt->next_workload_error_eos, true);
401 if(m_type == PM_EOS)
402 {
403 viddec_emit_set_inband_tag(&(cxt->emitter), VIDDEC_WORKLOAD_IBUF_EOS, true);
404 }
405 if(m_type == PM_DISCONTINUITY)
406 {
407 cxt->pending_inband_tags = PM_DISCONTINUITY;
408 }
409 }
410 }
411
viddec_pm_handle_new_es_buffer(viddec_pm_cxt_t * cxt,uint32_t codec_type,viddec_input_buffer_t * es_buf)412 static inline uint32_t viddec_pm_handle_new_es_buffer(viddec_pm_cxt_t *cxt, uint32_t codec_type, viddec_input_buffer_t *es_buf)
413 {
414 uint32_t state = PM_SUCCESS;
415 if(es_buf != NULL)
416 {
417 state = viddec_pm_add_es_buf_to_list(cxt, es_buf);
418 if(state == PM_OVERFLOW)
419 {
420 viddec_pm_handle_buffer_overflow(cxt, codec_type, es_buf);
421 }
422 }
423 return state;
424 }
425
viddec_pm_handle_pre_inband_messages(viddec_pm_cxt_t * cxt)426 static inline void viddec_pm_handle_pre_inband_messages(viddec_pm_cxt_t *cxt)
427 {
428 if(cxt->pending_inband_tags == PM_DISCONTINUITY)
429 {
430 viddec_emit_set_inband_tag(&(cxt->emitter), VIDDEC_WORKLOAD_IBUF_DISCONTINUITY, false);
431 cxt->pending_inband_tags = 0;
432 }
433 }
434
435 /*
436 Main function of parser manager.
437 It searches until start codes are found int he list if not through return type indicates kernel to provide more buffers.
438 If a start code is found it calls the codec to parse the syntax data it accumulated so far.
439 If codec says a frame is not done then continues to find the next start code.
440 If codec says frame is done it does tag association and indicates kernel a frame is done.
441 */
viddec_pm_parse_es_buffer(viddec_pm_cxt_t * cxt,uint32_t codec_type,viddec_input_buffer_t * es_buf)442 uint32_t viddec_pm_parse_es_buffer(viddec_pm_cxt_t *cxt, uint32_t codec_type, viddec_input_buffer_t *es_buf)
443 {
444 uint32_t state = PM_SUCCESS;
445
446 /* Step1: Append Es buffer to list */
447 viddec_pm_handle_pre_inband_messages(cxt);
448 state = viddec_pm_handle_new_es_buffer(cxt, codec_type, es_buf);
449 if(state == PM_SUCCESS)
450 {
451 uint32_t scdetect_ret;
452 output_omar_wires( 0x3 );
453 /* Step2: Phase1 of parsing, parse until a sc is found */
454 scdetect_ret = viddec_pm_parse_for_sccode(cxt,&parser_ops[codec_type]);
455 switch(scdetect_ret)
456 {
457 case PM_NO_DATA:
458 {
459 /* Step3: If we consumed all the data indicate we need more buffers */
460 state = PM_NO_DATA;
461 break;
462 }
463 case PM_EOS:
464 case PM_DISCONTINUITY:
465 case PM_SC_FOUND:
466 {
467 uint32_t codec_errors=0;
468 /* Create necessary state information to make the ES buffers look like linear data */
469 viddec_pm_utils_list_updatebytepos(&(cxt->list), cxt->sc_prefix_info.second_scprfx_length);
470 if(cxt->sc_prefix_info.first_sc_detect != 1)
471 {
472 /* Step4: If we saw two start codes init state and call codec to parse */
473 uint32_t codec_ret;
474 /* Initialise the state to provide get bits for codecs */
475 viddec_pm_utils_bstream_init(&(cxt->getbits), &(cxt->list), EMUL_REQD(codec_type));
476 output_omar_wires( 0x1 );
477 /* call the codec to do synatax parsing */
478 parser_ops[codec_type].parse_syntax((void *)cxt, (void *)&(cxt->codec_data[0]));
479 /* Check and see if frame start was detected. If we did update frame start in current au */
480 if(parser_ops[codec_type].is_frame_start((void *)&(cxt->codec_data[0])) == true)
481 {
482 cxt->frame_start_found += 1;
483 cxt->found_fm_st_in_current_au = true;
484 }
485 /* Query to see if we reached end of current frame */
486 codec_ret = parser_ops[codec_type].is_wkld_done((void *)cxt,
487 (void *)&(cxt->codec_data[0]),
488 (uint32_t)(cxt->sc_prefix_info.next_sc),
489 &codec_errors);
490
491 state = (codec_ret == VIDDEC_PARSE_FRMDONE) ? PM_WKLD_DONE : PM_SUCCESS;
492 /* generate contribution and association tags */
493 cxt->pending_tags.frame_done = (codec_ret == VIDDEC_PARSE_FRMDONE);
494 parser_ops[codec_type].gen_assoc_tags(cxt);
495 parser_ops[codec_type].gen_contrib_tags(cxt, (state != PM_WKLD_DONE));
496 }
497 else
498 {
499 /* Step4: If this is the first start code in this stream, clean up and return */
500 if(cxt->list.total_bytes != 0)
501 {
502 viddec_pm_generic_generate_contribution_tags(cxt, true);
503 viddec_generic_add_association_tags(cxt);
504 }
505 else
506 {
507 if(cxt->list.num_items >= 1)
508 {
509 uint32_t indx=0;
510 while((indx< (uint32_t)cxt->list.num_items) && (cxt->list.sc_ibuf[indx].len == 0))
511 {/* Dump all zero sized buffers until we see a buffer with valid data */
512 viddec_emit_contr_tag(&(cxt->emitter), &(cxt->list.sc_ibuf[indx]), false, false);
513 viddec_emit_assoc_tag(&(cxt->emitter), cxt->list.sc_ibuf[indx].id, false);
514 indx++;
515 }
516 }
517 }
518 if((scdetect_ret & ~(0xFF))!= PM_INBAND_MESSAGES)
519 {
520 state = PM_SUCCESS;//state = PM_FIRST_SC_FOUND;
521 cxt->sc_prefix_info.first_sc_detect = 0;
522 }
523 else
524 {
525 state = PM_WKLD_DONE;
526 }
527 }
528
529 viddec_pm_handle_post_inband_messages(cxt, scdetect_ret);
530
531 /* Step 5: If current frame is done, finalise the workload state with necessary information */
532 if(state == PM_WKLD_DONE)
533 {
534 DEB("\nFRAME ... DONE\n");
535 /* we decrement frame start. This can be 0 in cases like sending junk data with EOS */
536 cxt->frame_start_found -= (cxt->frame_start_found)? 1: 0;
537 if((scdetect_ret & ~(0xFF))== PM_INBAND_MESSAGES)
538 {/* If EOS dump pending tags and set state */
539 viddec_pm_generate_missed_association_tags(cxt, false);
540 state = scdetect_ret;
541 }
542 /* Write back stored state of workloads to memory to prepare for psuhing to output queue */
543 viddec_pm_finalize_workload(cxt, codec_type, codec_errors);
544 }
545 /* Step 6: Reset the list to prepare for next iteration */
546 viddec_pm_finalize_list(cxt);
547 break;
548 }
549 default:
550 break;
551 }
552 }//if(state == PM_SUCCESS)
553 return state;
554 } // viddec_pm_parse_es_buffer
555