static void debugCallback (int fd, short flags, void *param) {
 int acceptFD, option;
 struct sockaddr_un peeraddr;
 socklen_t socklen = sizeof (peeraddr);

     int data;
     unsigned int qxdm_data[6];
     const char *deactData[1] = {"1"};
     RIL_Dial dialData;
     int hangupData[1] = {1};
     int number;
     char **args;
     RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
    int MAX_DIAL_ADDRESS = 128;
     int sim_id = 0;

     RLOGI("debugCallback for socket %s", rilSocketIdToString(socket_id));

    acceptFD = accept (fd, (sockaddr *) &peeraddr, &socklen);

 if (acceptFD < 0) {
        RLOGE ("error accepting on debug port: %d\n", errno);
 return;
 }

 if (recv(acceptFD, &number, sizeof(int), 0) != sizeof(int)) {
        RLOGE ("error reading on socket: number of Args: \n");
        close(acceptFD);
 return;
 }

 if (number < 0) {
        RLOGE ("Invalid number of arguments: \n");
        close(acceptFD);
 return;
 }

    args = (char **) calloc(number, sizeof(char*));
 if (args == NULL) {
        RLOGE("Memory allocation failed for debug args");
        close(acceptFD);
 return;
 }

 for (int i = 0; i < number; i++) {
 int len;
 if (recv(acceptFD, &len, sizeof(int), 0) != sizeof(int)) {
            RLOGE ("error reading on socket: Len of Args: \n");
            freeDebugCallbackArgs(i, args);
            close(acceptFD);
 return;
 }
 if (len == INT_MAX || len < 0) {
            RLOGE("Invalid value of len: \n");
            freeDebugCallbackArgs(i, args);
            close(acceptFD);
 return;
 }

        args[i] = (char *) calloc(len + 1, sizeof(char));
 if (args[i] == NULL) {
            RLOGE("Memory allocation failed for debug args");
            freeDebugCallbackArgs(i, args);
            close(acceptFD);
 return;
 }
 if (recv(acceptFD, args[i], sizeof(char) * len, 0)
 != (int)sizeof(char) * len) {
            RLOGE ("error reading on socket: Args[%d] \n", i);
            freeDebugCallbackArgs(i, args);
            close(acceptFD);
 return;
 }
 char * buf = args[i];
        buf[len] = 0;
 if ((i+1) == number) {
 /* The last argument should be sim id 0(SIM1)~3(SIM4) */
            sim_id = atoi(args[i]);
 switch (sim_id) {
 case 0:
                    socket_id = RIL_SOCKET_1;
 break;
 #if (SIM_COUNT >= 2)
 case 1:
                    socket_id = RIL_SOCKET_2;
 break;
 #endif
 #if (SIM_COUNT >= 3)
 case 2:
                    socket_id = RIL_SOCKET_3;
 break;
 #endif
 #if (SIM_COUNT >= 4)
 case 3:
                    socket_id = RIL_SOCKET_4;
 break;
 #endif
 default:
                    socket_id = RIL_SOCKET_1;
 break;
 }
 }
 }

 switch (atoi(args[0])) {
 case 0:
            RLOGI ("Connection on debug port: issuing reset.");
            issueLocalRequest(RIL_REQUEST_RESET_RADIO, NULL, 0, socket_id);
 break;
 case 1:
            RLOGI ("Connection on debug port: issuing radio power off.");
            data = 0;
            issueLocalRequest(RIL_REQUEST_RADIO_POWER, &data, sizeof(int), socket_id);
 if (socket_id == RIL_SOCKET_1 && s_ril_param_socket.fdCommand > 0) {
                close(s_ril_param_socket.fdCommand);
                s_ril_param_socket.fdCommand = -1;
 }
 #if (SIM_COUNT == 2)
 else if (socket_id == RIL_SOCKET_2 && s_ril_param_socket2.fdCommand > 0) {
                close(s_ril_param_socket2.fdCommand);
                s_ril_param_socket2.fdCommand = -1;
 }
 #endif
 break;
 case 2:
            RLOGI ("Debug port: issuing unsolicited voice network change.");
            RIL_UNSOL_RESPONSE(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0, socket_id);
 break;
 case 3:
            RLOGI ("Debug port: QXDM log enable.");
            qxdm_data[0] = 65536; // head.func_tag
            qxdm_data[1] = 16; // head.len
            qxdm_data[2] = 1; // mode: 1 for 'start logging'
            qxdm_data[3] = 32; // log_file_size: 32megabytes
            qxdm_data[4] = 0; // log_mask
            qxdm_data[5] = 8; // log_max_fileindex
            issueLocalRequest(RIL_REQUEST_OEM_HOOK_RAW, qxdm_data,
 6 * sizeof(int), socket_id);
 break;
 case 4:
            RLOGI ("Debug port: QXDM log disable.");
            qxdm_data[0] = 65536;
            qxdm_data[1] = 16;
            qxdm_data[2] = 0; // mode: 0 for 'stop logging'
            qxdm_data[3] = 32;
            qxdm_data[4] = 0;
            qxdm_data[5] = 8;
            issueLocalRequest(RIL_REQUEST_OEM_HOOK_RAW, qxdm_data,
 6 * sizeof(int), socket_id);
 break;
 case 5:
            RLOGI("Debug port: Radio On");
            data = 1;
            issueLocalRequest(RIL_REQUEST_RADIO_POWER, &data, sizeof(int), socket_id);
            sleep(2);

             issueLocalRequest(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, NULL, 0, socket_id);
             break;
         case 7:
             RLOGI("Debug port: Deactivate Data Call");
             issueLocalRequest(RIL_REQUEST_DEACTIVATE_DATA_CALL, &deactData,
 sizeof(deactData), socket_id);
 break;

         case 8:
             RLOGI("Debug port: Dial Call");
             dialData.clir = 0;
            if (strlen(args[1]) > MAX_DIAL_ADDRESS) {
                RLOGE("Debug port: Error calling Dial");
                freeDebugCallbackArgs(number, args);
                close(acceptFD);
                return;
            }
             dialData.address = args[1];
             issueLocalRequest(RIL_REQUEST_DIAL, &dialData, sizeof(dialData), socket_id);
             break;
 case 9:
            RLOGI("Debug port: Answer Call");
            issueLocalRequest(RIL_REQUEST_ANSWER, NULL, 0, socket_id);
 break;
 case 10:
            RLOGI("Debug port: End Call");
            issueLocalRequest(RIL_REQUEST_HANGUP, &hangupData,
 sizeof(hangupData), socket_id);
 break;
 default:
            RLOGE ("Invalid request");
 break;
 }
    freeDebugCallbackArgs(number, args);
    close(acceptFD);
}


WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
{
    WORD32 ret = IV_SUCCESS;
 codec_t *ps_codec = (codec_t *)(ps_codec_obj->pv_codec_handle);
 ivd_video_decode_ip_t *ps_dec_ip;
 ivd_video_decode_op_t *ps_dec_op;

    WORD32 proc_idx = 0;
    WORD32 prev_proc_idx = 0;

 /* Initialize error code */
    ps_codec->i4_error_code = 0;

    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 = ps_dec_op->u4_size;
        memset(ps_dec_op, 0, sizeof(ivd_video_decode_op_t));
        ps_dec_op->u4_size = u4_size; //Restore size field
 }
 if(ps_codec->i4_init_done != 1)
 {
        ps_dec_op->u4_error_code |= 1 << IVD_FATALERROR;
        ps_dec_op->u4_error_code |= IHEVCD_INIT_NOT_DONE;
 return IV_FAIL;
 }

 if(ps_codec->u4_pic_cnt >= NUM_FRAMES_LIMIT)
 {
        ps_dec_op->u4_error_code |= 1 << IVD_FATALERROR;
        ps_dec_op->u4_error_code |= IHEVCD_NUM_FRAMES_LIMIT_REACHED;
 return IV_FAIL;
 }

 /* If reset flag is set, flush the existing buffers */
 if(ps_codec->i4_reset_flag)
 {
        ps_codec->i4_flush_mode = 1;
 }

 /*Data memory barries instruction,so that bitstream write by the application is complete*/
 /* In case the decoder is not in flush mode check for input buffer validity */
 if(0 == ps_codec->i4_flush_mode)
 {
 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 <= MIN_START_CODE_LEN)
 {
 if((WORD32)ps_dec_ip->u4_num_Bytes > 0)
                ps_dec_op->u4_num_bytes_consumed = ps_dec_ip->u4_num_Bytes;
 else
                ps_dec_op->u4_num_bytes_consumed = 0;

            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DEC_NUMBYTES_INV;
 return IV_FAIL;

 }
 }

#ifdef APPLY_CONCEALMENT
 {
        WORD32 num_mbs;

        num_mbs = (ps_codec->i4_wd * ps_codec->i4_ht + 255) >> 8;
 /* Reset MB Count at the beginning of every process call */
        ps_codec->mb_count = 0;
        memset(ps_codec->mb_map, 0, ((num_mbs + 7) >> 3));
 }
#endif

 if(0 == ps_codec->i4_share_disp_buf && ps_codec->i4_header_mode == 0)
 {
        UWORD32 i;
 if(ps_dec_ip->s_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_ip->s_out_buffer.u4_num_bufs; i++)
 {
 if(ps_dec_ip->s_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_ip->s_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;
 }
 }
 }

    ps_codec->ps_out_buffer = &ps_dec_ip->s_out_buffer;
    ps_codec->u4_ts = ps_dec_ip->u4_ts;
 if(ps_codec->i4_flush_mode)
 {

        ps_dec_op->u4_pic_wd = ps_codec->i4_disp_wd;
        ps_dec_op->u4_pic_ht = ps_codec->i4_disp_ht;

        ps_dec_op->u4_new_seq = 0;

        ps_codec->ps_disp_buf = (pic_buf_t *)ihevc_disp_mgr_get(
 (disp_mgr_t *)ps_codec->pv_disp_buf_mgr, &ps_codec->i4_disp_buf_id);
 /* In case of non-shared mode, then convert/copy the frame to output buffer */
 /* Only if the codec is in non-shared mode or in shared mode but needs 420P output */
 if((ps_codec->ps_disp_buf)
 && ((0 == ps_codec->i4_share_disp_buf)
 || (IV_YUV_420P
 == ps_codec->e_chroma_fmt)))
 {

 process_ctxt_t *ps_proc = &ps_codec->as_process[prev_proc_idx];
 if(0 == ps_proc->i4_init_done)
 {
                ihevcd_init_proc_ctxt(ps_proc, 0);
 }

 /* Output buffer check */
            ret = ihevcd_check_out_buf_size(ps_codec);
            RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);

 /* Set remaining number of rows to be processed */
            ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[0],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[1],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[2], 0,
                                  ps_codec->i4_disp_ht);

            ihevc_buf_mgr_release((buf_mgr_t *)ps_codec->pv_pic_buf_mgr,
                                  ps_codec->i4_disp_buf_id, BUF_MGR_DISP);
 }

        ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);

 if(1 == ps_dec_op->u4_output_present)
 {
            WORD32 xpos = ps_codec->i4_disp_wd - 32 - LOGO_WD;
            WORD32 ypos = ps_codec->i4_disp_ht - 32 - LOGO_HT;

 if(ypos < 0)
                ypos = 0;

 if(xpos < 0)
                xpos = 0;

            INSERT_LOGO(ps_dec_ip->s_out_buffer.pu1_bufs[0],
                        ps_dec_ip->s_out_buffer.pu1_bufs[1],
                        ps_dec_ip->s_out_buffer.pu1_bufs[2], ps_codec->i4_disp_strd,
                        xpos,
                        ypos,
                        ps_codec->e_chroma_fmt,
                        ps_codec->i4_disp_wd,
                        ps_codec->i4_disp_ht);
 }

 if(NULL == ps_codec->ps_disp_buf)
 {
 /* If in flush mode and there are no more buffers to flush,
             * check for the reset flag and reset the decoder */
 if(ps_codec->i4_reset_flag)
 {
                ihevcd_init(ps_codec);
 }
 return (IV_FAIL);
 }

 return (IV_SUCCESS);

 }
 /* In case of shared mode, check if there is a free buffer for reconstruction */
 if((0 == ps_codec->i4_header_mode) && (1 == ps_codec->i4_share_disp_buf))
 {
        WORD32 buf_status;
        buf_status = 1;
 if(ps_codec->pv_pic_buf_mgr)
            buf_status = ihevc_buf_mgr_check_free((buf_mgr_t *)ps_codec->pv_pic_buf_mgr);

 /* If there is no free buffer, then return with an error code */
 if(0 == buf_status)
 {
            ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;
            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
 return IV_FAIL;
 }
 }
    ps_codec->i4_bytes_remaining = ps_dec_ip->u4_num_Bytes;
    ps_codec->pu1_inp_bitsbuf = (UWORD8 *)ps_dec_ip->pv_stream_buffer;
    ps_codec->s_parse.i4_end_of_frame = 0;

    ps_codec->i4_pic_present = 0;
    ps_codec->i4_slice_error = 0;
    ps_codec->ps_disp_buf = NULL;

 if(ps_codec->i4_num_cores > 1)
 {
        ithread_set_affinity(0);
 }
 while(MIN_START_CODE_LEN < ps_codec->i4_bytes_remaining)
 {
        WORD32 nal_len;
        WORD32 nal_ofst;
        WORD32 bits_len;

 if(ps_codec->i4_slice_error)
 {
 slice_header_t *ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + (ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1));
            WORD32 next_slice_addr = ps_slice_hdr_next->i2_ctb_x +
                            ps_slice_hdr_next->i2_ctb_y * ps_codec->s_parse.ps_sps->i2_pic_wd_in_ctb;
 if(ps_codec->s_parse.i4_next_ctb_indx == next_slice_addr)
                ps_codec->i4_slice_error = 0;
 }

 if(ps_codec->pu1_bitsbuf_dynamic)
 {
            ps_codec->pu1_bitsbuf = ps_codec->pu1_bitsbuf_dynamic;
            ps_codec->u4_bitsbuf_size = ps_codec->u4_bitsbuf_size_dynamic;
 }
 else
 {
            ps_codec->pu1_bitsbuf = ps_codec->pu1_bitsbuf_static;
            ps_codec->u4_bitsbuf_size = ps_codec->u4_bitsbuf_size_static;
 }

        nal_ofst = ihevcd_nal_search_start_code(ps_codec->pu1_inp_bitsbuf,
                                                ps_codec->i4_bytes_remaining);

        ps_codec->i4_nal_ofst = nal_ofst;
 {
            WORD32 bytes_remaining = ps_codec->i4_bytes_remaining - nal_ofst;

            bytes_remaining = MIN((UWORD32)bytes_remaining, ps_codec->u4_bitsbuf_size);
            ihevcd_nal_remv_emuln_bytes(ps_codec->pu1_inp_bitsbuf + nal_ofst,
                                        ps_codec->pu1_bitsbuf,
                                        bytes_remaining,
 &nal_len, &bits_len);

 /* Decoder may read upto 8 extra bytes at the end of frame */
 /* These are not used, but still set them to zero to avoid uninitialized reads */
 if(bits_len < (WORD32)(ps_codec->u4_bitsbuf_size - 8))
 {
                memset(ps_codec->pu1_bitsbuf + bits_len, 0, 2 * sizeof(UWORD32));
 }
 }
 /* This may be used to update the offsets for tiles and entropy sync row offsets */
        ps_codec->i4_num_emln_bytes = nal_len - bits_len;
        ps_codec->i4_nal_len = nal_len;

        ihevcd_bits_init(&ps_codec->s_parse.s_bitstrm, ps_codec->pu1_bitsbuf,
                         bits_len);

        ret = ihevcd_nal_unit(ps_codec);

 /* If the frame is incomplete and
         * the bytes remaining is zero or a header is received,
         * complete the frame treating it to be in error */
 if(ps_codec->i4_pic_present &&
 (ps_codec->s_parse.i4_next_ctb_indx != ps_codec->s_parse.ps_sps->i4_pic_size_in_ctb))
 {
 if((ps_codec->i4_bytes_remaining - (nal_len + nal_ofst) <= MIN_START_CODE_LEN) ||
 (ps_codec->i4_header_in_slice_mode))
 {
 slice_header_t *ps_slice_hdr_next;

                ps_codec->s_parse.i4_cur_slice_idx--;
 if(ps_codec->s_parse.i4_cur_slice_idx < 0)
                    ps_codec->s_parse.i4_cur_slice_idx = 0;

                ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + ((ps_codec->s_parse.i4_cur_slice_idx + 1) & (MAX_SLICE_HDR_CNT - 1));
                ps_slice_hdr_next->i2_ctb_x = 0;
                ps_slice_hdr_next->i2_ctb_y = ps_codec->s_parse.ps_sps->i2_pic_ht_in_ctb;
                ps_codec->i4_slice_error = 1;
 continue;
 }
 }

         if(IHEVCD_IGNORE_SLICE == ret)
         {
            ps_codec->s_parse.i4_cur_slice_idx = MAX(0, (ps_codec->s_parse.i4_cur_slice_idx - 1));
             ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
             ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);

 continue;
 }

 if((IVD_RES_CHANGED == ret) ||
 (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == ret))
 {
 break;
 }

 /* Update bytes remaining and bytes consumed and input bitstream pointer */
 /* Do not consume the NAL in the following cases */
 /* Slice header reached during header decode mode */
 /* TODO: Next picture's slice reached */
 if(ret != IHEVCD_SLICE_IN_HEADER_MODE)
 {
 if((0 == ps_codec->i4_slice_error) ||
 (ps_codec->i4_bytes_remaining - (nal_len + nal_ofst) <= MIN_START_CODE_LEN))
 {
                ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
                ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);
 }
 if(ret != IHEVCD_SUCCESS)
 break;

 if(ps_codec->s_parse.i4_end_of_frame)
 break;
 }
 else
 {
            ret = IHEVCD_SUCCESS;
 break;
 }

 /* Allocate dynamic bitstream buffer once SPS is decoded */
 if((ps_codec->u4_allocate_dynamic_done == 0) && ps_codec->i4_sps_done)
 {
            WORD32 ret;
            ret = ihevcd_allocate_dynamic_bufs(ps_codec);
 if(ret != IV_SUCCESS)
 {
 /* Free any dynamic buffers that are allocated */
                ihevcd_free_dynamic_bufs(ps_codec);
                ps_codec->i4_error_code = IVD_MEM_ALLOC_FAILED;
                ps_dec_op->u4_error_code |= 1 << IVD_FATALERROR;
                ps_dec_op->u4_error_code |= IVD_MEM_ALLOC_FAILED;

 return IV_FAIL;
 }
 }

        BREAK_AFTER_SLICE_NAL();
 }

 if((ps_codec->u4_pic_cnt == 0) && (ret != IHEVCD_SUCCESS))
 {
        ps_codec->i4_error_code = ret;

        ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);
 return IV_FAIL;
 }

 if(1 == ps_codec->i4_pic_present)
 {
        WORD32 i;
 sps_t *ps_sps = ps_codec->s_parse.ps_sps;
        ps_codec->i4_first_pic_done = 1;

 /*TODO temporary fix: end_of_frame is checked before adding format conversion to job queue         */
 if(ps_codec->i4_num_cores > 1 && ps_codec->s_parse.i4_end_of_frame)
 {

 /* Add job queue for format conversion / frame copy for each ctb row */
 /* Only if the codec is in non-shared mode or in shared mode but needs 420P output */
 process_ctxt_t *ps_proc;

 /* i4_num_cores - 1 contexts are currently being used by other threads */
            ps_proc = &ps_codec->as_process[ps_codec->i4_num_cores - 1];

 if((ps_codec->ps_disp_buf) &&
 ((0 == ps_codec->i4_share_disp_buf) || (IV_YUV_420P == ps_codec->e_chroma_fmt)))
 {
 /* If format conversion jobs were not issued in pic_init() add them here */
 if((0 == ps_codec->u4_enable_fmt_conv_ahead) ||
 (ps_codec->i4_disp_buf_id == ps_proc->i4_cur_pic_buf_id))
 for(i = 0; i < ps_sps->i2_pic_ht_in_ctb; i++)
 {
 proc_job_t s_job;
                        IHEVCD_ERROR_T ret;
                        s_job.i4_cmd = CMD_FMTCONV;
                        s_job.i2_ctb_cnt = 0;
                        s_job.i2_ctb_x = 0;
                        s_job.i2_ctb_y = i;
                        s_job.i2_slice_idx = 0;
                        s_job.i4_tu_coeff_data_ofst = 0;
                        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 (WORD32)ret;
 }
 }
 /* Reached end of frame : Signal terminate */
 /* The terminate flag is checked only after all the jobs are dequeued */
            ret = ihevcd_jobq_terminate((jobq_t *)ps_codec->s_parse.pv_proc_jobq);

 while(1)
 {
                IHEVCD_ERROR_T ret;
 proc_job_t s_job;
 process_ctxt_t *ps_proc;

 /* i4_num_cores - 1 contexts are currently being used by other threads */
                ps_proc = &ps_codec->as_process[ps_codec->i4_num_cores - 1];

                ret = ihevcd_jobq_dequeue((jobq_t *)ps_proc->pv_proc_jobq, &s_job,
 sizeof(proc_job_t), 1);
 if((IHEVCD_ERROR_T)IHEVCD_SUCCESS != ret)
 break;

                ps_proc->i4_ctb_cnt = s_job.i2_ctb_cnt;
                ps_proc->i4_ctb_x = s_job.i2_ctb_x;
                ps_proc->i4_ctb_y = s_job.i2_ctb_y;
                ps_proc->i4_cur_slice_idx = s_job.i2_slice_idx;

 if(CMD_PROCESS == s_job.i4_cmd)
 {
                    ihevcd_init_proc_ctxt(ps_proc, s_job.i4_tu_coeff_data_ofst);

                    ihevcd_process(ps_proc);
 }
 else if(CMD_FMTCONV == s_job.i4_cmd)
 {
 sps_t *ps_sps = ps_codec->s_parse.ps_sps;
                    WORD32 num_rows = 1 << ps_sps->i1_log2_ctb_size;
 if(0 == ps_proc->i4_init_done)
 {
                        ihevcd_init_proc_ctxt(ps_proc, 0);
 }

                    num_rows = MIN(num_rows, (ps_codec->i4_disp_ht - (s_job.i2_ctb_y << ps_sps->i1_log2_ctb_size)));
 if(num_rows < 0)
                        num_rows = 0;

                    ihevcd_fmt_conv(ps_codec, ps_proc,
                                    ps_dec_ip->s_out_buffer.pu1_bufs[0],
                                    ps_dec_ip->s_out_buffer.pu1_bufs[1],
                                    ps_dec_ip->s_out_buffer.pu1_bufs[2],
                                    s_job.i2_ctb_y << ps_sps->i1_log2_ctb_size,
                                    num_rows);
 }
 }
 }
 /* In case of non-shared mode and while running in single core mode, then convert/copy the frame to output buffer */
 /* Only if the codec is in non-shared mode or in shared mode but needs 420P output */
 else if((ps_codec->ps_disp_buf) && ((0 == ps_codec->i4_share_disp_buf) ||
 (IV_YUV_420P == ps_codec->e_chroma_fmt)) &&
 (ps_codec->s_parse.i4_end_of_frame))
 {
 process_ctxt_t *ps_proc = &ps_codec->as_process[proc_idx];
 /* Set remaining number of rows to be processed */
            ps_codec->s_fmt_conv.i4_num_rows = ps_codec->i4_disp_ht
 - ps_codec->s_fmt_conv.i4_cur_row;
 if(0 == ps_proc->i4_init_done)
 {
                ihevcd_init_proc_ctxt(ps_proc, 0);
 }

 if(ps_codec->s_fmt_conv.i4_num_rows < 0)
                ps_codec->s_fmt_conv.i4_num_rows = 0;

            ret = ihevcd_fmt_conv(ps_codec, ps_proc,
                                  ps_dec_ip->s_out_buffer.pu1_bufs[0],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[1],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[2],
                                  ps_codec->s_fmt_conv.i4_cur_row,
                                  ps_codec->s_fmt_conv.i4_num_rows);
            ps_codec->s_fmt_conv.i4_cur_row += ps_codec->s_fmt_conv.i4_num_rows;

 }

        DEBUG_DUMP_MV_MAP(ps_codec);

 /* Mark MV Buf as needed for reference */
        ihevc_buf_mgr_set_status((buf_mgr_t *)ps_codec->pv_mv_buf_mgr,
                                 ps_codec->as_process[proc_idx].i4_cur_mv_bank_buf_id,
                                 BUF_MGR_REF);

 /* Mark pic buf as needed for reference */
        ihevc_buf_mgr_set_status((buf_mgr_t *)ps_codec->pv_pic_buf_mgr,
                                 ps_codec->as_process[proc_idx].i4_cur_pic_buf_id,
                                 BUF_MGR_REF);

 /* Mark pic buf as needed for display */
        ihevc_buf_mgr_set_status((buf_mgr_t *)ps_codec->pv_pic_buf_mgr,
                                 ps_codec->as_process[proc_idx].i4_cur_pic_buf_id,
                                 BUF_MGR_DISP);

 /* Insert the current picture as short term reference */
        ihevc_dpb_mgr_insert_ref((dpb_mgr_t *)ps_codec->pv_dpb_mgr,
                                 ps_codec->as_process[proc_idx].ps_cur_pic,
                                 ps_codec->as_process[proc_idx].i4_cur_pic_buf_id);

 /* If a frame was displayed (in non-shared mode), then release it from display manager */
 if((0 == ps_codec->i4_share_disp_buf) && (ps_codec->ps_disp_buf))
            ihevc_buf_mgr_release((buf_mgr_t *)ps_codec->pv_pic_buf_mgr,
                                  ps_codec->i4_disp_buf_id, BUF_MGR_DISP);

 /* Wait for threads */
 for(i = 0; i < (ps_codec->i4_num_cores - 1); i++)
 {
 if(ps_codec->ai4_process_thread_created[i])
 {
                ithread_join(ps_codec->apv_process_thread_handle[i], NULL);
                ps_codec->ai4_process_thread_created[i] = 0;
 }
 }

        DEBUG_VALIDATE_PADDED_REGION(&ps_codec->as_process[proc_idx]);
 if(ps_codec->u4_pic_cnt > 0)
 {
            DEBUG_DUMP_PIC_PU(ps_codec);
 }
        DEBUG_DUMP_PIC_BUFFERS(ps_codec);

 /* Increment the number of pictures decoded */
        ps_codec->u4_pic_cnt++;
 }
    ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);

 if(1 == ps_dec_op->u4_output_present)
 {
        WORD32 xpos = ps_codec->i4_disp_wd - 32 - LOGO_WD;
        WORD32 ypos = ps_codec->i4_disp_ht - 32 - LOGO_HT;

 if(ypos < 0)
            ypos = 0;

 if(xpos < 0)
            xpos = 0;

        INSERT_LOGO(ps_dec_ip->s_out_buffer.pu1_bufs[0],
                    ps_dec_ip->s_out_buffer.pu1_bufs[1],
                    ps_dec_ip->s_out_buffer.pu1_bufs[2], ps_codec->i4_disp_strd,
                    xpos,
                    ypos,
                    ps_codec->e_chroma_fmt,
                    ps_codec->i4_disp_wd,
                    ps_codec->i4_disp_ht);
 }

 return ret;
}

A vulnerability in the Android media framework (n/a). Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0. Android ID: A-63045918.


WORD32 ihevcd_decode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
{
    WORD32 ret = IV_SUCCESS;
 codec_t *ps_codec = (codec_t *)(ps_codec_obj->pv_codec_handle);
 ivd_video_decode_ip_t *ps_dec_ip;
 ivd_video_decode_op_t *ps_dec_op;

    WORD32 proc_idx = 0;
    WORD32 prev_proc_idx = 0;

 /* Initialize error code */
    ps_codec->i4_error_code = 0;

    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 = ps_dec_op->u4_size;
        memset(ps_dec_op, 0, sizeof(ivd_video_decode_op_t));
        ps_dec_op->u4_size = u4_size; //Restore size field
 }
 if(ps_codec->i4_init_done != 1)
 {
        ps_dec_op->u4_error_code |= 1 << IVD_FATALERROR;
        ps_dec_op->u4_error_code |= IHEVCD_INIT_NOT_DONE;
 return IV_FAIL;
 }

 if(ps_codec->u4_pic_cnt >= NUM_FRAMES_LIMIT)
 {
        ps_dec_op->u4_error_code |= 1 << IVD_FATALERROR;
        ps_dec_op->u4_error_code |= IHEVCD_NUM_FRAMES_LIMIT_REACHED;
 return IV_FAIL;
 }

 /* If reset flag is set, flush the existing buffers */
 if(ps_codec->i4_reset_flag)
 {
        ps_codec->i4_flush_mode = 1;
 }

 /*Data memory barries instruction,so that bitstream write by the application is complete*/
 /* In case the decoder is not in flush mode check for input buffer validity */
 if(0 == ps_codec->i4_flush_mode)
 {
 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 <= MIN_START_CODE_LEN)
 {
 if((WORD32)ps_dec_ip->u4_num_Bytes > 0)
                ps_dec_op->u4_num_bytes_consumed = ps_dec_ip->u4_num_Bytes;
 else
                ps_dec_op->u4_num_bytes_consumed = 0;

            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
            ps_dec_op->u4_error_code |= IVD_DEC_NUMBYTES_INV;
 return IV_FAIL;

 }
 }

#ifdef APPLY_CONCEALMENT
 {
        WORD32 num_mbs;

        num_mbs = (ps_codec->i4_wd * ps_codec->i4_ht + 255) >> 8;
 /* Reset MB Count at the beginning of every process call */
        ps_codec->mb_count = 0;
        memset(ps_codec->mb_map, 0, ((num_mbs + 7) >> 3));
 }
#endif

 if(0 == ps_codec->i4_share_disp_buf && ps_codec->i4_header_mode == 0)
 {
        UWORD32 i;
 if(ps_dec_ip->s_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_ip->s_out_buffer.u4_num_bufs; i++)
 {
 if(ps_dec_ip->s_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_ip->s_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;
 }
 }
 }

    ps_codec->ps_out_buffer = &ps_dec_ip->s_out_buffer;
    ps_codec->u4_ts = ps_dec_ip->u4_ts;
 if(ps_codec->i4_flush_mode)
 {

        ps_dec_op->u4_pic_wd = ps_codec->i4_disp_wd;
        ps_dec_op->u4_pic_ht = ps_codec->i4_disp_ht;

        ps_dec_op->u4_new_seq = 0;

        ps_codec->ps_disp_buf = (pic_buf_t *)ihevc_disp_mgr_get(
 (disp_mgr_t *)ps_codec->pv_disp_buf_mgr, &ps_codec->i4_disp_buf_id);
 /* In case of non-shared mode, then convert/copy the frame to output buffer */
 /* Only if the codec is in non-shared mode or in shared mode but needs 420P output */
 if((ps_codec->ps_disp_buf)
 && ((0 == ps_codec->i4_share_disp_buf)
 || (IV_YUV_420P
 == ps_codec->e_chroma_fmt)))
 {

 process_ctxt_t *ps_proc = &ps_codec->as_process[prev_proc_idx];
 if(0 == ps_proc->i4_init_done)
 {
                ihevcd_init_proc_ctxt(ps_proc, 0);
 }

 /* Output buffer check */
            ret = ihevcd_check_out_buf_size(ps_codec);
            RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);

 /* Set remaining number of rows to be processed */
            ret = ihevcd_fmt_conv(ps_codec, &ps_codec->as_process[prev_proc_idx],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[0],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[1],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[2], 0,
                                  ps_codec->i4_disp_ht);

            ihevc_buf_mgr_release((buf_mgr_t *)ps_codec->pv_pic_buf_mgr,
                                  ps_codec->i4_disp_buf_id, BUF_MGR_DISP);
 }

        ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);

 if(1 == ps_dec_op->u4_output_present)
 {
            WORD32 xpos = ps_codec->i4_disp_wd - 32 - LOGO_WD;
            WORD32 ypos = ps_codec->i4_disp_ht - 32 - LOGO_HT;

 if(ypos < 0)
                ypos = 0;

 if(xpos < 0)
                xpos = 0;

            INSERT_LOGO(ps_dec_ip->s_out_buffer.pu1_bufs[0],
                        ps_dec_ip->s_out_buffer.pu1_bufs[1],
                        ps_dec_ip->s_out_buffer.pu1_bufs[2], ps_codec->i4_disp_strd,
                        xpos,
                        ypos,
                        ps_codec->e_chroma_fmt,
                        ps_codec->i4_disp_wd,
                        ps_codec->i4_disp_ht);
 }

 if(NULL == ps_codec->ps_disp_buf)
 {
 /* If in flush mode and there are no more buffers to flush,
             * check for the reset flag and reset the decoder */
 if(ps_codec->i4_reset_flag)
 {
                ihevcd_init(ps_codec);
 }
 return (IV_FAIL);
 }

 return (IV_SUCCESS);

 }
 /* In case of shared mode, check if there is a free buffer for reconstruction */
 if((0 == ps_codec->i4_header_mode) && (1 == ps_codec->i4_share_disp_buf))
 {
        WORD32 buf_status;
        buf_status = 1;
 if(ps_codec->pv_pic_buf_mgr)
            buf_status = ihevc_buf_mgr_check_free((buf_mgr_t *)ps_codec->pv_pic_buf_mgr);

 /* If there is no free buffer, then return with an error code */
 if(0 == buf_status)
 {
            ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;
            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);
 return IV_FAIL;
 }
 }
    ps_codec->i4_bytes_remaining = ps_dec_ip->u4_num_Bytes;
    ps_codec->pu1_inp_bitsbuf = (UWORD8 *)ps_dec_ip->pv_stream_buffer;
    ps_codec->s_parse.i4_end_of_frame = 0;

    ps_codec->i4_pic_present = 0;
    ps_codec->i4_slice_error = 0;
    ps_codec->ps_disp_buf = NULL;

 if(ps_codec->i4_num_cores > 1)
 {
        ithread_set_affinity(0);
 }
 while(MIN_START_CODE_LEN < ps_codec->i4_bytes_remaining)
 {
        WORD32 nal_len;
        WORD32 nal_ofst;
        WORD32 bits_len;

 if(ps_codec->i4_slice_error)
 {
 slice_header_t *ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + (ps_codec->s_parse.i4_cur_slice_idx & (MAX_SLICE_HDR_CNT - 1));
            WORD32 next_slice_addr = ps_slice_hdr_next->i2_ctb_x +
                            ps_slice_hdr_next->i2_ctb_y * ps_codec->s_parse.ps_sps->i2_pic_wd_in_ctb;
 if(ps_codec->s_parse.i4_next_ctb_indx == next_slice_addr)
                ps_codec->i4_slice_error = 0;
 }

 if(ps_codec->pu1_bitsbuf_dynamic)
 {
            ps_codec->pu1_bitsbuf = ps_codec->pu1_bitsbuf_dynamic;
            ps_codec->u4_bitsbuf_size = ps_codec->u4_bitsbuf_size_dynamic;
 }
 else
 {
            ps_codec->pu1_bitsbuf = ps_codec->pu1_bitsbuf_static;
            ps_codec->u4_bitsbuf_size = ps_codec->u4_bitsbuf_size_static;
 }

        nal_ofst = ihevcd_nal_search_start_code(ps_codec->pu1_inp_bitsbuf,
                                                ps_codec->i4_bytes_remaining);

        ps_codec->i4_nal_ofst = nal_ofst;
 {
            WORD32 bytes_remaining = ps_codec->i4_bytes_remaining - nal_ofst;

            bytes_remaining = MIN((UWORD32)bytes_remaining, ps_codec->u4_bitsbuf_size);
            ihevcd_nal_remv_emuln_bytes(ps_codec->pu1_inp_bitsbuf + nal_ofst,
                                        ps_codec->pu1_bitsbuf,
                                        bytes_remaining,
 &nal_len, &bits_len);

 /* Decoder may read upto 8 extra bytes at the end of frame */
 /* These are not used, but still set them to zero to avoid uninitialized reads */
 if(bits_len < (WORD32)(ps_codec->u4_bitsbuf_size - 8))
 {
                memset(ps_codec->pu1_bitsbuf + bits_len, 0, 2 * sizeof(UWORD32));
 }
 }
 /* This may be used to update the offsets for tiles and entropy sync row offsets */
        ps_codec->i4_num_emln_bytes = nal_len - bits_len;
        ps_codec->i4_nal_len = nal_len;

        ihevcd_bits_init(&ps_codec->s_parse.s_bitstrm, ps_codec->pu1_bitsbuf,
                         bits_len);

        ret = ihevcd_nal_unit(ps_codec);

 /* If the frame is incomplete and
         * the bytes remaining is zero or a header is received,
         * complete the frame treating it to be in error */
 if(ps_codec->i4_pic_present &&
 (ps_codec->s_parse.i4_next_ctb_indx != ps_codec->s_parse.ps_sps->i4_pic_size_in_ctb))
 {
 if((ps_codec->i4_bytes_remaining - (nal_len + nal_ofst) <= MIN_START_CODE_LEN) ||
 (ps_codec->i4_header_in_slice_mode))
 {
 slice_header_t *ps_slice_hdr_next;

                ps_codec->s_parse.i4_cur_slice_idx--;
 if(ps_codec->s_parse.i4_cur_slice_idx < 0)
                    ps_codec->s_parse.i4_cur_slice_idx = 0;

                ps_slice_hdr_next = ps_codec->s_parse.ps_slice_hdr_base + ((ps_codec->s_parse.i4_cur_slice_idx + 1) & (MAX_SLICE_HDR_CNT - 1));
                ps_slice_hdr_next->i2_ctb_x = 0;
                ps_slice_hdr_next->i2_ctb_y = ps_codec->s_parse.ps_sps->i2_pic_ht_in_ctb;
                ps_codec->i4_slice_error = 1;
 continue;
 }
 }

         if(IHEVCD_IGNORE_SLICE == ret)
         {
             ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
             ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);

 continue;
 }

 if((IVD_RES_CHANGED == ret) ||
 (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == ret))
 {
 break;
 }

 /* Update bytes remaining and bytes consumed and input bitstream pointer */
 /* Do not consume the NAL in the following cases */
 /* Slice header reached during header decode mode */
 /* TODO: Next picture's slice reached */
 if(ret != IHEVCD_SLICE_IN_HEADER_MODE)
 {
 if((0 == ps_codec->i4_slice_error) ||
 (ps_codec->i4_bytes_remaining - (nal_len + nal_ofst) <= MIN_START_CODE_LEN))
 {
                ps_codec->pu1_inp_bitsbuf += (nal_ofst + nal_len);
                ps_codec->i4_bytes_remaining -= (nal_ofst + nal_len);
 }
 if(ret != IHEVCD_SUCCESS)
 break;

 if(ps_codec->s_parse.i4_end_of_frame)
 break;
 }
 else
 {
            ret = IHEVCD_SUCCESS;
 break;
 }

 /* Allocate dynamic bitstream buffer once SPS is decoded */
 if((ps_codec->u4_allocate_dynamic_done == 0) && ps_codec->i4_sps_done)
 {
            WORD32 ret;
            ret = ihevcd_allocate_dynamic_bufs(ps_codec);
 if(ret != IV_SUCCESS)
 {
 /* Free any dynamic buffers that are allocated */
                ihevcd_free_dynamic_bufs(ps_codec);
                ps_codec->i4_error_code = IVD_MEM_ALLOC_FAILED;
                ps_dec_op->u4_error_code |= 1 << IVD_FATALERROR;
                ps_dec_op->u4_error_code |= IVD_MEM_ALLOC_FAILED;

 return IV_FAIL;
 }
 }

        BREAK_AFTER_SLICE_NAL();
 }

 if((ps_codec->u4_pic_cnt == 0) && (ret != IHEVCD_SUCCESS))
 {
        ps_codec->i4_error_code = ret;

        ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);
 return IV_FAIL;
 }

 if(1 == ps_codec->i4_pic_present)
 {
        WORD32 i;
 sps_t *ps_sps = ps_codec->s_parse.ps_sps;
        ps_codec->i4_first_pic_done = 1;

 /*TODO temporary fix: end_of_frame is checked before adding format conversion to job queue         */
 if(ps_codec->i4_num_cores > 1 && ps_codec->s_parse.i4_end_of_frame)
 {

 /* Add job queue for format conversion / frame copy for each ctb row */
 /* Only if the codec is in non-shared mode or in shared mode but needs 420P output */
 process_ctxt_t *ps_proc;

 /* i4_num_cores - 1 contexts are currently being used by other threads */
            ps_proc = &ps_codec->as_process[ps_codec->i4_num_cores - 1];

 if((ps_codec->ps_disp_buf) &&
 ((0 == ps_codec->i4_share_disp_buf) || (IV_YUV_420P == ps_codec->e_chroma_fmt)))
 {
 /* If format conversion jobs were not issued in pic_init() add them here */
 if((0 == ps_codec->u4_enable_fmt_conv_ahead) ||
 (ps_codec->i4_disp_buf_id == ps_proc->i4_cur_pic_buf_id))
 for(i = 0; i < ps_sps->i2_pic_ht_in_ctb; i++)
 {
 proc_job_t s_job;
                        IHEVCD_ERROR_T ret;
                        s_job.i4_cmd = CMD_FMTCONV;
                        s_job.i2_ctb_cnt = 0;
                        s_job.i2_ctb_x = 0;
                        s_job.i2_ctb_y = i;
                        s_job.i2_slice_idx = 0;
                        s_job.i4_tu_coeff_data_ofst = 0;
                        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 (WORD32)ret;
 }
 }
 /* Reached end of frame : Signal terminate */
 /* The terminate flag is checked only after all the jobs are dequeued */
            ret = ihevcd_jobq_terminate((jobq_t *)ps_codec->s_parse.pv_proc_jobq);

 while(1)
 {
                IHEVCD_ERROR_T ret;
 proc_job_t s_job;
 process_ctxt_t *ps_proc;

 /* i4_num_cores - 1 contexts are currently being used by other threads */
                ps_proc = &ps_codec->as_process[ps_codec->i4_num_cores - 1];

                ret = ihevcd_jobq_dequeue((jobq_t *)ps_proc->pv_proc_jobq, &s_job,
 sizeof(proc_job_t), 1);
 if((IHEVCD_ERROR_T)IHEVCD_SUCCESS != ret)
 break;

                ps_proc->i4_ctb_cnt = s_job.i2_ctb_cnt;
                ps_proc->i4_ctb_x = s_job.i2_ctb_x;
                ps_proc->i4_ctb_y = s_job.i2_ctb_y;
                ps_proc->i4_cur_slice_idx = s_job.i2_slice_idx;

 if(CMD_PROCESS == s_job.i4_cmd)
 {
                    ihevcd_init_proc_ctxt(ps_proc, s_job.i4_tu_coeff_data_ofst);

                    ihevcd_process(ps_proc);
 }
 else if(CMD_FMTCONV == s_job.i4_cmd)
 {
 sps_t *ps_sps = ps_codec->s_parse.ps_sps;
                    WORD32 num_rows = 1 << ps_sps->i1_log2_ctb_size;
 if(0 == ps_proc->i4_init_done)
 {
                        ihevcd_init_proc_ctxt(ps_proc, 0);
 }

                    num_rows = MIN(num_rows, (ps_codec->i4_disp_ht - (s_job.i2_ctb_y << ps_sps->i1_log2_ctb_size)));
 if(num_rows < 0)
                        num_rows = 0;

                    ihevcd_fmt_conv(ps_codec, ps_proc,
                                    ps_dec_ip->s_out_buffer.pu1_bufs[0],
                                    ps_dec_ip->s_out_buffer.pu1_bufs[1],
                                    ps_dec_ip->s_out_buffer.pu1_bufs[2],
                                    s_job.i2_ctb_y << ps_sps->i1_log2_ctb_size,
                                    num_rows);
 }
 }
 }
 /* In case of non-shared mode and while running in single core mode, then convert/copy the frame to output buffer */
 /* Only if the codec is in non-shared mode or in shared mode but needs 420P output */
 else if((ps_codec->ps_disp_buf) && ((0 == ps_codec->i4_share_disp_buf) ||
 (IV_YUV_420P == ps_codec->e_chroma_fmt)) &&
 (ps_codec->s_parse.i4_end_of_frame))
 {
 process_ctxt_t *ps_proc = &ps_codec->as_process[proc_idx];
 /* Set remaining number of rows to be processed */
            ps_codec->s_fmt_conv.i4_num_rows = ps_codec->i4_disp_ht
 - ps_codec->s_fmt_conv.i4_cur_row;
 if(0 == ps_proc->i4_init_done)
 {
                ihevcd_init_proc_ctxt(ps_proc, 0);
 }

 if(ps_codec->s_fmt_conv.i4_num_rows < 0)
                ps_codec->s_fmt_conv.i4_num_rows = 0;

            ret = ihevcd_fmt_conv(ps_codec, ps_proc,
                                  ps_dec_ip->s_out_buffer.pu1_bufs[0],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[1],
                                  ps_dec_ip->s_out_buffer.pu1_bufs[2],
                                  ps_codec->s_fmt_conv.i4_cur_row,
                                  ps_codec->s_fmt_conv.i4_num_rows);
            ps_codec->s_fmt_conv.i4_cur_row += ps_codec->s_fmt_conv.i4_num_rows;

 }

        DEBUG_DUMP_MV_MAP(ps_codec);

 /* Mark MV Buf as needed for reference */
        ihevc_buf_mgr_set_status((buf_mgr_t *)ps_codec->pv_mv_buf_mgr,
                                 ps_codec->as_process[proc_idx].i4_cur_mv_bank_buf_id,
                                 BUF_MGR_REF);

 /* Mark pic buf as needed for reference */
        ihevc_buf_mgr_set_status((buf_mgr_t *)ps_codec->pv_pic_buf_mgr,
                                 ps_codec->as_process[proc_idx].i4_cur_pic_buf_id,
                                 BUF_MGR_REF);

 /* Mark pic buf as needed for display */
        ihevc_buf_mgr_set_status((buf_mgr_t *)ps_codec->pv_pic_buf_mgr,
                                 ps_codec->as_process[proc_idx].i4_cur_pic_buf_id,
                                 BUF_MGR_DISP);

 /* Insert the current picture as short term reference */
        ihevc_dpb_mgr_insert_ref((dpb_mgr_t *)ps_codec->pv_dpb_mgr,
                                 ps_codec->as_process[proc_idx].ps_cur_pic,
                                 ps_codec->as_process[proc_idx].i4_cur_pic_buf_id);

 /* If a frame was displayed (in non-shared mode), then release it from display manager */
 if((0 == ps_codec->i4_share_disp_buf) && (ps_codec->ps_disp_buf))
            ihevc_buf_mgr_release((buf_mgr_t *)ps_codec->pv_pic_buf_mgr,
                                  ps_codec->i4_disp_buf_id, BUF_MGR_DISP);

 /* Wait for threads */
 for(i = 0; i < (ps_codec->i4_num_cores - 1); i++)
 {
 if(ps_codec->ai4_process_thread_created[i])
 {
                ithread_join(ps_codec->apv_process_thread_handle[i], NULL);
                ps_codec->ai4_process_thread_created[i] = 0;
 }
 }

        DEBUG_VALIDATE_PADDED_REGION(&ps_codec->as_process[proc_idx]);
 if(ps_codec->u4_pic_cnt > 0)
 {
            DEBUG_DUMP_PIC_PU(ps_codec);
 }
        DEBUG_DUMP_PIC_BUFFERS(ps_codec);

 /* Increment the number of pictures decoded */
        ps_codec->u4_pic_cnt++;
 }
    ihevcd_fill_outargs(ps_codec, ps_dec_ip, ps_dec_op);

 if(1 == ps_dec_op->u4_output_present)
 {
        WORD32 xpos = ps_codec->i4_disp_wd - 32 - LOGO_WD;
        WORD32 ypos = ps_codec->i4_disp_ht - 32 - LOGO_HT;

 if(ypos < 0)
            ypos = 0;

 if(xpos < 0)
            xpos = 0;

        INSERT_LOGO(ps_dec_ip->s_out_buffer.pu1_bufs[0],
                    ps_dec_ip->s_out_buffer.pu1_bufs[1],
                    ps_dec_ip->s_out_buffer.pu1_bufs[2], ps_codec->i4_disp_strd,
                    xpos,
                    ypos,
                    ps_codec->e_chroma_fmt,
                    ps_codec->i4_disp_wd,
                    ps_codec->i4_disp_ht);
 }

 return ret;
}


status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
 if (mOffset <= mFirstDataOffset && mStartGranulePosition < 0) {
 MediaBuffer *mBuf;
 uint32_t numSamples = 0;
 uint64_t curGranulePosition = 0;
 while (true) {
 status_t err = _readNextPacket(&mBuf, /* calcVorbisTimestamp = */false);
 if (err != OK && err != ERROR_END_OF_STREAM) {
 return err;

             }
             if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
                 break;
             }
             curGranulePosition = mCurrentPage.mGranulePosition;
            numSamples += getNumSamplesInPacket(mBuf);
            mBuf->release();
            mBuf = NULL;
 }

 if (curGranulePosition > numSamples) {
            mStartGranulePosition = curGranulePosition - numSamples;
 } else {
            mStartGranulePosition = 0;
 }
        seekToOffset(0);
 }

 status_t err = _readNextPacket(out, /* calcVorbisTimestamp = */false);
 if (err != OK) {
 return err;
 }

 int32_t currentPageSamples;
 if ((*out)->meta_data()->findInt32(kKeyValidSamples, &currentPageSamples)) {
 if (mOffset == mFirstDataOffset) {
            currentPageSamples -= mStartGranulePosition;
 (*out)->meta_data()->setInt32(kKeyValidSamples, currentPageSamples);
 }
        mCurGranulePosition = mCurrentPage.mGranulePosition - currentPageSamples;
 }

 int64_t timeUs = getTimeUsOfGranule(mCurGranulePosition);
 (*out)->meta_data()->setInt64(kKeyTime, timeUs);

 uint32_t frames = getNumSamplesInPacket(*out);
    mCurGranulePosition += frames;
 return OK;
}

A vulnerability in the Android media framework (n/a). Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0. Android ID: A-63581671.


status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
 if (mOffset <= mFirstDataOffset && mStartGranulePosition < 0) {
 MediaBuffer *mBuf;
 uint32_t numSamples = 0;
 uint64_t curGranulePosition = 0;
 while (true) {
 status_t err = _readNextPacket(&mBuf, /* calcVorbisTimestamp = */false);
 if (err != OK && err != ERROR_END_OF_STREAM) {
 return err;

             }
             if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
                if (mBuf != NULL) {
                    mBuf->release();
                    mBuf = NULL;
                }
                 break;
             }
             curGranulePosition = mCurrentPage.mGranulePosition;
            numSamples += getNumSamplesInPacket(mBuf);
            mBuf->release();
            mBuf = NULL;
 }

 if (curGranulePosition > numSamples) {
            mStartGranulePosition = curGranulePosition - numSamples;
 } else {
            mStartGranulePosition = 0;
 }
        seekToOffset(0);
 }

 status_t err = _readNextPacket(out, /* calcVorbisTimestamp = */false);
 if (err != OK) {
 return err;
 }

 int32_t currentPageSamples;
 if ((*out)->meta_data()->findInt32(kKeyValidSamples, &currentPageSamples)) {
 if (mOffset == mFirstDataOffset) {
            currentPageSamples -= mStartGranulePosition;
 (*out)->meta_data()->setInt32(kKeyValidSamples, currentPageSamples);
 }
        mCurGranulePosition = mCurrentPage.mGranulePosition - currentPageSamples;
 }

 int64_t timeUs = getTimeUsOfGranule(mCurGranulePosition);
 (*out)->meta_data()->setInt64(kKeyTime, timeUs);

 uint32_t frames = getNumSamplesInPacket(*out);
    mCurGranulePosition += frames;
 return OK;
}


status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
 if (mSyncSampleOffset >= 0 || data_size < 8) {
 return ERROR_MALFORMED;
 }

 uint8_t header[8];
 if (mDataSource->readAt(
                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
 return ERROR_IO;
 }

 if (U32_AT(header) != 0) {
 return ERROR_MALFORMED;
 }

 uint32_t numSyncSamples = U32_AT(&header[4]);

 if (numSyncSamples < 2) {
        ALOGV("Table of sync samples is empty or has only a single entry!");
 }

 uint64_t allocSize = (uint64_t)numSyncSamples * sizeof(uint32_t);
 if (allocSize > kMaxTotalSize) {
        ALOGE("Sync sample table size too large.");
 return ERROR_OUT_OF_RANGE;
 }

    mTotalSize += allocSize;
 if (mTotalSize > kMaxTotalSize) {
        ALOGE("Sync sample table size would make sample table too large.\n"
 "    Requested sync sample table size = %llu\n"
 "    Eventual sample table size >= %llu\n"
 "    Allowed sample table size = %llu\n",
 (unsigned long long)allocSize,
 (unsigned long long)mTotalSize,
 (unsigned long long)kMaxTotalSize);
 return ERROR_OUT_OF_RANGE;
 }

    mSyncSamples = new (std::nothrow) uint32_t[numSyncSamples];
 if (!mSyncSamples) {
        ALOGE("Cannot allocate sync sample table with %llu entries.",
 (unsigned long long)numSyncSamples);
 return ERROR_OUT_OF_RANGE;
 }

     if (mDataSource->readAt(data_offset + 8, mSyncSamples,
             (size_t)allocSize) != (ssize_t)allocSize) {
        delete mSyncSamples;
         mSyncSamples = NULL;
         return ERROR_IO;
     }

 for (size_t i = 0; i < numSyncSamples; ++i) {
 if (mSyncSamples[i] == 0) {
            ALOGE("b/32423862, unexpected zero value in stss");
 continue;
 }
        mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
 }

    mSyncSampleOffset = data_offset;
    mNumSyncSamples = numSyncSamples;

 return OK;
}

A denial of service vulnerability in the Android media framework (libstagefright). Product: Android. Versions: 7.0, 7.1.1, 7.1.2. Android ID: A-36531046.


status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
 if (mSyncSampleOffset >= 0 || data_size < 8) {
 return ERROR_MALFORMED;
 }

 uint8_t header[8];
 if (mDataSource->readAt(
                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
 return ERROR_IO;
 }

 if (U32_AT(header) != 0) {
 return ERROR_MALFORMED;
 }

 uint32_t numSyncSamples = U32_AT(&header[4]);

 if (numSyncSamples < 2) {
        ALOGV("Table of sync samples is empty or has only a single entry!");
 }

 uint64_t allocSize = (uint64_t)numSyncSamples * sizeof(uint32_t);
 if (allocSize > kMaxTotalSize) {
        ALOGE("Sync sample table size too large.");
 return ERROR_OUT_OF_RANGE;
 }

    mTotalSize += allocSize;
 if (mTotalSize > kMaxTotalSize) {
        ALOGE("Sync sample table size would make sample table too large.\n"
 "    Requested sync sample table size = %llu\n"
 "    Eventual sample table size >= %llu\n"
 "    Allowed sample table size = %llu\n",
 (unsigned long long)allocSize,
 (unsigned long long)mTotalSize,
 (unsigned long long)kMaxTotalSize);
 return ERROR_OUT_OF_RANGE;
 }

    mSyncSamples = new (std::nothrow) uint32_t[numSyncSamples];
 if (!mSyncSamples) {
        ALOGE("Cannot allocate sync sample table with %llu entries.",
 (unsigned long long)numSyncSamples);
 return ERROR_OUT_OF_RANGE;
 }

     if (mDataSource->readAt(data_offset + 8, mSyncSamples,
             (size_t)allocSize) != (ssize_t)allocSize) {
        delete[] mSyncSamples;
         mSyncSamples = NULL;
         return ERROR_IO;
     }

 for (size_t i = 0; i < numSyncSamples; ++i) {
 if (mSyncSamples[i] == 0) {
            ALOGE("b/32423862, unexpected zero value in stss");
 continue;
 }
        mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
 }

    mSyncSampleOffset = data_offset;
    mNumSyncSamples = numSyncSamples;

 return OK;
}


static ssize_t read_and_process_frames(struct audio_stream_in *stream, void* buffer, ssize_t frames_num)
{
 struct stream_in *in = (struct stream_in *)stream;

     ssize_t frames_wr = 0; /* Number of frames actually read */
     size_t bytes_per_sample = audio_bytes_per_sample(stream->common.get_format(&stream->common));
     void *proc_buf_out = buffer;
#ifdef PREPROCESSING_ENABLED
    audio_buffer_t in_buf;
    audio_buffer_t out_buf;
    int i;
    bool has_processing = in->num_preprocessors != 0;
#endif
     /* Additional channels might be added on top of main_channels:
     * - aux_channels (by processing effects)
     * - extra channels due to HW limitations
    * In case of additional channels, we cannot work inplace
    */

     size_t src_channels = in->config.channels;
     size_t dst_channels = audio_channel_count_from_in_mask(in->main_channels);
     bool channel_remapping_needed = (dst_channels != src_channels);
    size_t src_buffer_size = frames_num * src_channels * bytes_per_sample;

 #ifdef PREPROCESSING_ENABLED
     if (has_processing) {
 /* since all the processing below is done in frames and using the config.channels
         * as the number of channels, no changes is required in case aux_channels are present */

         while (frames_wr < frames_num) {
             /* first reload enough frames at the end of process input buffer */
             if (in->proc_buf_frames < (size_t)frames_num) {
                ssize_t frames_rd;
                if (in->proc_buf_size < (size_t)frames_num) {
                    in->proc_buf_size = (size_t)frames_num;
                    in->proc_buf_in = realloc(in->proc_buf_in, src_buffer_size);
                    ALOG_ASSERT((in->proc_buf_in != NULL),
                                "process_frames() failed to reallocate proc_buf_in");
                    if (channel_remapping_needed) {
                        in->proc_buf_out = realloc(in->proc_buf_out, src_buffer_size);
                        ALOG_ASSERT((in->proc_buf_out != NULL),
                                    "process_frames() failed to reallocate proc_buf_out");
                        proc_buf_out = in->proc_buf_out;
                    }
                }
                frames_rd = read_frames(in,
                                        in->proc_buf_in +
                                            in->proc_buf_frames * src_channels * bytes_per_sample,
                                        frames_num - in->proc_buf_frames);
                  if (frames_rd < 0) {
                     /* Return error code */
                     frames_wr = frames_rd;
                     break;
 }
                in->proc_buf_frames += frames_rd;
 }

              /* in_buf.frameCount and out_buf.frameCount indicate respectively
               * the maximum number of frames to be consumed and produced by process() */
             in_buf.frameCount = in->proc_buf_frames;
            in_buf.s16 = in->proc_buf_in;
             out_buf.frameCount = frames_num - frames_wr;
            out_buf.s16 = (int16_t *)proc_buf_out + frames_wr * in->config.channels;

             /* FIXME: this works because of current pre processing library implementation that
              * does the actual process only when the last enabled effect process is called.
              * The generic solution is to have an output buffer for each effect and pass it as
              * input to the next.
              */
            for (i = 0; i < in->num_preprocessors; i++) {
                 (*in->preprocessors[i].effect_itfe)->process(in->preprocessors[i].effect_itfe,
                                                    &in_buf,
                                                    &out_buf);
 }

 /* process() has updated the number of frames consumed and produced in
             * in_buf.frameCount and out_buf.frameCount respectively
             * move remaining frames to the beginning of in->proc_buf_in */
            in->proc_buf_frames -= in_buf.frameCount;

             if (in->proc_buf_frames) {
                 memcpy(in->proc_buf_in,
                       in->proc_buf_in + in_buf.frameCount * src_channels * bytes_per_sample,
                       in->proc_buf_frames * in->config.channels * audio_bytes_per_sample(in_get_format(in)));
             }

             /* if not enough frames were passed to process(), read more and retry. */
 if (out_buf.frameCount == 0) {
                ALOGW("No frames produced by preproc");
 continue;
 }

 if ((frames_wr + (ssize_t)out_buf.frameCount) <= frames_num) {
                frames_wr += out_buf.frameCount;
 } else {
 /* The effect does not comply to the API. In theory, we should never end up here! */
                ALOGE("preprocessing produced too many frames: %d + %zd  > %d !",
 (unsigned int)frames_wr, out_buf.frameCount, (unsigned int)frames_num);
                frames_wr = frames_num;
 }
 }
 }
 else

 #endif //PREPROCESSING_ENABLED
     {
         /* No processing effects attached */
        if (channel_remapping_needed) {
            /* With additional channels, we cannot use original buffer */
            if (in->proc_buf_size < src_buffer_size) {
                in->proc_buf_size = src_buffer_size;
                in->proc_buf_out = realloc(in->proc_buf_out, src_buffer_size);
                ALOG_ASSERT((in->proc_buf_out != NULL),
                            "process_frames() failed to reallocate proc_buf_out");
            }
            proc_buf_out = in->proc_buf_out;
        }
         frames_wr = read_frames(in, proc_buf_out, frames_num);
         ALOG_ASSERT(frames_wr <= frames_num, "read more frames than requested");
     }

    if (channel_remapping_needed) {
         size_t ret = adjust_channels(proc_buf_out, src_channels, buffer, dst_channels,
            bytes_per_sample, frames_wr * src_channels * bytes_per_sample);
         ALOG_ASSERT(ret == (frames_wr * dst_channels * bytes_per_sample));
     }

 return frames_wr;
}

An elevation of privilege vulnerability in the Android media framework (audio hal). Product: Android. Versions: 7.0, 7.1.1, 7.1.2, 8.0. Android ID: A-62873231.


static ssize_t read_and_process_frames(struct audio_stream_in *stream, void* buffer, ssize_t frames_num)
{
 struct stream_in *in = (struct stream_in *)stream;

     ssize_t frames_wr = 0; /* Number of frames actually read */
     size_t bytes_per_sample = audio_bytes_per_sample(stream->common.get_format(&stream->common));
     void *proc_buf_out = buffer;

     /* Additional channels might be added on top of main_channels:
     * - aux_channels (by processing effects)
     * - extra channels due to HW limitations
    * In case of additional channels, we cannot work inplace
    */

     size_t src_channels = in->config.channels;
     size_t dst_channels = audio_channel_count_from_in_mask(in->main_channels);
     bool channel_remapping_needed = (dst_channels != src_channels);
    const size_t src_frame_size = src_channels * bytes_per_sample;

#ifdef PREPROCESSING_ENABLED
    const bool has_processing = in->num_preprocessors != 0;
#else
    const bool has_processing = false;
#endif

    /* With additional channels or processing, we need intermediate buffers */
    if (channel_remapping_needed || has_processing) {
        const size_t src_buffer_size = frames_num * src_frame_size;

        if (in->proc_buf_size < src_buffer_size) {
            in->proc_buf_size = src_buffer_size;
#ifdef PREPROCESSING_ENABLED
            /* we always reallocate both buffers in case # of effects change dynamically. */
            in->proc_buf_in = realloc(in->proc_buf_in, src_buffer_size);
            ALOG_ASSERT((in->proc_buf_in != NULL),
                    "process_frames() failed to reallocate proc_buf_in");
#endif
            in->proc_buf_out = realloc(in->proc_buf_out, src_buffer_size);
            ALOG_ASSERT((in->proc_buf_out != NULL),
                    "process_frames() failed to reallocate proc_buf_out");
        }
        if (channel_remapping_needed) {
            proc_buf_out = in->proc_buf_out;
        }
    }

 #ifdef PREPROCESSING_ENABLED
     if (has_processing) {
 /* since all the processing below is done in frames and using the config.channels
         * as the number of channels, no changes is required in case aux_channels are present */

         while (frames_wr < frames_num) {
             /* first reload enough frames at the end of process input buffer */
             if (in->proc_buf_frames < (size_t)frames_num) {
                ssize_t frames_rd = read_frames(in,
                        (char *)in->proc_buf_in + in->proc_buf_frames * src_frame_size,
                        frames_num - in->proc_buf_frames);
                if (frames_rd < 0) {
                     /* Return error code */
                     frames_wr = frames_rd;
                     break;
 }
                in->proc_buf_frames += frames_rd;
 }

              /* in_buf.frameCount and out_buf.frameCount indicate respectively
               * the maximum number of frames to be consumed and produced by process() */
            audio_buffer_t in_buf;
            audio_buffer_t out_buf;

             in_buf.frameCount = in->proc_buf_frames;
            in_buf.s16 = in->proc_buf_in;  /* currently assumes PCM 16 effects */
             out_buf.frameCount = frames_num - frames_wr;
            out_buf.s16 = (int16_t *)proc_buf_out + frames_wr * src_channels;

             /* FIXME: this works because of current pre processing library implementation that
              * does the actual process only when the last enabled effect process is called.
              * The generic solution is to have an output buffer for each effect and pass it as
              * input to the next.
              */
            for (int i = 0; i < in->num_preprocessors; i++) {
                 (*in->preprocessors[i].effect_itfe)->process(in->preprocessors[i].effect_itfe,
                                                    &in_buf,
                                                    &out_buf);
 }

 /* process() has updated the number of frames consumed and produced in
             * in_buf.frameCount and out_buf.frameCount respectively
             * move remaining frames to the beginning of in->proc_buf_in */
            in->proc_buf_frames -= in_buf.frameCount;

             if (in->proc_buf_frames) {
                 memcpy(in->proc_buf_in,
                       (char *)in->proc_buf_in + in_buf.frameCount * src_frame_size,
                       in->proc_buf_frames * src_frame_size);
             }

             /* if not enough frames were passed to process(), read more and retry. */
 if (out_buf.frameCount == 0) {
                ALOGW("No frames produced by preproc");
 continue;
 }

 if ((frames_wr + (ssize_t)out_buf.frameCount) <= frames_num) {
                frames_wr += out_buf.frameCount;
 } else {
 /* The effect does not comply to the API. In theory, we should never end up here! */
                ALOGE("preprocessing produced too many frames: %d + %zd  > %d !",
 (unsigned int)frames_wr, out_buf.frameCount, (unsigned int)frames_num);
                frames_wr = frames_num;
 }
 }
 }
 else

 #endif //PREPROCESSING_ENABLED
     {
         /* No processing effects attached */
         frames_wr = read_frames(in, proc_buf_out, frames_num);
         ALOG_ASSERT(frames_wr <= frames_num, "read more frames than requested");
     }

    /* check negative frames_wr (error) before channel remapping to avoid overwriting memory. */
    if (channel_remapping_needed && frames_wr > 0) {
         size_t ret = adjust_channels(proc_buf_out, src_channels, buffer, dst_channels,
            bytes_per_sample, frames_wr * src_frame_size);
         ALOG_ASSERT(ret == (frames_wr * dst_channels * bytes_per_sample));
     }

 return frames_wr;
}


IMPEG2D_ERROR_CODES_T impeg2d_dec_p_b_slice(dec_state_t *ps_dec)
{
    WORD16 *pi2_vld_out;
    UWORD32 i;
 yuv_buf_t *ps_cur_frm_buf      = &ps_dec->s_cur_frm_buf;

    UWORD32 u4_frm_offset          = 0;
 const dec_mb_params_t *ps_dec_mb_params;
    IMPEG2D_ERROR_CODES_T e_error   = (IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE;

    pi2_vld_out = ps_dec->ai2_vld_buf;
    memset(ps_dec->ai2_pred_mv,0,sizeof(ps_dec->ai2_pred_mv));

    ps_dec->u2_prev_intra_mb    = 0;
    ps_dec->u2_first_mb       = 1;

    ps_dec->u2_picture_width = ps_dec->u2_frame_width;

 if(ps_dec->u2_picture_structure != FRAME_PICTURE)
 {
        ps_dec->u2_picture_width <<= 1;
 if(ps_dec->u2_picture_structure == BOTTOM_FIELD)
 {
            u4_frm_offset = ps_dec->u2_frame_width;
 }
 }

 do
 {
        UWORD32 u4_x_offset, u4_y_offset;
        WORD32 ret;

        UWORD32 u4_x_dst_offset = 0;
        UWORD32 u4_y_dst_offset = 0;
        UWORD8  *pu1_out_p;
        UWORD8  *pu1_pred;
        WORD32 u4_pred_strd;

        IMPEG2D_TRACE_MB_START(ps_dec->u2_mb_x, ps_dec->u2_mb_y);

 if(ps_dec->e_pic_type == B_PIC)
            ret = impeg2d_dec_pnb_mb_params(ps_dec);
 else
            ret = impeg2d_dec_p_mb_params(ps_dec);

         if(ret)
             return IMPEG2D_MB_TEX_DECODE_ERR;
         IMPEG2D_TRACE_MB_START(ps_dec->u2_mb_x, ps_dec->u2_mb_y);

         u4_x_dst_offset = u4_frm_offset + (ps_dec->u2_mb_x << 4);
        u4_y_dst_offset = (ps_dec->u2_mb_y << 4) * ps_dec->u2_picture_width;
        pu1_out_p = ps_cur_frm_buf->pu1_y + u4_x_dst_offset + u4_y_dst_offset;
 if(ps_dec->u2_prev_intra_mb == 0)
 {
            UWORD32 offset_x, offset_y, stride;
            UWORD16 index = (ps_dec->u2_motion_type);
 /*only for non intra mb's*/
 if(ps_dec->e_mb_pred == BIDIRECT)
 {
                ps_dec_mb_params = &ps_dec->ps_func_bi_direct[index];
 }
 else
 {
                ps_dec_mb_params = &ps_dec->ps_func_forw_or_back[index];
 }

            stride = ps_dec->u2_picture_width;

            offset_x = u4_frm_offset + (ps_dec->u2_mb_x << 4);

            offset_y = (ps_dec->u2_mb_y << 4);

            ps_dec->s_dest_buf.pu1_y = ps_cur_frm_buf->pu1_y + offset_y * stride + offset_x;

            stride = stride >> 1;

            ps_dec->s_dest_buf.pu1_u = ps_cur_frm_buf->pu1_u + (offset_y >> 1) * stride
 + (offset_x >> 1);

            ps_dec->s_dest_buf.pu1_v = ps_cur_frm_buf->pu1_v + (offset_y >> 1) * stride
 + (offset_x >> 1);

            PROFILE_DISABLE_MC_IF0
            ps_dec_mb_params->pf_mc(ps_dec);

 }
 for(i = 0; i < NUM_LUMA_BLKS; ++i)
 {
 if((ps_dec->u2_cbp & (1 << (BLOCKS_IN_MB - 1 - i))) != 0)
 {
                e_error = ps_dec->pf_vld_inv_quant(ps_dec, pi2_vld_out, ps_dec->pu1_inv_scan_matrix,
                              ps_dec->u2_prev_intra_mb, Y_LUMA, 0);
 if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
 {
 return e_error;
 }

                u4_x_offset = gai2_impeg2_blk_x_off[i];

 if(ps_dec->u2_field_dct == 0)
                    u4_y_offset = gai2_impeg2_blk_y_off_frm[i] ;
 else
                    u4_y_offset = gai2_impeg2_blk_y_off_fld[i] ;

                IMPEG2D_IDCT_INP_STATISTICS(pi2_vld_out, ps_dec->u4_non_zero_cols, ps_dec->u4_non_zero_rows);

                PROFILE_DISABLE_IDCT_IF0
 {
                    WORD32 idx;
 if(1 == (ps_dec->u4_non_zero_cols | ps_dec->u4_non_zero_rows))
                        idx = 0;
 else
                        idx = 1;

 if(0 == ps_dec->u2_prev_intra_mb)
 {
                        pu1_pred = pu1_out_p + u4_y_offset * ps_dec->u2_picture_width + u4_x_offset;
                        u4_pred_strd = ps_dec->u2_picture_width << ps_dec->u2_field_dct;
 }
 else
 {
                        pu1_pred = (UWORD8 *)gau1_impeg2_zerobuf;
                        u4_pred_strd = 8;
 }

                    ps_dec->pf_idct_recon[idx * 2 + ps_dec->i4_last_value_one](pi2_vld_out,
                                                            ps_dec->ai2_idct_stg1,
                                                            pu1_pred,
                                                            pu1_out_p + u4_y_offset * ps_dec->u2_picture_width + u4_x_offset,
 8,
                                                            u4_pred_strd,
                                                            ps_dec->u2_picture_width << ps_dec->u2_field_dct,
 ~ps_dec->u4_non_zero_cols, ~ps_dec->u4_non_zero_rows);
 }
 }

 }

 /* For U and V blocks, divide the x and y offsets by 2. */
        u4_x_dst_offset >>= 1;
        u4_y_dst_offset >>= 2;

 /* In case of chrominance blocks the DCT will be frame DCT */
 /* i = 0, U component and i = 1 is V componet */
 if((ps_dec->u2_cbp & 0x02) != 0)
 {
            pu1_out_p = ps_cur_frm_buf->pu1_u + u4_x_dst_offset + u4_y_dst_offset;
            e_error = ps_dec->pf_vld_inv_quant(ps_dec, pi2_vld_out, ps_dec->pu1_inv_scan_matrix,
                          ps_dec->u2_prev_intra_mb, U_CHROMA, 0);
 if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
 {
 return e_error;
 }

            IMPEG2D_IDCT_INP_STATISTICS(pi2_vld_out, ps_dec->u4_non_zero_cols, ps_dec->u4_non_zero_rows);

            PROFILE_DISABLE_IDCT_IF0
 {
                WORD32 idx;
 if(1 == (ps_dec->u4_non_zero_cols | ps_dec->u4_non_zero_rows))
                    idx = 0;
 else
                    idx = 1;

 if(0 == ps_dec->u2_prev_intra_mb)
 {
                    pu1_pred = pu1_out_p;
                    u4_pred_strd = ps_dec->u2_picture_width >> 1;
 }
 else
 {
                    pu1_pred = (UWORD8 *)gau1_impeg2_zerobuf;
                    u4_pred_strd = 8;
 }

                ps_dec->pf_idct_recon[idx * 2 + ps_dec->i4_last_value_one](pi2_vld_out,
                                                        ps_dec->ai2_idct_stg1,
                                                        pu1_pred,
                                                        pu1_out_p,
 8,
                                                        u4_pred_strd,
                                                        ps_dec->u2_picture_width >> 1,
 ~ps_dec->u4_non_zero_cols, ~ps_dec->u4_non_zero_rows);

 }

 }

 if((ps_dec->u2_cbp & 0x01) != 0)
 {
            pu1_out_p = ps_cur_frm_buf->pu1_v + u4_x_dst_offset + u4_y_dst_offset;
            e_error = ps_dec->pf_vld_inv_quant(ps_dec, pi2_vld_out, ps_dec->pu1_inv_scan_matrix,
                          ps_dec->u2_prev_intra_mb, V_CHROMA, 0);
 if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
 {
 return e_error;
 }

            IMPEG2D_IDCT_INP_STATISTICS(pi2_vld_out, ps_dec->u4_non_zero_cols, ps_dec->u4_non_zero_rows);

            PROFILE_DISABLE_IDCT_IF0
 {
                WORD32 idx;
 if(1 == (ps_dec->u4_non_zero_cols | ps_dec->u4_non_zero_rows))
                    idx = 0;
 else
                    idx = 1;
 if(0 == ps_dec->u2_prev_intra_mb)
 {
                    pu1_pred = pu1_out_p;
                    u4_pred_strd = ps_dec->u2_picture_width >> 1;
 }
 else
 {
                    pu1_pred = (UWORD8 *)gau1_impeg2_zerobuf;
                    u4_pred_strd = 8;
 }

                ps_dec->pf_idct_recon[idx * 2 + ps_dec->i4_last_value_one](pi2_vld_out,
                                                        ps_dec->ai2_idct_stg1,
                                                        pu1_pred,
                                                        pu1_out_p,
 8,
                                                        u4_pred_strd,
                                                        ps_dec->u2_picture_width >> 1,
 ~ps_dec->u4_non_zero_cols, ~ps_dec->u4_non_zero_rows);

 }
 }

        ps_dec->u2_num_mbs_left--;
        ps_dec->u2_first_mb = 0;
        ps_dec->u2_mb_x++;

 if(ps_dec->s_bit_stream.u4_offset > ps_dec->s_bit_stream.u4_max_offset)
 {
 return IMPEG2D_BITSTREAM_BUFF_EXCEEDED_ERR;
 }
 else if (ps_dec->u2_mb_x == ps_dec->u2_num_horiz_mb)
 {
            ps_dec->u2_mb_x = 0;
            ps_dec->u2_mb_y++;

 }
 }
 while(ps_dec->u2_num_mbs_left != 0 && impeg2d_bit_stream_nxt(&ps_dec->s_bit_stream,23) != 0x0);
 return e_error;
}

A remote code execution vulnerability in the Android media framework (libmpeg2). Product: Android. Versions: 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2, 8.0. Android ID: A-38207066.


IMPEG2D_ERROR_CODES_T impeg2d_dec_p_b_slice(dec_state_t *ps_dec)
{
    WORD16 *pi2_vld_out;
    UWORD32 i;
 yuv_buf_t *ps_cur_frm_buf      = &ps_dec->s_cur_frm_buf;

    UWORD32 u4_frm_offset          = 0;
 const dec_mb_params_t *ps_dec_mb_params;
    IMPEG2D_ERROR_CODES_T e_error   = (IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE;

    pi2_vld_out = ps_dec->ai2_vld_buf;
    memset(ps_dec->ai2_pred_mv,0,sizeof(ps_dec->ai2_pred_mv));

    ps_dec->u2_prev_intra_mb    = 0;
    ps_dec->u2_first_mb       = 1;

    ps_dec->u2_picture_width = ps_dec->u2_frame_width;

 if(ps_dec->u2_picture_structure != FRAME_PICTURE)
 {
        ps_dec->u2_picture_width <<= 1;
 if(ps_dec->u2_picture_structure == BOTTOM_FIELD)
 {
            u4_frm_offset = ps_dec->u2_frame_width;
 }
 }

 do
 {
        UWORD32 u4_x_offset, u4_y_offset;
        WORD32 ret;

        UWORD32 u4_x_dst_offset = 0;
        UWORD32 u4_y_dst_offset = 0;
        UWORD8  *pu1_out_p;
        UWORD8  *pu1_pred;
        WORD32 u4_pred_strd;

        IMPEG2D_TRACE_MB_START(ps_dec->u2_mb_x, ps_dec->u2_mb_y);

 if(ps_dec->e_pic_type == B_PIC)
            ret = impeg2d_dec_pnb_mb_params(ps_dec);
 else
            ret = impeg2d_dec_p_mb_params(ps_dec);

         if(ret)
             return IMPEG2D_MB_TEX_DECODE_ERR;

        if(0 >= ps_dec->u2_num_mbs_left)
        {
            break;
        }

         IMPEG2D_TRACE_MB_START(ps_dec->u2_mb_x, ps_dec->u2_mb_y);

         u4_x_dst_offset = u4_frm_offset + (ps_dec->u2_mb_x << 4);
        u4_y_dst_offset = (ps_dec->u2_mb_y << 4) * ps_dec->u2_picture_width;
        pu1_out_p = ps_cur_frm_buf->pu1_y + u4_x_dst_offset + u4_y_dst_offset;
 if(ps_dec->u2_prev_intra_mb == 0)
 {
            UWORD32 offset_x, offset_y, stride;
            UWORD16 index = (ps_dec->u2_motion_type);
 /*only for non intra mb's*/
 if(ps_dec->e_mb_pred == BIDIRECT)
 {
                ps_dec_mb_params = &ps_dec->ps_func_bi_direct[index];
 }
 else
 {
                ps_dec_mb_params = &ps_dec->ps_func_forw_or_back[index];
 }

            stride = ps_dec->u2_picture_width;

            offset_x = u4_frm_offset + (ps_dec->u2_mb_x << 4);

            offset_y = (ps_dec->u2_mb_y << 4);

            ps_dec->s_dest_buf.pu1_y = ps_cur_frm_buf->pu1_y + offset_y * stride + offset_x;

            stride = stride >> 1;

            ps_dec->s_dest_buf.pu1_u = ps_cur_frm_buf->pu1_u + (offset_y >> 1) * stride
 + (offset_x >> 1);

            ps_dec->s_dest_buf.pu1_v = ps_cur_frm_buf->pu1_v + (offset_y >> 1) * stride
 + (offset_x >> 1);

            PROFILE_DISABLE_MC_IF0
            ps_dec_mb_params->pf_mc(ps_dec);

 }
 for(i = 0; i < NUM_LUMA_BLKS; ++i)
 {
 if((ps_dec->u2_cbp & (1 << (BLOCKS_IN_MB - 1 - i))) != 0)
 {
                e_error = ps_dec->pf_vld_inv_quant(ps_dec, pi2_vld_out, ps_dec->pu1_inv_scan_matrix,
                              ps_dec->u2_prev_intra_mb, Y_LUMA, 0);
 if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
 {
 return e_error;
 }

                u4_x_offset = gai2_impeg2_blk_x_off[i];

 if(ps_dec->u2_field_dct == 0)
                    u4_y_offset = gai2_impeg2_blk_y_off_frm[i] ;
 else
                    u4_y_offset = gai2_impeg2_blk_y_off_fld[i] ;

                IMPEG2D_IDCT_INP_STATISTICS(pi2_vld_out, ps_dec->u4_non_zero_cols, ps_dec->u4_non_zero_rows);

                PROFILE_DISABLE_IDCT_IF0
 {
                    WORD32 idx;
 if(1 == (ps_dec->u4_non_zero_cols | ps_dec->u4_non_zero_rows))
                        idx = 0;
 else
                        idx = 1;

 if(0 == ps_dec->u2_prev_intra_mb)
 {
                        pu1_pred = pu1_out_p + u4_y_offset * ps_dec->u2_picture_width + u4_x_offset;
                        u4_pred_strd = ps_dec->u2_picture_width << ps_dec->u2_field_dct;
 }
 else
 {
                        pu1_pred = (UWORD8 *)gau1_impeg2_zerobuf;
                        u4_pred_strd = 8;
 }

                    ps_dec->pf_idct_recon[idx * 2 + ps_dec->i4_last_value_one](pi2_vld_out,
                                                            ps_dec->ai2_idct_stg1,
                                                            pu1_pred,
                                                            pu1_out_p + u4_y_offset * ps_dec->u2_picture_width + u4_x_offset,
 8,
                                                            u4_pred_strd,
                                                            ps_dec->u2_picture_width << ps_dec->u2_field_dct,
 ~ps_dec->u4_non_zero_cols, ~ps_dec->u4_non_zero_rows);
 }
 }

 }

 /* For U and V blocks, divide the x and y offsets by 2. */
        u4_x_dst_offset >>= 1;
        u4_y_dst_offset >>= 2;

 /* In case of chrominance blocks the DCT will be frame DCT */
 /* i = 0, U component and i = 1 is V componet */
 if((ps_dec->u2_cbp & 0x02) != 0)
 {
            pu1_out_p = ps_cur_frm_buf->pu1_u + u4_x_dst_offset + u4_y_dst_offset;
            e_error = ps_dec->pf_vld_inv_quant(ps_dec, pi2_vld_out, ps_dec->pu1_inv_scan_matrix,
                          ps_dec->u2_prev_intra_mb, U_CHROMA, 0);
 if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
 {
 return e_error;
 }

            IMPEG2D_IDCT_INP_STATISTICS(pi2_vld_out, ps_dec->u4_non_zero_cols, ps_dec->u4_non_zero_rows);

            PROFILE_DISABLE_IDCT_IF0
 {
                WORD32 idx;
 if(1 == (ps_dec->u4_non_zero_cols | ps_dec->u4_non_zero_rows))
                    idx = 0;
 else
                    idx = 1;

 if(0 == ps_dec->u2_prev_intra_mb)
 {
                    pu1_pred = pu1_out_p;
                    u4_pred_strd = ps_dec->u2_picture_width >> 1;
 }
 else
 {
                    pu1_pred = (UWORD8 *)gau1_impeg2_zerobuf;
                    u4_pred_strd = 8;
 }

                ps_dec->pf_idct_recon[idx * 2 + ps_dec->i4_last_value_one](pi2_vld_out,
                                                        ps_dec->ai2_idct_stg1,
                                                        pu1_pred,
                                                        pu1_out_p,
 8,
                                                        u4_pred_strd,
                                                        ps_dec->u2_picture_width >> 1,
 ~ps_dec->u4_non_zero_cols, ~ps_dec->u4_non_zero_rows);

 }

 }

 if((ps_dec->u2_cbp & 0x01) != 0)
 {
            pu1_out_p = ps_cur_frm_buf->pu1_v + u4_x_dst_offset + u4_y_dst_offset;
            e_error = ps_dec->pf_vld_inv_quant(ps_dec, pi2_vld_out, ps_dec->pu1_inv_scan_matrix,
                          ps_dec->u2_prev_intra_mb, V_CHROMA, 0);
 if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
 {
 return e_error;
 }

            IMPEG2D_IDCT_INP_STATISTICS(pi2_vld_out, ps_dec->u4_non_zero_cols, ps_dec->u4_non_zero_rows);

            PROFILE_DISABLE_IDCT_IF0
 {
                WORD32 idx;
 if(1 == (ps_dec->u4_non_zero_cols | ps_dec->u4_non_zero_rows))
                    idx = 0;
 else
                    idx = 1;
 if(0 == ps_dec->u2_prev_intra_mb)
 {
                    pu1_pred = pu1_out_p;
                    u4_pred_strd = ps_dec->u2_picture_width >> 1;
 }
 else
 {
                    pu1_pred = (UWORD8 *)gau1_impeg2_zerobuf;
                    u4_pred_strd = 8;
 }

                ps_dec->pf_idct_recon[idx * 2 + ps_dec->i4_last_value_one](pi2_vld_out,
                                                        ps_dec->ai2_idct_stg1,
                                                        pu1_pred,
                                                        pu1_out_p,
 8,
                                                        u4_pred_strd,
                                                        ps_dec->u2_picture_width >> 1,
 ~ps_dec->u4_non_zero_cols, ~ps_dec->u4_non_zero_rows);

 }
 }

        ps_dec->u2_num_mbs_left--;
        ps_dec->u2_first_mb = 0;
        ps_dec->u2_mb_x++;

 if(ps_dec->s_bit_stream.u4_offset > ps_dec->s_bit_stream.u4_max_offset)
 {
 return IMPEG2D_BITSTREAM_BUFF_EXCEEDED_ERR;
 }
 else if (ps_dec->u2_mb_x == ps_dec->u2_num_horiz_mb)
 {
            ps_dec->u2_mb_x = 0;
            ps_dec->u2_mb_y++;

 }
 }
 while(ps_dec->u2_num_mbs_left != 0 && impeg2d_bit_stream_nxt(&ps_dec->s_bit_stream,23) != 0x0);
 return e_error;
}


IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
{
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    WORD32 value;
    WORD32 pps_id;

 pps_t *ps_pps;
 sps_t *ps_sps;
 bitstrm_t *ps_bitstrm = &ps_codec->s_parse.s_bitstrm;

 if(0 == ps_codec->i4_sps_done)
 return IHEVCD_INVALID_HEADER;

    UEV_PARSE("pic_parameter_set_id", value, ps_bitstrm);

    pps_id = value;
 if((pps_id >= MAX_PPS_CNT) || (pps_id < 0))
 {
 if(ps_codec->i4_pps_done)
 return IHEVCD_UNSUPPORTED_PPS_ID;
 else
            pps_id = 0;
 }

    ps_pps = (ps_codec->s_parse.ps_pps_base + MAX_PPS_CNT - 1);

    ps_pps->i1_pps_id = pps_id;

    UEV_PARSE("seq_parameter_set_id", value, ps_bitstrm);
    ps_pps->i1_sps_id = value;
    ps_pps->i1_sps_id = CLIP3(ps_pps->i1_sps_id, 0, MAX_SPS_CNT - 2);

    ps_sps = (ps_codec->s_parse.ps_sps_base + ps_pps->i1_sps_id);

 /* If the SPS that is being referred to has not been parsed,
     * copy an existing SPS to the current location */
 if(0 == ps_sps->i1_sps_valid)
 {
 return IHEVCD_INVALID_HEADER;

/*
        sps_t *ps_sps_ref = ps_codec->ps_sps_base;
        while(0 == ps_sps_ref->i1_sps_valid)
            ps_sps_ref++;
        ihevcd_copy_sps(ps_codec, ps_pps->i1_sps_id, ps_sps_ref->i1_sps_id);
*/
 }

    BITS_PARSE("dependent_slices_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_dependent_slice_enabled_flag = value;

    BITS_PARSE("output_flag_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_output_flag_present_flag = value;

    BITS_PARSE("num_extra_slice_header_bits", value, ps_bitstrm, 3);
    ps_pps->i1_num_extra_slice_header_bits = value;

    BITS_PARSE("sign_data_hiding_flag", value, ps_bitstrm, 1);
    ps_pps->i1_sign_data_hiding_flag = value;

    BITS_PARSE("cabac_init_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_cabac_init_present_flag = value;

    UEV_PARSE("num_ref_idx_l0_default_active_minus1", value, ps_bitstrm);
    ps_pps->i1_num_ref_idx_l0_default_active = value + 1;

    UEV_PARSE("num_ref_idx_l1_default_active_minus1", value, ps_bitstrm);
    ps_pps->i1_num_ref_idx_l1_default_active = value + 1;

    SEV_PARSE("pic_init_qp_minus26", value, ps_bitstrm);
    ps_pps->i1_pic_init_qp = value + 26;

    BITS_PARSE("constrained_intra_pred_flag", value, ps_bitstrm, 1);
    ps_pps->i1_constrained_intra_pred_flag = value;

    BITS_PARSE("transform_skip_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_transform_skip_enabled_flag = value;

    BITS_PARSE("cu_qp_delta_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_cu_qp_delta_enabled_flag = value;

 if(ps_pps->i1_cu_qp_delta_enabled_flag)
 {
        UEV_PARSE("diff_cu_qp_delta_depth", value, ps_bitstrm);
        ps_pps->i1_diff_cu_qp_delta_depth = value;
 }
 else
 {
        ps_pps->i1_diff_cu_qp_delta_depth = 0;
 }
    ps_pps->i1_log2_min_cu_qp_delta_size = ps_sps->i1_log2_ctb_size - ps_pps->i1_diff_cu_qp_delta_depth;
 /* Print different */
    SEV_PARSE("cb_qp_offset", value, ps_bitstrm);
    ps_pps->i1_pic_cb_qp_offset = value;

 /* Print different */
    SEV_PARSE("cr_qp_offset", value, ps_bitstrm);
    ps_pps->i1_pic_cr_qp_offset = value;

 /* Print different */
    BITS_PARSE("slicelevel_chroma_qp_flag", value, ps_bitstrm, 1);
    ps_pps->i1_pic_slice_level_chroma_qp_offsets_present_flag = value;

    BITS_PARSE("weighted_pred_flag", value, ps_bitstrm, 1);
    ps_pps->i1_weighted_pred_flag = value;

    BITS_PARSE("weighted_bipred_flag", value, ps_bitstrm, 1);
    ps_pps->i1_weighted_bipred_flag = value;

    BITS_PARSE("transquant_bypass_enable_flag", value, ps_bitstrm, 1);
    ps_pps->i1_transquant_bypass_enable_flag = value;

    BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_tiles_enabled_flag = value;

    BITS_PARSE("entropy_coding_sync_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_entropy_coding_sync_enabled_flag = value;

     ps_pps->i1_loop_filter_across_tiles_enabled_flag = 0;
     if(ps_pps->i1_tiles_enabled_flag)
     {
         UEV_PARSE("num_tile_columns_minus1", value, ps_bitstrm);
         ps_pps->i1_num_tile_columns = value + 1;

        UEV_PARSE("num_tile_rows_minus1", value, ps_bitstrm);

         ps_pps->i1_num_tile_rows = value + 1;

         if((ps_pps->i1_num_tile_columns < 1) ||
                        (ps_pps->i1_num_tile_columns > ps_sps->i2_pic_wd_in_ctb) ||
                         (ps_pps->i1_num_tile_rows < 1) ||
                        (ps_pps->i1_num_tile_rows > ps_sps->i2_pic_ht_in_ctb))
             return IHEVCD_INVALID_HEADER;

         BITS_PARSE("uniform_spacing_flag", value, ps_bitstrm, 1);
        ps_pps->i1_uniform_spacing_flag = value;

 {

            WORD32 start;
            WORD32 i, j;

            start = 0;
 for(i = 0; i < ps_pps->i1_num_tile_columns; i++)
 {
 tile_t *ps_tile;
 if(!ps_pps->i1_uniform_spacing_flag)
 {
 if(i < (ps_pps->i1_num_tile_columns - 1))
 {
                        UEV_PARSE("column_width_minus1[ i ]", value, ps_bitstrm);
                        value += 1;
 }
 else
 {
                        value = ps_sps->i2_pic_wd_in_ctb - start;
 }
 }
 else
 {
                    value = ((i + 1) * ps_sps->i2_pic_wd_in_ctb) / ps_pps->i1_num_tile_columns -
 (i * ps_sps->i2_pic_wd_in_ctb) / ps_pps->i1_num_tile_columns;
 }

 for(j = 0; j < ps_pps->i1_num_tile_rows; j++)
 {
                    ps_tile = ps_pps->ps_tile + j * ps_pps->i1_num_tile_columns + i;
                    ps_tile->u1_pos_x = start;
                    ps_tile->u2_wd = value;
 }
                start += value;

 if((start > ps_sps->i2_pic_wd_in_ctb) ||
 (value <= 0))
 return IHEVCD_INVALID_HEADER;
 }

            start = 0;
 for(i = 0; i < (ps_pps->i1_num_tile_rows); i++)
 {
 tile_t *ps_tile;
 if(!ps_pps->i1_uniform_spacing_flag)
 {
 if(i < (ps_pps->i1_num_tile_rows - 1))
 {

                        UEV_PARSE("row_height_minus1[ i ]", value, ps_bitstrm);
                        value += 1;
 }
 else
 {
                        value = ps_sps->i2_pic_ht_in_ctb - start;
 }
 }
 else
 {
                    value = ((i + 1) * ps_sps->i2_pic_ht_in_ctb) / ps_pps->i1_num_tile_rows -
 (i * ps_sps->i2_pic_ht_in_ctb) / ps_pps->i1_num_tile_rows;
 }

 for(j = 0; j < ps_pps->i1_num_tile_columns; j++)
 {
                    ps_tile = ps_pps->ps_tile + i * ps_pps->i1_num_tile_columns + j;
                    ps_tile->u1_pos_y = start;
                    ps_tile->u2_ht = value;
 }
                start += value;

 if((start > ps_sps->i2_pic_ht_in_ctb) ||
 (value <= 0))
 return IHEVCD_INVALID_HEADER;
 }
 }

        BITS_PARSE("loop_filter_across_tiles_enabled_flag", value, ps_bitstrm, 1);
        ps_pps->i1_loop_filter_across_tiles_enabled_flag = value;

 }
 else
 {
 /* If tiles are not present, set first tile in each PPS to have tile
        width and height equal to picture width and height */
        ps_pps->i1_num_tile_columns = 1;
        ps_pps->i1_num_tile_rows = 1;
        ps_pps->i1_uniform_spacing_flag = 1;

        ps_pps->ps_tile->u1_pos_x = 0;
        ps_pps->ps_tile->u1_pos_y = 0;
        ps_pps->ps_tile->u2_wd = ps_sps->i2_pic_wd_in_ctb;
        ps_pps->ps_tile->u2_ht = ps_sps->i2_pic_ht_in_ctb;
 }

    BITS_PARSE("loop_filter_across_slices_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_loop_filter_across_slices_enabled_flag = value;

    BITS_PARSE("deblocking_filter_control_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_deblocking_filter_control_present_flag = value;

 /* Default values */
    ps_pps->i1_pic_disable_deblocking_filter_flag = 0;
    ps_pps->i1_deblocking_filter_override_enabled_flag = 0;
    ps_pps->i1_beta_offset_div2 = 0;
    ps_pps->i1_tc_offset_div2 = 0;

 if(ps_pps->i1_deblocking_filter_control_present_flag)
 {

        BITS_PARSE("deblocking_filter_override_enabled_flag", value, ps_bitstrm, 1);
        ps_pps->i1_deblocking_filter_override_enabled_flag = value;

        BITS_PARSE("pic_disable_deblocking_filter_flag", value, ps_bitstrm, 1);
        ps_pps->i1_pic_disable_deblocking_filter_flag = value;

 if(!ps_pps->i1_pic_disable_deblocking_filter_flag)
 {

            SEV_PARSE("pps_beta_offset_div2", value, ps_bitstrm);
            ps_pps->i1_beta_offset_div2 = value;

            SEV_PARSE("pps_tc_offset_div2", value, ps_bitstrm);
            ps_pps->i1_tc_offset_div2 = value;

 }
 }

    BITS_PARSE("pps_scaling_list_data_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_pps_scaling_list_data_present_flag = value;

 if(ps_pps->i1_pps_scaling_list_data_present_flag)
 {
        COPY_DEFAULT_SCALING_LIST(ps_pps->pi2_scaling_mat);
        ihevcd_scaling_list_data(ps_codec, ps_pps->pi2_scaling_mat);
 }

    BITS_PARSE("lists_modification_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_lists_modification_present_flag = value;
    UEV_PARSE("log2_parallel_merge_level_minus2", value, ps_bitstrm);
    ps_pps->i1_log2_parallel_merge_level = value + 2;

    BITS_PARSE("slice_header_extension_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_slice_header_extension_present_flag = value;
 /* Not present in HM */
    BITS_PARSE("pps_extension_flag", value, ps_bitstrm, 1);

    ps_codec->i4_pps_done = 1;
 return ret;
}

A remote code execution vulnerability in libhevc in Mediaserver could enable an attacker using a specially crafted file to cause memory corruption during media file and data processing. This issue is rated as Critical due to the possibility of remote code execution within the context of the Mediaserver process.Product: Android. Versions: 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2. Android ID: A-34064500.


IHEVCD_ERROR_T ihevcd_parse_pps(codec_t *ps_codec)
{
    IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
    WORD32 value;
    WORD32 pps_id;

 pps_t *ps_pps;
 sps_t *ps_sps;
 bitstrm_t *ps_bitstrm = &ps_codec->s_parse.s_bitstrm;

 if(0 == ps_codec->i4_sps_done)
 return IHEVCD_INVALID_HEADER;

    UEV_PARSE("pic_parameter_set_id", value, ps_bitstrm);

    pps_id = value;
 if((pps_id >= MAX_PPS_CNT) || (pps_id < 0))
 {
 if(ps_codec->i4_pps_done)
 return IHEVCD_UNSUPPORTED_PPS_ID;
 else
            pps_id = 0;
 }

    ps_pps = (ps_codec->s_parse.ps_pps_base + MAX_PPS_CNT - 1);

    ps_pps->i1_pps_id = pps_id;

    UEV_PARSE("seq_parameter_set_id", value, ps_bitstrm);
    ps_pps->i1_sps_id = value;
    ps_pps->i1_sps_id = CLIP3(ps_pps->i1_sps_id, 0, MAX_SPS_CNT - 2);

    ps_sps = (ps_codec->s_parse.ps_sps_base + ps_pps->i1_sps_id);

 /* If the SPS that is being referred to has not been parsed,
     * copy an existing SPS to the current location */
 if(0 == ps_sps->i1_sps_valid)
 {
 return IHEVCD_INVALID_HEADER;

/*
        sps_t *ps_sps_ref = ps_codec->ps_sps_base;
        while(0 == ps_sps_ref->i1_sps_valid)
            ps_sps_ref++;
        ihevcd_copy_sps(ps_codec, ps_pps->i1_sps_id, ps_sps_ref->i1_sps_id);
*/
 }

    BITS_PARSE("dependent_slices_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_dependent_slice_enabled_flag = value;

    BITS_PARSE("output_flag_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_output_flag_present_flag = value;

    BITS_PARSE("num_extra_slice_header_bits", value, ps_bitstrm, 3);
    ps_pps->i1_num_extra_slice_header_bits = value;

    BITS_PARSE("sign_data_hiding_flag", value, ps_bitstrm, 1);
    ps_pps->i1_sign_data_hiding_flag = value;

    BITS_PARSE("cabac_init_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_cabac_init_present_flag = value;

    UEV_PARSE("num_ref_idx_l0_default_active_minus1", value, ps_bitstrm);
    ps_pps->i1_num_ref_idx_l0_default_active = value + 1;

    UEV_PARSE("num_ref_idx_l1_default_active_minus1", value, ps_bitstrm);
    ps_pps->i1_num_ref_idx_l1_default_active = value + 1;

    SEV_PARSE("pic_init_qp_minus26", value, ps_bitstrm);
    ps_pps->i1_pic_init_qp = value + 26;

    BITS_PARSE("constrained_intra_pred_flag", value, ps_bitstrm, 1);
    ps_pps->i1_constrained_intra_pred_flag = value;

    BITS_PARSE("transform_skip_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_transform_skip_enabled_flag = value;

    BITS_PARSE("cu_qp_delta_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_cu_qp_delta_enabled_flag = value;

 if(ps_pps->i1_cu_qp_delta_enabled_flag)
 {
        UEV_PARSE("diff_cu_qp_delta_depth", value, ps_bitstrm);
        ps_pps->i1_diff_cu_qp_delta_depth = value;
 }
 else
 {
        ps_pps->i1_diff_cu_qp_delta_depth = 0;
 }
    ps_pps->i1_log2_min_cu_qp_delta_size = ps_sps->i1_log2_ctb_size - ps_pps->i1_diff_cu_qp_delta_depth;
 /* Print different */
    SEV_PARSE("cb_qp_offset", value, ps_bitstrm);
    ps_pps->i1_pic_cb_qp_offset = value;

 /* Print different */
    SEV_PARSE("cr_qp_offset", value, ps_bitstrm);
    ps_pps->i1_pic_cr_qp_offset = value;

 /* Print different */
    BITS_PARSE("slicelevel_chroma_qp_flag", value, ps_bitstrm, 1);
    ps_pps->i1_pic_slice_level_chroma_qp_offsets_present_flag = value;

    BITS_PARSE("weighted_pred_flag", value, ps_bitstrm, 1);
    ps_pps->i1_weighted_pred_flag = value;

    BITS_PARSE("weighted_bipred_flag", value, ps_bitstrm, 1);
    ps_pps->i1_weighted_bipred_flag = value;

    BITS_PARSE("transquant_bypass_enable_flag", value, ps_bitstrm, 1);
    ps_pps->i1_transquant_bypass_enable_flag = value;

    BITS_PARSE("tiles_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_tiles_enabled_flag = value;

    BITS_PARSE("entropy_coding_sync_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_entropy_coding_sync_enabled_flag = value;

     ps_pps->i1_loop_filter_across_tiles_enabled_flag = 0;
     if(ps_pps->i1_tiles_enabled_flag)
     {
        WORD32 wd = ALIGN64(ps_codec->i4_wd);
        WORD32 ht = ALIGN64(ps_codec->i4_ht);

        WORD32 max_tile_cols = (wd + MIN_TILE_WD - 1) / MIN_TILE_WD;
        WORD32 max_tile_rows = (ht + MIN_TILE_HT - 1) / MIN_TILE_HT;

         UEV_PARSE("num_tile_columns_minus1", value, ps_bitstrm);
         ps_pps->i1_num_tile_columns = value + 1;

        UEV_PARSE("num_tile_rows_minus1", value, ps_bitstrm);

         ps_pps->i1_num_tile_rows = value + 1;

         if((ps_pps->i1_num_tile_columns < 1) ||
                        (ps_pps->i1_num_tile_columns > max_tile_cols) ||
                         (ps_pps->i1_num_tile_rows < 1) ||
                        (ps_pps->i1_num_tile_rows > max_tile_rows))
             return IHEVCD_INVALID_HEADER;

         BITS_PARSE("uniform_spacing_flag", value, ps_bitstrm, 1);
        ps_pps->i1_uniform_spacing_flag = value;

 {

            WORD32 start;
            WORD32 i, j;

            start = 0;
 for(i = 0; i < ps_pps->i1_num_tile_columns; i++)
 {
 tile_t *ps_tile;
 if(!ps_pps->i1_uniform_spacing_flag)
 {
 if(i < (ps_pps->i1_num_tile_columns - 1))
 {
                        UEV_PARSE("column_width_minus1[ i ]", value, ps_bitstrm);
                        value += 1;
 }
 else
 {
                        value = ps_sps->i2_pic_wd_in_ctb - start;
 }
 }
 else
 {
                    value = ((i + 1) * ps_sps->i2_pic_wd_in_ctb) / ps_pps->i1_num_tile_columns -
 (i * ps_sps->i2_pic_wd_in_ctb) / ps_pps->i1_num_tile_columns;
 }

 for(j = 0; j < ps_pps->i1_num_tile_rows; j++)
 {
                    ps_tile = ps_pps->ps_tile + j * ps_pps->i1_num_tile_columns + i;
                    ps_tile->u1_pos_x = start;
                    ps_tile->u2_wd = value;
 }
                start += value;

 if((start > ps_sps->i2_pic_wd_in_ctb) ||
 (value <= 0))
 return IHEVCD_INVALID_HEADER;
 }

            start = 0;
 for(i = 0; i < (ps_pps->i1_num_tile_rows); i++)
 {
 tile_t *ps_tile;
 if(!ps_pps->i1_uniform_spacing_flag)
 {
 if(i < (ps_pps->i1_num_tile_rows - 1))
 {

                        UEV_PARSE("row_height_minus1[ i ]", value, ps_bitstrm);
                        value += 1;
 }
 else
 {
                        value = ps_sps->i2_pic_ht_in_ctb - start;
 }
 }
 else
 {
                    value = ((i + 1) * ps_sps->i2_pic_ht_in_ctb) / ps_pps->i1_num_tile_rows -
 (i * ps_sps->i2_pic_ht_in_ctb) / ps_pps->i1_num_tile_rows;
 }

 for(j = 0; j < ps_pps->i1_num_tile_columns; j++)
 {
                    ps_tile = ps_pps->ps_tile + i * ps_pps->i1_num_tile_columns + j;
                    ps_tile->u1_pos_y = start;
                    ps_tile->u2_ht = value;
 }
                start += value;

 if((start > ps_sps->i2_pic_ht_in_ctb) ||
 (value <= 0))
 return IHEVCD_INVALID_HEADER;
 }
 }

        BITS_PARSE("loop_filter_across_tiles_enabled_flag", value, ps_bitstrm, 1);
        ps_pps->i1_loop_filter_across_tiles_enabled_flag = value;

 }
 else
 {
 /* If tiles are not present, set first tile in each PPS to have tile
        width and height equal to picture width and height */
        ps_pps->i1_num_tile_columns = 1;
        ps_pps->i1_num_tile_rows = 1;
        ps_pps->i1_uniform_spacing_flag = 1;

        ps_pps->ps_tile->u1_pos_x = 0;
        ps_pps->ps_tile->u1_pos_y = 0;
        ps_pps->ps_tile->u2_wd = ps_sps->i2_pic_wd_in_ctb;
        ps_pps->ps_tile->u2_ht = ps_sps->i2_pic_ht_in_ctb;
 }

    BITS_PARSE("loop_filter_across_slices_enabled_flag", value, ps_bitstrm, 1);
    ps_pps->i1_loop_filter_across_slices_enabled_flag = value;

    BITS_PARSE("deblocking_filter_control_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_deblocking_filter_control_present_flag = value;

 /* Default values */
    ps_pps->i1_pic_disable_deblocking_filter_flag = 0;
    ps_pps->i1_deblocking_filter_override_enabled_flag = 0;
    ps_pps->i1_beta_offset_div2 = 0;
    ps_pps->i1_tc_offset_div2 = 0;

 if(ps_pps->i1_deblocking_filter_control_present_flag)
 {

        BITS_PARSE("deblocking_filter_override_enabled_flag", value, ps_bitstrm, 1);
        ps_pps->i1_deblocking_filter_override_enabled_flag = value;

        BITS_PARSE("pic_disable_deblocking_filter_flag", value, ps_bitstrm, 1);
        ps_pps->i1_pic_disable_deblocking_filter_flag = value;

 if(!ps_pps->i1_pic_disable_deblocking_filter_flag)
 {

            SEV_PARSE("pps_beta_offset_div2", value, ps_bitstrm);
            ps_pps->i1_beta_offset_div2 = value;

            SEV_PARSE("pps_tc_offset_div2", value, ps_bitstrm);
            ps_pps->i1_tc_offset_div2 = value;

 }
 }

    BITS_PARSE("pps_scaling_list_data_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_pps_scaling_list_data_present_flag = value;

 if(ps_pps->i1_pps_scaling_list_data_present_flag)
 {
        COPY_DEFAULT_SCALING_LIST(ps_pps->pi2_scaling_mat);
        ihevcd_scaling_list_data(ps_codec, ps_pps->pi2_scaling_mat);
 }

    BITS_PARSE("lists_modification_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_lists_modification_present_flag = value;
    UEV_PARSE("log2_parallel_merge_level_minus2", value, ps_bitstrm);
    ps_pps->i1_log2_parallel_merge_level = value + 2;

    BITS_PARSE("slice_header_extension_present_flag", value, ps_bitstrm, 1);
    ps_pps->i1_slice_header_extension_present_flag = value;
 /* Not present in HM */
    BITS_PARSE("pps_extension_flag", value, ps_bitstrm, 1);

    ps_codec->i4_pps_done = 1;
 return ret;
}


 status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) {
     uint8_t nalUnitType = (data[0] >> 1) & 0x3f;
     status_t err = OK;
     switch (nalUnitType) {
         case 32:  // VPS
             err = parseVps(data + 2, size - 2);
             break;
         case 33:  // SPS
             err = parseSps(data + 2, size - 2);
             break;
         case 34:  // PPS
             err = parsePps(data + 2, size - 2);
             break;
         case 39:  // Prefix SEI
 case 40: // Suffix SEI
 break;
 default:
            ALOGE("Unrecognized NAL unit type.");
 return ERROR_MALFORMED;
 }

 if (err != OK) {
 return err;
 }

    sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
    buffer->setInt32Data(nalUnitType);
    mNalUnits.push(buffer);
 return OK;
}

A remote denial of service vulnerability in HevcUtils.cpp in libstagefright in Mediaserver could enable an attacker to use a specially crafted file to cause a device hang or reboot. This issue is rated as Low due to details specific to the vulnerability. Product: Android. Versions: 7.0, 7.1.1, 7.1.2. Android ID: A-35467107.


 status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) {
    if (size < 1) {
        ALOGE("empty NAL b/35467107");
        return ERROR_MALFORMED;
    }
     uint8_t nalUnitType = (data[0] >> 1) & 0x3f;
     status_t err = OK;
     switch (nalUnitType) {
         case 32:  // VPS
            if (size < 2) {
                ALOGE("invalid NAL/VPS size b/35467107");
                return ERROR_MALFORMED;
            }
             err = parseVps(data + 2, size - 2);
             break;
         case 33:  // SPS
            if (size < 2) {
                ALOGE("invalid NAL/SPS size b/35467107");
                return ERROR_MALFORMED;
            }
             err = parseSps(data + 2, size - 2);
             break;
         case 34:  // PPS
            if (size < 2) {
                ALOGE("invalid NAL/PPS size b/35467107");
                return ERROR_MALFORMED;
            }
             err = parsePps(data + 2, size - 2);
             break;
         case 39:  // Prefix SEI
 case 40: // Suffix SEI
 break;
 default:
            ALOGE("Unrecognized NAL unit type.");
 return ERROR_MALFORMED;
 }

 if (err != OK) {
 return err;
 }

    sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
    buffer->setInt32Data(nalUnitType);
    mNalUnits.push(buffer);
 return OK;
}