| |
| #include "viddec_pm.h" |
| #include "viddec_fw_debug.h" |
| #include "viddec_fw_common_defs.h" |
| #include "viddec_pm_tags.h" |
| #include "viddec_parser_ops.h" |
| #include "viddec_vc1_parse.h" |
| #include "viddec_mp4_parse.h" |
| #include "viddec_mpeg2_parse.h" |
| #include "viddec_h264_parse.h" |
| /* |
| Overview of Parser manager: |
| Parser manager is the glue between Kernel(main.c) and actual codecs. We abstract common functionality as much as we can |
| in this module. The parser Manager context allocates memory for Parsers. At any point in time there is only one active stream. |
| During open stream we setup all necessary initialisation for the codec we are handling. The parser manager context is |
| stored on DDR when the current stream gets swapped out by the kernel. When the next stream comes in it has it's own |
| version of parser manager. |
| Parser manager is reponsible for providing information on when its a good time to swap a stream. |
| High level algorithm of parser Manager once a stream is opened and active(RET's are returns to Kernel): |
| |
| 1. create a list data structure to hold any incoming ES descriptors. |
| 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. |
| 3. If data is present parse until a scprefix+sc is found. If not goto step2. |
| 4. If startcode detected update list state to make ES data look like Linear buffer. |
| 5. Setup required state to provide getbits interface for codecs to access bit stream maximum 32bits at a time. |
| 6. Setup Current & Next workloads provided by Kernel. |
| 7. Call the codec to parse the data we collected between start codes. |
| 8. Query to see if we parsed frame worth of data. |
| 9. Do necessary TAG association and remove used buffers from List. |
| 10. Send information to kernel on whether workload is done or Not.(RET). When kernel reschedules start from step2. |
| |
| Kernel can swap current stream at RET points described above. |
| |
| Other additional things supported: |
| - Generic start code detect function which is same for most of codecs. |
| - Memory Management. |
| - Flush of stream. |
| - Emulation prevention. |
| - Interface to emit necessary tags for codec specific types. |
| */ |
| |
| |
| /* check to see if codec needs emulation prevention */ |
| #define EMUL_REQD(codec) ((codec == MFD_STREAM_FORMAT_VC1) || (codec_type == MFD_STREAM_FORMAT_H264) ? 1: 0) |
| |
| #ifdef RTL_SIMULATION |
| extern void output_omar_wires( unsigned int value ); |
| #else |
| #define output_omar_wires(x) |
| #endif |
| |
| /* Place to store Function pointers for all supported interfaces for each codec */ |
| viddec_parser_ops_t parser_ops[MFD_STREAM_FORMAT_MAX]; |
| |
| |
| |
| /* we need to define as external function so that for host mode we can use the same code without |
| modifications by overloading dma function with a copy function |
| */ |
| extern uint32_t cp_using_dma(uint32_t ddr_addr, uint32_t local_addr, uint32_t size, char to_ddr, char swap); |
| |
| void viddec_pm_init_ops() |
| { |
| viddec_vc1_get_ops(&parser_ops[MFD_STREAM_FORMAT_VC1]); |
| parser_ops[MFD_STREAM_FORMAT_VC1].parse_sc = viddec_parse_sc; |
| parser_ops[MFD_STREAM_FORMAT_VC1].gen_contrib_tags = viddec_pm_generic_generate_contribution_tags; |
| parser_ops[MFD_STREAM_FORMAT_VC1].gen_assoc_tags = viddec_generic_add_association_tags; |
| |
| viddec_mpeg2_get_ops(&parser_ops[MFD_STREAM_FORMAT_MPEG]); |
| parser_ops[MFD_STREAM_FORMAT_MPEG].parse_sc = viddec_parse_sc; |
| parser_ops[MFD_STREAM_FORMAT_MPEG].gen_contrib_tags = viddec_pm_generic_generate_contribution_tags; |
| parser_ops[MFD_STREAM_FORMAT_MPEG].gen_assoc_tags = viddec_mpeg2_add_association_tags; |
| |
| viddec_h264_get_ops(&parser_ops[MFD_STREAM_FORMAT_H264]); |
| parser_ops[MFD_STREAM_FORMAT_H264].parse_sc = viddec_parse_sc; |
| parser_ops[MFD_STREAM_FORMAT_H264].gen_contrib_tags = viddec_pm_lateframe_generate_contribution_tags; |
| parser_ops[MFD_STREAM_FORMAT_H264].gen_assoc_tags = viddec_h264_add_association_tags; |
| |
| viddec_mp4_get_ops(&parser_ops[MFD_STREAM_FORMAT_MPEG42]); |
| parser_ops[MFD_STREAM_FORMAT_MPEG42].gen_contrib_tags = viddec_pm_generic_generate_contribution_tags; |
| parser_ops[MFD_STREAM_FORMAT_MPEG42].gen_assoc_tags = viddec_generic_add_association_tags; |
| } |
| |
| /* |
| Returns size of persistent DDR memory required for the codec. If the required memory is less than max allocated |
| scratch memory in FW we always give the max scratch size. |
| */ |
| uint32_t viddec_pm_get_parser_sizes(uint32_t codec_type, viddec_parser_memory_sizes_t *size) |
| { |
| parser_ops[codec_type].get_cxt_size(size); |
| if (size->context_size > MAX_CODEC_CXT_SIZE) |
| { |
| DEB("ERROR: size(%d) of context for codec=%d is greater than max=%d\n",size->context_size,codec_type,MAX_CODEC_CXT_SIZE); |
| } |
| size->context_size = sizeof(viddec_pm_cxt_t); |
| return 1; |
| } |
| |
| /* |
| Initialize the scratch memory allocated to the stream based on clean. if clean is true initialize to |
| start state, if not then preserve stream information. |
| */ |
| void viddec_pm_init_context(viddec_pm_cxt_t *cxt, uint32_t codec_type, uint32_t *persist_mem, uint32_t clean) |
| { |
| int i; |
| |
| for (i=0; i<MAX_IBUFS_PER_SC; i++) |
| { |
| cxt->pending_tags.pending_tags[i] = INVALID_ENTRY; |
| } |
| cxt->frame_start_found = false; |
| cxt->found_fm_st_in_current_au = false; |
| cxt->late_frame_detect = (MFD_STREAM_FORMAT_H264 == codec_type) ? true:false; |
| cxt->pending_tags.first_buf_aligned = cxt->pending_tags.using_next = cxt->pending_tags.frame_done =false; |
| cxt->next_workload_error_eos = VIDDEC_FW_WORKLOAD_ERR_FLUSHED_FRAME | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE; |
| viddec_pm_utils_list_init(&(cxt->list)); |
| cxt->cur_buf.list_index = -1; |
| cxt->parse_cubby.phase=0; |
| parser_ops[codec_type].init((void *)&(cxt->codec_data[0]), persist_mem, !clean); |
| if (clean) |
| { |
| cxt->pending_inband_tags = 0; |
| } |
| else |
| { |
| /* TODO: Enable this once codecs support this function */ |
| //parser_ops[codec_type].flush_preserve((void *)&(cxt->codec_data[0]), persist_mem); |
| } |
| |
| } |
| |
| void viddec_pm_update_time(viddec_pm_cxt_t *cxt, uint32_t time) |
| { |
| viddec_emit_time(&(cxt->emitter), time); |
| } |
| |
| /* add an esbuffer to list */ |
| static inline uint32_t viddec_pm_add_es_buf_to_list(viddec_pm_cxt_t *cxt, viddec_input_buffer_t *es_buf) |
| { |
| uint32_t val , ret = PM_OVERFLOW; |
| |
| val = viddec_pm_utils_list_addbuf(&(cxt->list), es_buf); |
| if (val == 1) ret = PM_SUCCESS; |
| return ret; |
| } |
| |
| static inline uint32_t viddec_pm_check_inband_messages(viddec_pm_sc_cur_buf_t *cur_buf, uint32_t *type) |
| { |
| uint32_t ret=false; |
| if (cur_buf->cur_es->flags != 0) |
| { |
| /* update offset to point to next position for loading data */ |
| cur_buf->cur_offset +=(cur_buf->cur_size); |
| cur_buf->cur_size = 0; |
| switch (cur_buf->cur_es->flags) |
| { |
| case VIDDEC_STREAM_EOS: |
| { |
| *type = PM_EOS; |
| } |
| break; |
| case VIDDEC_STREAM_DISCONTINUITY: |
| { |
| *type = PM_DISCONTINUITY; |
| } |
| default: |
| break; |
| } |
| ret =true; |
| } |
| return ret; |
| } |
| |
| /* creates an ibuf from the current position in list. Fills sc_parse_cubby_cxt */ |
| uint32_t viddec_pm_create_ibuf(viddec_pm_cxt_t *cxt) |
| { |
| uint32_t ret = PM_NO_DATA; |
| #ifndef VBP |
| viddec_sc_parse_cubby_cxt_t *cubby = &(cxt->parse_cubby); |
| #endif |
| viddec_pm_sc_cur_buf_t *cur_buf = &(cxt->cur_buf); |
| viddec_pm_utils_list_t *list = &(cxt->list); |
| |
| /* Step1: check if list is Empty, If yes return No data */ |
| if (list->num_items > 0) |
| { |
| /* Step 2: Check to see If current index into list is empty & we have data in list, |
| if so increment index and initialise it*/ |
| if (cur_buf->list_index == -1) |
| { |
| if (viddec_pm_utils_list_getbyte_position(list, |
| list->first_scprfx_length+1, |
| (uint32_t *)&(cur_buf->list_index), |
| &(cur_buf->cur_offset)) != 1) |
| {/* This return's offset and index from where we have to start for sc detect */ |
| cur_buf->cur_size = 0; |
| cur_buf->cur_es = &(list->sc_ibuf[cur_buf->list_index]); |
| } |
| else |
| { |
| return PM_NO_DATA; |
| } |
| } |
| |
| /* Step3: If we are done with current buffer then try to go to next item in list */ |
| if ((cur_buf->cur_offset + cur_buf->cur_size) >= cur_buf->cur_es->len) |
| { |
| /* Need to handle In band messages before going to next buffer */ |
| //if(viddec_pm_check_inband_messages(cur_buf)) |
| if (viddec_pm_check_inband_messages(cur_buf, &ret)) |
| { |
| return ret; |
| } |
| /* If no items in list after the current buffer return no data */ |
| if ((uint32_t)(cur_buf->list_index + 1) >= list->num_items) |
| { |
| return PM_NO_DATA; |
| } |
| cur_buf->list_index++; |
| cur_buf->cur_es = &(list->sc_ibuf[cur_buf->list_index]); |
| cur_buf->cur_offset = cur_buf->cur_size = 0; |
| } |
| /* Step4: Fill the cubby with data to send to parser sc code function */ |
| { |
| int32_t data_left; |
| /* data left is the leftout size in current ES buffer */ |
| data_left = cur_buf->cur_es->len - (cur_buf->cur_offset + cur_buf->cur_size); |
| |
| /* update offset to point to next position for loading data */ |
| cur_buf->cur_offset +=(cur_buf->cur_size); |
| |
| #ifndef VBP |
| /* Load maximum of array size */ |
| if (data_left >= SC_DETECT_BUF_SIZE) |
| { |
| data_left = SC_DETECT_BUF_SIZE; |
| } |
| /* can be zero if we have zero sized buffers in our list.EX:NEW segment */ |
| if (data_left > 0) |
| {/* do a copy using Linear Dma */ |
| uint32_t size , ddr_addr = 0, ddr_mask=0; |
| /* get ddr adress of current offset in ES buffer */ |
| #ifdef HOST_ONLY |
| ddr_addr = cur_buf->cur_offset + (uint32_t)cur_buf->cur_es->buf; |
| #else |
| ddr_addr = cur_buf->cur_offset + cur_buf->cur_es->phys; |
| #endif |
| ddr_mask = (ddr_addr & 3); |
| ddr_addr = ddr_addr & ~3; |
| /* return from this function can be more bytes based on input buf alignment. |
| The adress for local memory we are sending is on DWORD boundary so it should be safe. |
| */ |
| |
| size = cp_using_dma(ddr_addr, (uint32_t)&(cxt->scbuf[0]), data_left+ddr_mask, 0,1);//false, true); |
| cubby->size = data_left; |
| |
| /* point to actual memory location which has the data(skip aligment bytes) */ |
| cubby->buf = &(cxt->scbuf[ddr_mask]); |
| cur_buf->cur_size = data_left; |
| ret = PM_SUCCESS; |
| } |
| else |
| { |
| /* If we completely consumed this buffer or this is a zero sized buffer we want to check inband messages */ |
| //if(viddec_pm_check_inband_messages(cur_buf)) |
| if (viddec_pm_check_inband_messages(cur_buf, &ret)) |
| { |
| return ret; |
| } |
| } |
| #else |
| ret = PM_SUCCESS; |
| #endif |
| } |
| } |
| |
| return ret; |
| } |
| |
| /* |
| Read data from esbuffer list and parse for start codes or EOS. If we consumed all the data we return no data left. |
| */ |
| static inline uint32_t viddec_pm_parse_for_sccode(viddec_pm_cxt_t *cxt, viddec_parser_ops_t *func) |
| { |
| uint32_t ret = PM_NO_DATA; |
| uint32_t sc_boundary_found = 0; |
| |
| while (!sc_boundary_found) |
| { |
| /* Create an buffer from list to parse */ |
| ret = viddec_pm_create_ibuf(cxt); |
| switch (ret) |
| { |
| case PM_NO_DATA: |
| {/* No data in esbuffer list for parsing sc */ |
| sc_boundary_found = 1; |
| } |
| break; |
| case PM_EOS: |
| case PM_DISCONTINUITY: |
| { |
| sc_boundary_found = 1; |
| cxt->list.end_offset = cxt->cur_buf.cur_offset+1; |
| cxt->parse_cubby.phase = 0; |
| /* we didn't find a start code so second start code length would be 0 */ |
| cxt->sc_prefix_info.second_scprfx_length = 0; |
| //cxt->sc_prefix_info.next_sc = VIDDEC_PARSE_EOS; |
| if (ret == PM_EOS) |
| { |
| cxt->sc_prefix_info.next_sc = VIDDEC_PARSE_EOS; |
| } |
| if (ret == PM_DISCONTINUITY) |
| { |
| cxt->sc_prefix_info.next_sc = VIDDEC_PARSE_DISCONTINUITY; |
| } |
| } |
| break; |
| case PM_SUCCESS: |
| default: |
| { |
| /* parse the created buffer for sc */ |
| ret = func->parse_sc((void *)&(cxt->parse_cubby), (void *)&(cxt->codec_data[0]), &(cxt->sc_prefix_info)); |
| if (ret == 1) |
| { |
| cxt->list.end_offset = cxt->parse_cubby.sc_end_pos + cxt->cur_buf.cur_offset; |
| cxt->parse_cubby.phase = 0; |
| cxt->list.total_bytes+=cxt->parse_cubby.sc_end_pos; |
| ret = PM_SC_FOUND; |
| sc_boundary_found = 1; |
| break; |
| } |
| else |
| { |
| cxt->list.total_bytes+=cxt->cur_buf.cur_size; |
| } |
| } |
| break; |
| } |
| } |
| |
| return ret; |
| } |
| |
| /* |
| Once we are ready to flush the current workload, we update current workload on DDR with our internal information |
| that was not written before like num of items in workload, errors in stream etc... |
| */ |
| void viddec_pm_finalize_workload(viddec_pm_cxt_t *cxt, uint32_t codec_type, uint32_t codec_errors) |
| { |
| viddec_emit_set_codec(&(cxt->emitter), codec_type); |
| viddec_emit_set_codec_errors(&(cxt->emitter), codec_errors); |
| viddec_emit_flush_current_wkld(&(cxt->emitter)); |
| output_omar_wires( 0x5 ); |
| output_omar_wires( 0x1 ); |
| } |
| |
| /* |
| After parsing between start codes we cleanup our list so that it has only buffers that are not consumed yet. |
| */ |
| uint32_t viddec_pm_finalize_list(viddec_pm_cxt_t *cxt) |
| { |
| uint32_t ret=1; |
| |
| viddec_pm_utils_list_remove_used_entries(&(cxt->list), cxt->sc_prefix_info.second_scprfx_length); |
| cxt->cur_buf.list_index = -1; |
| cxt->list.first_scprfx_length = cxt->sc_prefix_info.second_scprfx_length; |
| return ret; |
| } |
| |
| /* Case to handle if we encounter list overflow without seeing second start code */ |
| void viddec_pm_handle_buffer_overflow(viddec_pm_cxt_t *cxt, uint32_t codec_type, viddec_input_buffer_t *es_buf) |
| { |
| uint32_t indx=0; |
| while (indx< (uint32_t)cxt->list.num_items) |
| {/* Dump tags for all entries in list to prevent buffer leak */ |
| viddec_emit_contr_tag(&(cxt->emitter), &(cxt->list.sc_ibuf[indx]), false, true); |
| viddec_emit_assoc_tag(&(cxt->emitter), cxt->list.sc_ibuf[indx].id, true); |
| indx++; |
| } |
| /* Dump tags for the new buffer that was received */ |
| viddec_emit_contr_tag(&(cxt->emitter), es_buf, 0, true); |
| viddec_emit_assoc_tag(&(cxt->emitter), es_buf->id, true); |
| /* Set errors on both current and next as both can be invalid */ |
| viddec_emit_set_workload_error(&(cxt->emitter), |
| (VIDDEC_FW_WORKLOAD_ERR_BUFFERS_OVERFLOW | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE), |
| true); |
| viddec_emit_set_workload_error(&(cxt->emitter), |
| (VIDDEC_FW_WORKLOAD_ERR_BUFFERS_OVERFLOW | VIDDEC_FW_WORKLOAD_ERR_NOTDECODABLE), |
| false); |
| /* cleanup the pending tags */ |
| viddec_pm_generate_missed_association_tags(cxt, true); |
| viddec_pm_finalize_workload(cxt, codec_type, 0); |
| WRITE_SVEN(SVEN_MODULE_EVENT_GV_FW_FATAL_BUFFER_OVERLFOW, (int)es_buf->phys, (int)es_buf->len, 0, 0, 0, 0); |
| } |
| |
| static inline void viddec_pm_handle_post_inband_messages(viddec_pm_cxt_t *cxt, uint32_t m_type) |
| { |
| if ((m_type & ~(0xFF))== PM_INBAND_MESSAGES) |
| { |
| /* If EOS decide set error on next workload too */ |
| viddec_emit_set_workload_error(&(cxt->emitter), cxt->next_workload_error_eos, true); |
| if (m_type == PM_EOS) |
| { |
| viddec_emit_set_inband_tag(&(cxt->emitter), VIDDEC_WORKLOAD_IBUF_EOS, true); |
| } |
| if (m_type == PM_DISCONTINUITY) |
| { |
| cxt->pending_inband_tags = PM_DISCONTINUITY; |
| } |
| } |
| } |
| |
| 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) |
| { |
| uint32_t state = PM_SUCCESS; |
| if (es_buf != NULL) |
| { |
| state = viddec_pm_add_es_buf_to_list(cxt, es_buf); |
| if (state == PM_OVERFLOW) |
| { |
| viddec_pm_handle_buffer_overflow(cxt, codec_type, es_buf); |
| } |
| } |
| return state; |
| } |
| |
| static inline void viddec_pm_handle_pre_inband_messages(viddec_pm_cxt_t *cxt) |
| { |
| if (cxt->pending_inband_tags == PM_DISCONTINUITY) |
| { |
| viddec_emit_set_inband_tag(&(cxt->emitter), VIDDEC_WORKLOAD_IBUF_DISCONTINUITY, false); |
| cxt->pending_inband_tags = 0; |
| } |
| } |
| |
| /* |
| Main function of parser manager. |
| It searches until start codes are found int he list if not through return type indicates kernel to provide more buffers. |
| If a start code is found it calls the codec to parse the syntax data it accumulated so far. |
| If codec says a frame is not done then continues to find the next start code. |
| If codec says frame is done it does tag association and indicates kernel a frame is done. |
| */ |
| uint32_t viddec_pm_parse_es_buffer(viddec_pm_cxt_t *cxt, uint32_t codec_type, viddec_input_buffer_t *es_buf) |
| { |
| uint32_t state = PM_SUCCESS; |
| |
| /* Step1: Append Es buffer to list */ |
| viddec_pm_handle_pre_inband_messages(cxt); |
| state = viddec_pm_handle_new_es_buffer(cxt, codec_type, es_buf); |
| if (state == PM_SUCCESS) |
| { |
| uint32_t scdetect_ret; |
| output_omar_wires( 0x3 ); |
| /* Step2: Phase1 of parsing, parse until a sc is found */ |
| scdetect_ret = viddec_pm_parse_for_sccode(cxt,&parser_ops[codec_type]); |
| switch (scdetect_ret) |
| { |
| case PM_NO_DATA: |
| { |
| /* Step3: If we consumed all the data indicate we need more buffers */ |
| state = PM_NO_DATA; |
| break; |
| } |
| case PM_EOS: |
| case PM_DISCONTINUITY: |
| case PM_SC_FOUND: |
| { |
| uint32_t codec_errors=0; |
| /* Create necessary state information to make the ES buffers look like linear data */ |
| viddec_pm_utils_list_updatebytepos(&(cxt->list), cxt->sc_prefix_info.second_scprfx_length); |
| if (cxt->sc_prefix_info.first_sc_detect != 1) |
| { |
| /* Step4: If we saw two start codes init state and call codec to parse */ |
| uint32_t codec_ret; |
| /* Initialise the state to provide get bits for codecs */ |
| viddec_pm_utils_bstream_init(&(cxt->getbits), &(cxt->list), EMUL_REQD(codec_type)); |
| output_omar_wires( 0x1 ); |
| /* call the codec to do synatax parsing */ |
| parser_ops[codec_type].parse_syntax((void *)cxt, (void *)&(cxt->codec_data[0])); |
| /* Check and see if frame start was detected. If we did update frame start in current au */ |
| if (parser_ops[codec_type].is_frame_start((void *)&(cxt->codec_data[0])) == true) |
| { |
| cxt->frame_start_found += 1; |
| cxt->found_fm_st_in_current_au = true; |
| } |
| /* Query to see if we reached end of current frame */ |
| codec_ret = parser_ops[codec_type].is_wkld_done((void *)cxt, |
| (void *)&(cxt->codec_data[0]), |
| (uint32_t)(cxt->sc_prefix_info.next_sc), |
| &codec_errors); |
| |
| state = (codec_ret == VIDDEC_PARSE_FRMDONE) ? PM_WKLD_DONE : PM_SUCCESS; |
| /* generate contribution and association tags */ |
| cxt->pending_tags.frame_done = (codec_ret == VIDDEC_PARSE_FRMDONE); |
| parser_ops[codec_type].gen_assoc_tags(cxt); |
| parser_ops[codec_type].gen_contrib_tags(cxt, (state != PM_WKLD_DONE)); |
| } |
| else |
| { |
| /* Step4: If this is the first start code in this stream, clean up and return */ |
| if (cxt->list.total_bytes != 0) |
| { |
| viddec_pm_generic_generate_contribution_tags(cxt, true); |
| viddec_generic_add_association_tags(cxt); |
| } |
| else |
| { |
| if (cxt->list.num_items >= 1) |
| { |
| uint32_t indx=0; |
| while ((indx< (uint32_t)cxt->list.num_items) && (cxt->list.sc_ibuf[indx].len == 0)) |
| {/* Dump all zero sized buffers until we see a buffer with valid data */ |
| viddec_emit_contr_tag(&(cxt->emitter), &(cxt->list.sc_ibuf[indx]), false, false); |
| viddec_emit_assoc_tag(&(cxt->emitter), cxt->list.sc_ibuf[indx].id, false); |
| indx++; |
| } |
| } |
| } |
| if ((scdetect_ret & ~(0xFF))!= PM_INBAND_MESSAGES) |
| { |
| state = PM_SUCCESS;//state = PM_FIRST_SC_FOUND; |
| cxt->sc_prefix_info.first_sc_detect = 0; |
| } |
| else |
| { |
| state = PM_WKLD_DONE; |
| } |
| } |
| |
| viddec_pm_handle_post_inband_messages(cxt, scdetect_ret); |
| |
| /* Step 5: If current frame is done, finalise the workload state with necessary information */ |
| if (state == PM_WKLD_DONE) |
| { |
| DEB("\nFRAME ... DONE\n"); |
| /* we decrement frame start. This can be 0 in cases like sending junk data with EOS */ |
| cxt->frame_start_found -= (cxt->frame_start_found)? 1: 0; |
| if ((scdetect_ret & ~(0xFF))== PM_INBAND_MESSAGES) |
| {/* If EOS dump pending tags and set state */ |
| viddec_pm_generate_missed_association_tags(cxt, false); |
| state = scdetect_ret; |
| } |
| /* Write back stored state of workloads to memory to prepare for psuhing to output queue */ |
| viddec_pm_finalize_workload(cxt, codec_type, codec_errors); |
| } |
| /* Step 6: Reset the list to prepare for next iteration */ |
| viddec_pm_finalize_list(cxt); |
| break; |
| } |
| default: |
| break; |
| } |
| }//if(state == PM_SUCCESS) |
| return state; |
| } // viddec_pm_parse_es_buffer |