IHEVCD_ERROR_T ihevcd_parse_slice_data(codec_t *ps_codec)
{

    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    WORD32 end_of_slice_flag = 0;
 sps_t *ps_sps;
 pps_t *ps_pps;
 slice_header_t *ps_slice_hdr;
    WORD32 end_of_pic;
 tile_t *ps_tile, *ps_tile_prev;
    WORD32 i;
    WORD32 ctb_addr;
    WORD32 tile_idx;
    WORD32 cabac_init_idc;
    WORD32 ctb_size;
    WORD32 num_ctb_in_row;
    WORD32 num_min4x4_in_ctb;
    WORD32 slice_qp;
    WORD32 slice_start_ctb_idx;
    WORD32 tile_start_ctb_idx;

    ps_slice_hdr = ps_codec->s_parse.ps_slice_hdr_base;
    ps_pps = ps_codec->s_parse.ps_pps_base;
    ps_sps = ps_codec->s_parse.ps_sps_base;

 /* Get current slice header, pps and sps */
    ps_slice_hdr += (ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1));
    ps_pps  += ps_slice_hdr->i1_pps_id;
    ps_sps  += ps_pps->i1_sps_id;

 if(0 != ps_codec->s_parse.i4_cur_slice_idx)
 {
 if(!ps_slice_hdr->i1_dependent_slice_flag)
 {
            ps_codec->s_parse.i4_cur_independent_slice_idx++;
 if(MAX_SLICE_HDR_CNT == ps_codec->s_parse.i4_cur_independent_slice_idx)
                ps_codec->s_parse.i4_cur_independent_slice_idx = 0;
 }
 }

    ctb_size = 1 << ps_sps->i1_log2_ctb_size;
    num_min4x4_in_ctb = (ctb_size / 4) * (ctb_size / 4);
    num_ctb_in_row = ps_sps->i2_pic_wd_in_ctb;

 /* Update the parse context */
 if(0 == ps_codec->i4_slice_error)
 {
        ps_codec->s_parse.i4_ctb_x = ps_slice_hdr->i2_ctb_x;
        ps_codec->s_parse.i4_ctb_y = ps_slice_hdr->i2_ctb_y;
 }
    ps_codec->s_parse.ps_pps = ps_pps;
    ps_codec->s_parse.ps_sps = ps_sps;
    ps_codec->s_parse.ps_slice_hdr = ps_slice_hdr;

 /* Derive Tile positions for the current CTB */
 /* Change this to lookup if required */
    ihevcd_get_tile_pos(ps_pps, ps_sps, ps_codec->s_parse.i4_ctb_x,
                        ps_codec->s_parse.i4_ctb_y,
 &ps_codec->s_parse.i4_ctb_tile_x,
 &ps_codec->s_parse.i4_ctb_tile_y,
 &tile_idx);
    ps_codec->s_parse.ps_tile = ps_pps->ps_tile + tile_idx;
    ps_codec->s_parse.i4_cur_tile_idx = tile_idx;
    ps_tile = ps_codec->s_parse.ps_tile;
 if(tile_idx)
        ps_tile_prev = ps_tile - 1;
 else
        ps_tile_prev = ps_tile;

 /* If the present slice is dependent, then store the previous
     * independent slices' ctb x and y values for decoding process */
 if(0 == ps_codec->i4_slice_error)
 {
 if(1 == ps_slice_hdr->i1_dependent_slice_flag)
 {
 /*If slice is present at the start of a new tile*/
 if((0 == ps_codec->s_parse.i4_ctb_tile_x) && (0 == ps_codec->s_parse.i4_ctb_tile_y))
 {
                ps_codec->s_parse.i4_ctb_slice_x = 0;
                ps_codec->s_parse.i4_ctb_slice_y = 0;
 }
 }

 if(!ps_slice_hdr->i1_dependent_slice_flag)
 {
            ps_codec->s_parse.i4_ctb_slice_x = 0;
            ps_codec->s_parse.i4_ctb_slice_y = 0;
 }
 }

 /* Frame level initializations */
 if((0 == ps_codec->s_parse.i4_ctb_y) &&
 (0 == ps_codec->s_parse.i4_ctb_x))
 {
        ret = ihevcd_parse_pic_init(ps_codec);
        RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);

        ps_codec->s_parse.pu4_pic_tu_idx[0] = 0;
        ps_codec->s_parse.pu4_pic_pu_idx[0] = 0;
        ps_codec->s_parse.i4_cur_independent_slice_idx = 0;
        ps_codec->s_parse.i4_ctb_tile_x = 0;
        ps_codec->s_parse.i4_ctb_tile_y = 0;
 }

 {
 /* Updating the poc list of current slice to ps_mv_buf */
 mv_buf_t *ps_mv_buf = ps_codec->s_parse.ps_cur_mv_buf;

 if(ps_slice_hdr->i1_num_ref_idx_l1_active != 0)
 {
 for(i = 0; i < ps_slice_hdr->i1_num_ref_idx_l1_active; i++)
 {
                ps_mv_buf->l1_collocated_poc[(ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1))][i] = ((pic_buf_t *)ps_slice_hdr->as_ref_pic_list1[i].pv_pic_buf)->i4_abs_poc;
                ps_mv_buf->u1_l1_collocated_poc_lt[(ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1))][i] = ((pic_buf_t *)ps_slice_hdr->as_ref_pic_list1[i].pv_pic_buf)->u1_used_as_ref;
 }
 }

 if(ps_slice_hdr->i1_num_ref_idx_l0_active != 0)
 {
 for(i = 0; i < ps_slice_hdr->i1_num_ref_idx_l0_active; i++)
 {
                ps_mv_buf->l0_collocated_poc[(ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1))][i] = ((pic_buf_t *)ps_slice_hdr->as_ref_pic_list0[i].pv_pic_buf)->i4_abs_poc;
                ps_mv_buf->u1_l0_collocated_poc_lt[(ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1))][i] = ((pic_buf_t *)ps_slice_hdr->as_ref_pic_list0[i].pv_pic_buf)->u1_used_as_ref;
 }
 }
 }

 /*Initialize the low delay flag at the beginning of every slice*/
 if((0 == ps_codec->s_parse.i4_ctb_slice_x) || (0 == ps_codec->s_parse.i4_ctb_slice_y))
 {
 /* Lowdelay flag */
        WORD32 cur_poc, ref_list_poc, flag = 1;
        cur_poc = ps_slice_hdr->i4_abs_pic_order_cnt;
 for(i = 0; i < ps_slice_hdr->i1_num_ref_idx_l0_active; i++)
 {
            ref_list_poc = ((mv_buf_t *)ps_slice_hdr->as_ref_pic_list0[i].pv_mv_buf)->i4_abs_poc;
 if(ref_list_poc > cur_poc)
 {
                flag = 0;
 break;
 }
 }
 if(flag && (ps_slice_hdr->i1_slice_type == BSLICE))
 {
 for(i = 0; i < ps_slice_hdr->i1_num_ref_idx_l1_active; i++)
 {
                ref_list_poc = ((mv_buf_t *)ps_slice_hdr->as_ref_pic_list1[i].pv_mv_buf)->i4_abs_poc;
 if(ref_list_poc > cur_poc)
 {
                    flag = 0;
 break;
 }
 }
 }
        ps_slice_hdr->i1_low_delay_flag = flag;
 }

 /* initialize the cabac init idc based on slice type */
 if(ps_slice_hdr->i1_slice_type == ISLICE)
 {
        cabac_init_idc = 0;
 }
 else if(ps_slice_hdr->i1_slice_type == PSLICE)
 {
        cabac_init_idc = ps_slice_hdr->i1_cabac_init_flag ? 2 : 1;
 }
 else
 {
        cabac_init_idc = ps_slice_hdr->i1_cabac_init_flag ? 1 : 2;
 }

    slice_qp = ps_slice_hdr->i1_slice_qp_delta + ps_pps->i1_pic_init_qp;
    slice_qp = CLIP3(slice_qp, 0, 51);

 /*Update QP value for every indepndent slice or for every dependent slice that begins at the start of a new tile*/
 if((0 == ps_slice_hdr->i1_dependent_slice_flag) ||
 ((1 == ps_slice_hdr->i1_dependent_slice_flag) && ((0 == ps_codec->s_parse.i4_ctb_tile_x) && (0 == ps_codec->s_parse.i4_ctb_tile_y))))
 {
        ps_codec->s_parse.u4_qp = slice_qp;
 }

 /*Cabac init at the beginning of a slice*/
 if((1 == ps_slice_hdr->i1_dependent_slice_flag) && (!((ps_codec->s_parse.i4_ctb_tile_x == 0) && (ps_codec->s_parse.i4_ctb_tile_y == 0))))
 {
 if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
 {
            ihevcd_cabac_reset(&ps_codec->s_parse.s_cabac,
 &ps_codec->s_parse.s_bitstrm);
 }
 }
 else if((0 == ps_pps->i1_entropy_coding_sync_enabled_flag) || (ps_pps->i1_entropy_coding_sync_enabled_flag && (0 != ps_codec->s_parse.i4_ctb_x)))
 {
        ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
 &ps_codec->s_parse.s_bitstrm,
                                slice_qp,
                                cabac_init_idc,
 &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);
 if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
 {
            ps_codec->i4_slice_error = 1;
            end_of_slice_flag = 1;
            ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
 }
 }

 do
 {

 {
            WORD32 cur_ctb_idx = ps_codec->s_parse.i4_ctb_x
 + ps_codec->s_parse.i4_ctb_y * (ps_sps->i2_pic_wd_in_ctb);
 if(1 == ps_codec->i4_num_cores && 0 == cur_ctb_idx % RESET_TU_BUF_NCTB)
 {
                ps_codec->s_parse.ps_tu = ps_codec->s_parse.ps_pic_tu;
                ps_codec->s_parse.i4_pic_tu_idx = 0;
 }
 }

        end_of_pic = 0;
 /* Section:7.3.7 Coding tree unit syntax */
 /* coding_tree_unit() inlined here */
 /* If number of cores is greater than 1, then add job to the queue */
 /* At the start of ctb row parsing in a tile, queue a job for processing the current tile row */
        ps_codec->s_parse.i4_ctb_num_pcm_blks = 0;

 /*At the beginning of each tile-which is not the beginning of a slice, cabac context must be initialized.
         * Hence, check for the tile beginning here */
 if(((0 == ps_codec->s_parse.i4_ctb_tile_x) && (0 == ps_codec->s_parse.i4_ctb_tile_y))
 && (!((ps_tile->u1_pos_x == 0) && (ps_tile->u1_pos_y == 0)))
 && (!((0 == ps_codec->s_parse.i4_ctb_slice_x) && (0 == ps_codec->s_parse.i4_ctb_slice_y))))
 {
            slice_qp = ps_slice_hdr->i1_slice_qp_delta + ps_pps->i1_pic_init_qp;
            slice_qp = CLIP3(slice_qp, 0, 51);
            ps_codec->s_parse.u4_qp = slice_qp;

            ihevcd_get_tile_pos(ps_pps, ps_sps, ps_codec->s_parse.i4_ctb_x,
                                ps_codec->s_parse.i4_ctb_y,
 &ps_codec->s_parse.i4_ctb_tile_x,
 &ps_codec->s_parse.i4_ctb_tile_y,
 &tile_idx);

            ps_codec->s_parse.ps_tile = ps_pps->ps_tile + tile_idx;
            ps_codec->s_parse.i4_cur_tile_idx = tile_idx;
            ps_tile_prev = ps_tile - 1;

            tile_start_ctb_idx = ps_tile->u1_pos_x
 + ps_tile->u1_pos_y * (ps_sps->i2_pic_wd_in_ctb);

            slice_start_ctb_idx =  ps_slice_hdr->i2_ctb_x
 + ps_slice_hdr->i2_ctb_y * (ps_sps->i2_pic_wd_in_ctb);

 /*For slices that span across multiple tiles*/
 if(slice_start_ctb_idx < tile_start_ctb_idx)
 { /* 2 Cases
             * 1 - slice spans across frame-width- but does not start from 1st column
             * 2 - Slice spans across multiple tiles anywhere is a frame
             */
                ps_codec->s_parse.i4_ctb_slice_y = ps_tile->u1_pos_y - ps_slice_hdr->i2_ctb_y;
 if(!(((ps_slice_hdr->i2_ctb_x + ps_tile_prev->u2_wd) % ps_sps->i2_pic_wd_in_ctb) == ps_tile->u1_pos_x)) //Case 2
 {
 if(ps_slice_hdr->i2_ctb_y <= ps_tile->u1_pos_y)
 {
 if(ps_slice_hdr->i2_ctb_x > ps_tile->u1_pos_x)
 {
                            ps_codec->s_parse.i4_ctb_slice_y -= 1;
 }
 }
 }
 /*ps_codec->s_parse.i4_ctb_slice_y = ps_tile->u1_pos_y - ps_slice_hdr->i2_ctb_y;
                if (ps_slice_hdr->i2_ctb_y <= ps_tile->u1_pos_y)
                {
                    if (ps_slice_hdr->i2_ctb_x > ps_tile->u1_pos_x )
                    {
                        ps_codec->s_parse.i4_ctb_slice_y -= 1 ;
                    }
                }*/
 }

 if(!ps_slice_hdr->i1_dependent_slice_flag)
 {
                ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
 &ps_codec->s_parse.s_bitstrm,
                                        slice_qp,
                                        cabac_init_idc,
 &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);
 if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
 {
                    ps_codec->i4_slice_error = 1;
                    end_of_slice_flag = 1;
                    ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
 }

 }
 }
 /* If number of cores is greater than 1, then add job to the queue */
 /* At the start of ctb row parsing in a tile, queue a job for processing the current tile row */

 if(0 == ps_codec->s_parse.i4_ctb_tile_x)
 {

 if(1 < ps_codec->i4_num_cores)
 {
 proc_job_t s_job;
                IHEVCD_ERROR_T ret;
                s_job.i4_cmd    = CMD_PROCESS;
                s_job.i2_ctb_cnt = (WORD16)ps_tile->u2_wd;
                s_job.i2_ctb_x = (WORD16)ps_codec->s_parse.i4_ctb_x;
                s_job.i2_ctb_y = (WORD16)ps_codec->s_parse.i4_ctb_y;
                s_job.i2_slice_idx = (WORD16)ps_codec->s_parse.i4_cur_slice_idx;
                s_job.i4_tu_coeff_data_ofst = (UWORD8 *)ps_codec->s_parse.pv_tu_coeff_data -
 (UWORD8 *)ps_codec->s_parse.pv_pic_tu_coeff_data;
                ret = ihevcd_jobq_queue((jobq_t *)ps_codec->s_parse.pv_proc_jobq, &s_job, sizeof(proc_job_t), 1);

 if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
 return ret;
 }
 else
 {
 process_ctxt_t *ps_proc = &ps_codec->as_process[0];
                WORD32 tu_coeff_data_ofst = (UWORD8 *)ps_codec->s_parse.pv_tu_coeff_data -
 (UWORD8 *)ps_codec->s_parse.pv_pic_tu_coeff_data;

 /* If the codec is running in single core mode,
                 * initialize zeroth process context
                 * TODO: Dual core mode might need a different implementation instead of jobq
                 */

                ps_proc->i4_ctb_cnt = ps_tile->u2_wd;
                ps_proc->i4_ctb_x   = ps_codec->s_parse.i4_ctb_x;
                ps_proc->i4_ctb_y   = ps_codec->s_parse.i4_ctb_y;
                ps_proc->i4_cur_slice_idx = ps_codec->s_parse.i4_cur_slice_idx;

                ihevcd_init_proc_ctxt(ps_proc, tu_coeff_data_ofst);
 }
 }

 /* Restore cabac context model from top right CTB if entropy sync is enabled */
 if(ps_pps->i1_entropy_coding_sync_enabled_flag)
 {
 /*TODO Handle single CTB and top-right belonging to a different slice */
 if(0 == ps_codec->s_parse.i4_ctb_x)
 {
                WORD32 default_ctxt = 0;

 if((0 == ps_codec->s_parse.i4_ctb_slice_y) && (!ps_slice_hdr->i1_dependent_slice_flag))
                    default_ctxt = 1;
 if(1 == ps_sps->i2_pic_wd_in_ctb)
                    default_ctxt = 1;

                ps_codec->s_parse.u4_qp = slice_qp;
 if(default_ctxt)
 {
                    ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
 &ps_codec->s_parse.s_bitstrm,
                                            slice_qp,
                                            cabac_init_idc,
 &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0]);

 if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
 {
                        ps_codec->i4_slice_error = 1;
                        end_of_slice_flag = 1;
                        ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
 }
 }
 else
 {
                    ret = ihevcd_cabac_init(&ps_codec->s_parse.s_cabac,
 &ps_codec->s_parse.s_bitstrm,
                                            slice_qp,
                                            cabac_init_idc,
 (const UWORD8 *)&ps_codec->s_parse.s_cabac.au1_ctxt_models_sync);

 if(ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
 {
                        ps_codec->i4_slice_error = 1;
                        end_of_slice_flag = 1;
                        ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
 }
 }
 }
 }

 if(0 == ps_codec->i4_slice_error)
 {
 if(ps_slice_hdr->i1_slice_sao_luma_flag || ps_slice_hdr->i1_slice_sao_chroma_flag)
                ihevcd_parse_sao(ps_codec);
 }
 else
 {
 sao_t *ps_sao = ps_codec->s_parse.ps_pic_sao +
                            ps_codec->s_parse.i4_ctb_x +
                            ps_codec->s_parse.i4_ctb_y * ps_sps->i2_pic_wd_in_ctb;

 /* Default values */
            ps_sao->b3_y_type_idx = 0;
            ps_sao->b3_cb_type_idx = 0;
            ps_sao->b3_cr_type_idx = 0;
 }

 {
            WORD32 ctb_indx;
            ctb_indx = ps_codec->s_parse.i4_ctb_x + ps_sps->i2_pic_wd_in_ctb * ps_codec->s_parse.i4_ctb_y;
            ps_codec->s_parse.s_bs_ctxt.pu1_pic_qp_const_in_ctb[ctb_indx >> 3] |= (1 << (ctb_indx & 7));
 {
                UWORD16 *pu1_slice_idx = ps_codec->s_parse.pu1_slice_idx;
                pu1_slice_idx[ctb_indx] = ps_codec->s_parse.i4_cur_independent_slice_idx;
 }
 }

 if(0 == ps_codec->i4_slice_error)
 {
 tu_t *ps_tu = ps_codec->s_parse.ps_tu;
            WORD32 i4_tu_cnt = ps_codec->s_parse.s_cu.i4_tu_cnt;
            WORD32 i4_pic_tu_idx = ps_codec->s_parse.i4_pic_tu_idx;

 pu_t *ps_pu = ps_codec->s_parse.ps_pu;
            WORD32 i4_pic_pu_idx = ps_codec->s_parse.i4_pic_pu_idx;

            UWORD8 *pu1_tu_coeff_data = (UWORD8 *)ps_codec->s_parse.pv_tu_coeff_data;

            ret = ihevcd_parse_coding_quadtree(ps_codec,
 (ps_codec->s_parse.i4_ctb_x << ps_sps->i1_log2_ctb_size),
 (ps_codec->s_parse.i4_ctb_y << ps_sps->i1_log2_ctb_size),
                                               ps_sps->i1_log2_ctb_size,
 0);
 /* Check for error */

             if (ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
             {
                 /* Reset tu and pu parameters, and signal current ctb as skip */
                 WORD32 tu_coeff_data_reset_size;

                 ps_codec->s_parse.ps_tu = ps_tu;
                 ps_codec->s_parse.s_cu.i4_tu_cnt = i4_tu_cnt;
                 ps_codec->s_parse.i4_pic_tu_idx = i4_pic_tu_idx;

                 ps_codec->s_parse.ps_pu = ps_pu;
                 ps_codec->s_parse.i4_pic_pu_idx = i4_pic_pu_idx;

                 tu_coeff_data_reset_size = (UWORD8 *)ps_codec->s_parse.pv_tu_coeff_data - pu1_tu_coeff_data;
                 memset(pu1_tu_coeff_data, 0, tu_coeff_data_reset_size);
                 ps_codec->s_parse.pv_tu_coeff_data = (void *)pu1_tu_coeff_data;

                ihevcd_set_ctb_skip(ps_codec);

                 /* Set slice error to suppress further parsing and
                  * signal end of slice.
                 */
                ps_codec->i4_slice_error = 1;
                end_of_slice_flag = 1;
                ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
 }

         }
         else
         {
            ihevcd_set_ctb_skip(ps_codec);
         }

         if(0 == ps_codec->i4_slice_error)
            end_of_slice_flag = ihevcd_cabac_decode_terminate(&ps_codec->s_parse.s_cabac, &ps_codec->s_parse.s_bitstrm);

        AEV_TRACE("end_of_slice_flag", end_of_slice_flag, ps_codec->s_parse.s_cabac.u4_range);

 /* In case of tiles or entropy sync, terminate cabac and copy cabac context backed up at the end of top-right CTB */
 if(ps_pps->i1_tiles_enabled_flag || ps_pps->i1_entropy_coding_sync_enabled_flag)
 {
            WORD32 end_of_tile = 0;
            WORD32 end_of_tile_row = 0;

 /* Take a back up of cabac context models if entropy sync is enabled */
 if(ps_pps->i1_entropy_coding_sync_enabled_flag || ps_pps->i1_tiles_enabled_flag)
 {
 if(1 == ps_codec->s_parse.i4_ctb_x)
 {
                    WORD32 size = sizeof(ps_codec->s_parse.s_cabac.au1_ctxt_models);
                    memcpy(&ps_codec->s_parse.s_cabac.au1_ctxt_models_sync, &ps_codec->s_parse.s_cabac.au1_ctxt_models, size);
 }
 }

 /* Since tiles and entropy sync are not enabled simultaneously, the following will not result in any problems */
 if((ps_codec->s_parse.i4_ctb_tile_x + 1) == (ps_tile->u2_wd))
 {
                end_of_tile_row = 1;
 if((ps_codec->s_parse.i4_ctb_tile_y + 1) == ps_tile->u2_ht)
                    end_of_tile = 1;
 }
 if((0 == end_of_slice_flag) &&
 ((ps_pps->i1_tiles_enabled_flag && end_of_tile) ||
 (ps_pps->i1_entropy_coding_sync_enabled_flag && end_of_tile_row)))
 {
                WORD32 end_of_sub_stream_one_bit;
                end_of_sub_stream_one_bit = ihevcd_cabac_decode_terminate(&ps_codec->s_parse.s_cabac, &ps_codec->s_parse.s_bitstrm);
                AEV_TRACE("end_of_sub_stream_one_bit", end_of_sub_stream_one_bit, ps_codec->s_parse.s_cabac.u4_range);

 /* TODO: Remove the check for offset when HM is updated to include a byte unconditionally even for aligned location */
 /* For Ittiam streams this check should not be there, for HM9.1 streams this should be there */
 if(ps_codec->s_parse.s_bitstrm.u4_bit_ofst % 8)
                    ihevcd_bits_flush_to_byte_boundary(&ps_codec->s_parse.s_bitstrm);

                UNUSED(end_of_sub_stream_one_bit);
 }
 }
 {
            WORD32 ctb_indx;

            ctb_addr = ps_codec->s_parse.i4_ctb_y * num_ctb_in_row + ps_codec->s_parse.i4_ctb_x;

            ctb_indx = ++ctb_addr;

 /* Store pu_idx for next CTB in frame level pu_idx array */

 if((ps_tile->u2_wd == (ps_codec->s_parse.i4_ctb_tile_x + 1)) && (ps_tile->u2_wd != ps_sps->i2_pic_wd_in_ctb))
 {
                ctb_indx = (ps_sps->i2_pic_wd_in_ctb * (ps_codec->s_parse.i4_ctb_tile_y + 1 + ps_tile->u1_pos_y)) + ps_tile->u1_pos_x; //idx is the beginning of next row in current tile.
 if(ps_tile->u2_ht == (ps_codec->s_parse.i4_ctb_tile_y + 1))
 {
 if((ps_tile->u2_wd + ps_tile->u1_pos_x == ps_sps->i2_pic_wd_in_ctb) && ((ps_tile->u2_ht + ps_tile->u1_pos_y == ps_sps->i2_pic_ht_in_ctb)))
 {
                        ctb_indx = ctb_addr; //Next continuous ctb address
 }
 else //Not last tile's end , but a tile end
 {
 tile_t *ps_next_tile = ps_codec->s_parse.ps_tile + 1;
                        ctb_indx = ps_next_tile->u1_pos_x + (ps_next_tile->u1_pos_y * ps_sps->i2_pic_wd_in_ctb); //idx is the beginning of first row in next tile.
 }
 }
 }

            ps_codec->s_parse.pu4_pic_pu_idx[ctb_indx] = ps_codec->s_parse.i4_pic_pu_idx;
            ps_codec->s_parse.i4_next_pu_ctb_cnt = ctb_indx;

            ps_codec->s_parse.pu1_pu_map += num_min4x4_in_ctb;

 /* Store tu_idx for next CTB in frame level tu_idx array */
 if(1 == ps_codec->i4_num_cores)
 {
                ctb_indx = (0 == ctb_addr % RESET_TU_BUF_NCTB) ?
                                RESET_TU_BUF_NCTB : ctb_addr % RESET_TU_BUF_NCTB;

 if((ps_tile->u2_wd == (ps_codec->s_parse.i4_ctb_tile_x + 1)) && (ps_tile->u2_wd != ps_sps->i2_pic_wd_in_ctb))
 {
                    ctb_indx = (ps_sps->i2_pic_wd_in_ctb * (ps_codec->s_parse.i4_ctb_tile_y + 1 + ps_tile->u1_pos_y)) + ps_tile->u1_pos_x; //idx is the beginning of next row in current tile.
 if(ps_tile->u2_ht == (ps_codec->s_parse.i4_ctb_tile_y + 1))
 {
 if((ps_tile->u2_wd + ps_tile->u1_pos_x == ps_sps->i2_pic_wd_in_ctb) && ((ps_tile->u2_ht + ps_tile->u1_pos_y == ps_sps->i2_pic_ht_in_ctb)))
 {
                            ctb_indx = (0 == ctb_addr % RESET_TU_BUF_NCTB) ?
                                            RESET_TU_BUF_NCTB : ctb_addr % RESET_TU_BUF_NCTB;
 }
 else //Not last tile's end , but a tile end
 {
 tile_t *ps_next_tile = ps_codec->s_parse.ps_tile + 1;
                            ctb_indx =  ps_next_tile->u1_pos_x + (ps_next_tile->u1_pos_y * ps_sps->i2_pic_wd_in_ctb); //idx is the beginning of first row in next tile.
 }
 }
 }
                ps_codec->s_parse.i4_next_tu_ctb_cnt = ctb_indx;
                ps_codec->s_parse.pu4_pic_tu_idx[ctb_indx] = ps_codec->s_parse.i4_pic_tu_idx;
 }
 else
 {
                ctb_indx = ctb_addr;
 if((ps_tile->u2_wd == (ps_codec->s_parse.i4_ctb_tile_x + 1)) && (ps_tile->u2_wd != ps_sps->i2_pic_wd_in_ctb))
 {
                    ctb_indx = (ps_sps->i2_pic_wd_in_ctb * (ps_codec->s_parse.i4_ctb_tile_y + 1 + ps_tile->u1_pos_y)) + ps_tile->u1_pos_x; //idx is the beginning of next row in current tile.
 if(ps_tile->u2_ht == (ps_codec->s_parse.i4_ctb_tile_y + 1))
 {
 if((ps_tile->u2_wd + ps_tile->u1_pos_x == ps_sps->i2_pic_wd_in_ctb) && ((ps_tile->u2_ht + ps_tile->u1_pos_y == ps_sps->i2_pic_ht_in_ctb)))
 {
                            ctb_indx = ctb_addr;
 }
 else //Not last tile's end , but a tile end
 {
 tile_t *ps_next_tile = ps_codec->s_parse.ps_tile + 1;
                            ctb_indx =  ps_next_tile->u1_pos_x + (ps_next_tile->u1_pos_y * ps_sps->i2_pic_wd_in_ctb); //idx is the beginning of first row in next tile.
 }
 }
 }
                ps_codec->s_parse.i4_next_tu_ctb_cnt = ctb_indx;
                ps_codec->s_parse.pu4_pic_tu_idx[ctb_indx] = ps_codec->s_parse.i4_pic_tu_idx;
 }
            ps_codec->s_parse.pu1_tu_map += num_min4x4_in_ctb;
 }

 if(ps_codec->i4_num_cores <= MV_PRED_NUM_CORES_THRESHOLD)
 {
 /*************************************************/
 /****************   MV pred **********************/
 /*************************************************/
            WORD8 u1_top_ctb_avail = 1;
            WORD8 u1_left_ctb_avail = 1;
            WORD8 u1_top_lt_ctb_avail = 1;
            WORD8 u1_top_rt_ctb_avail = 1;
            WORD16 i2_wd_in_ctb;

            tile_start_ctb_idx = ps_tile->u1_pos_x
 + ps_tile->u1_pos_y * (ps_sps->i2_pic_wd_in_ctb);

            slice_start_ctb_idx =  ps_slice_hdr->i2_ctb_x
 + ps_slice_hdr->i2_ctb_y * (ps_sps->i2_pic_wd_in_ctb);

 if((slice_start_ctb_idx < tile_start_ctb_idx))
 {
                i2_wd_in_ctb = ps_sps->i2_pic_wd_in_ctb;
 }
 else
 {
                i2_wd_in_ctb = ps_tile->u2_wd;
 }
 /* slice and tile boundaries */
 if((0 == ps_codec->s_parse.i4_ctb_y) || (0 == ps_codec->s_parse.i4_ctb_tile_y))
 {
                u1_top_ctb_avail = 0;
                u1_top_lt_ctb_avail = 0;
                u1_top_rt_ctb_avail = 0;
 }

 if((0 == ps_codec->s_parse.i4_ctb_x) || (0 == ps_codec->s_parse.i4_ctb_tile_x))
 {
                u1_left_ctb_avail = 0;
                u1_top_lt_ctb_avail = 0;
 if((0 == ps_codec->s_parse.i4_ctb_slice_y) || (0 == ps_codec->s_parse.i4_ctb_tile_y))
 {
                    u1_top_ctb_avail = 0;
 if((i2_wd_in_ctb - 1) != ps_codec->s_parse.i4_ctb_slice_x) //TODO: For tile, not implemented
 {
                        u1_top_rt_ctb_avail = 0;
 }
 }
 }
 /*For slices not beginning at start of a ctb row*/
 else if(ps_codec->s_parse.i4_ctb_x > 0)
 {
 if((0 == ps_codec->s_parse.i4_ctb_slice_y) || (0 == ps_codec->s_parse.i4_ctb_tile_y))
 {
                    u1_top_ctb_avail = 0;
                    u1_top_lt_ctb_avail = 0;
 if(0 == ps_codec->s_parse.i4_ctb_slice_x)
 {
                        u1_left_ctb_avail = 0;
 }
 if((i2_wd_in_ctb - 1) != ps_codec->s_parse.i4_ctb_slice_x)
 {
                        u1_top_rt_ctb_avail = 0;
 }
 }
 else if((1 == ps_codec->s_parse.i4_ctb_slice_y) && (0 == ps_codec->s_parse.i4_ctb_slice_x))
 {
                    u1_top_lt_ctb_avail = 0;
 }
 }

 if(((ps_sps->i2_pic_wd_in_ctb - 1) == ps_codec->s_parse.i4_ctb_x) || ((ps_tile->u2_wd - 1) == ps_codec->s_parse.i4_ctb_tile_x))
 {
                u1_top_rt_ctb_avail = 0;
 }

 if(PSLICE == ps_slice_hdr->i1_slice_type
 || BSLICE == ps_slice_hdr->i1_slice_type)
 {
 mv_ctxt_t s_mv_ctxt;
 process_ctxt_t *ps_proc;
                UWORD32 *pu4_ctb_top_pu_idx;
                UWORD32 *pu4_ctb_left_pu_idx;
                UWORD32 *pu4_ctb_top_left_pu_idx;
                WORD32 i4_ctb_pu_cnt;
                WORD32 cur_ctb_idx;
                WORD32 next_ctb_idx;
                WORD32 cur_pu_idx;
                ps_proc = &ps_codec->as_process[(ps_codec->i4_num_cores == 1) ? 1 : (ps_codec->i4_num_cores - 1)];
                cur_ctb_idx = ps_codec->s_parse.i4_ctb_x
 + ps_codec->s_parse.i4_ctb_y * (ps_sps->i2_pic_wd_in_ctb);
                next_ctb_idx = ps_codec->s_parse.i4_next_pu_ctb_cnt;
                i4_ctb_pu_cnt = ps_codec->s_parse.pu4_pic_pu_idx[next_ctb_idx]
 - ps_codec->s_parse.pu4_pic_pu_idx[cur_ctb_idx];

                cur_pu_idx = ps_codec->s_parse.pu4_pic_pu_idx[cur_ctb_idx];

                pu4_ctb_top_pu_idx = ps_proc->pu4_pic_pu_idx_top
 + (ps_codec->s_parse.i4_ctb_x * ctb_size / MIN_PU_SIZE);
                pu4_ctb_left_pu_idx = ps_proc->pu4_pic_pu_idx_left;
                pu4_ctb_top_left_pu_idx = &ps_proc->u4_ctb_top_left_pu_idx;

 /* Initializing s_mv_ctxt */
 {
                    s_mv_ctxt.ps_pps = ps_pps;
                    s_mv_ctxt.ps_sps = ps_sps;
                    s_mv_ctxt.ps_slice_hdr = ps_slice_hdr;
                    s_mv_ctxt.i4_ctb_x = ps_codec->s_parse.i4_ctb_x;
                    s_mv_ctxt.i4_ctb_y = ps_codec->s_parse.i4_ctb_y;
                    s_mv_ctxt.ps_pu = &ps_codec->s_parse.ps_pic_pu[cur_pu_idx];
                    s_mv_ctxt.ps_pic_pu = ps_codec->s_parse.ps_pic_pu;
                    s_mv_ctxt.ps_tile = ps_tile;
                    s_mv_ctxt.pu4_pic_pu_idx_map = ps_proc->pu4_pic_pu_idx_map;
                    s_mv_ctxt.pu4_pic_pu_idx = ps_codec->s_parse.pu4_pic_pu_idx;
                    s_mv_ctxt.pu1_pic_pu_map = ps_codec->s_parse.pu1_pic_pu_map;
                    s_mv_ctxt.i4_ctb_pu_cnt = i4_ctb_pu_cnt;
                    s_mv_ctxt.i4_ctb_start_pu_idx = cur_pu_idx;
                    s_mv_ctxt.u1_top_ctb_avail = u1_top_ctb_avail;
                    s_mv_ctxt.u1_top_rt_ctb_avail = u1_top_rt_ctb_avail;
                    s_mv_ctxt.u1_top_lt_ctb_avail = u1_top_lt_ctb_avail;
                    s_mv_ctxt.u1_left_ctb_avail = u1_left_ctb_avail;
 }

                ihevcd_get_mv_ctb(&s_mv_ctxt, pu4_ctb_top_pu_idx,
                                  pu4_ctb_left_pu_idx, pu4_ctb_top_left_pu_idx);

 }
 else
 {
                WORD32 num_minpu_in_ctb = (ctb_size / MIN_PU_SIZE) * (ctb_size / MIN_PU_SIZE);
                UWORD8 *pu1_pic_pu_map_ctb = ps_codec->s_parse.pu1_pic_pu_map +
 (ps_codec->s_parse.i4_ctb_x + ps_codec->s_parse.i4_ctb_y * ps_sps->i2_pic_wd_in_ctb) * num_minpu_in_ctb;
 process_ctxt_t *ps_proc = &ps_codec->as_process[(ps_codec->i4_num_cores == 1) ? 1 : (ps_codec->i4_num_cores - 1)];
                WORD32 row, col;
                WORD32 pu_cnt;
                WORD32 num_pu_per_ctb;
                WORD32 cur_ctb_idx;
                WORD32 next_ctb_idx;
                WORD32 ctb_start_pu_idx;
                UWORD32 *pu4_nbr_pu_idx = ps_proc->pu4_pic_pu_idx_map;
                WORD32 nbr_pu_idx_strd = MAX_CTB_SIZE / MIN_PU_SIZE + 2;
 pu_t *ps_pu;

 for(row = 0; row < ctb_size / MIN_PU_SIZE; row++)
 {
 for(col = 0; col < ctb_size / MIN_PU_SIZE; col++)
 {
                        pu1_pic_pu_map_ctb[row * ctb_size / MIN_PU_SIZE + col] = 0;
 }
 }

 /* Neighbor PU idx update inside CTB */
 /* 1byte per 4x4. Indicates the PU idx that 4x4 block belongs to */

                cur_ctb_idx = ps_codec->s_parse.i4_ctb_x
 + ps_codec->s_parse.i4_ctb_y * (ps_sps->i2_pic_wd_in_ctb);
                next_ctb_idx = ps_codec->s_parse.i4_next_pu_ctb_cnt;
                num_pu_per_ctb = ps_codec->s_parse.pu4_pic_pu_idx[next_ctb_idx]
 - ps_codec->s_parse.pu4_pic_pu_idx[cur_ctb_idx];
                ctb_start_pu_idx = ps_codec->s_parse.pu4_pic_pu_idx[cur_ctb_idx];
                ps_pu = &ps_codec->s_parse.ps_pic_pu[ctb_start_pu_idx];

 for(pu_cnt = 0; pu_cnt < num_pu_per_ctb; pu_cnt++, ps_pu++)
 {
                    UWORD32 cur_pu_idx;
                    WORD32 pu_ht = (ps_pu->b4_ht + 1) << 2;
                    WORD32 pu_wd = (ps_pu->b4_wd + 1) << 2;

                    cur_pu_idx = ctb_start_pu_idx + pu_cnt;

 for(row = 0; row < pu_ht / MIN_PU_SIZE; row++)
 for(col = 0; col < pu_wd / MIN_PU_SIZE; col++)
                            pu4_nbr_pu_idx[(1 + ps_pu->b4_pos_x + col)
 + (1 + ps_pu->b4_pos_y + row)
 * nbr_pu_idx_strd] =
                                            cur_pu_idx;
 }

 /* Updating Top and Left pointers */
 {
                    WORD32 rows_remaining = ps_sps->i2_pic_height_in_luma_samples
 - (ps_codec->s_parse.i4_ctb_y << ps_sps->i1_log2_ctb_size);
                    WORD32 ctb_size_left = MIN(ctb_size, rows_remaining);

 /* Top Left */
 /* saving top left before updating top ptr, as updating top ptr will overwrite the top left for the next ctb */
                    ps_proc->u4_ctb_top_left_pu_idx = ps_proc->pu4_pic_pu_idx_top[(ps_codec->s_parse.i4_ctb_x * ctb_size / MIN_PU_SIZE) + ctb_size / MIN_PU_SIZE - 1];
 for(i = 0; i < ctb_size / MIN_PU_SIZE; i++)
 {
 /* Left */
 /* Last column of au4_nbr_pu_idx */
                        ps_proc->pu4_pic_pu_idx_left[i] = pu4_nbr_pu_idx[(ctb_size / MIN_PU_SIZE)
 + (i + 1) * nbr_pu_idx_strd];
 /* Top */
 /* Last row of au4_nbr_pu_idx */
                        ps_proc->pu4_pic_pu_idx_top[(ps_codec->s_parse.i4_ctb_x * ctb_size / MIN_PU_SIZE) + i] =
                                        pu4_nbr_pu_idx[(ctb_size_left / MIN_PU_SIZE) * nbr_pu_idx_strd + i + 1];

 }
 }
 }

 /*************************************************/
 /******************  BS, QP  *********************/
 /*************************************************/
 /* Check if deblock is disabled for the current slice or if it is disabled for the current picture
             * because of disable deblock api
             */
 if(0 == ps_codec->i4_disable_deblk_pic)
 {
 if((0 == ps_slice_hdr->i1_slice_disable_deblocking_filter_flag) &&
 (0 == ps_codec->i4_slice_error))
 {
                    WORD32 i4_ctb_tu_cnt;
                    WORD32 cur_ctb_idx, next_ctb_idx;
                    WORD32 cur_pu_idx;
                    WORD32 cur_tu_idx;
 process_ctxt_t *ps_proc;

                    ps_proc = &ps_codec->as_process[(ps_codec->i4_num_cores == 1) ? 1 : (ps_codec->i4_num_cores - 1)];
                    cur_ctb_idx = ps_codec->s_parse.i4_ctb_x
 + ps_codec->s_parse.i4_ctb_y * (ps_sps->i2_pic_wd_in_ctb);

                    cur_pu_idx = ps_codec->s_parse.pu4_pic_pu_idx[cur_ctb_idx];
                    next_ctb_idx = ps_codec->s_parse.i4_next_tu_ctb_cnt;
 if(1 == ps_codec->i4_num_cores)
 {
                        i4_ctb_tu_cnt = ps_codec->s_parse.pu4_pic_tu_idx[next_ctb_idx] -
                                        ps_codec->s_parse.pu4_pic_tu_idx[cur_ctb_idx % RESET_TU_BUF_NCTB];

                        cur_tu_idx = ps_codec->s_parse.pu4_pic_tu_idx[cur_ctb_idx % RESET_TU_BUF_NCTB];
 }
 else
 {
                        i4_ctb_tu_cnt = ps_codec->s_parse.pu4_pic_tu_idx[next_ctb_idx] -
                                        ps_codec->s_parse.pu4_pic_tu_idx[cur_ctb_idx];

                        cur_tu_idx = ps_codec->s_parse.pu4_pic_tu_idx[cur_ctb_idx];
 }

                    ps_codec->s_parse.s_bs_ctxt.ps_pps = ps_codec->s_parse.ps_pps;
                    ps_codec->s_parse.s_bs_ctxt.ps_sps = ps_codec->s_parse.ps_sps;
                    ps_codec->s_parse.s_bs_ctxt.ps_codec = ps_codec;
                    ps_codec->s_parse.s_bs_ctxt.i4_ctb_tu_cnt = i4_ctb_tu_cnt;
                    ps_codec->s_parse.s_bs_ctxt.i4_ctb_x = ps_codec->s_parse.i4_ctb_x;
                    ps_codec->s_parse.s_bs_ctxt.i4_ctb_y = ps_codec->s_parse.i4_ctb_y;
                    ps_codec->s_parse.s_bs_ctxt.i4_ctb_tile_x = ps_codec->s_parse.i4_ctb_tile_x;
                    ps_codec->s_parse.s_bs_ctxt.i4_ctb_tile_y = ps_codec->s_parse.i4_ctb_tile_y;
                    ps_codec->s_parse.s_bs_ctxt.i4_ctb_slice_x = ps_codec->s_parse.i4_ctb_slice_x;
                    ps_codec->s_parse.s_bs_ctxt.i4_ctb_slice_y = ps_codec->s_parse.i4_ctb_slice_y;
                    ps_codec->s_parse.s_bs_ctxt.ps_tu = &ps_codec->s_parse.ps_pic_tu[cur_tu_idx];
                    ps_codec->s_parse.s_bs_ctxt.ps_pu = &ps_codec->s_parse.ps_pic_pu[cur_pu_idx];
                    ps_codec->s_parse.s_bs_ctxt.pu4_pic_pu_idx_map = ps_proc->pu4_pic_pu_idx_map;
                    ps_codec->s_parse.s_bs_ctxt.i4_next_pu_ctb_cnt = ps_codec->s_parse.i4_next_pu_ctb_cnt;
                    ps_codec->s_parse.s_bs_ctxt.i4_next_tu_ctb_cnt = ps_codec->s_parse.i4_next_tu_ctb_cnt;
                    ps_codec->s_parse.s_bs_ctxt.pu1_slice_idx = ps_codec->s_parse.pu1_slice_idx;
                    ps_codec->s_parse.s_bs_ctxt.ps_slice_hdr = ps_codec->s_parse.ps_slice_hdr;
                    ps_codec->s_parse.s_bs_ctxt.ps_tile = ps_codec->s_parse.ps_tile;

 if(ISLICE == ps_slice_hdr->i1_slice_type)
 {
                        ihevcd_ctb_boundary_strength_islice(&ps_codec->s_parse.s_bs_ctxt);
 }
 else
 {
                        ihevcd_ctb_boundary_strength_pbslice(&ps_codec->s_parse.s_bs_ctxt);
 }
 }
 else
 {
                    WORD32 bs_strd = (ps_sps->i2_pic_wd_in_ctb + 1) * (ctb_size * ctb_size / 8 / 16);

                    UWORD32 *pu4_vert_bs = (UWORD32 *)((UWORD8 *)ps_codec->s_parse.s_bs_ctxt.pu4_pic_vert_bs +
                                    ps_codec->s_parse.i4_ctb_x * (ctb_size * ctb_size / 8 / 16) +
                                    ps_codec->s_parse.i4_ctb_y * bs_strd);
                    UWORD32 *pu4_horz_bs = (UWORD32 *)((UWORD8 *)ps_codec->s_parse.s_bs_ctxt.pu4_pic_horz_bs +
                                    ps_codec->s_parse.i4_ctb_x * (ctb_size * ctb_size / 8 / 16) +
                                    ps_codec->s_parse.i4_ctb_y * bs_strd);

                    memset(pu4_vert_bs, 0, (ctb_size / 8 + 1) * (ctb_size / 4) / 8 * 2);
                    memset(pu4_horz_bs, 0, (ctb_size / 8) * (ctb_size / 4) / 8 * 2);

 }
 }

 }

 /* Update the parse status map */
 {
 sps_t *ps_sps = ps_codec->s_parse.ps_sps;
            UWORD8 *pu1_buf;
            WORD32 idx;
            idx = (ps_codec->s_parse.i4_ctb_x);
            idx += ((ps_codec->s_parse.i4_ctb_y) * ps_sps->i2_pic_wd_in_ctb);
            pu1_buf = (ps_codec->pu1_parse_map + idx);
 *pu1_buf = 1;
 }

 /* Increment CTB x and y positions */
        ps_codec->s_parse.i4_ctb_tile_x++;
        ps_codec->s_parse.i4_ctb_x++;
        ps_codec->s_parse.i4_ctb_slice_x++;

 /*If tiles are enabled, handle the slice counters differently*/
 if(ps_pps->i1_tiles_enabled_flag)
 {
            tile_start_ctb_idx = ps_tile->u1_pos_x
 + ps_tile->u1_pos_y * (ps_sps->i2_pic_wd_in_ctb);

            slice_start_ctb_idx =  ps_slice_hdr->i2_ctb_x
 + ps_slice_hdr->i2_ctb_y * (ps_sps->i2_pic_wd_in_ctb);

 if((slice_start_ctb_idx < tile_start_ctb_idx))
 {
 if(ps_codec->s_parse.i4_ctb_slice_x == (ps_tile->u1_pos_x + ps_tile->u2_wd))
 {
 /* Reached end of slice row within a tile /frame */
                    ps_codec->s_parse.i4_ctb_slice_y++;
                    ps_codec->s_parse.i4_ctb_slice_x = ps_tile->u1_pos_x; //todo:Check
 }
 }
 else if(ps_codec->s_parse.i4_ctb_slice_x == (ps_tile->u2_wd))
 {
                ps_codec->s_parse.i4_ctb_slice_y++;
                ps_codec->s_parse.i4_ctb_slice_x = 0;
 }
 }
 else
 {
 if(ps_codec->s_parse.i4_ctb_slice_x == ps_tile->u2_wd)
 {
 /* Reached end of slice row within a tile /frame */
                ps_codec->s_parse.i4_ctb_slice_y++;
                ps_codec->s_parse.i4_ctb_slice_x = 0;
 }
 }

 if(ps_codec->s_parse.i4_ctb_tile_x == (ps_tile->u2_wd))
 {
 /* Reached end of tile row */
            ps_codec->s_parse.i4_ctb_tile_x = 0;
            ps_codec->s_parse.i4_ctb_x = ps_tile->u1_pos_x;

            ps_codec->s_parse.i4_ctb_tile_y++;
            ps_codec->s_parse.i4_ctb_y++;

 if(ps_codec->s_parse.i4_ctb_tile_y == (ps_tile->u2_ht))
 {
 /* Reached End of Tile */
                ps_codec->s_parse.i4_ctb_tile_y = 0;
                ps_codec->s_parse.i4_ctb_tile_x = 0;
                ps_codec->s_parse.ps_tile++;

 if((ps_tile->u2_ht + ps_tile->u1_pos_y  ==  ps_sps->i2_pic_ht_in_ctb) && (ps_tile->u2_wd + ps_tile->u1_pos_x  ==  ps_sps->i2_pic_wd_in_ctb))
 {
 /* Reached end of frame */
                    end_of_pic = 1;
                    ps_codec->s_parse.i4_ctb_x = 0;
                    ps_codec->s_parse.i4_ctb_y = ps_sps->i2_pic_ht_in_ctb;
 }
 else
 {
 /* Initialize ctb_x and ctb_y to start of next tile */
                    ps_tile = ps_codec->s_parse.ps_tile;
                    ps_codec->s_parse.i4_ctb_x = ps_tile->u1_pos_x;
                    ps_codec->s_parse.i4_ctb_y = ps_tile->u1_pos_y;
                    ps_codec->s_parse.i4_ctb_tile_y = 0;
                    ps_codec->s_parse.i4_ctb_tile_x = 0;
                    ps_codec->s_parse.i4_ctb_slice_x = ps_tile->u1_pos_x;
                    ps_codec->s_parse.i4_ctb_slice_y = ps_tile->u1_pos_y;

 }
 }

 }

        ps_codec->s_parse.i4_next_ctb_indx = ps_codec->s_parse.i4_ctb_x +
                        ps_codec->s_parse.i4_ctb_y * ps_sps->i2_pic_wd_in_ctb;

 /* If the current slice is in error, check if the next slice's address
         * is reached and mark the end_of_slice flag */
 if(ps_codec->i4_slice_error)
 {
 slice_header_t *ps_slice_hdr_next = ps_slice_hdr + 1;
            WORD32 next_slice_addr = ps_slice_hdr_next->i2_ctb_x +
                            ps_slice_hdr_next->i2_ctb_y * ps_sps->i2_pic_wd_in_ctb;

 if(ps_codec->s_parse.i4_next_ctb_indx == next_slice_addr)
                end_of_slice_flag = 1;
 }

 /* If the codec is running in single core mode
         * then call process function for current CTB
         */
 if((1 == ps_codec->i4_num_cores) && (ps_codec->s_parse.i4_ctb_tile_x == 0))
 {
 process_ctxt_t *ps_proc = &ps_codec->as_process[0];
            ps_proc->i4_ctb_cnt = ps_proc->ps_tile->u2_wd;
            ihevcd_process(ps_proc);
 }

 /* If the bytes for the current slice are exhausted
         * set end_of_slice flag to 1
         * This slice will be treated as incomplete */
 if((UWORD8 *)ps_codec->s_parse.s_bitstrm.pu1_buf_max + BITSTRM_OFF_THRS <
 ((UWORD8 *)ps_codec->s_parse.s_bitstrm.pu4_buf + (ps_codec->s_parse.s_bitstrm.u4_bit_ofst / 8)))
 {

 if(0 == ps_codec->i4_slice_error)
                end_of_slice_flag = 1;
 }

 if(end_of_pic)
 break;
 } while(!end_of_slice_flag);

 /* Reset slice error */
    ps_codec->i4_slice_error = 0;

 /* Increment the slice index for parsing next slice */
 if(0 == end_of_pic)
 {
 while(1)
 {

            WORD32 parse_slice_idx;
            parse_slice_idx = ps_codec->s_parse.i4_cur_slice_idx;
            parse_slice_idx++;

 {
 /* If the next slice header is not initialized, update cur_slice_idx and break */
 if((1 == ps_codec->i4_num_cores) || (0 != (parse_slice_idx & (MAX_SLICE_HDR_CNT - 1))))
 {
                    ps_codec->s_parse.i4_cur_slice_idx = parse_slice_idx;
 break;
 }

 /* If the next slice header is initialised, wait for the parsed slices to be processed */
 else
 {
                    WORD32 ctb_indx = 0;

 while(ctb_indx != ps_sps->i4_pic_size_in_ctb)
 {
                        WORD32 parse_status = *(ps_codec->pu1_parse_map + ctb_indx);
 volatile WORD32 proc_status = *(ps_codec->pu1_proc_map + ctb_indx) & 1;

 if(parse_status == proc_status)
                            ctb_indx++;
 }
                    ps_codec->s_parse.i4_cur_slice_idx = parse_slice_idx;
 break;
 }

 }
 }

 }
 else
 {
#if FRAME_ILF_PAD
 if(FRAME_ILF_PAD && 1 == ps_codec->i4_num_cores)
 {
 if(ps_slice_hdr->i4_abs_pic_order_cnt == 0)
 {
                DUMP_PRE_ILF(ps_codec->as_process[0].pu1_cur_pic_luma,
                             ps_codec->as_process[0].pu1_cur_pic_chroma,
                             ps_sps->i2_pic_width_in_luma_samples,
                             ps_sps->i2_pic_height_in_luma_samples,
                             ps_codec->i4_strd);

                DUMP_BS(ps_codec->as_process[0].s_bs_ctxt.pu4_pic_vert_bs,
                        ps_codec->as_process[0].s_bs_ctxt.pu4_pic_horz_bs,
                        ps_sps->i2_pic_wd_in_ctb * (ctb_size * ctb_size / 8 / 16) * ps_sps->i2_pic_ht_in_ctb,
 (ps_sps->i2_pic_wd_in_ctb + 1) * (ctb_size * ctb_size / 8 / 16) * ps_sps->i2_pic_ht_in_ctb);

                DUMP_QP(ps_codec->as_process[0].s_bs_ctxt.pu1_pic_qp,
 (ps_sps->i2_pic_height_in_luma_samples * ps_sps->i2_pic_width_in_luma_samples) / (MIN_CU_SIZE * MIN_CU_SIZE));

                DUMP_QP_CONST_IN_CTB(ps_codec->as_process[0].s_bs_ctxt.pu1_pic_qp_const_in_ctb,
 (ps_sps->i2_pic_height_in_luma_samples * ps_sps->i2_pic_width_in_luma_samples) / (MIN_CTB_SIZE * MIN_CTB_SIZE) / 8);

                DUMP_NO_LOOP_FILTER(ps_codec->as_process[0].pu1_pic_no_loop_filter_flag,
 (ps_sps->i2_pic_width_in_luma_samples / MIN_CU_SIZE) * (ps_sps->i2_pic_height_in_luma_samples / MIN_CU_SIZE) / 8);

                DUMP_OFFSETS(ps_slice_hdr->i1_beta_offset_div2,
                             ps_slice_hdr->i1_tc_offset_div2,
                             ps_pps->i1_pic_cb_qp_offset,
                             ps_pps->i1_pic_cr_qp_offset);
 }
            ps_codec->s_parse.s_deblk_ctxt.ps_pps = ps_codec->s_parse.ps_pps;
            ps_codec->s_parse.s_deblk_ctxt.ps_sps = ps_codec->s_parse.ps_sps;
            ps_codec->s_parse.s_deblk_ctxt.ps_codec = ps_codec;
            ps_codec->s_parse.s_deblk_ctxt.ps_slice_hdr = ps_codec->s_parse.ps_slice_hdr;
            ps_codec->s_parse.s_deblk_ctxt.is_chroma_yuv420sp_vu = (ps_codec->e_ref_chroma_fmt == IV_YUV_420SP_VU);

            ps_codec->s_parse.s_sao_ctxt.ps_pps = ps_codec->s_parse.ps_pps;
            ps_codec->s_parse.s_sao_ctxt.ps_sps = ps_codec->s_parse.ps_sps;
            ps_codec->s_parse.s_sao_ctxt.ps_codec = ps_codec;
            ps_codec->s_parse.s_sao_ctxt.ps_slice_hdr = ps_codec->s_parse.ps_slice_hdr;

            ihevcd_ilf_pad_frame(&ps_codec->s_parse.s_deblk_ctxt, &ps_codec->s_parse.s_sao_ctxt);

 }
#endif
        ps_codec->s_parse.i4_end_of_frame = 1;
 }
 return ret;
}


xmlParse3986Port(xmlURIPtr uri, const char **str)
{
 const char *cur = *str;
 unsigned port = 0; /* unsigned for defined overflow behavior */

 if (ISA_DIGIT(cur)) {
 while (ISA_DIGIT(cur)) {
	    port = port * 10 + (*cur - '0');

 	    cur++;
 	}
 	if (uri != NULL)
	    uri->port = port & INT_MAX; /* port value modulo INT_MAX+1 */
 	*str = cur;
 	return(0);
     }
 return(1);
}

Buffer overflow in libxml2 allows remote attackers to execute arbitrary code by leveraging an incorrect limit for port values when handling redirects.


xmlParse3986Port(xmlURIPtr uri, const char **str)
{
 const char *cur = *str;
 unsigned port = 0; /* unsigned for defined overflow behavior */

 if (ISA_DIGIT(cur)) {
 while (ISA_DIGIT(cur)) {
	    port = port * 10 + (*cur - '0');

 	    cur++;
 	}
 	if (uri != NULL)
	    uri->port = port & USHRT_MAX; /* port value modulo INT_MAX+1 */
 	*str = cur;
 	return(0);
     }
 return(1);
}


static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
{
 if (parcel == NULL) {
 return NULL;
 }

    android::Parcel* p = android::parcelForJavaObject(env, parcel);

 const size_t size = p->readInt32();
 const void* regionData = p->readInplace(size);
 if (regionData == NULL) {

         return NULL;
     }
     SkRegion* region = new SkRegion;
    region->readFromMemory(regionData, size);

     return reinterpret_cast<jlong>(region);
 }

The Region_createFromParcel function in core/jni/android/graphics/Region.cpp in Region in Android before 5.1.1 LMY48M does not check the return values of certain read operations, which allows attackers to execute arbitrary code via an application that sends a crafted message to a service, aka internal bug 21585255.


static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
{
 if (parcel == NULL) {
 return NULL;
 }

    android::Parcel* p = android::parcelForJavaObject(env, parcel);

 const size_t size = p->readInt32();
 const void* regionData = p->readInplace(size);
 if (regionData == NULL) {

         return NULL;
     }
     SkRegion* region = new SkRegion;
    size_t actualSize = region->readFromMemory(regionData, size);

    if (size != actualSize) {
        delete region;
        return NULL;
    }

     return reinterpret_cast<jlong>(region);
 }


status_t OMXNodeInstance::emptyBuffer(
        OMX::buffer_id buffer,
        OMX_U32 rangeOffset, OMX_U32 rangeLength,
        OMX_U32 flags, OMX_TICKS timestamp) {

     Mutex::Autolock autoLock(mLock);

     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
     header->nFilledLen = rangeLength;
     header->nOffset = rangeOffset;

 BufferMeta *buffer_meta =
 static_cast<BufferMeta *>(header->pAppPrivate);
    buffer_meta->CopyToOMX(header);

 return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer);
}

Buffer overflow in the OMXNodeInstance::emptyBuffer function in omx/OMXNodeInstance.cpp in libstagefright in Android before 5.1.1 LMY48I allows attackers to execute arbitrary code via a crafted application, aka internal bug 20634516.


status_t OMXNodeInstance::emptyBuffer(
        OMX::buffer_id buffer,
        OMX_U32 rangeOffset, OMX_U32 rangeLength,
        OMX_U32 flags, OMX_TICKS timestamp) {

     Mutex::Autolock autoLock(mLock);

     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
    // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
    // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0.
    if (rangeOffset > header->nAllocLen
            || rangeLength > header->nAllocLen - rangeOffset) {
        return BAD_VALUE;
    }
     header->nFilledLen = rangeLength;
     header->nOffset = rangeOffset;

 BufferMeta *buffer_meta =
 static_cast<BufferMeta *>(header->pAppPrivate);
    buffer_meta->CopyToOMX(header);

 return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer);
}


 native_handle_t* native_handle_create(int numFds, int numInts)
 {
    native_handle_t* h = malloc(
            sizeof(native_handle_t) + sizeof(int)*(numFds+numInts));

     if (h) {
         h->version = sizeof(native_handle_t);
         h->numFds = numFds;
        h->numInts = numInts;
 }
 return h;
}

Integer overflow in the native_handle_create function in libcutils/native_handle.c in Android before 5.1.1 LMY48M allows attackers to obtain a different application's privileges or cause a denial of service (Binder heap memory corruption) via a crafted application, aka internal bug 19334482.


 native_handle_t* native_handle_create(int numFds, int numInts)
 {
    if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
        return NULL;
    }

    size_t mallocSize = sizeof(native_handle_t) + (sizeof(int) * (numFds + numInts));
    native_handle_t* h = malloc(mallocSize);
     if (h) {
         h->version = sizeof(native_handle_t);
         h->numFds = numFds;
        h->numInts = numInts;
 }
 return h;
}


status_t OMXNodeInstance::allocateBufferWithBackup(
        OMX_U32 portIndex, const sp<IMemory> &params,
        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
 if (params == NULL || buffer == NULL) {
        ALOGE("b/25884056");
 return BAD_VALUE;
 }

 Mutex::Autolock autoLock(mLock);
 if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
 return BAD_VALUE;
 }

 bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;

 BufferMeta *buffer_meta = new BufferMeta(
            params, portIndex,
 (portIndex == kPortIndexInput) && copy /* copyToOmx */,
 (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
            NULL /* data */);

    OMX_BUFFERHEADERTYPE *header;

    OMX_ERRORTYPE err = OMX_AllocateBuffer(
            mHandle, &header, portIndex, buffer_meta, allottedSize);
 if (err != OMX_ErrorNone) {
        CLOG_ERROR(allocateBufferWithBackup, err,
                SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer()));
 delete buffer_meta;
        buffer_meta = NULL;

 *buffer = 0;

 return StatusFromOMXError(err);

     }

     CHECK_EQ(header->pAppPrivate, buffer_meta);
    memset(header->pBuffer, 0, header->nAllocLen);

     *buffer = makeBufferID(header);

    addActiveBuffer(portIndex, *buffer);

    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
 if (bufferSource != NULL && portIndex == kPortIndexInput) {
        bufferSource->addCodecBuffer(header);
 }

    CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %u@%p",
            params->size(), params->pointer(), allottedSize, header->pBuffer));

 return OK;
}

An information disclosure vulnerability 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-11-01, and 7.0 before 2016-11-01 could enable a local malicious application to access data outside of its permission levels. This issue is rated as Moderate because it could be used to access sensitive data without permission. Android ID: A-29422020.


status_t OMXNodeInstance::allocateBufferWithBackup(
        OMX_U32 portIndex, const sp<IMemory> &params,
        OMX::buffer_id *buffer, OMX_U32 allottedSize) {
 if (params == NULL || buffer == NULL) {
        ALOGE("b/25884056");
 return BAD_VALUE;
 }

 Mutex::Autolock autoLock(mLock);
 if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
 return BAD_VALUE;
 }

 bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;

 BufferMeta *buffer_meta = new BufferMeta(
            params, portIndex,
 (portIndex == kPortIndexInput) && copy /* copyToOmx */,
 (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
            NULL /* data */);

    OMX_BUFFERHEADERTYPE *header;

    OMX_ERRORTYPE err = OMX_AllocateBuffer(
            mHandle, &header, portIndex, buffer_meta, allottedSize);
 if (err != OMX_ErrorNone) {
        CLOG_ERROR(allocateBufferWithBackup, err,
                SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer()));
 delete buffer_meta;
        buffer_meta = NULL;

 *buffer = 0;

 return StatusFromOMXError(err);

     }

     CHECK_EQ(header->pAppPrivate, buffer_meta);

     *buffer = makeBufferID(header);

    addActiveBuffer(portIndex, *buffer);

    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
 if (bufferSource != NULL && portIndex == kPortIndexInput) {
        bufferSource->addCodecBuffer(header);
 }

    CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %u@%p",
            params->size(), params->pointer(), allottedSize, header->pBuffer));

 return OK;
}


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

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

 while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
 BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
 if (inHeader == NULL) {
            inQueue.erase(inQueue.begin());
            inInfo->mOwnedByUs = false;
 continue;
 }

 PortInfo *port = editPortInfo(1);

        OMX_BUFFERHEADERTYPE *outHeader =
            port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;

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

 ++mInputBufferCount;

 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                outHeader->nFilledLen = 0;
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;

 List<BufferInfo *>::iterator it = outQueue.begin();
 while ((*it)->mHeader != outHeader) {
 ++it;
 }

 BufferInfo *outInfo = *it;
                outInfo->mOwnedByUs = false;
                outQueue.erase(it);
                outInfo = NULL;

                notifyFillBufferDone(outHeader);
                outHeader = NULL;
 }
 return;
 }

 uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
 uint32_t *start_code = (uint32_t *)bitstream;
 bool volHeader = *start_code == 0xB0010000;
 if (volHeader) {
 PVCleanUpVideoDecoder(mHandle);
            mInitialized = false;
 }

 if (!mInitialized) {
 uint8_t *vol_data[1];
 int32_t vol_size = 0;

            vol_data[0] = NULL;

 if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) {
                vol_data[0] = bitstream;
                vol_size = inHeader->nFilledLen;
 }

            MP4DecodingMode mode =
 (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;

 Bool success = PVInitVideoDecoder(
                    mHandle, vol_data, &vol_size, 1,
                    outputBufferWidth(), outputBufferHeight(), mode);

 if (!success) {
                ALOGW("PVInitVideoDecoder failed. Unsupported content?");

                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
 return;
 }

            MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
 if (mode != actualMode) {
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
 return;
 }

 PVSetPostProcType((VideoDecControls *) mHandle, 0);

 bool hasFrameData = false;
 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
 } else if (volHeader) {
                hasFrameData = true;
 }

            mInitialized = true;

 if (mode == MPEG4_MODE && handlePortSettingsChange()) {
 return;
 }

 if (!hasFrameData) {
 continue;
 }
 }

 if (!mFramesConfigured) {
 PortInfo *port = editPortInfo(1);
            OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;

             OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size;
             if ((outHeader->nAllocLen < yFrameSize) ||
                     (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) {
                ALOGE("Too small output buffer for reference frame: %zu bytes",
                        outHeader->nAllocLen);
                 android_errorWriteLog(0x534e4554, "30033990");
                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                 mSignalledError = true;
 return;
 }
 PVSetReferenceYUV(mHandle, outHeader->pBuffer);
            mFramesConfigured = true;
 }

 uint32_t useExtTimestamp = (inHeader->nOffset == 0);

 uint32_t timestamp = 0xFFFFFFFF;
 if (useExtTimestamp) {
            mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp);
            timestamp = mPvTime;
            mPvTime++;
 }

 int32_t bufferSize = inHeader->nFilledLen;
 int32_t tmp = bufferSize;

        OMX_U32 frameSize;
        OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight;
 if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) {
            ALOGE("Frame size too large");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
 return;
 }
        frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2));

 if (outHeader->nAllocLen < frameSize) {
            android_errorWriteLog(0x534e4554, "27833616");
            ALOGE("Insufficient output buffer size");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
 return;
 }
 if (PVDecodeVideoFrame(
                    mHandle, &bitstream, &timestamp, &tmp,
 &useExtTimestamp,
                    outHeader->pBuffer) != PV_TRUE) {
            ALOGE("failed to decode video frame.");

            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
 return;
 }

 if (handlePortSettingsChange()) {
 return;
 }

        outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
        mPvToOmxTimeMap.removeItem(timestamp);

        inHeader->nOffset += bufferSize;
        inHeader->nFilledLen = 0;
 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 } else {
            outHeader->nFlags = 0;
 }

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

 ++mInputBufferCount;

        outHeader->nOffset = 0;
        outHeader->nFilledLen = frameSize;

 List<BufferInfo *>::iterator it = outQueue.begin();
 while ((*it)->mHeader != outHeader) {
 ++it;
 }

 BufferInfo *outInfo = *it;
        outInfo->mOwnedByUs = false;
        outQueue.erase(it);
        outInfo = NULL;

        notifyFillBufferDone(outHeader);
        outHeader = NULL;

 ++mNumSamplesOutput;
 }
}

The SoftMPEG4 component 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-10-01, and 7.0 before 2016-10-01 allows attackers to gain privileges via a crafted application, aka internal bug 30033990.


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

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

 while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
 BufferInfo *inInfo = *inQueue.begin();
        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
 if (inHeader == NULL) {
            inQueue.erase(inQueue.begin());
            inInfo->mOwnedByUs = false;
 continue;
 }

 PortInfo *port = editPortInfo(1);

        OMX_BUFFERHEADERTYPE *outHeader =
            port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;

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

 ++mInputBufferCount;

 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                outHeader->nFilledLen = 0;
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;

 List<BufferInfo *>::iterator it = outQueue.begin();
 while ((*it)->mHeader != outHeader) {
 ++it;
 }

 BufferInfo *outInfo = *it;
                outInfo->mOwnedByUs = false;
                outQueue.erase(it);
                outInfo = NULL;

                notifyFillBufferDone(outHeader);
                outHeader = NULL;
 }
 return;
 }

 uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
 uint32_t *start_code = (uint32_t *)bitstream;
 bool volHeader = *start_code == 0xB0010000;
 if (volHeader) {
 PVCleanUpVideoDecoder(mHandle);
            mInitialized = false;
 }

 if (!mInitialized) {
 uint8_t *vol_data[1];
 int32_t vol_size = 0;

            vol_data[0] = NULL;

 if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) {
                vol_data[0] = bitstream;
                vol_size = inHeader->nFilledLen;
 }

            MP4DecodingMode mode =
 (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;

 Bool success = PVInitVideoDecoder(
                    mHandle, vol_data, &vol_size, 1,
                    outputBufferWidth(), outputBufferHeight(), mode);

 if (!success) {
                ALOGW("PVInitVideoDecoder failed. Unsupported content?");

                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
 return;
 }

            MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
 if (mode != actualMode) {
                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                mSignalledError = true;
 return;
 }

 PVSetPostProcType((VideoDecControls *) mHandle, 0);

 bool hasFrameData = false;
 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
 } else if (volHeader) {
                hasFrameData = true;
 }

            mInitialized = true;

 if (mode == MPEG4_MODE && handlePortSettingsChange()) {
 return;
 }

 if (!hasFrameData) {
 continue;
 }
 }

 if (!mFramesConfigured) {
 PortInfo *port = editPortInfo(1);
            OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;

             OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size;
             if ((outHeader->nAllocLen < yFrameSize) ||
                     (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) {
                ALOGE("Too small output buffer for reference frame: %lu bytes",
                        (unsigned long)outHeader->nAllocLen);
                 android_errorWriteLog(0x534e4554, "30033990");
                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                 mSignalledError = true;
 return;
 }
 PVSetReferenceYUV(mHandle, outHeader->pBuffer);
            mFramesConfigured = true;
 }

 uint32_t useExtTimestamp = (inHeader->nOffset == 0);

 uint32_t timestamp = 0xFFFFFFFF;
 if (useExtTimestamp) {
            mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp);
            timestamp = mPvTime;
            mPvTime++;
 }

 int32_t bufferSize = inHeader->nFilledLen;
 int32_t tmp = bufferSize;

        OMX_U32 frameSize;
        OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight;
 if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) {
            ALOGE("Frame size too large");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
 return;
 }
        frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2));

 if (outHeader->nAllocLen < frameSize) {
            android_errorWriteLog(0x534e4554, "27833616");
            ALOGE("Insufficient output buffer size");
            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
 return;
 }
 if (PVDecodeVideoFrame(
                    mHandle, &bitstream, &timestamp, &tmp,
 &useExtTimestamp,
                    outHeader->pBuffer) != PV_TRUE) {
            ALOGE("failed to decode video frame.");

            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
            mSignalledError = true;
 return;
 }

 if (handlePortSettingsChange()) {
 return;
 }

        outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
        mPvToOmxTimeMap.removeItem(timestamp);

        inHeader->nOffset += bufferSize;
        inHeader->nFilledLen = 0;
 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 } else {
            outHeader->nFlags = 0;
 }

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

 ++mInputBufferCount;

        outHeader->nOffset = 0;
        outHeader->nFilledLen = frameSize;

 List<BufferInfo *>::iterator it = outQueue.begin();
 while ((*it)->mHeader != outHeader) {
 ++it;
 }

 BufferInfo *outInfo = *it;
        outInfo->mOwnedByUs = false;
        outQueue.erase(it);
        outInfo = NULL;

        notifyFillBufferDone(outHeader);
        outHeader = NULL;

 ++mNumSamplesOutput;
 }
}


bool SoftVPX::outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset) {
 List<BufferInfo *> &outQueue = getPortQueue(1);
 BufferInfo *outInfo = NULL;
    OMX_BUFFERHEADERTYPE *outHeader = NULL;
 vpx_codec_iter_t iter = NULL;

 if (flushDecoder && mFrameParallelMode) {
 if (vpx_codec_decode((vpx_codec_ctx_t *)mCtx, NULL, 0, NULL, 0)) {
            ALOGE("Failed to flush on2 decoder.");
 return false;
 }
 }

 if (!display) {
 if (!flushDecoder) {
            ALOGE("Invalid operation.");
 return false;
 }
 while ((mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter))) {
 }
 return true;
 }

 while (!outQueue.empty()) {
 if (mImg == NULL) {
            mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
 if (mImg == NULL) {
 break;
 }
 }
 uint32_t width = mImg->d_w;
 uint32_t height = mImg->d_h;
        outInfo = *outQueue.begin();
        outHeader = outInfo->mHeader;
        CHECK_EQ(mImg->fmt, VPX_IMG_FMT_I420);
        handlePortSettingsChange(portWillReset, width, height);
 if (*portWillReset) {
 return true;
 }

        outHeader->nOffset = 0;

         outHeader->nFlags = 0;
         outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
         outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
        if (outHeader->nAllocLen >= outHeader->nFilledLen) {
             uint8_t *dst = outHeader->pBuffer;
             const uint8_t *srcY = (const uint8_t *)mImg->planes[VPX_PLANE_Y];
             const uint8_t *srcU = (const uint8_t *)mImg->planes[VPX_PLANE_U];
 const uint8_t *srcV = (const uint8_t *)mImg->planes[VPX_PLANE_V];
 size_t srcYStride = mImg->stride[VPX_PLANE_Y];
 size_t srcUStride = mImg->stride[VPX_PLANE_U];

             size_t srcVStride = mImg->stride[VPX_PLANE_V];
             copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
         } else {
            ALOGE("b/27597103, buffer too small");
            android_errorWriteLog(0x534e4554, "27597103");
             outHeader->nFilledLen = 0;
         }

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

 if (!eos) {
 return true;
 }

 if (!outQueue.empty()) {
        outInfo = *outQueue.begin();
        outQueue.erase(outQueue.begin());
        outHeader = outInfo->mHeader;
        outHeader->nTimeStamp = 0;
        outHeader->nFilledLen = 0;
        outHeader->nFlags = OMX_BUFFERFLAG_EOS;
        outInfo->mOwnedByUs = false;
        notifyFillBufferDone(outHeader);
        mEOSStatus = OUTPUT_FRAMES_FLUSHED;
 }

     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::outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset) {
 List<BufferInfo *> &outQueue = getPortQueue(1);
 BufferInfo *outInfo = NULL;
    OMX_BUFFERHEADERTYPE *outHeader = NULL;
 vpx_codec_iter_t iter = NULL;

 if (flushDecoder && mFrameParallelMode) {
 if (vpx_codec_decode((vpx_codec_ctx_t *)mCtx, NULL, 0, NULL, 0)) {
            ALOGE("Failed to flush on2 decoder.");
 return false;
 }
 }

 if (!display) {
 if (!flushDecoder) {
            ALOGE("Invalid operation.");
 return false;
 }
 while ((mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter))) {
 }
 return true;
 }

 while (!outQueue.empty()) {
 if (mImg == NULL) {
            mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
 if (mImg == NULL) {
 break;
 }
 }
 uint32_t width = mImg->d_w;
 uint32_t height = mImg->d_h;
        outInfo = *outQueue.begin();
        outHeader = outInfo->mHeader;
        CHECK_EQ(mImg->fmt, VPX_IMG_FMT_I420);
        handlePortSettingsChange(portWillReset, width, height);
 if (*portWillReset) {
 return true;
 }

        outHeader->nOffset = 0;

         outHeader->nFlags = 0;
         outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
         outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
        if (outputBufferSafe(outHeader)) {
             uint8_t *dst = outHeader->pBuffer;
             const uint8_t *srcY = (const uint8_t *)mImg->planes[VPX_PLANE_Y];
             const uint8_t *srcU = (const uint8_t *)mImg->planes[VPX_PLANE_U];
 const uint8_t *srcV = (const uint8_t *)mImg->planes[VPX_PLANE_V];
 size_t srcYStride = mImg->stride[VPX_PLANE_Y];
 size_t srcUStride = mImg->stride[VPX_PLANE_U];

             size_t srcVStride = mImg->stride[VPX_PLANE_V];
             copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
         } else {
             outHeader->nFilledLen = 0;
         }

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

 if (!eos) {
 return true;
 }

 if (!outQueue.empty()) {
        outInfo = *outQueue.begin();
        outQueue.erase(outQueue.begin());
        outHeader = outInfo->mHeader;
        outHeader->nTimeStamp = 0;
        outHeader->nFilledLen = 0;
        outHeader->nFlags = OMX_BUFFERFLAG_EOS;
        outInfo->mOwnedByUs = false;
        notifyFillBufferDone(outHeader);
        mEOSStatus = OUTPUT_FRAMES_FLUSHED;
 }

     return true;
 }


 void *SoftMP3::memsetSafe(OMX_BUFFERHEADERTYPE *outHeader, int c, size_t len) {
     if (len > outHeader->nAllocLen) {
        ALOGE("memset buffer too small: got %lu, expected %zu", (unsigned long)outHeader->nAllocLen, len);
         android_errorWriteLog(0x534e4554, "29422022");
         notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL);
         mSignalledError = true;
 return NULL;
 }
 return memset(outHeader->pBuffer, c, len);
}

Multiple buffer overflows in codecs/mp3dec/SoftMP3.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 allow attackers to gain privileges via a crafted application, aka internal bug 29422022.


 void *SoftMP3::memsetSafe(OMX_BUFFERHEADERTYPE *outHeader, int c, size_t len) {
     if (len > outHeader->nAllocLen) {
        ALOGE("memset buffer too small: got %u, expected %zu", outHeader->nAllocLen, len);
         android_errorWriteLog(0x534e4554, "29422022");
         notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL);
         mSignalledError = true;
 return NULL;
 }
 return memset(outHeader->pBuffer, c, len);
}


status_t Parcel::readUtf8FromUtf16(std::string* str) const {
 size_t utf16Size = 0;
 const char16_t* src = readString16Inplace(&utf16Size);
 if (!src) {
 return UNEXPECTED_NULL;
 }

 if (utf16Size == 0u) {
        str->clear();

        return NO_ERROR;
     }

    ssize_t utf8Size = utf16_to_utf8_length(src, utf16Size);
    if (utf8Size < 0) {
         return BAD_VALUE;
     }
    str->resize(utf8Size + 1);
    utf16_to_utf8(src, utf16Size, &((*str)[0]));
     str->resize(utf8Size);
     return NO_ERROR;
 }

LibUtils 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 mishandles conversions between Unicode character encodings with different encoding widths, which allows remote attackers to execute arbitrary code or cause a denial of service (heap-based buffer overflow) via a crafted file, aka internal bug 29250543.


status_t Parcel::readUtf8FromUtf16(std::string* str) const {
 size_t utf16Size = 0;
 const char16_t* src = readString16Inplace(&utf16Size);
 if (!src) {
 return UNEXPECTED_NULL;
 }

 if (utf16Size == 0u) {
        str->clear();

        return NO_ERROR;
     }

    // Allow for closing '\0'
    ssize_t utf8Size = utf16_to_utf8_length(src, utf16Size) + 1;
    if (utf8Size < 1) {
         return BAD_VALUE;
     }
    // spare byte around for the trailing null, we still pass the size including the trailing null
     str->resize(utf8Size);
    utf16_to_utf8(src, utf16Size, &((*str)[0]), utf8Size);
    str->resize(utf8Size - 1);
     return NO_ERROR;
 }


std::string utf16ToUtf8(const StringPiece16& utf16) {
 ssize_t utf8Length = utf16_to_utf8_length(utf16.data(), utf16.length());
 if (utf8Length <= 0) {
 return {};

     }

     std::string utf8;
     utf8.resize(utf8Length);
    utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin());
     return utf8;
 }


std::string utf16ToUtf8(const StringPiece16& utf16) {
 ssize_t utf8Length = utf16_to_utf8_length(utf16.data(), utf16.length());
 if (utf8Length <= 0) {
 return {};

     }

     std::string utf8;
    // Make room for '\0' explicitly.
    utf8.resize(utf8Length + 1);
    utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin(), utf8Length + 1);
     utf8.resize(utf8Length);
     return utf8;
 }


static jboolean enableNative(JNIEnv* env, jobject obj) {
     ALOGV("%s:",__FUNCTION__);

     jboolean result = JNI_FALSE;
     if (!sBluetoothInterface) return result;
    int ret = sBluetoothInterface->enable();
     result = (ret == BT_STATUS_SUCCESS || ret == BT_STATUS_DONE) ? JNI_TRUE : JNI_FALSE;
     return result;
 }

Bluetooth in Android 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-07-01 allows local users to gain privileges by establishing a pairing that remains present during a session of the primary user, aka internal bug 27410683.


static jboolean cancelDiscoveryNative(JNIEnv* env, jobject obj) {
    ALOGV("%s:",__FUNCTION__);

    jboolean result = JNI_FALSE;
 if (!sBluetoothInterface) return result;

 int ret = sBluetoothInterface->cancel_discovery();
    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 return result;
}


 status_t NuPlayer::GenericSource::setBuffers(
         bool audio, Vector<MediaBuffer *> &buffers) {
    if (mIsWidevine && !audio && mVideoTrack.mSource != NULL) {
         return mVideoTrack.mSource->setBuffers(buffers);
     }
     return INVALID_OPERATION;
}

media/libmediaplayerservice/nuplayer/GenericSource.cpp 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-07-01 does not validate certain track data, which allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted media file, aka internal bug 28799341.


 status_t NuPlayer::GenericSource::setBuffers(
         bool audio, Vector<MediaBuffer *> &buffers) {
    if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
         return mVideoTrack.mSource->setBuffers(buffers);
     }
     return INVALID_OPERATION;
}


status_t BnOMX::onTransact(
 uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
 switch (code) {
 case LIVES_LOCALLY:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);
            node_id node = (node_id)data.readInt32();
 pid_t pid = (pid_t)data.readInt32();
            reply->writeInt32(livesLocally(node, pid));

 return OK;
 }

 case LIST_NODES:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

 List<ComponentInfo> list;
            listNodes(&list);

            reply->writeInt32(list.size());
 for (List<ComponentInfo>::iterator it = list.begin();
                 it != list.end(); ++it) {
 ComponentInfo &cur = *it;

                reply->writeString8(cur.mName);
                reply->writeInt32(cur.mRoles.size());
 for (List<String8>::iterator role_it = cur.mRoles.begin();
                     role_it != cur.mRoles.end(); ++role_it) {
                    reply->writeString8(*role_it);
 }
 }

 return NO_ERROR;
 }

 case ALLOCATE_NODE:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

 const char *name = data.readCString();

            sp<IOMXObserver> observer =
                interface_cast<IOMXObserver>(data.readStrongBinder());

            node_id node;

 status_t err = allocateNode(name, observer, &node);
            reply->writeInt32(err);
 if (err == OK) {
                reply->writeInt32((int32_t)node);
 }

 return NO_ERROR;
 }

 case FREE_NODE:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();

            reply->writeInt32(freeNode(node));

 return NO_ERROR;
 }

 case SEND_COMMAND:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();

            OMX_COMMANDTYPE cmd =
 static_cast<OMX_COMMANDTYPE>(data.readInt32());

            OMX_S32 param = data.readInt32();
            reply->writeInt32(sendCommand(node, cmd, param));

 return NO_ERROR;
 }

 case GET_PARAMETER:
 case SET_PARAMETER:
 case GET_CONFIG:
 case SET_CONFIG:
 case SET_INTERNAL_OPTION:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());

 size_t size = data.readInt64();

 status_t err = NOT_ENOUGH_DATA;

             void *params = NULL;
             size_t pageSize = 0;
             size_t allocSize = 0;
            if ((index == (OMX_INDEXTYPE) OMX_IndexParamConsumerUsageBits && size < 4) ||
                    (code != SET_INTERNAL_OPTION && size < 8)) {
                ALOGE("b/27207275 (%zu)", size);
                 android_errorWriteLog(0x534e4554, "27207275");
             } else {
                 err = NO_MEMORY;
                pageSize = (size_t) sysconf(_SC_PAGE_SIZE);
 if (size > SIZE_MAX - (pageSize * 2)) {
                    ALOGE("requested param size too big");
 } else {
                    allocSize = (size + pageSize * 2) & ~(pageSize - 1);
                    params = mmap(NULL, allocSize, PROT_READ | PROT_WRITE,
                            MAP_PRIVATE | MAP_ANONYMOUS, -1 /* fd */, 0 /* offset */);
 }
 if (params != MAP_FAILED) {
                    err = data.read(params, size);
 if (err != OK) {
                        android_errorWriteLog(0x534e4554, "26914474");
 } else {
                        err = NOT_ENOUGH_DATA;
                        OMX_U32 declaredSize = *(OMX_U32*)params;
 if (code != SET_INTERNAL_OPTION &&
                                index != (OMX_INDEXTYPE) OMX_IndexParamConsumerUsageBits &&
                                declaredSize > size) {
                            ALOGE("b/27207275 (%u/%zu)", declaredSize, size);
                            android_errorWriteLog(0x534e4554, "27207275");
 } else {
                            mprotect((char*)params + allocSize - pageSize, pageSize, PROT_NONE);
 switch (code) {
 case GET_PARAMETER:
                                    err = getParameter(node, index, params, size);
 break;
 case SET_PARAMETER:
                                    err = setParameter(node, index, params, size);
 break;
 case GET_CONFIG:
                                    err = getConfig(node, index, params, size);
 break;
 case SET_CONFIG:
                                    err = setConfig(node, index, params, size);
 break;
 case SET_INTERNAL_OPTION:
 {
 InternalOptionType type =
 (InternalOptionType)data.readInt32();

                                    err = setInternalOption(node, index, type, params, size);
 break;
 }

 default:
                                    TRESPASS();
 }
 }
 }
 } else {
                    ALOGE("couldn't map: %s", strerror(errno));
 }
 }

            reply->writeInt32(err);

 if ((code == GET_PARAMETER || code == GET_CONFIG) && err == OK) {
                reply->write(params, size);
 }

 if (params) {
                munmap(params, allocSize);
 }
            params = NULL;

 return NO_ERROR;
 }

 case GET_STATE:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_STATETYPE state = OMX_StateInvalid;

 status_t err = getState(node, &state);
            reply->writeInt32(state);
            reply->writeInt32(err);

 return NO_ERROR;
 }

 case ENABLE_GRAPHIC_BUFFERS:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            OMX_BOOL enable = (OMX_BOOL)data.readInt32();

 status_t err = enableGraphicBuffers(node, port_index, enable);
            reply->writeInt32(err);

 return NO_ERROR;
 }

 case GET_GRAPHIC_BUFFER_USAGE:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();

            OMX_U32 usage = 0;
 status_t err = getGraphicBufferUsage(node, port_index, &usage);
            reply->writeInt32(err);
            reply->writeInt32(usage);

 return NO_ERROR;
 }

 case USE_BUFFER:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            sp<IMemory> params =
                interface_cast<IMemory>(data.readStrongBinder());
            OMX_U32 allottedSize = data.readInt32();

            buffer_id buffer;
 status_t err = useBuffer(node, port_index, params, &buffer, allottedSize);
            reply->writeInt32(err);

 if (err == OK) {
                reply->writeInt32((int32_t)buffer);
 }

 return NO_ERROR;
 }

 case USE_GRAPHIC_BUFFER:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
            data.read(*graphicBuffer);

            buffer_id buffer;
 status_t err = useGraphicBuffer(
                    node, port_index, graphicBuffer, &buffer);
            reply->writeInt32(err);

 if (err == OK) {
                reply->writeInt32((int32_t)buffer);
 }

 return NO_ERROR;
 }

 case UPDATE_GRAPHIC_BUFFER_IN_META:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
            data.read(*graphicBuffer);
            buffer_id buffer = (buffer_id)data.readInt32();

 status_t err = updateGraphicBufferInMeta(
                    node, port_index, graphicBuffer, buffer);
            reply->writeInt32(err);

 return NO_ERROR;
 }

 case CREATE_INPUT_SURFACE:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();

            sp<IGraphicBufferProducer> bufferProducer;
 MetadataBufferType type = kMetadataBufferTypeInvalid;
 status_t err = createInputSurface(node, port_index, &bufferProducer, &type);

 if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
                android_errorWriteLog(0x534e4554, "26324358");
 }

            reply->writeInt32(type);
            reply->writeInt32(err);

 if (err == OK) {
                reply->writeStrongBinder(IInterface::asBinder(bufferProducer));
 }

 return NO_ERROR;
 }

 case CREATE_PERSISTENT_INPUT_SURFACE:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            sp<IGraphicBufferProducer> bufferProducer;
            sp<IGraphicBufferConsumer> bufferConsumer;
 status_t err = createPersistentInputSurface(
 &bufferProducer, &bufferConsumer);

            reply->writeInt32(err);

 if (err == OK) {
                reply->writeStrongBinder(IInterface::asBinder(bufferProducer));
                reply->writeStrongBinder(IInterface::asBinder(bufferConsumer));
 }

 return NO_ERROR;
 }

 case SET_INPUT_SURFACE:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();

            sp<IGraphicBufferConsumer> bufferConsumer =
                    interface_cast<IGraphicBufferConsumer>(data.readStrongBinder());

 MetadataBufferType type = kMetadataBufferTypeInvalid;
 status_t err = setInputSurface(node, port_index, bufferConsumer, &type);

 if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
                android_errorWriteLog(0x534e4554, "26324358");
 }

            reply->writeInt32(type);
            reply->writeInt32(err);
 return NO_ERROR;
 }

 case SIGNAL_END_OF_INPUT_STREAM:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();

 status_t err = signalEndOfInputStream(node);
            reply->writeInt32(err);

 return NO_ERROR;
 }

 case STORE_META_DATA_IN_BUFFERS:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            OMX_BOOL enable = (OMX_BOOL)data.readInt32();

 MetadataBufferType type = kMetadataBufferTypeInvalid;
 status_t err = storeMetaDataInBuffers(node, port_index, enable, &type);

            reply->writeInt32(type);
            reply->writeInt32(err);

 return NO_ERROR;
 }

 case PREPARE_FOR_ADAPTIVE_PLAYBACK:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            OMX_BOOL enable = (OMX_BOOL)data.readInt32();
            OMX_U32 max_width = data.readInt32();
            OMX_U32 max_height = data.readInt32();

 status_t err = prepareForAdaptivePlayback(
                    node, port_index, enable, max_width, max_height);
            reply->writeInt32(err);

 return NO_ERROR;
 }

 case CONFIGURE_VIDEO_TUNNEL_MODE:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            OMX_BOOL tunneled = (OMX_BOOL)data.readInt32();
            OMX_U32 audio_hw_sync = data.readInt32();

 native_handle_t *sideband_handle = NULL;
 status_t err = configureVideoTunnelMode(
                    node, port_index, tunneled, audio_hw_sync, &sideband_handle);
            reply->writeInt32(err);
 if(err == OK){
                reply->writeNativeHandle(sideband_handle);
 }

 return NO_ERROR;
 }

 case ALLOC_BUFFER:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
 if (!isSecure(node) || port_index != 0 /* kPortIndexInput */) {
                ALOGE("b/24310423");
                reply->writeInt32(INVALID_OPERATION);
 return NO_ERROR;
 }

 size_t size = data.readInt64();

            buffer_id buffer;
 void *buffer_data;
 status_t err = allocateBuffer(
                    node, port_index, size, &buffer, &buffer_data);
            reply->writeInt32(err);

 if (err == OK) {
                reply->writeInt32((int32_t)buffer);
                reply->writeInt64((uintptr_t)buffer_data);
 }

 return NO_ERROR;
 }

 case ALLOC_BUFFER_WITH_BACKUP:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            sp<IMemory> params =
                interface_cast<IMemory>(data.readStrongBinder());
            OMX_U32 allottedSize = data.readInt32();

            buffer_id buffer;
 status_t err = allocateBufferWithBackup(
                    node, port_index, params, &buffer, allottedSize);

            reply->writeInt32(err);

 if (err == OK) {
                reply->writeInt32((int32_t)buffer);
 }

 return NO_ERROR;
 }

 case FREE_BUFFER:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            OMX_U32 port_index = data.readInt32();
            buffer_id buffer = (buffer_id)data.readInt32();
            reply->writeInt32(freeBuffer(node, port_index, buffer));

 return NO_ERROR;
 }

 case FILL_BUFFER:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            buffer_id buffer = (buffer_id)data.readInt32();
 bool haveFence = data.readInt32();
 int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
            reply->writeInt32(fillBuffer(node, buffer, fenceFd));

 return NO_ERROR;
 }

 case EMPTY_BUFFER:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
            buffer_id buffer = (buffer_id)data.readInt32();
            OMX_U32 range_offset = data.readInt32();
            OMX_U32 range_length = data.readInt32();
            OMX_U32 flags = data.readInt32();
            OMX_TICKS timestamp = data.readInt64();
 bool haveFence = data.readInt32();
 int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
            reply->writeInt32(emptyBuffer(
                    node, buffer, range_offset, range_length, flags, timestamp, fenceFd));

 return NO_ERROR;
 }

 case GET_EXTENSION_INDEX:
 {
            CHECK_OMX_INTERFACE(IOMX, data, reply);

            node_id node = (node_id)data.readInt32();
 const char *parameter_name = data.readCString();

            OMX_INDEXTYPE index;
 status_t err = getExtensionIndex(node, parameter_name, &index);

            reply->writeInt32(err);

 if (err == OK) {
                reply->writeInt32(index);
 }

 return OK;
 }

 default:
 return BBinder::onTransact(code, data, reply, flags);
 }
}

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-06-01 does not validate OMX buffer sizes, which allows attackers to gain privileges via a crafted application, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 27207275.