WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
{
 /* ! */

 dec_struct_t * ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);

    WORD32 i4_err_status = 0;
    UWORD8 *pu1_buf = NULL;
    WORD32 buflen;
    UWORD32 u4_max_ofst, u4_length_of_start_code = 0;

    UWORD32 bytes_consumed = 0;
    UWORD32 cur_slice_is_nonref = 0;
    UWORD32 u4_next_is_aud;
    UWORD32 u4_first_start_code_found = 0;
    WORD32 ret = 0,api_ret_value = IV_SUCCESS;
    WORD32 header_data_left = 0,frame_data_left = 0;
    UWORD8 *pu1_bitstrm_buf;
 ivd_video_decode_ip_t *ps_dec_ip;
 ivd_video_decode_op_t *ps_dec_op;

    ithread_set_name((void*)"Parse_thread");

    ps_dec_ip = (ivd_video_decode_ip_t *)pv_api_ip;
    ps_dec_op = (ivd_video_decode_op_t *)pv_api_op;

 {
        UWORD32 u4_size;
        u4_size = ps_dec_op->u4_size;
        memset(ps_dec_op, 0, sizeof(ivd_video_decode_op_t));
        ps_dec_op->u4_size = u4_size;
 }

    ps_dec->pv_dec_out = ps_dec_op;
 if(ps_dec->init_done != 1)
 {
 return IV_FAIL;
 }

 /*Data memory barries instruction,so that bitstream write by the application is complete*/
    DATA_SYNC();

 if(0 == ps_dec->u1_flushfrm)
 {
 if(ps_dec_ip->pv_stream_buffer == NULL)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DEC_FRM_BS_BUF_NULL;
 return IV_FAIL;
 }
 if(ps_dec_ip->u4_num_Bytes <= 0)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DEC_NUMBYTES_INV;
 return IV_FAIL;

 }
 }
    ps_dec->u1_pic_decode_done = 0;

    ps_dec_op->u4_num_bytes_consumed = 0;

    ps_dec->ps_out_buffer = NULL;

 if(ps_dec_ip->u4_size
 >= offsetof(ivd_video_decode_ip_t, s_out_buffer))
        ps_dec->ps_out_buffer = &ps_dec_ip->s_out_buffer;

    ps_dec->u4_fmt_conv_cur_row = 0;

    ps_dec->u4_output_present = 0;
    ps_dec->s_disp_op.u4_error_code = 1;
    ps_dec->u4_fmt_conv_num_rows = FMT_CONV_NUM_ROWS;
 if(0 == ps_dec->u4_share_disp_buf
 && ps_dec->i4_decode_header == 0)
 {
        UWORD32 i;
 if(ps_dec->ps_out_buffer->u4_num_bufs == 0)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
 return IV_FAIL;
 }

 for(i = 0; i < ps_dec->ps_out_buffer->u4_num_bufs; i++)
 {
 if(ps_dec->ps_out_buffer->pu1_bufs[i] == NULL)
 {
                ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                ps_dec_op->u4_error_code |= IVD_DISP_FRM_OP_BUF_NULL;
 return IV_FAIL;
 }

 if(ps_dec->ps_out_buffer->u4_min_out_buf_size[i] == 0)
 {
                ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                ps_dec_op->u4_error_code |=
                                IVD_DISP_FRM_ZERO_OP_BUF_SIZE;
 return IV_FAIL;
 }
 }
 }

 if(ps_dec->u4_total_frames_decoded >= NUM_FRAMES_LIMIT)
 {
        ps_dec_op->u4_error_code = ERROR_FRAME_LIMIT_OVER;
 return IV_FAIL;
 }

 /* ! */
    ps_dec->u4_ts = ps_dec_ip->u4_ts;

    ps_dec_op->u4_error_code = 0;
    ps_dec_op->e_pic_type = -1;
    ps_dec_op->u4_output_present = 0;
    ps_dec_op->u4_frame_decoded_flag = 0;

    ps_dec->i4_frametype = -1;
    ps_dec->i4_content_type = -1;
 /*
     * For field pictures, set the bottom and top picture decoded u4_flag correctly.
     */
 {
 if((TOP_FIELD_ONLY | BOT_FIELD_ONLY) == ps_dec->u1_top_bottom_decoded)
 {
            ps_dec->u1_top_bottom_decoded = 0;
 }
 }
    ps_dec->u4_slice_start_code_found = 0;

 /* In case the deocder is not in flush mode(in shared mode),
     then decoder has to pick up a buffer to write current frame.
     Check if a frame is available in such cases */

 if(ps_dec->u1_init_dec_flag == 1 && ps_dec->u4_share_disp_buf == 1
 && ps_dec->u1_flushfrm == 0)
 {
        UWORD32 i;

        WORD32 disp_avail = 0, free_id;

 /* Check if at least one buffer is available with the codec */
 /* If not then return to application with error */
 for(i = 0; i < ps_dec->u1_pic_bufs; i++)
 {
 if(0 == ps_dec->u4_disp_buf_mapping[i]
 || 1 == ps_dec->u4_disp_buf_to_be_freed[i])
 {
                disp_avail = 1;
 break;
 }

 }

 if(0 == disp_avail)
 {
 /* If something is queued for display wait for that buffer to be returned */

            ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;
            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
 return (IV_FAIL);
 }

 while(1)
 {
 pic_buffer_t *ps_pic_buf;
            ps_pic_buf = (pic_buffer_t *)ih264_buf_mgr_get_next_free(
 (buf_mgr_t *)ps_dec->pv_pic_buf_mgr, &free_id);

 if(ps_pic_buf == NULL)
 {
                UWORD32 i, display_queued = 0;

 /* check if any buffer was given for display which is not returned yet */
 for(i = 0; i < (MAX_DISP_BUFS_NEW); i++)
 {
 if(0 != ps_dec->u4_disp_buf_mapping[i])
 {
                        display_queued = 1;
 break;
 }
 }
 /* If some buffer is queued for display, then codec has to singal an error and wait
                 for that buffer to be returned.
                 If nothing is queued for display then codec has ownership of all display buffers
                 and it can reuse any of the existing buffers and continue decoding */

 if(1 == display_queued)
 {
 /* If something is queued for display wait for that buffer to be returned */
                    ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;
                    ps_dec_op->u4_error_code |= (1
 << IVD_UNSUPPORTEDPARAM);
 return (IV_FAIL);
 }
 }
 else
 {
 /* If the buffer is with display, then mark it as in use and then look for a buffer again */
 if(1 == ps_dec->u4_disp_buf_mapping[free_id])
 {
                    ih264_buf_mgr_set_status(
 (buf_mgr_t *)ps_dec->pv_pic_buf_mgr,
                                    free_id,
                                    BUF_MGR_IO);
 }
 else
 {
 /**
                     *  Found a free buffer for present call. Release it now.
                     *  Will be again obtained later.
                     */
                    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,
                                          free_id,
                                          BUF_MGR_IO);
 break;
 }
 }
 }

 }

 if(ps_dec->u1_flushfrm && ps_dec->u1_init_dec_flag)
 {

        ih264d_get_next_display_field(ps_dec, ps_dec->ps_out_buffer,
 &(ps_dec->s_disp_op));
 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
            ps_dec->u4_fmt_conv_cur_row = 0;
            ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht;
            ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
                                  ps_dec->u4_fmt_conv_cur_row,
                                  ps_dec->u4_fmt_conv_num_rows);
            ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;
            ps_dec->u4_output_present = 1;

 }
        ih264d_release_display_field(ps_dec, &(ps_dec->s_disp_op));

        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;
        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;

        ps_dec_op->u4_new_seq = 0;

        ps_dec_op->u4_output_present = ps_dec->u4_output_present;
        ps_dec_op->u4_progressive_frame_flag =
                        ps_dec->s_disp_op.u4_progressive_frame_flag;
        ps_dec_op->e_output_format =
                        ps_dec->s_disp_op.e_output_format;
        ps_dec_op->s_disp_frm_buf = ps_dec->s_disp_op.s_disp_frm_buf;
        ps_dec_op->e4_fld_type = ps_dec->s_disp_op.e4_fld_type;
        ps_dec_op->u4_ts = ps_dec->s_disp_op.u4_ts;
        ps_dec_op->u4_disp_buf_id = ps_dec->s_disp_op.u4_disp_buf_id;

 /*In the case of flush ,since no frame is decoded set pic type as invalid*/
        ps_dec_op->u4_is_ref_flag = -1;
        ps_dec_op->e_pic_type = IV_NA_FRAME;
        ps_dec_op->u4_frame_decoded_flag = 0;

 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
 return (IV_SUCCESS);
 }
 else
 return (IV_FAIL);

 }
 if(ps_dec->u1_res_changed == 1)
 {
 /*if resolution has changed and all buffers have been flushed, reset decoder*/
        ih264d_init_decoder(ps_dec);
 }

    ps_dec->u4_prev_nal_skipped = 0;

    ps_dec->u2_cur_mb_addr = 0;
    ps_dec->u2_total_mbs_coded = 0;
    ps_dec->u2_cur_slice_num = 0;
    ps_dec->cur_dec_mb_num = 0;
    ps_dec->cur_recon_mb_num = 0;
    ps_dec->u4_first_slice_in_pic = 2;
    ps_dec->u1_first_pb_nal_in_pic = 1;
    ps_dec->u1_slice_header_done = 0;
    ps_dec->u1_dangling_field = 0;

    ps_dec->u4_dec_thread_created = 0;
    ps_dec->u4_bs_deblk_thread_created = 0;
    ps_dec->u4_cur_bs_mb_num = 0;
    ps_dec->u4_start_recon_deblk  = 0;

    DEBUG_THREADS_PRINTF(" Starting process call\n");

    ps_dec->u4_pic_buf_got = 0;

 do
 {
        WORD32 buf_size;

        pu1_buf = (UWORD8*)ps_dec_ip->pv_stream_buffer
 + ps_dec_op->u4_num_bytes_consumed;

        u4_max_ofst = ps_dec_ip->u4_num_Bytes
 - ps_dec_op->u4_num_bytes_consumed;

 /* If dynamic bitstream buffer is not allocated and
         * header decode is done, then allocate dynamic bitstream buffer
         */
 if((NULL == ps_dec->pu1_bits_buf_dynamic) &&
 (ps_dec->i4_header_decoded & 1))
 {
            WORD32 size;

 void *pv_buf;
 void *pv_mem_ctxt = ps_dec->pv_mem_ctxt;
            size = MAX(256000, ps_dec->u2_pic_wd * ps_dec->u2_pic_ht * 3 / 2);
            pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
            RETURN_IF((NULL == pv_buf), IV_FAIL);
            ps_dec->pu1_bits_buf_dynamic = pv_buf;
            ps_dec->u4_dynamic_bits_buf_size = size;
 }

 if(ps_dec->pu1_bits_buf_dynamic)
 {
            pu1_bitstrm_buf = ps_dec->pu1_bits_buf_dynamic;
            buf_size = ps_dec->u4_dynamic_bits_buf_size;
 }
 else
 {
            pu1_bitstrm_buf = ps_dec->pu1_bits_buf_static;
            buf_size = ps_dec->u4_static_bits_buf_size;
 }

        u4_next_is_aud = 0;

        buflen = ih264d_find_start_code(pu1_buf, 0, u4_max_ofst,
 &u4_length_of_start_code,
 &u4_next_is_aud);

 if(buflen == -1)
            buflen = 0;
 /* Ignore bytes beyond the allocated size of intermediate buffer */
        buflen = MIN(buflen, buf_size);

        bytes_consumed = buflen + u4_length_of_start_code;
        ps_dec_op->u4_num_bytes_consumed += bytes_consumed;

 {
            UWORD8 u1_firstbyte, u1_nal_ref_idc;

 if(ps_dec->i4_app_skip_mode == IVD_SKIP_B)
 {
                u1_firstbyte = *(pu1_buf + u4_length_of_start_code);
                u1_nal_ref_idc = (UWORD8)(NAL_REF_IDC(u1_firstbyte));
 if(u1_nal_ref_idc == 0)
 {
 /*skip non reference frames*/
                    cur_slice_is_nonref = 1;
 continue;
 }
 else
 {
 if(1 == cur_slice_is_nonref)
 {
 /*We have encountered a referenced frame,return to app*/
                        ps_dec_op->u4_num_bytes_consumed -=
                                        bytes_consumed;
                        ps_dec_op->e_pic_type = IV_B_FRAME;
                        ps_dec_op->u4_error_code =
                                        IVD_DEC_FRM_SKIPPED;
                        ps_dec_op->u4_error_code |= (1
 << IVD_UNSUPPORTEDPARAM);
                        ps_dec_op->u4_frame_decoded_flag = 0;
                        ps_dec_op->u4_size =
 sizeof(ivd_video_decode_op_t);
 /*signal the decode thread*/
                        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
                            ih264d_signal_bs_deblk_thread(ps_dec);
 }

 return (IV_FAIL);
 }
 }

 }

 }

 if(buflen)
 {
            memcpy(pu1_bitstrm_buf, pu1_buf + u4_length_of_start_code,
                   buflen);
 /* Decoder may read extra 8 bytes near end of the frame */
 if((buflen + 8) < buf_size)
 {
                memset(pu1_bitstrm_buf + buflen, 0, 8);
 }
            u4_first_start_code_found = 1;

 }
 else
 {
 /*start code not found*/

 if(u4_first_start_code_found == 0)
 {
 /*no start codes found in current process call*/

                ps_dec->i4_error_code = ERROR_START_CODE_NOT_FOUND;
                ps_dec_op->u4_error_code |= 1 << IVD_INSUFFICIENTDATA;

 if(ps_dec->u4_pic_buf_got == 0)
 {

                    ih264d_fill_output_struct_from_context(ps_dec,
                                                           ps_dec_op);

                    ps_dec_op->u4_error_code = ps_dec->i4_error_code;
                    ps_dec_op->u4_frame_decoded_flag = 0;

 return (IV_FAIL);
 }
 else
 {
                    ps_dec->u1_pic_decode_done = 1;
 continue;
 }
 }
 else
 {
 /* a start code has already been found earlier in the same process call*/
                frame_data_left = 0;
 continue;
 }

 }

        ps_dec->u4_return_to_app = 0;
        ret = ih264d_parse_nal_unit(dec_hdl, ps_dec_op,
                              pu1_bitstrm_buf, buflen);
 if(ret != OK)
 {
            UWORD32 error =  ih264d_map_error(ret);
            ps_dec_op->u4_error_code = error | ret;
            api_ret_value = IV_FAIL;

 if((ret == IVD_RES_CHANGED)
 || (ret == IVD_MEM_ALLOC_FAILED)
 || (ret == ERROR_UNAVAIL_PICBUF_T)
 || (ret == ERROR_UNAVAIL_MVBUF_T)
 || (ret == ERROR_INV_SPS_PPS_T))
 {
                ps_dec->u4_slice_start_code_found = 0;
 break;
 }

 if((ret == ERROR_INCOMPLETE_FRAME) || (ret == ERROR_DANGLING_FIELD_IN_PIC))
 {
                ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
                api_ret_value = IV_FAIL;
 break;
 }

 if(ret == ERROR_IN_LAST_SLICE_OF_PIC)
 {
                api_ret_value = IV_FAIL;
 break;
 }

 }

 if(ps_dec->u4_return_to_app)
 {
 /*We have encountered a referenced frame,return to app*/
            ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
            ps_dec_op->u4_error_code = IVD_DEC_FRM_SKIPPED;
            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
            ps_dec_op->u4_frame_decoded_flag = 0;
            ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
 /*signal the decode thread*/
            ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
                ih264d_signal_bs_deblk_thread(ps_dec);
 }
 return (IV_FAIL);

 }

        header_data_left = ((ps_dec->i4_decode_header == 1)
 && (ps_dec->i4_header_decoded != 3)
 && (ps_dec_op->u4_num_bytes_consumed
 < ps_dec_ip->u4_num_Bytes));
        frame_data_left = (((ps_dec->i4_decode_header == 0)
 && ((ps_dec->u1_pic_decode_done == 0)
 || (u4_next_is_aud == 1)))
 && (ps_dec_op->u4_num_bytes_consumed
 < ps_dec_ip->u4_num_Bytes));
 }
 while(( header_data_left == 1)||(frame_data_left == 1));

 if((ps_dec->u4_slice_start_code_found == 1)
 && (ret != IVD_MEM_ALLOC_FAILED)
 && ps_dec->u2_total_mbs_coded < ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
 {
        WORD32 num_mb_skipped;
        WORD32 prev_slice_err;
 pocstruct_t temp_poc;
        WORD32 ret1;

        num_mb_skipped = (ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
 - ps_dec->u2_total_mbs_coded;

 if(ps_dec->u4_first_slice_in_pic && (ps_dec->u4_pic_buf_got == 0))
            prev_slice_err = 1;

         else
             prev_slice_err = 2;

         ret1 = ih264d_mark_err_slice_skip(ps_dec, num_mb_skipped, ps_dec->u1_nal_unit_type == IDR_SLICE_NAL, ps_dec->ps_cur_slice->u2_frame_num,
                                    &temp_poc, prev_slice_err);

 if((ret1 == ERROR_UNAVAIL_PICBUF_T) || (ret1 == ERROR_UNAVAIL_MVBUF_T))
 {
 return IV_FAIL;
 }
 }

 if((ret == IVD_RES_CHANGED)
 || (ret == IVD_MEM_ALLOC_FAILED)
 || (ret == ERROR_UNAVAIL_PICBUF_T)
 || (ret == ERROR_UNAVAIL_MVBUF_T)
 || (ret == ERROR_INV_SPS_PPS_T))
 {

 /* signal the decode thread */
        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet */
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 /* dont consume bitstream for change in resolution case */
 if(ret == IVD_RES_CHANGED)
 {
            ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
 }
 return IV_FAIL;
 }

 if(ps_dec->u1_separate_parse)
 {
 /* If Format conversion is not complete,
         complete it here */
 if(ps_dec->u4_num_cores == 2)
 {

 /*do deblocking of all mbs*/
 if((ps_dec->u4_nmb_deblk == 0) &&(ps_dec->u4_start_recon_deblk == 1) && (ps_dec->ps_cur_sps->u1_mb_aff_flag == 0))
 {
                UWORD32 u4_num_mbs,u4_max_addr;
 tfr_ctxt_t s_tfr_ctxt;
 tfr_ctxt_t *ps_tfr_cxt = &s_tfr_ctxt;
 pad_mgr_t *ps_pad_mgr = &ps_dec->s_pad_mgr;

 /*BS is done for all mbs while parsing*/
                u4_max_addr = (ps_dec->u2_frm_wd_in_mbs * ps_dec->u2_frm_ht_in_mbs) - 1;
                ps_dec->u4_cur_bs_mb_num = u4_max_addr + 1;

                ih264d_init_deblk_tfr_ctxt(ps_dec, ps_pad_mgr, ps_tfr_cxt,
                                           ps_dec->u2_frm_wd_in_mbs, 0);

                u4_num_mbs = u4_max_addr
 - ps_dec->u4_cur_deblk_mb_num + 1;

                DEBUG_PERF_PRINTF("mbs left for deblocking= %d \n",u4_num_mbs);

 if(u4_num_mbs != 0)
                    ih264d_check_mb_map_deblk(ps_dec, u4_num_mbs,
                                                   ps_tfr_cxt,1);

                ps_dec->u4_start_recon_deblk  = 0;

 }

 }

 /*signal the decode thread*/
        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 }

    DATA_SYNC();

 if((ps_dec_op->u4_error_code & 0xff)
 != ERROR_DYNAMIC_RESOLUTION_NOT_SUPPORTED)
 {
        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;
        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;
 }

 if(ps_dec->i4_header_decoded != 3)
 {
        ps_dec_op->u4_error_code |= (1 << IVD_INSUFFICIENTDATA);

 }

 if(ps_dec->i4_decode_header == 1 && ps_dec->i4_header_decoded != 3)
 {
        ps_dec_op->u4_error_code |= (1 << IVD_INSUFFICIENTDATA);

 }
 if(ps_dec->u4_prev_nal_skipped)
 {
 /*We have encountered a referenced frame,return to app*/
        ps_dec_op->u4_error_code = IVD_DEC_FRM_SKIPPED;
        ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
        ps_dec_op->u4_frame_decoded_flag = 0;
        ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 return (IV_FAIL);

 }

 if((ps_dec->u4_slice_start_code_found == 1)
 && (ERROR_DANGLING_FIELD_IN_PIC != i4_err_status))
 {
 /*
         * For field pictures, set the bottom and top picture decoded u4_flag correctly.
         */

 if(ps_dec->ps_cur_slice->u1_field_pic_flag)
 {
 if(1 == ps_dec->ps_cur_slice->u1_bottom_field_flag)
 {
                ps_dec->u1_top_bottom_decoded |= BOT_FIELD_ONLY;
 }
 else
 {
                ps_dec->u1_top_bottom_decoded |= TOP_FIELD_ONLY;
 }
 }

 /* if new frame in not found (if we are still getting slices from previous frame)
         * ih264d_deblock_display is not called. Such frames will not be added to reference /display
         */
 if((ps_dec->ps_dec_err_status->u1_err_flag & REJECT_CUR_PIC) == 0)
 {
 /* Calling Function to deblock Picture and Display */
            ret = ih264d_deblock_display(ps_dec);
 if(ret != 0)
 {
 return IV_FAIL;
 }
 }

 /*set to complete ,as we dont support partial frame decode*/
 if(ps_dec->i4_header_decoded == 3)
 {
            ps_dec->u2_total_mbs_coded = ps_dec->ps_cur_sps->u2_max_mb_addr + 1;
 }

 /*Update the i4_frametype at the end of picture*/
 if(ps_dec->ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL)
 {
            ps_dec->i4_frametype = IV_IDR_FRAME;
 }
 else if(ps_dec->i4_pic_type == B_SLICE)
 {
            ps_dec->i4_frametype = IV_B_FRAME;
 }
 else if(ps_dec->i4_pic_type == P_SLICE)
 {
            ps_dec->i4_frametype = IV_P_FRAME;
 }
 else if(ps_dec->i4_pic_type == I_SLICE)
 {
            ps_dec->i4_frametype = IV_I_FRAME;
 }
 else
 {
            H264_DEC_DEBUG_PRINT("Shouldn't come here\n");
 }

        ps_dec->i4_content_type = ps_dec->ps_cur_slice->u1_field_pic_flag;

        ps_dec->u4_total_frames_decoded = ps_dec->u4_total_frames_decoded + 2;
        ps_dec->u4_total_frames_decoded = ps_dec->u4_total_frames_decoded
 - ps_dec->ps_cur_slice->u1_field_pic_flag;

 }

 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
        ih264d_signal_bs_deblk_thread(ps_dec);
 }

 {
 /* In case the decoder is configured to run in low delay mode,
         * then get display buffer and then format convert.
         * Note in this mode, format conversion does not run paralelly in a thread and adds to the codec cycles
         */

 if((IVD_DECODE_FRAME_OUT == ps_dec->e_frm_out_mode)
 && ps_dec->u1_init_dec_flag)
 {

            ih264d_get_next_display_field(ps_dec, ps_dec->ps_out_buffer,
 &(ps_dec->s_disp_op));
 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
                ps_dec->u4_fmt_conv_cur_row = 0;
                ps_dec->u4_output_present = 1;
 }
 }

        ih264d_fill_output_struct_from_context(ps_dec, ps_dec_op);

 /* If Format conversion is not complete,
         complete it here */
 if(ps_dec->u4_output_present &&
 (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))
 {
            ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht
 - ps_dec->u4_fmt_conv_cur_row;
            ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
                                  ps_dec->u4_fmt_conv_cur_row,
                                  ps_dec->u4_fmt_conv_num_rows);
            ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;
 }

        ih264d_release_display_field(ps_dec, &(ps_dec->s_disp_op));
 }

 if(ps_dec->i4_decode_header == 1 && (ps_dec->i4_header_decoded & 1) == 1)
 {
        ps_dec_op->u4_progressive_frame_flag = 1;
 if((NULL != ps_dec->ps_cur_sps) && (1 == (ps_dec->ps_cur_sps->u1_is_valid)))
 {
 if((0 == ps_dec->ps_sps->u1_frame_mbs_only_flag)
 && (0 == ps_dec->ps_sps->u1_mb_aff_flag))
                ps_dec_op->u4_progressive_frame_flag = 0;

 }
 }

 /*Data memory barrier instruction,so that yuv write by the library is complete*/
    DATA_SYNC();

    H264_DEC_DEBUG_PRINT("The num bytes consumed: %d\n",
                         ps_dec_op->u4_num_bytes_consumed);
 return api_ret_value;
}

decoder/ih264d_api.c in mediaserver in Android 6.x before 2016-09-01 mishandles the case of decoding zero MBs, which allows remote attackers to cause a denial of service (device hang or reboot) via a crafted media file, aka internal bug 29493002.


WORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
{
 /* ! */

 dec_struct_t * ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);

    WORD32 i4_err_status = 0;
    UWORD8 *pu1_buf = NULL;
    WORD32 buflen;
    UWORD32 u4_max_ofst, u4_length_of_start_code = 0;

    UWORD32 bytes_consumed = 0;
    UWORD32 cur_slice_is_nonref = 0;
    UWORD32 u4_next_is_aud;
    UWORD32 u4_first_start_code_found = 0;
    WORD32 ret = 0,api_ret_value = IV_SUCCESS;
    WORD32 header_data_left = 0,frame_data_left = 0;
    UWORD8 *pu1_bitstrm_buf;
 ivd_video_decode_ip_t *ps_dec_ip;
 ivd_video_decode_op_t *ps_dec_op;

    ithread_set_name((void*)"Parse_thread");

    ps_dec_ip = (ivd_video_decode_ip_t *)pv_api_ip;
    ps_dec_op = (ivd_video_decode_op_t *)pv_api_op;

 {
        UWORD32 u4_size;
        u4_size = ps_dec_op->u4_size;
        memset(ps_dec_op, 0, sizeof(ivd_video_decode_op_t));
        ps_dec_op->u4_size = u4_size;
 }

    ps_dec->pv_dec_out = ps_dec_op;
 if(ps_dec->init_done != 1)
 {
 return IV_FAIL;
 }

 /*Data memory barries instruction,so that bitstream write by the application is complete*/
    DATA_SYNC();

 if(0 == ps_dec->u1_flushfrm)
 {
 if(ps_dec_ip->pv_stream_buffer == NULL)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DEC_FRM_BS_BUF_NULL;
 return IV_FAIL;
 }
 if(ps_dec_ip->u4_num_Bytes <= 0)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DEC_NUMBYTES_INV;
 return IV_FAIL;

 }
 }
    ps_dec->u1_pic_decode_done = 0;

    ps_dec_op->u4_num_bytes_consumed = 0;

    ps_dec->ps_out_buffer = NULL;

 if(ps_dec_ip->u4_size
 >= offsetof(ivd_video_decode_ip_t, s_out_buffer))
        ps_dec->ps_out_buffer = &ps_dec_ip->s_out_buffer;

    ps_dec->u4_fmt_conv_cur_row = 0;

    ps_dec->u4_output_present = 0;
    ps_dec->s_disp_op.u4_error_code = 1;
    ps_dec->u4_fmt_conv_num_rows = FMT_CONV_NUM_ROWS;
 if(0 == ps_dec->u4_share_disp_buf
 && ps_dec->i4_decode_header == 0)
 {
        UWORD32 i;
 if(ps_dec->ps_out_buffer->u4_num_bufs == 0)
 {
            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;
 return IV_FAIL;
 }

 for(i = 0; i < ps_dec->ps_out_buffer->u4_num_bufs; i++)
 {
 if(ps_dec->ps_out_buffer->pu1_bufs[i] == NULL)
 {
                ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                ps_dec_op->u4_error_code |= IVD_DISP_FRM_OP_BUF_NULL;
 return IV_FAIL;
 }

 if(ps_dec->ps_out_buffer->u4_min_out_buf_size[i] == 0)
 {
                ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
                ps_dec_op->u4_error_code |=
                                IVD_DISP_FRM_ZERO_OP_BUF_SIZE;
 return IV_FAIL;
 }
 }
 }

 if(ps_dec->u4_total_frames_decoded >= NUM_FRAMES_LIMIT)
 {
        ps_dec_op->u4_error_code = ERROR_FRAME_LIMIT_OVER;
 return IV_FAIL;
 }

 /* ! */
    ps_dec->u4_ts = ps_dec_ip->u4_ts;

    ps_dec_op->u4_error_code = 0;
    ps_dec_op->e_pic_type = -1;
    ps_dec_op->u4_output_present = 0;
    ps_dec_op->u4_frame_decoded_flag = 0;

    ps_dec->i4_frametype = -1;
    ps_dec->i4_content_type = -1;
 /*
     * For field pictures, set the bottom and top picture decoded u4_flag correctly.
     */
 {
 if((TOP_FIELD_ONLY | BOT_FIELD_ONLY) == ps_dec->u1_top_bottom_decoded)
 {
            ps_dec->u1_top_bottom_decoded = 0;
 }
 }
    ps_dec->u4_slice_start_code_found = 0;

 /* In case the deocder is not in flush mode(in shared mode),
     then decoder has to pick up a buffer to write current frame.
     Check if a frame is available in such cases */

 if(ps_dec->u1_init_dec_flag == 1 && ps_dec->u4_share_disp_buf == 1
 && ps_dec->u1_flushfrm == 0)
 {
        UWORD32 i;

        WORD32 disp_avail = 0, free_id;

 /* Check if at least one buffer is available with the codec */
 /* If not then return to application with error */
 for(i = 0; i < ps_dec->u1_pic_bufs; i++)
 {
 if(0 == ps_dec->u4_disp_buf_mapping[i]
 || 1 == ps_dec->u4_disp_buf_to_be_freed[i])
 {
                disp_avail = 1;
 break;
 }

 }

 if(0 == disp_avail)
 {
 /* If something is queued for display wait for that buffer to be returned */

            ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;
            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
 return (IV_FAIL);
 }

 while(1)
 {
 pic_buffer_t *ps_pic_buf;
            ps_pic_buf = (pic_buffer_t *)ih264_buf_mgr_get_next_free(
 (buf_mgr_t *)ps_dec->pv_pic_buf_mgr, &free_id);

 if(ps_pic_buf == NULL)
 {
                UWORD32 i, display_queued = 0;

 /* check if any buffer was given for display which is not returned yet */
 for(i = 0; i < (MAX_DISP_BUFS_NEW); i++)
 {
 if(0 != ps_dec->u4_disp_buf_mapping[i])
 {
                        display_queued = 1;
 break;
 }
 }
 /* If some buffer is queued for display, then codec has to singal an error and wait
                 for that buffer to be returned.
                 If nothing is queued for display then codec has ownership of all display buffers
                 and it can reuse any of the existing buffers and continue decoding */

 if(1 == display_queued)
 {
 /* If something is queued for display wait for that buffer to be returned */
                    ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;
                    ps_dec_op->u4_error_code |= (1
 << IVD_UNSUPPORTEDPARAM);
 return (IV_FAIL);
 }
 }
 else
 {
 /* If the buffer is with display, then mark it as in use and then look for a buffer again */
 if(1 == ps_dec->u4_disp_buf_mapping[free_id])
 {
                    ih264_buf_mgr_set_status(
 (buf_mgr_t *)ps_dec->pv_pic_buf_mgr,
                                    free_id,
                                    BUF_MGR_IO);
 }
 else
 {
 /**
                     *  Found a free buffer for present call. Release it now.
                     *  Will be again obtained later.
                     */
                    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,
                                          free_id,
                                          BUF_MGR_IO);
 break;
 }
 }
 }

 }

 if(ps_dec->u1_flushfrm && ps_dec->u1_init_dec_flag)
 {

        ih264d_get_next_display_field(ps_dec, ps_dec->ps_out_buffer,
 &(ps_dec->s_disp_op));
 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
            ps_dec->u4_fmt_conv_cur_row = 0;
            ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht;
            ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
                                  ps_dec->u4_fmt_conv_cur_row,
                                  ps_dec->u4_fmt_conv_num_rows);
            ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;
            ps_dec->u4_output_present = 1;

 }
        ih264d_release_display_field(ps_dec, &(ps_dec->s_disp_op));

        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;
        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;

        ps_dec_op->u4_new_seq = 0;

        ps_dec_op->u4_output_present = ps_dec->u4_output_present;
        ps_dec_op->u4_progressive_frame_flag =
                        ps_dec->s_disp_op.u4_progressive_frame_flag;
        ps_dec_op->e_output_format =
                        ps_dec->s_disp_op.e_output_format;
        ps_dec_op->s_disp_frm_buf = ps_dec->s_disp_op.s_disp_frm_buf;
        ps_dec_op->e4_fld_type = ps_dec->s_disp_op.e4_fld_type;
        ps_dec_op->u4_ts = ps_dec->s_disp_op.u4_ts;
        ps_dec_op->u4_disp_buf_id = ps_dec->s_disp_op.u4_disp_buf_id;

 /*In the case of flush ,since no frame is decoded set pic type as invalid*/
        ps_dec_op->u4_is_ref_flag = -1;
        ps_dec_op->e_pic_type = IV_NA_FRAME;
        ps_dec_op->u4_frame_decoded_flag = 0;

 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
 return (IV_SUCCESS);
 }
 else
 return (IV_FAIL);

 }
 if(ps_dec->u1_res_changed == 1)
 {
 /*if resolution has changed and all buffers have been flushed, reset decoder*/
        ih264d_init_decoder(ps_dec);
 }

    ps_dec->u4_prev_nal_skipped = 0;

    ps_dec->u2_cur_mb_addr = 0;
    ps_dec->u2_total_mbs_coded = 0;
    ps_dec->u2_cur_slice_num = 0;
    ps_dec->cur_dec_mb_num = 0;
    ps_dec->cur_recon_mb_num = 0;
    ps_dec->u4_first_slice_in_pic = 2;
    ps_dec->u1_first_pb_nal_in_pic = 1;
    ps_dec->u1_slice_header_done = 0;
    ps_dec->u1_dangling_field = 0;

    ps_dec->u4_dec_thread_created = 0;
    ps_dec->u4_bs_deblk_thread_created = 0;
    ps_dec->u4_cur_bs_mb_num = 0;
    ps_dec->u4_start_recon_deblk  = 0;

    DEBUG_THREADS_PRINTF(" Starting process call\n");

    ps_dec->u4_pic_buf_got = 0;

 do
 {
        WORD32 buf_size;

        pu1_buf = (UWORD8*)ps_dec_ip->pv_stream_buffer
 + ps_dec_op->u4_num_bytes_consumed;

        u4_max_ofst = ps_dec_ip->u4_num_Bytes
 - ps_dec_op->u4_num_bytes_consumed;

 /* If dynamic bitstream buffer is not allocated and
         * header decode is done, then allocate dynamic bitstream buffer
         */
 if((NULL == ps_dec->pu1_bits_buf_dynamic) &&
 (ps_dec->i4_header_decoded & 1))
 {
            WORD32 size;

 void *pv_buf;
 void *pv_mem_ctxt = ps_dec->pv_mem_ctxt;
            size = MAX(256000, ps_dec->u2_pic_wd * ps_dec->u2_pic_ht * 3 / 2);
            pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
            RETURN_IF((NULL == pv_buf), IV_FAIL);
            ps_dec->pu1_bits_buf_dynamic = pv_buf;
            ps_dec->u4_dynamic_bits_buf_size = size;
 }

 if(ps_dec->pu1_bits_buf_dynamic)
 {
            pu1_bitstrm_buf = ps_dec->pu1_bits_buf_dynamic;
            buf_size = ps_dec->u4_dynamic_bits_buf_size;
 }
 else
 {
            pu1_bitstrm_buf = ps_dec->pu1_bits_buf_static;
            buf_size = ps_dec->u4_static_bits_buf_size;
 }

        u4_next_is_aud = 0;

        buflen = ih264d_find_start_code(pu1_buf, 0, u4_max_ofst,
 &u4_length_of_start_code,
 &u4_next_is_aud);

 if(buflen == -1)
            buflen = 0;
 /* Ignore bytes beyond the allocated size of intermediate buffer */
        buflen = MIN(buflen, buf_size);

        bytes_consumed = buflen + u4_length_of_start_code;
        ps_dec_op->u4_num_bytes_consumed += bytes_consumed;

 {
            UWORD8 u1_firstbyte, u1_nal_ref_idc;

 if(ps_dec->i4_app_skip_mode == IVD_SKIP_B)
 {
                u1_firstbyte = *(pu1_buf + u4_length_of_start_code);
                u1_nal_ref_idc = (UWORD8)(NAL_REF_IDC(u1_firstbyte));
 if(u1_nal_ref_idc == 0)
 {
 /*skip non reference frames*/
                    cur_slice_is_nonref = 1;
 continue;
 }
 else
 {
 if(1 == cur_slice_is_nonref)
 {
 /*We have encountered a referenced frame,return to app*/
                        ps_dec_op->u4_num_bytes_consumed -=
                                        bytes_consumed;
                        ps_dec_op->e_pic_type = IV_B_FRAME;
                        ps_dec_op->u4_error_code =
                                        IVD_DEC_FRM_SKIPPED;
                        ps_dec_op->u4_error_code |= (1
 << IVD_UNSUPPORTEDPARAM);
                        ps_dec_op->u4_frame_decoded_flag = 0;
                        ps_dec_op->u4_size =
 sizeof(ivd_video_decode_op_t);
 /*signal the decode thread*/
                        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
                            ih264d_signal_bs_deblk_thread(ps_dec);
 }

 return (IV_FAIL);
 }
 }

 }

 }

 if(buflen)
 {
            memcpy(pu1_bitstrm_buf, pu1_buf + u4_length_of_start_code,
                   buflen);
 /* Decoder may read extra 8 bytes near end of the frame */
 if((buflen + 8) < buf_size)
 {
                memset(pu1_bitstrm_buf + buflen, 0, 8);
 }
            u4_first_start_code_found = 1;

 }
 else
 {
 /*start code not found*/

 if(u4_first_start_code_found == 0)
 {
 /*no start codes found in current process call*/

                ps_dec->i4_error_code = ERROR_START_CODE_NOT_FOUND;
                ps_dec_op->u4_error_code |= 1 << IVD_INSUFFICIENTDATA;

 if(ps_dec->u4_pic_buf_got == 0)
 {

                    ih264d_fill_output_struct_from_context(ps_dec,
                                                           ps_dec_op);

                    ps_dec_op->u4_error_code = ps_dec->i4_error_code;
                    ps_dec_op->u4_frame_decoded_flag = 0;

 return (IV_FAIL);
 }
 else
 {
                    ps_dec->u1_pic_decode_done = 1;
 continue;
 }
 }
 else
 {
 /* a start code has already been found earlier in the same process call*/
                frame_data_left = 0;
 continue;
 }

 }

        ps_dec->u4_return_to_app = 0;
        ret = ih264d_parse_nal_unit(dec_hdl, ps_dec_op,
                              pu1_bitstrm_buf, buflen);
 if(ret != OK)
 {
            UWORD32 error =  ih264d_map_error(ret);
            ps_dec_op->u4_error_code = error | ret;
            api_ret_value = IV_FAIL;

 if((ret == IVD_RES_CHANGED)
 || (ret == IVD_MEM_ALLOC_FAILED)
 || (ret == ERROR_UNAVAIL_PICBUF_T)
 || (ret == ERROR_UNAVAIL_MVBUF_T)
 || (ret == ERROR_INV_SPS_PPS_T))
 {
                ps_dec->u4_slice_start_code_found = 0;
 break;
 }

 if((ret == ERROR_INCOMPLETE_FRAME) || (ret == ERROR_DANGLING_FIELD_IN_PIC))
 {
                ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
                api_ret_value = IV_FAIL;
 break;
 }

 if(ret == ERROR_IN_LAST_SLICE_OF_PIC)
 {
                api_ret_value = IV_FAIL;
 break;
 }

 }

 if(ps_dec->u4_return_to_app)
 {
 /*We have encountered a referenced frame,return to app*/
            ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
            ps_dec_op->u4_error_code = IVD_DEC_FRM_SKIPPED;
            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
            ps_dec_op->u4_frame_decoded_flag = 0;
            ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
 /*signal the decode thread*/
            ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
                ih264d_signal_bs_deblk_thread(ps_dec);
 }
 return (IV_FAIL);

 }

        header_data_left = ((ps_dec->i4_decode_header == 1)
 && (ps_dec->i4_header_decoded != 3)
 && (ps_dec_op->u4_num_bytes_consumed
 < ps_dec_ip->u4_num_Bytes));
        frame_data_left = (((ps_dec->i4_decode_header == 0)
 && ((ps_dec->u1_pic_decode_done == 0)
 || (u4_next_is_aud == 1)))
 && (ps_dec_op->u4_num_bytes_consumed
 < ps_dec_ip->u4_num_Bytes));
 }
 while(( header_data_left == 1)||(frame_data_left == 1));

 if((ps_dec->u4_slice_start_code_found == 1)
 && (ret != IVD_MEM_ALLOC_FAILED)
 && ps_dec->u2_total_mbs_coded < ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
 {
        WORD32 num_mb_skipped;
        WORD32 prev_slice_err;
 pocstruct_t temp_poc;
        WORD32 ret1;

        num_mb_skipped = (ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)
 - ps_dec->u2_total_mbs_coded;

 if(ps_dec->u4_first_slice_in_pic && (ps_dec->u4_pic_buf_got == 0))
            prev_slice_err = 1;

         else
             prev_slice_err = 2;

        if(ps_dec->u4_first_slice_in_pic && (ps_dec->u2_total_mbs_coded == 0))
            prev_slice_err = 1;

         ret1 = ih264d_mark_err_slice_skip(ps_dec, num_mb_skipped, ps_dec->u1_nal_unit_type == IDR_SLICE_NAL, ps_dec->ps_cur_slice->u2_frame_num,
                                    &temp_poc, prev_slice_err);

 if((ret1 == ERROR_UNAVAIL_PICBUF_T) || (ret1 == ERROR_UNAVAIL_MVBUF_T))
 {
 return IV_FAIL;
 }
 }

 if((ret == IVD_RES_CHANGED)
 || (ret == IVD_MEM_ALLOC_FAILED)
 || (ret == ERROR_UNAVAIL_PICBUF_T)
 || (ret == ERROR_UNAVAIL_MVBUF_T)
 || (ret == ERROR_INV_SPS_PPS_T))
 {

 /* signal the decode thread */
        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet */
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 /* dont consume bitstream for change in resolution case */
 if(ret == IVD_RES_CHANGED)
 {
            ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;
 }
 return IV_FAIL;
 }

 if(ps_dec->u1_separate_parse)
 {
 /* If Format conversion is not complete,
         complete it here */
 if(ps_dec->u4_num_cores == 2)
 {

 /*do deblocking of all mbs*/
 if((ps_dec->u4_nmb_deblk == 0) &&(ps_dec->u4_start_recon_deblk == 1) && (ps_dec->ps_cur_sps->u1_mb_aff_flag == 0))
 {
                UWORD32 u4_num_mbs,u4_max_addr;
 tfr_ctxt_t s_tfr_ctxt;
 tfr_ctxt_t *ps_tfr_cxt = &s_tfr_ctxt;
 pad_mgr_t *ps_pad_mgr = &ps_dec->s_pad_mgr;

 /*BS is done for all mbs while parsing*/
                u4_max_addr = (ps_dec->u2_frm_wd_in_mbs * ps_dec->u2_frm_ht_in_mbs) - 1;
                ps_dec->u4_cur_bs_mb_num = u4_max_addr + 1;

                ih264d_init_deblk_tfr_ctxt(ps_dec, ps_pad_mgr, ps_tfr_cxt,
                                           ps_dec->u2_frm_wd_in_mbs, 0);

                u4_num_mbs = u4_max_addr
 - ps_dec->u4_cur_deblk_mb_num + 1;

                DEBUG_PERF_PRINTF("mbs left for deblocking= %d \n",u4_num_mbs);

 if(u4_num_mbs != 0)
                    ih264d_check_mb_map_deblk(ps_dec, u4_num_mbs,
                                                   ps_tfr_cxt,1);

                ps_dec->u4_start_recon_deblk  = 0;

 }

 }

 /*signal the decode thread*/
        ih264d_signal_decode_thread(ps_dec);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 }

    DATA_SYNC();

 if((ps_dec_op->u4_error_code & 0xff)
 != ERROR_DYNAMIC_RESOLUTION_NOT_SUPPORTED)
 {
        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;
        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;
 }

 if(ps_dec->i4_header_decoded != 3)
 {
        ps_dec_op->u4_error_code |= (1 << IVD_INSUFFICIENTDATA);

 }

 if(ps_dec->i4_decode_header == 1 && ps_dec->i4_header_decoded != 3)
 {
        ps_dec_op->u4_error_code |= (1 << IVD_INSUFFICIENTDATA);

 }
 if(ps_dec->u4_prev_nal_skipped)
 {
 /*We have encountered a referenced frame,return to app*/
        ps_dec_op->u4_error_code = IVD_DEC_FRM_SKIPPED;
        ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
        ps_dec_op->u4_frame_decoded_flag = 0;
        ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
            ih264d_signal_bs_deblk_thread(ps_dec);
 }
 return (IV_FAIL);

 }

 if((ps_dec->u4_slice_start_code_found == 1)
 && (ERROR_DANGLING_FIELD_IN_PIC != i4_err_status))
 {
 /*
         * For field pictures, set the bottom and top picture decoded u4_flag correctly.
         */

 if(ps_dec->ps_cur_slice->u1_field_pic_flag)
 {
 if(1 == ps_dec->ps_cur_slice->u1_bottom_field_flag)
 {
                ps_dec->u1_top_bottom_decoded |= BOT_FIELD_ONLY;
 }
 else
 {
                ps_dec->u1_top_bottom_decoded |= TOP_FIELD_ONLY;
 }
 }

 /* if new frame in not found (if we are still getting slices from previous frame)
         * ih264d_deblock_display is not called. Such frames will not be added to reference /display
         */
 if((ps_dec->ps_dec_err_status->u1_err_flag & REJECT_CUR_PIC) == 0)
 {
 /* Calling Function to deblock Picture and Display */
            ret = ih264d_deblock_display(ps_dec);
 if(ret != 0)
 {
 return IV_FAIL;
 }
 }

 /*set to complete ,as we dont support partial frame decode*/
 if(ps_dec->i4_header_decoded == 3)
 {
            ps_dec->u2_total_mbs_coded = ps_dec->ps_cur_sps->u2_max_mb_addr + 1;
 }

 /*Update the i4_frametype at the end of picture*/
 if(ps_dec->ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL)
 {
            ps_dec->i4_frametype = IV_IDR_FRAME;
 }
 else if(ps_dec->i4_pic_type == B_SLICE)
 {
            ps_dec->i4_frametype = IV_B_FRAME;
 }
 else if(ps_dec->i4_pic_type == P_SLICE)
 {
            ps_dec->i4_frametype = IV_P_FRAME;
 }
 else if(ps_dec->i4_pic_type == I_SLICE)
 {
            ps_dec->i4_frametype = IV_I_FRAME;
 }
 else
 {
            H264_DEC_DEBUG_PRINT("Shouldn't come here\n");
 }

        ps_dec->i4_content_type = ps_dec->ps_cur_slice->u1_field_pic_flag;

        ps_dec->u4_total_frames_decoded = ps_dec->u4_total_frames_decoded + 2;
        ps_dec->u4_total_frames_decoded = ps_dec->u4_total_frames_decoded
 - ps_dec->ps_cur_slice->u1_field_pic_flag;

 }

 /* close deblock thread if it is not closed yet*/
 if(ps_dec->u4_num_cores == 3)
 {
        ih264d_signal_bs_deblk_thread(ps_dec);
 }

 {
 /* In case the decoder is configured to run in low delay mode,
         * then get display buffer and then format convert.
         * Note in this mode, format conversion does not run paralelly in a thread and adds to the codec cycles
         */

 if((IVD_DECODE_FRAME_OUT == ps_dec->e_frm_out_mode)
 && ps_dec->u1_init_dec_flag)
 {

            ih264d_get_next_display_field(ps_dec, ps_dec->ps_out_buffer,
 &(ps_dec->s_disp_op));
 if(0 == ps_dec->s_disp_op.u4_error_code)
 {
                ps_dec->u4_fmt_conv_cur_row = 0;
                ps_dec->u4_output_present = 1;
 }
 }

        ih264d_fill_output_struct_from_context(ps_dec, ps_dec_op);

 /* If Format conversion is not complete,
         complete it here */
 if(ps_dec->u4_output_present &&
 (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))
 {
            ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht
 - ps_dec->u4_fmt_conv_cur_row;
            ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),
                                  ps_dec->u4_fmt_conv_cur_row,
                                  ps_dec->u4_fmt_conv_num_rows);
            ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;
 }

        ih264d_release_display_field(ps_dec, &(ps_dec->s_disp_op));
 }

 if(ps_dec->i4_decode_header == 1 && (ps_dec->i4_header_decoded & 1) == 1)
 {
        ps_dec_op->u4_progressive_frame_flag = 1;
 if((NULL != ps_dec->ps_cur_sps) && (1 == (ps_dec->ps_cur_sps->u1_is_valid)))
 {
 if((0 == ps_dec->ps_sps->u1_frame_mbs_only_flag)
 && (0 == ps_dec->ps_sps->u1_mb_aff_flag))
                ps_dec_op->u4_progressive_frame_flag = 0;

 }
 }

 /*Data memory barrier instruction,so that yuv write by the library is complete*/
    DATA_SYNC();

    H264_DEC_DEBUG_PRINT("The num bytes consumed: %d\n",
                         ps_dec_op->u4_num_bytes_consumed);
 return api_ret_value;
}


bool SoftVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
 uint32_t width = outputBufferWidth();
 uint32_t height = outputBufferHeight();

     uint64_t nFilledLen = width;
     nFilledLen *= height;
     if (nFilledLen > UINT32_MAX / 3) {
        ALOGE("b/29421675, nFilledLen overflow %llu w %u h %u", nFilledLen, width, height);
         android_errorWriteLog(0x534e4554, "29421675");
         return false;
     } else if (outHeader->nAllocLen < outHeader->nFilledLen) {
        ALOGE("b/27597103, buffer too small");
        android_errorWriteLog(0x534e4554, "27597103");
 return false;
 }

 return true;
}

Buffer overflow in codecs/on2/dec/SoftVPX.cpp in libstagefright in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, 6.x before 2016-09-01, and 7.0 before 2016-09-01 allows attackers to gain privileges via a crafted application, aka internal bug 29421675.


bool SoftVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
 uint32_t width = outputBufferWidth();
 uint32_t height = outputBufferHeight();

     uint64_t nFilledLen = width;
     nFilledLen *= height;
     if (nFilledLen > UINT32_MAX / 3) {
        ALOGE("b/29421675, nFilledLen overflow %llu w %u h %u",
                (unsigned long long)nFilledLen, width, height);
         android_errorWriteLog(0x534e4554, "29421675");
         return false;
     } else if (outHeader->nAllocLen < outHeader->nFilledLen) {
        ALOGE("b/27597103, buffer too small");
        android_errorWriteLog(0x534e4554, "27597103");
 return false;
 }

 return true;
}


 static byte parseHexByte(const char * &str) {
     byte b = parseHexChar(str[0]);
    if (str[1] == ':' || str[1] == '\0') {
        str += 2;
        return b;
     } else {
         b = b << 4 | parseHexChar(str[1]);
        str += 3;
        return b;
     }
 }

service/jni/com_android_server_wifi_WifiNative.cpp in Wi-Fi in Android 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-08-01 allows attackers to obtain sensitive information via a crafted application that provides a MAC address with too few characters, aka internal bug 28164077.


 static byte parseHexByte(const char * &str) {
    if (str[0] == '\0') {
        ALOGE("Passed an empty string");
        return 0;
    }
     byte b = parseHexChar(str[0]);
    if (str[1] == '\0' || str[1] == ':') {
        str ++;
     } else {
         b = b << 4 | parseHexChar(str[1]);
        str += 2;
     }

    // Skip trailing delimiter if not at the end of the string.
    if (str[0] != '\0') {
        str++;
    }
    return b;
 }


void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
 if (mSignalledError || mOutputPortSettingsChange != NONE) {
 return;
 }

    UCHAR* inBuffer[FILEREAD_MAX_LAYERS];
    UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0};
    UINT bytesValid[FILEREAD_MAX_LAYERS] = {0};

 List<BufferInfo *> &inQueue = getPortQueue(0);
 List<BufferInfo *> &outQueue = getPortQueue(1);

 while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) {
 if (!inQueue.empty()) {
            INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
 BufferInfo *inInfo = *inQueue.begin();
            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;

            mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;

 if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
                ALOGE("first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
                inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
 }
 if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
 BufferInfo *inInfo = *inQueue.begin();
                OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;

                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
                inBufferLength[0] = inHeader->nFilledLen;

                AAC_DECODER_ERROR decoderErr =
                    aacDecoder_ConfigRaw(mAACDecoder,
                                         inBuffer,
                                         inBufferLength);

 if (decoderErr != AAC_DEC_OK) {
                    ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr);
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
 return;
 }

                mInputBufferCount++;
                mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned

                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                mLastInHeader = NULL;
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;

                configureDownmix();
 if (mStreamInfo->sampleRate && mStreamInfo->numChannels) {
                    ALOGI("Initially configuring decoder: %d Hz, %d channels",
                        mStreamInfo->sampleRate,
                        mStreamInfo->numChannels);

                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                    mOutputPortSettingsChange = AWAITING_DISABLED;
 }
 return;
 }

 if (inHeader->nFilledLen == 0) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                mLastInHeader = NULL;
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
 continue;
 }

 if (mIsADTS) {
 size_t adtsHeaderSize = 0;

 const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;

 bool signalError = false;
 if (inHeader->nFilledLen < 7) {
                    ALOGE("Audio data too short to contain even the ADTS header. "
 "Got %d bytes.", inHeader->nFilledLen);
                    hexdump(adtsHeader, inHeader->nFilledLen);
                    signalError = true;
 } else {
 bool protectionAbsent = (adtsHeader[1] & 1);

 unsigned aac_frame_length =
 ((adtsHeader[3] & 3) << 11)
 | (adtsHeader[4] << 3)
 | (adtsHeader[5] >> 5);

 if (inHeader->nFilledLen < aac_frame_length) {
                        ALOGE("Not enough audio data for the complete frame. "
 "Got %d bytes, frame size according to the ADTS "
 "header is %u bytes.",
                                inHeader->nFilledLen, aac_frame_length);
                        hexdump(adtsHeader, inHeader->nFilledLen);

                         signalError = true;
                     } else {
                         adtsHeaderSize = (protectionAbsent ? 7 : 9);

                        inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
                        inBufferLength[0] = aac_frame_length - adtsHeaderSize;
                        inHeader->nOffset += adtsHeaderSize;
                        inHeader->nFilledLen -= adtsHeaderSize;
                     }
                 }

 if (signalError) {
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL);
 return;
 }

                mBufferSizes.add(inBufferLength[0]);
 if (mLastInHeader != inHeader) {
                    mBufferTimestamps.add(inHeader->nTimeStamp);
                    mLastInHeader = inHeader;
 } else {
 int64_t currentTime = mBufferTimestamps.top();
                    currentTime += mStreamInfo->aacSamplesPerFrame *
 1000000ll / mStreamInfo->aacSampleRate;
                    mBufferTimestamps.add(currentTime);
 }
 } else {
                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
                inBufferLength[0] = inHeader->nFilledLen;
                mLastInHeader = inHeader;
                mBufferTimestamps.add(inHeader->nTimeStamp);
                mBufferSizes.add(inHeader->nFilledLen);
 }

            bytesValid[0] = inBufferLength[0];

            INT prevSampleRate = mStreamInfo->sampleRate;
            INT prevNumChannels = mStreamInfo->numChannels;

            aacDecoder_Fill(mAACDecoder,
                            inBuffer,
                            inBufferLength,
                            bytesValid);

            mDrcWrap.submitStreamData(mStreamInfo);
            mDrcWrap.update();

            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
            inHeader->nFilledLen -= inBufferUsedLength;
            inHeader->nOffset += inBufferUsedLength;

            AAC_DECODER_ERROR decoderErr;
 int numLoops = 0;
 do {
 if (outputDelayRingBufferSpaceLeft() <
 (mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                    ALOGV("skipping decode: not enough space left in ringbuffer");
 break;
 }

 int numConsumed = mStreamInfo->numTotalBytes;
                decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                           tmpOutBuffer,
 2048 * MAX_CHANNEL_COUNT,
 0 /* flags */);

                numConsumed = mStreamInfo->numTotalBytes - numConsumed;
                numLoops++;

 if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
 break;
 }
                mDecodedSizes.add(numConsumed);

 if (decoderErr != AAC_DEC_OK) {
                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
 }

 if (bytesValid[0] != 0) {
                    ALOGE("bytesValid[0] != 0 should never happen");
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
 return;
 }

 size_t numOutBytes =
                    mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;

 if (decoderErr == AAC_DEC_OK) {
 if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                        mSignalledError = true;
                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
 return;
 }
 } else {
                    ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);

                    memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow

 if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                        mSignalledError = true;
                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
 return;
 }

 if (inHeader) {
                        inHeader->nFilledLen = 0;
 }

                    aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);

                    mBufferSizes.pop();
 int n = 0;
 for (int i = 0; i < numLoops; i++) {
                        n += mDecodedSizes.itemAt(mDecodedSizes.size() - numLoops + i);
 }
                    mBufferSizes.add(n);

 }

 /*
                 * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
                 * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
                 * rate system and the sampling rate in the final output is actually
                 * doubled compared with the core AAC decoder sampling rate.
                 *
                 * Explicit signalling is done by explicitly defining SBR audio object
                 * type in the bitstream. Implicit signalling is done by embedding
                 * SBR content in AAC extension payload specific to SBR, and hence
                 * requires an AAC decoder to perform pre-checks on actual audio frames.
                 *
                 * Thus, we could not say for sure whether a stream is
                 * AAC+/eAAC+ until the first data frame is decoded.
                 */
 if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1
 if (mStreamInfo->sampleRate != prevSampleRate ||
                        mStreamInfo->numChannels != prevNumChannels) {
                        ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
                              prevSampleRate, mStreamInfo->sampleRate,
                              prevNumChannels, mStreamInfo->numChannels);

                        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                        mOutputPortSettingsChange = AWAITING_DISABLED;

 if (inHeader && inHeader->nFilledLen == 0) {
                            inInfo->mOwnedByUs = false;
                            mInputBufferCount++;
                            inQueue.erase(inQueue.begin());
                            mLastInHeader = NULL;
                            inInfo = NULL;
                            notifyEmptyBufferDone(inHeader);
                            inHeader = NULL;
 }
 return;
 }
 } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
                    ALOGW("Invalid AAC stream");
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
 return;
 }
 if (inHeader && inHeader->nFilledLen == 0) {
                    inInfo->mOwnedByUs = false;
                    mInputBufferCount++;
                    inQueue.erase(inQueue.begin());
                    mLastInHeader = NULL;
                    inInfo = NULL;
                    notifyEmptyBufferDone(inHeader);
                    inHeader = NULL;
 } else {
                    ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0);
 }
 } while (decoderErr == AAC_DEC_OK);
 }

 int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;

 if (!mEndOfInput && mOutputDelayCompensated < outputDelay) {
 int32_t toCompensate = outputDelay - mOutputDelayCompensated;
 int32_t discard = outputDelayRingBufferSamplesAvailable();
 if (discard > toCompensate) {
                discard = toCompensate;
 }
 int32_t discarded = outputDelayRingBufferGetSamples(0, discard);
            mOutputDelayCompensated += discarded;
 continue;
 }

 if (mEndOfInput) {
 while (mOutputDelayCompensated > 0) {
                INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];

                 mDrcWrap.submitStreamData(mStreamInfo);
                 mDrcWrap.update();

                AAC_DECODER_ERROR decoderErr =
                    aacDecoder_DecodeFrame(mAACDecoder,
                                           tmpOutBuffer,
 2048 * MAX_CHANNEL_COUNT,
                                           AACDEC_FLUSH);
 if (decoderErr != AAC_DEC_OK) {
                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
 }

 int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels;
 if (tmpOutBufferSamples > mOutputDelayCompensated) {
                    tmpOutBufferSamples = mOutputDelayCompensated;
 }
                outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples);
                mOutputDelayCompensated -= tmpOutBufferSamples;
 }
 }

 while (!outQueue.empty()
 && outputDelayRingBufferSamplesAvailable()
 >= mStreamInfo->frameSize * mStreamInfo->numChannels) {
 BufferInfo *outInfo = *outQueue.begin();
            OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;

 if (outHeader->nOffset != 0) {
                ALOGE("outHeader->nOffset != 0 is not handled");
                mSignalledError = true;
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
 return;
 }

            INT_PCM *outBuffer =
 reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
 int samplesize = mStreamInfo->numChannels * sizeof(int16_t);
 if (outHeader->nOffset
 + mStreamInfo->frameSize * samplesize
 > outHeader->nAllocLen) {
                ALOGE("buffer overflow");
                mSignalledError = true;
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
 return;

 }

 int available = outputDelayRingBufferSamplesAvailable();
 int numSamples = outHeader->nAllocLen / sizeof(int16_t);
 if (numSamples > available) {
                numSamples = available;
 }
 int64_t currentTime = 0;
 if (available) {

 int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels);
                numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels);

                ALOGV("%d samples available (%d), or %d frames",
                        numSamples, available, numFrames);
 int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0);
                currentTime = *nextTimeStamp;
 int32_t *currentBufLeft = &mBufferSizes.editItemAt(0);
 for (int i = 0; i < numFrames; i++) {
 int32_t decodedSize = mDecodedSizes.itemAt(0);
                    mDecodedSizes.removeAt(0);
                    ALOGV("decoded %d of %d", decodedSize, *currentBufLeft);
 if (*currentBufLeft > decodedSize) {
 *currentBufLeft -= decodedSize;
 *nextTimeStamp += mStreamInfo->aacSamplesPerFrame *
 1000000ll / mStreamInfo->aacSampleRate;
                        ALOGV("adjusted nextTimeStamp/size to %lld/%d",
 (long long) *nextTimeStamp, *currentBufLeft);
 } else {
 if (mBufferTimestamps.size() > 0) {
                            mBufferTimestamps.removeAt(0);
                            nextTimeStamp = &mBufferTimestamps.editItemAt(0);
                            mBufferSizes.removeAt(0);
                            currentBufLeft = &mBufferSizes.editItemAt(0);
                            ALOGV("moved to next time/size: %lld/%d",
 (long long) *nextTimeStamp, *currentBufLeft);
 }
                        numFrames = i + 1;
                        numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels;
 break;
 }
 }

                ALOGV("getting %d from ringbuffer", numSamples);
 int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples);
 if (ns != numSamples) {
                    ALOGE("not a complete frame of samples available");
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
 return;
 }
 }

            outHeader->nFilledLen = numSamples * sizeof(int16_t);

 if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) {
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                mEndOfOutput = true;
 } else {
                outHeader->nFlags = 0;
 }

            outHeader->nTimeStamp = currentTime;

            mOutputBufferCount++;
            outInfo->mOwnedByUs = false;
            outQueue.erase(outQueue.begin());
            outInfo = NULL;
            ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen);
            notifyFillBufferDone(outHeader);
            outHeader = NULL;
 }

 if (mEndOfInput) {
 int ringBufAvail = outputDelayRingBufferSamplesAvailable();
 if (!outQueue.empty()
 && ringBufAvail < mStreamInfo->frameSize * mStreamInfo->numChannels) {
 if (!mEndOfOutput) {
                    mEndOfOutput = true;
 BufferInfo *outInfo = *outQueue.begin();
                    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;

                    INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(outHeader->pBuffer
 + outHeader->nOffset);
 int32_t ns = outputDelayRingBufferGetSamples(outBuffer, ringBufAvail);
 if (ns < 0) {
                        ns = 0;
 }
                    outHeader->nFilledLen = ns;
                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;

                    outHeader->nTimeStamp = mBufferTimestamps.itemAt(0);
                    mBufferTimestamps.clear();
                    mBufferSizes.clear();
                    mDecodedSizes.clear();

                    mOutputBufferCount++;
                    outInfo->mOwnedByUs = false;
                    outQueue.erase(outQueue.begin());
                    outInfo = NULL;
                    notifyFillBufferDone(outHeader);
                    outHeader = NULL;
 }
 break; // if outQueue not empty but no more output
 }
 }
 }
}

codecs/aacdec/SoftAAC2.cpp in libstagefright in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-08-01 allows remote attackers to cause a denial of service (device hang or reboot) via crafted ADTS data, aka internal bug 29153599.


void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
 if (mSignalledError || mOutputPortSettingsChange != NONE) {
 return;
 }

    UCHAR* inBuffer[FILEREAD_MAX_LAYERS];
    UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0};
    UINT bytesValid[FILEREAD_MAX_LAYERS] = {0};

 List<BufferInfo *> &inQueue = getPortQueue(0);
 List<BufferInfo *> &outQueue = getPortQueue(1);

 while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) {
 if (!inQueue.empty()) {
            INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];
 BufferInfo *inInfo = *inQueue.begin();
            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;

            mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;

 if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
                ALOGE("first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
                inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
 }
 if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
 BufferInfo *inInfo = *inQueue.begin();
                OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;

                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
                inBufferLength[0] = inHeader->nFilledLen;

                AAC_DECODER_ERROR decoderErr =
                    aacDecoder_ConfigRaw(mAACDecoder,
                                         inBuffer,
                                         inBufferLength);

 if (decoderErr != AAC_DEC_OK) {
                    ALOGW("aacDecoder_ConfigRaw decoderErr = 0x%4.4x", decoderErr);
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
 return;
 }

                mInputBufferCount++;
                mOutputBufferCount++; // fake increase of outputBufferCount to keep the counters aligned

                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                mLastInHeader = NULL;
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;

                configureDownmix();
 if (mStreamInfo->sampleRate && mStreamInfo->numChannels) {
                    ALOGI("Initially configuring decoder: %d Hz, %d channels",
                        mStreamInfo->sampleRate,
                        mStreamInfo->numChannels);

                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                    mOutputPortSettingsChange = AWAITING_DISABLED;
 }
 return;
 }

 if (inHeader->nFilledLen == 0) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                mLastInHeader = NULL;
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
 continue;
 }

 if (mIsADTS) {
 size_t adtsHeaderSize = 0;

 const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;

 bool signalError = false;
 if (inHeader->nFilledLen < 7) {
                    ALOGE("Audio data too short to contain even the ADTS header. "
 "Got %d bytes.", inHeader->nFilledLen);
                    hexdump(adtsHeader, inHeader->nFilledLen);
                    signalError = true;
 } else {
 bool protectionAbsent = (adtsHeader[1] & 1);

 unsigned aac_frame_length =
 ((adtsHeader[3] & 3) << 11)
 | (adtsHeader[4] << 3)
 | (adtsHeader[5] >> 5);

 if (inHeader->nFilledLen < aac_frame_length) {
                        ALOGE("Not enough audio data for the complete frame. "
 "Got %d bytes, frame size according to the ADTS "
 "header is %u bytes.",
                                inHeader->nFilledLen, aac_frame_length);
                        hexdump(adtsHeader, inHeader->nFilledLen);

                         signalError = true;
                     } else {
                         adtsHeaderSize = (protectionAbsent ? 7 : 9);
                        if (aac_frame_length < adtsHeaderSize) {
                            signalError = true;
                        } else {
                            inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
                            inBufferLength[0] = aac_frame_length - adtsHeaderSize;

                            inHeader->nOffset += adtsHeaderSize;
                            inHeader->nFilledLen -= adtsHeaderSize;
                        }
                     }
                 }

 if (signalError) {
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL);
 return;
 }

                mBufferSizes.add(inBufferLength[0]);
 if (mLastInHeader != inHeader) {
                    mBufferTimestamps.add(inHeader->nTimeStamp);
                    mLastInHeader = inHeader;
 } else {
 int64_t currentTime = mBufferTimestamps.top();
                    currentTime += mStreamInfo->aacSamplesPerFrame *
 1000000ll / mStreamInfo->aacSampleRate;
                    mBufferTimestamps.add(currentTime);
 }
 } else {
                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
                inBufferLength[0] = inHeader->nFilledLen;
                mLastInHeader = inHeader;
                mBufferTimestamps.add(inHeader->nTimeStamp);
                mBufferSizes.add(inHeader->nFilledLen);
 }

            bytesValid[0] = inBufferLength[0];

            INT prevSampleRate = mStreamInfo->sampleRate;
            INT prevNumChannels = mStreamInfo->numChannels;

            aacDecoder_Fill(mAACDecoder,
                            inBuffer,
                            inBufferLength,
                            bytesValid);

            mDrcWrap.submitStreamData(mStreamInfo);
            mDrcWrap.update();

            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
            inHeader->nFilledLen -= inBufferUsedLength;
            inHeader->nOffset += inBufferUsedLength;

            AAC_DECODER_ERROR decoderErr;
 int numLoops = 0;
 do {
 if (outputDelayRingBufferSpaceLeft() <
 (mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                    ALOGV("skipping decode: not enough space left in ringbuffer");
 break;
 }

 int numConsumed = mStreamInfo->numTotalBytes;
                decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                           tmpOutBuffer,
 2048 * MAX_CHANNEL_COUNT,
 0 /* flags */);

                numConsumed = mStreamInfo->numTotalBytes - numConsumed;
                numLoops++;

 if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
 break;
 }
                mDecodedSizes.add(numConsumed);

 if (decoderErr != AAC_DEC_OK) {
                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
 }

 if (bytesValid[0] != 0) {
                    ALOGE("bytesValid[0] != 0 should never happen");
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
 return;
 }

 size_t numOutBytes =
                    mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;

 if (decoderErr == AAC_DEC_OK) {
 if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                        mSignalledError = true;
                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
 return;
 }
 } else {
                    ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);

                    memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow

 if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                        mSignalledError = true;
                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
 return;
 }

 if (inHeader) {
                        inHeader->nFilledLen = 0;
 }

                    aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);

                    mBufferSizes.pop();
 int n = 0;
 for (int i = 0; i < numLoops; i++) {
                        n += mDecodedSizes.itemAt(mDecodedSizes.size() - numLoops + i);
 }
                    mBufferSizes.add(n);

 }

 /*
                 * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
                 * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
                 * rate system and the sampling rate in the final output is actually
                 * doubled compared with the core AAC decoder sampling rate.
                 *
                 * Explicit signalling is done by explicitly defining SBR audio object
                 * type in the bitstream. Implicit signalling is done by embedding
                 * SBR content in AAC extension payload specific to SBR, and hence
                 * requires an AAC decoder to perform pre-checks on actual audio frames.
                 *
                 * Thus, we could not say for sure whether a stream is
                 * AAC+/eAAC+ until the first data frame is decoded.
                 */
 if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1
 if (mStreamInfo->sampleRate != prevSampleRate ||
                        mStreamInfo->numChannels != prevNumChannels) {
                        ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
                              prevSampleRate, mStreamInfo->sampleRate,
                              prevNumChannels, mStreamInfo->numChannels);

                        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                        mOutputPortSettingsChange = AWAITING_DISABLED;

 if (inHeader && inHeader->nFilledLen == 0) {
                            inInfo->mOwnedByUs = false;
                            mInputBufferCount++;
                            inQueue.erase(inQueue.begin());
                            mLastInHeader = NULL;
                            inInfo = NULL;
                            notifyEmptyBufferDone(inHeader);
                            inHeader = NULL;
 }
 return;
 }
 } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
                    ALOGW("Invalid AAC stream");
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
 return;
 }
 if (inHeader && inHeader->nFilledLen == 0) {
                    inInfo->mOwnedByUs = false;
                    mInputBufferCount++;
                    inQueue.erase(inQueue.begin());
                    mLastInHeader = NULL;
                    inInfo = NULL;
                    notifyEmptyBufferDone(inHeader);
                    inHeader = NULL;
 } else {
                    ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0);
 }
 } while (decoderErr == AAC_DEC_OK);
 }

 int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;

 if (!mEndOfInput && mOutputDelayCompensated < outputDelay) {
 int32_t toCompensate = outputDelay - mOutputDelayCompensated;
 int32_t discard = outputDelayRingBufferSamplesAvailable();
 if (discard > toCompensate) {
                discard = toCompensate;
 }
 int32_t discarded = outputDelayRingBufferGetSamples(0, discard);
            mOutputDelayCompensated += discarded;
 continue;
 }

 if (mEndOfInput) {
 while (mOutputDelayCompensated > 0) {
                INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT];

                 mDrcWrap.submitStreamData(mStreamInfo);
                 mDrcWrap.update();

                AAC_DECODER_ERROR decoderErr =
                    aacDecoder_DecodeFrame(mAACDecoder,
                                           tmpOutBuffer,
 2048 * MAX_CHANNEL_COUNT,
                                           AACDEC_FLUSH);
 if (decoderErr != AAC_DEC_OK) {
                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
 }

 int32_t tmpOutBufferSamples = mStreamInfo->frameSize * mStreamInfo->numChannels;
 if (tmpOutBufferSamples > mOutputDelayCompensated) {
                    tmpOutBufferSamples = mOutputDelayCompensated;
 }
                outputDelayRingBufferPutSamples(tmpOutBuffer, tmpOutBufferSamples);
                mOutputDelayCompensated -= tmpOutBufferSamples;
 }
 }

 while (!outQueue.empty()
 && outputDelayRingBufferSamplesAvailable()
 >= mStreamInfo->frameSize * mStreamInfo->numChannels) {
 BufferInfo *outInfo = *outQueue.begin();
            OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;

 if (outHeader->nOffset != 0) {
                ALOGE("outHeader->nOffset != 0 is not handled");
                mSignalledError = true;
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
 return;
 }

            INT_PCM *outBuffer =
 reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
 int samplesize = mStreamInfo->numChannels * sizeof(int16_t);
 if (outHeader->nOffset
 + mStreamInfo->frameSize * samplesize
 > outHeader->nAllocLen) {
                ALOGE("buffer overflow");
                mSignalledError = true;
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
 return;

 }

 int available = outputDelayRingBufferSamplesAvailable();
 int numSamples = outHeader->nAllocLen / sizeof(int16_t);
 if (numSamples > available) {
                numSamples = available;
 }
 int64_t currentTime = 0;
 if (available) {

 int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels);
                numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels);

                ALOGV("%d samples available (%d), or %d frames",
                        numSamples, available, numFrames);
 int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0);
                currentTime = *nextTimeStamp;
 int32_t *currentBufLeft = &mBufferSizes.editItemAt(0);
 for (int i = 0; i < numFrames; i++) {
 int32_t decodedSize = mDecodedSizes.itemAt(0);
                    mDecodedSizes.removeAt(0);
                    ALOGV("decoded %d of %d", decodedSize, *currentBufLeft);
 if (*currentBufLeft > decodedSize) {
 *currentBufLeft -= decodedSize;
 *nextTimeStamp += mStreamInfo->aacSamplesPerFrame *
 1000000ll / mStreamInfo->aacSampleRate;
                        ALOGV("adjusted nextTimeStamp/size to %lld/%d",
 (long long) *nextTimeStamp, *currentBufLeft);
 } else {
 if (mBufferTimestamps.size() > 0) {
                            mBufferTimestamps.removeAt(0);
                            nextTimeStamp = &mBufferTimestamps.editItemAt(0);
                            mBufferSizes.removeAt(0);
                            currentBufLeft = &mBufferSizes.editItemAt(0);
                            ALOGV("moved to next time/size: %lld/%d",
 (long long) *nextTimeStamp, *currentBufLeft);
 }
                        numFrames = i + 1;
                        numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels;
 break;
 }
 }

                ALOGV("getting %d from ringbuffer", numSamples);
 int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples);
 if (ns != numSamples) {
                    ALOGE("not a complete frame of samples available");
                    mSignalledError = true;
                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
 return;
 }
 }

            outHeader->nFilledLen = numSamples * sizeof(int16_t);

 if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) {
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                mEndOfOutput = true;
 } else {
                outHeader->nFlags = 0;
 }

            outHeader->nTimeStamp = currentTime;

            mOutputBufferCount++;
            outInfo->mOwnedByUs = false;
            outQueue.erase(outQueue.begin());
            outInfo = NULL;
            ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen);
            notifyFillBufferDone(outHeader);
            outHeader = NULL;
 }

 if (mEndOfInput) {
 int ringBufAvail = outputDelayRingBufferSamplesAvailable();
 if (!outQueue.empty()
 && ringBufAvail < mStreamInfo->frameSize * mStreamInfo->numChannels) {
 if (!mEndOfOutput) {
                    mEndOfOutput = true;
 BufferInfo *outInfo = *outQueue.begin();
                    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;

                    INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(outHeader->pBuffer
 + outHeader->nOffset);
 int32_t ns = outputDelayRingBufferGetSamples(outBuffer, ringBufAvail);
 if (ns < 0) {
                        ns = 0;
 }
                    outHeader->nFilledLen = ns;
                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;

                    outHeader->nTimeStamp = mBufferTimestamps.itemAt(0);
                    mBufferTimestamps.clear();
                    mBufferSizes.clear();
                    mDecodedSizes.clear();

                    mOutputBufferCount++;
                    outInfo->mOwnedByUs = false;
                    outQueue.erase(outQueue.begin());
                    outInfo = NULL;
                    notifyFillBufferDone(outHeader);
                    outHeader = NULL;
 }
 break; // if outQueue not empty but no more output
 }
 }
 }
}


void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
    UNUSED(portIndex);

 if (mSignalledError) {
 return;
 }
 if (mOutputPortSettingsChange != NONE) {
 return;
 }

     if (NULL == mCodecCtx) {
         if (OK != initDecoder()) {
             return;
         }
     }
 if (outputBufferWidth() != mStride) {
 /* Set the run-time (dynamic) parameters */
        mStride = outputBufferWidth();
        setParams(mStride);
 }

 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);

 /* If input EOS is seen and decoder is not in flush mode,
     * set the decoder in flush mode.
     * There can be a case where EOS is sent along with last picture data
     * In that case, only after decoding that input data, decoder has to be
     * put in flush. This case is handled here  */

 if (mReceivedEOS && !mIsInFlush) {
        setFlushMode();
 }

 while (!outQueue.empty()) {
 BufferInfo *inInfo;
        OMX_BUFFERHEADERTYPE *inHeader;

 BufferInfo *outInfo;
        OMX_BUFFERHEADERTYPE *outHeader;
 size_t timeStampIx;

        inInfo = NULL;
        inHeader = NULL;

 if (!mIsInFlush) {
 if (!inQueue.empty()) {
                inInfo = *inQueue.begin();
                inHeader = inInfo->mHeader;
 } else {
 break;
 }
 }

        outInfo = *outQueue.begin();
        outHeader = outInfo->mHeader;
        outHeader->nFlags = 0;
        outHeader->nTimeStamp = 0;
        outHeader->nOffset = 0;

 if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
            mReceivedEOS = true;
 if (inHeader->nFilledLen == 0) {
                inQueue.erase(inQueue.begin());
                inInfo->mOwnedByUs = false;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
                setFlushMode();
 }
 }

 /* Get a free slot in timestamp array to hold input timestamp */
 {
 size_t i;
            timeStampIx = 0;
 for (i = 0; i < MAX_TIME_STAMPS; i++) {
 if (!mTimeStampsValid[i]) {
                    timeStampIx = i;
 break;
 }
 }
 if (inHeader != NULL) {
                mTimeStampsValid[timeStampIx] = true;
                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
 }
 }

 {
 ivd_video_decode_ip_t s_dec_ip;
 ivd_video_decode_op_t s_dec_op;
            WORD32 timeDelay, timeTaken;
 size_t sizeY, sizeUV;

 if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
                ALOGE("Decoder arg setup failed");
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
 return;
 }

            GETTIME(&mTimeStart, NULL);
 /* Compute time elapsed between end of previous decode()
             * to start of current decode() */
            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);

             IV_API_CALL_STATUS_T status;
             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);

             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));

             GETTIME(&mTimeEnd, NULL);
 /* Compute time taken for decode() */
            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);

            ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
                   s_dec_op.u4_num_bytes_consumed);
 if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
                mFlushNeeded = true;
 }

 if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
 /* If the input did not contain picture data, then ignore
                 * the associated timestamp */
                mTimeStampsValid[timeStampIx] = false;
 }

 if (mChangingResolution && !s_dec_op.u4_output_present) {
                mChangingResolution = false;
                resetDecoder();
                resetPlugin();
 continue;
 }

 if (resChanged) {
                mChangingResolution = true;
 if (mFlushNeeded) {
                    setFlushMode();
 }
 continue;
 }

 if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
 uint32_t width = s_dec_op.u4_pic_wd;
 uint32_t height = s_dec_op.u4_pic_ht;
 bool portWillReset = false;
                handlePortSettingsChange(&portWillReset, width, height);

 if (portWillReset) {
                    resetDecoder();
 return;
 }
 }

 if (s_dec_op.u4_output_present) {
                outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;

                outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
                mTimeStampsValid[s_dec_op.u4_ts] = false;

                outInfo->mOwnedByUs = false;
                outQueue.erase(outQueue.begin());
                outInfo = NULL;
                notifyFillBufferDone(outHeader);
                outHeader = NULL;
 } else {
 /* If in flush mode and no output is returned by the codec,
                 * then come out of flush mode */
                mIsInFlush = false;

 /* If EOS was recieved on input port and there is no output
                 * from the codec, then signal EOS on output port */
 if (mReceivedEOS) {
                    outHeader->nFilledLen = 0;
                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;

                    outInfo->mOwnedByUs = false;
                    outQueue.erase(outQueue.begin());
                    outInfo = NULL;
                    notifyFillBufferDone(outHeader);
                    outHeader = NULL;
                    resetPlugin();
 }
 }
 }

 if (inHeader != NULL) {
            inInfo->mOwnedByUs = false;
            inQueue.erase(inQueue.begin());
            inInfo = NULL;
            notifyEmptyBufferDone(inHeader);
            inHeader = NULL;
 }
 }
}

codecs/hevcdec/SoftHEVC.cpp in libstagefright in mediaserver in Android 6.0.1 before 2016-08-01 mishandles decoder errors, which allows remote attackers to cause a denial of service (device hang or reboot) via a crafted media file, aka internal bug 28816956.


void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
    UNUSED(portIndex);

 if (mSignalledError) {
 return;
 }
 if (mOutputPortSettingsChange != NONE) {
 return;
 }

     if (NULL == mCodecCtx) {
         if (OK != initDecoder()) {
            ALOGE("Failed to initialize decoder");
            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
            mSignalledError = true;
             return;
         }
     }
 if (outputBufferWidth() != mStride) {
 /* Set the run-time (dynamic) parameters */
        mStride = outputBufferWidth();
        setParams(mStride);
 }

 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);

 /* If input EOS is seen and decoder is not in flush mode,
     * set the decoder in flush mode.
     * There can be a case where EOS is sent along with last picture data
     * In that case, only after decoding that input data, decoder has to be
     * put in flush. This case is handled here  */

 if (mReceivedEOS && !mIsInFlush) {
        setFlushMode();
 }

 while (!outQueue.empty()) {
 BufferInfo *inInfo;
        OMX_BUFFERHEADERTYPE *inHeader;

 BufferInfo *outInfo;
        OMX_BUFFERHEADERTYPE *outHeader;
 size_t timeStampIx;

        inInfo = NULL;
        inHeader = NULL;

 if (!mIsInFlush) {
 if (!inQueue.empty()) {
                inInfo = *inQueue.begin();
                inHeader = inInfo->mHeader;
 } else {
 break;
 }
 }

        outInfo = *outQueue.begin();
        outHeader = outInfo->mHeader;
        outHeader->nFlags = 0;
        outHeader->nTimeStamp = 0;
        outHeader->nOffset = 0;

 if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
            mReceivedEOS = true;
 if (inHeader->nFilledLen == 0) {
                inQueue.erase(inQueue.begin());
                inInfo->mOwnedByUs = false;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
                setFlushMode();
 }
 }

 /* Get a free slot in timestamp array to hold input timestamp */
 {
 size_t i;
            timeStampIx = 0;
 for (i = 0; i < MAX_TIME_STAMPS; i++) {
 if (!mTimeStampsValid[i]) {
                    timeStampIx = i;
 break;
 }
 }
 if (inHeader != NULL) {
                mTimeStampsValid[timeStampIx] = true;
                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
 }
 }

 {
 ivd_video_decode_ip_t s_dec_ip;
 ivd_video_decode_op_t s_dec_op;
            WORD32 timeDelay, timeTaken;
 size_t sizeY, sizeUV;

 if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
                ALOGE("Decoder arg setup failed");
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
 return;
 }

            GETTIME(&mTimeStart, NULL);
 /* Compute time elapsed between end of previous decode()
             * to start of current decode() */
            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);

             IV_API_CALL_STATUS_T status;
             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);

            bool unsupportedResolution =
                (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF));

            /* Check for unsupported dimensions */
            if (unsupportedResolution) {
                ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight);
                notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
                mSignalledError = true;
                return;
            }

            bool allocationFailed = (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & 0xFF));
            if (allocationFailed) {
                ALOGE("Allocation failure in decoder");
                notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
                mSignalledError = true;
                return;
            }

             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));

             GETTIME(&mTimeEnd, NULL);
 /* Compute time taken for decode() */
            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);

            ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
                   s_dec_op.u4_num_bytes_consumed);
 if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
                mFlushNeeded = true;
 }

 if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
 /* If the input did not contain picture data, then ignore
                 * the associated timestamp */
                mTimeStampsValid[timeStampIx] = false;
 }

 if (mChangingResolution && !s_dec_op.u4_output_present) {
                mChangingResolution = false;
                resetDecoder();
                resetPlugin();
 continue;
 }

 if (resChanged) {
                mChangingResolution = true;
 if (mFlushNeeded) {
                    setFlushMode();
 }
 continue;
 }

 if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
 uint32_t width = s_dec_op.u4_pic_wd;
 uint32_t height = s_dec_op.u4_pic_ht;
 bool portWillReset = false;
                handlePortSettingsChange(&portWillReset, width, height);

 if (portWillReset) {
                    resetDecoder();
 return;
 }
 }

 if (s_dec_op.u4_output_present) {
                outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;

                outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
                mTimeStampsValid[s_dec_op.u4_ts] = false;

                outInfo->mOwnedByUs = false;
                outQueue.erase(outQueue.begin());
                outInfo = NULL;
                notifyFillBufferDone(outHeader);
                outHeader = NULL;
 } else {
 /* If in flush mode and no output is returned by the codec,
                 * then come out of flush mode */
                mIsInFlush = false;

 /* If EOS was recieved on input port and there is no output
                 * from the codec, then signal EOS on output port */
 if (mReceivedEOS) {
                    outHeader->nFilledLen = 0;
                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;

                    outInfo->mOwnedByUs = false;
                    outQueue.erase(outQueue.begin());
                    outInfo = NULL;
                    notifyFillBufferDone(outHeader);
                    outHeader = NULL;
                    resetPlugin();
 }
 }
 }

 if (inHeader != NULL) {
            inInfo->mOwnedByUs = false;
            inQueue.erase(inQueue.begin());
            inInfo = NULL;
            notifyEmptyBufferDone(inHeader);
            inHeader = NULL;
 }
 }
}