You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
966 lines
35 KiB
966 lines
35 KiB
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
******************************************************************************/
|
|
/**
|
|
*******************************************************************************
|
|
* @file
|
|
* ihevcd_decode.c
|
|
*
|
|
* @brief
|
|
* Contains codecs main decode function
|
|
*
|
|
* @author
|
|
* Harish
|
|
*
|
|
* @par List of Functions:
|
|
* - fill_outargs()
|
|
* - ihevcd_decode
|
|
* @remarks
|
|
* None
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
/*****************************************************************************/
|
|
/* File Includes */
|
|
/*****************************************************************************/
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include "ihevc_typedefs.h"
|
|
#include "iv.h"
|
|
#include "ivd.h"
|
|
#include "ihevcd_cxa.h"
|
|
#include "ithread.h"
|
|
|
|
#include "ihevc_defs.h"
|
|
#include "ihevc_debug.h"
|
|
#include "ihevc_structs.h"
|
|
#include "ihevc_macros.h"
|
|
#include "ihevc_platform_macros.h"
|
|
#include "ihevc_cabac_tables.h"
|
|
#include "ihevc_disp_mgr.h"
|
|
#include "ihevc_buf_mgr.h"
|
|
#include "ihevc_dpb_mgr.h"
|
|
#include "ihevc_error.h"
|
|
|
|
#include "ihevcd_defs.h"
|
|
#include "ihevcd_function_selector.h"
|
|
#include "ihevcd_structs.h"
|
|
#include "ihevcd_error.h"
|
|
#include "ihevcd_nal.h"
|
|
#include "ihevcd_bitstream.h"
|
|
#include "ihevcd_fmt_conv.h"
|
|
#include "ihevcd_job_queue.h"
|
|
#include "ihevcd_debug.h"
|
|
#include "ihevcd_parse_slice.h"
|
|
#include "ihevcd_process_slice.h"
|
|
#include "ihevcd_ittiam_logo.h"
|
|
#include "ihevcd_profile.h"
|
|
|
|
#define NUM_FRAMES_LIMIT_ENABLED 0
|
|
|
|
#if NUM_FRAMES_LIMIT_ENABLED
|
|
#define NUM_FRAMES_LIMIT 10000
|
|
#else
|
|
#define NUM_FRAMES_LIMIT 0x7FFFFFFF
|
|
#endif
|
|
|
|
IHEVCD_ERROR_T ihevcd_check_out_buf_size(codec_t *ps_codec);
|
|
IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
|
|
process_ctxt_t *ps_proc,
|
|
UWORD8 *pu1_y_dst,
|
|
UWORD8 *pu1_u_dst,
|
|
UWORD8 *pu1_v_dst,
|
|
WORD32 cur_row,
|
|
WORD32 num_rows);
|
|
WORD32 ihevcd_init(codec_t *ps_codec);
|
|
|
|
WORD32 ihevcd_allocate_dynamic_bufs(codec_t *ps_codec);
|
|
WORD32 ihevcd_free_dynamic_bufs(codec_t *ps_codec);
|
|
/*****************************************************************************/
|
|
/* Function Prototypes */
|
|
/*****************************************************************************/
|
|
|
|
|
|
/**
|
|
*******************************************************************************
|
|
*
|
|
* @brief Fills output arguments for decode process
|
|
*
|
|
* @par Description
|
|
* Fills elements in the output structure based on the current state
|
|
*
|
|
* @param[in] ps_codec
|
|
* Codec context
|
|
*
|
|
* @param[in] ps_dec_ip
|
|
* Pointer to input structure
|
|
*
|
|
* @param[in] ps_dec_op
|
|
* Pointer to output structure
|
|
*
|
|
* @returns none
|
|
*
|
|
* @remarks
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
static UWORD32 ihevcd_map_error(IHEVCD_ERROR_T e_error)
|
|
{
|
|
UWORD32 error_code = 0;
|
|
error_code = e_error;
|
|
switch(error_code)
|
|
{
|
|
case IHEVCD_SUCCESS :
|
|
break;
|
|
case IHEVCD_INIT_NOT_DONE:
|
|
case IHEVCD_LEVEL_UNSUPPORTED:
|
|
case IHEVCD_NUM_REF_UNSUPPORTED:
|
|
case IHEVCD_NUM_REORDER_UNSUPPORTED:
|
|
case IHEVCD_NUM_EXTRA_DISP_UNSUPPORTED:
|
|
case IHEVCD_INSUFFICIENT_MEM_MVBANK:
|
|
case IHEVCD_INSUFFICIENT_MEM_PICBUF:
|
|
case IHEVCD_UNSUPPORTED_CHROMA_FMT_IDC:
|
|
case IHEVCD_UNSUPPORTED_BIT_DEPTH:
|
|
case IVD_MEM_ALLOC_FAILED:
|
|
case IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED:
|
|
error_code |= 1 << IVD_FATALERROR;
|
|
break;
|
|
case IHEVCD_INVALID_DISP_STRD:
|
|
case IHEVCD_CXA_VERS_BUF_INSUFFICIENT:
|
|
case IHEVCD_UNSUPPORTED_VPS_ID:
|
|
case IHEVCD_UNSUPPORTED_SPS_ID:
|
|
case IHEVCD_UNSUPPORTED_PPS_ID:
|
|
case IHEVCD_BUF_MGR_ERROR:
|
|
case IHEVCD_NO_FREE_MVBANK:
|
|
case IHEVCD_NO_FREE_PICBUF:
|
|
case IHEVCD_SLICE_IN_HEADER_MODE:
|
|
case IHEVCD_END_OF_SEQUENCE:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return error_code;
|
|
}
|
|
/**
|
|
*******************************************************************************
|
|
*
|
|
* @brief Fills output arguments for decode process
|
|
*
|
|
* @par Description
|
|
* Fills elements in the output structure based on the current state
|
|
*
|
|
* @param[in] ps_codec
|
|
* Codec context
|
|
*
|
|
* @param[in] ps_dec_ip
|
|
* Pointer to input structure
|
|
*
|
|
* @param[in] ps_dec_op
|
|
* Pointer to output structure
|
|
*
|
|
* @returns none
|
|
*
|
|
* @remarks
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
static void ihevcd_fill_outargs(codec_t *ps_codec,
|
|
ivd_video_decode_ip_t *ps_dec_ip,
|
|
ivd_video_decode_op_t *ps_dec_op)
|
|
{
|
|
|
|
ps_dec_op->u4_error_code = ihevcd_map_error((IHEVCD_ERROR_T)ps_codec->i4_error_code);
|
|
ps_dec_op->u4_num_bytes_consumed = ps_dec_ip->u4_num_Bytes
|
|
- ps_codec->i4_bytes_remaining;
|
|
if(ps_codec->i4_sps_done)
|
|
{
|
|
ps_dec_op->u4_pic_wd = ps_codec->i4_disp_wd;
|
|
ps_dec_op->u4_pic_ht = ps_codec->i4_disp_ht;
|
|
}
|
|
else
|
|
{
|
|
ps_dec_op->u4_pic_wd = 0;
|
|
ps_dec_op->u4_pic_ht = 0;
|
|
}
|
|
|
|
ps_dec_op->e_pic_type = ps_codec->e_dec_pic_type;
|
|
ps_dec_op->u4_frame_decoded_flag = ps_codec->i4_pic_present;
|
|
ps_dec_op->u4_new_seq = 0;
|
|
|
|
ps_dec_op->u4_output_present = 0;
|
|
ps_dec_op->u4_progressive_frame_flag = 1;
|
|
ps_dec_op->i4_display_index = -1;
|
|
ps_dec_op->i4_reorder_depth = -1;
|
|
if(ps_codec->i4_sps_done)
|
|
{
|
|
sps_t *ps_sps = (ps_codec->s_parse.ps_sps_base + ps_codec->i4_sps_id);
|
|
profile_tier_lvl_info_t *ps_ptl;
|
|
ps_ptl = &ps_sps->s_ptl;
|
|
if((0 == ps_ptl->s_ptl_gen.i1_general_progressive_source_flag) &&
|
|
(1 == ps_ptl->s_ptl_gen.i1_general_interlaced_source_flag))
|
|
{
|
|
ps_dec_op->u4_progressive_frame_flag = 0;
|
|
}
|
|
ps_dec_op->i4_reorder_depth =
|
|
ps_sps->ai1_sps_max_num_reorder_pics[ps_sps->i1_sps_max_sub_layers - 1];
|
|
}
|
|
|
|
ps_dec_op->u4_is_ref_flag = 1;
|
|
ps_dec_op->e_output_format = ps_codec->e_chroma_fmt;
|
|
ps_dec_op->u4_is_ref_flag = 1;
|
|
|
|
ps_dec_op->e4_fld_type = IV_FLD_TYPE_DEFAULT;
|
|
ps_dec_op->u4_ts = (UWORD32)(-1);
|
|
ps_dec_op->u4_disp_buf_id = ps_codec->i4_disp_buf_id;
|
|
if(ps_codec->i4_flush_mode)
|
|
{
|
|
ps_dec_op->u4_num_bytes_consumed = 0;
|
|
/*In the case of flush ,since no frame is decoded set pic type as invalid*/
|
|
ps_dec_op->u4_is_ref_flag = 0;
|
|
ps_dec_op->e_pic_type = IV_NA_FRAME;
|
|
ps_dec_op->u4_frame_decoded_flag = 0;
|
|
|
|
}
|
|
/* If there is a display buffer */
|
|
if(ps_codec->ps_disp_buf)
|
|
{
|
|
pic_buf_t *ps_disp_buf = ps_codec->ps_disp_buf;
|
|
sei_params_t *ps_sei = &ps_disp_buf->s_sei_params;
|
|
|
|
if(ps_sei->i1_sei_parameters_present_flag &&
|
|
ps_sei->i1_pic_timing_params_present_flag)
|
|
{
|
|
UWORD32 u4_pic_struct;
|
|
u4_pic_struct = ps_sei->s_pic_timing_sei_params.u4_pic_struct;
|
|
switch(u4_pic_struct)
|
|
{
|
|
case 1:
|
|
ps_dec_op->e4_fld_type = IV_TOP_FLD;
|
|
ps_dec_op->u4_progressive_frame_flag = 0;
|
|
break;
|
|
case 2:
|
|
ps_dec_op->e4_fld_type = IV_BOT_FLD;
|
|
ps_dec_op->u4_progressive_frame_flag = 0;
|
|
break;
|
|
case 0:
|
|
default:
|
|
ps_dec_op->e4_fld_type = IV_FLD_TYPE_DEFAULT;
|
|
ps_dec_op->u4_progressive_frame_flag = 1;
|
|
break;
|
|
}
|
|
}
|
|
ps_dec_op->i4_display_index = ps_disp_buf->i4_abs_poc;
|
|
ps_dec_op->u4_output_present = 1;
|
|
ps_dec_op->u4_ts = ps_disp_buf->u4_ts;
|
|
if((ps_codec->i4_flush_mode == 0) && (ps_codec->s_parse.i4_end_of_frame == 0))
|
|
ps_dec_op->u4_output_present = 0;
|
|
ps_dec_op->s_disp_frm_buf.u4_y_wd = ps_codec->i4_disp_wd;
|
|
ps_dec_op->s_disp_frm_buf.u4_y_ht = ps_codec->i4_disp_ht;
|
|
|
|
if(ps_codec->i4_share_disp_buf)
|
|
{
|
|
ps_dec_op->s_disp_frm_buf.pv_y_buf = ps_disp_buf->pu1_luma;
|
|
if(ps_codec->e_chroma_fmt != IV_YUV_420P)
|
|
{
|
|
ps_dec_op->s_disp_frm_buf.pv_u_buf = ps_disp_buf->pu1_chroma;
|
|
ps_dec_op->s_disp_frm_buf.pv_v_buf = NULL;
|
|
}
|
|
else
|
|
{
|
|
WORD32 i;
|
|
UWORD8 *pu1_u_dst = NULL, *pu1_v_dst = NULL;
|
|
for(i = 0; i < ps_codec->i4_share_disp_buf_cnt; i++)
|
|
{
|
|
WORD32 diff = ps_disp_buf->pu1_luma - ps_codec->s_disp_buffer[i].pu1_bufs[0];
|
|
if(diff == (ps_codec->i4_strd * PAD_TOP + PAD_LEFT))
|
|
{
|
|
pu1_u_dst = ps_codec->s_disp_buffer[i].pu1_bufs[1];
|
|
pu1_u_dst += (ps_codec->i4_strd * PAD_TOP) / 4 + (PAD_LEFT / 2);
|
|
|
|
pu1_v_dst = ps_codec->s_disp_buffer[i].pu1_bufs[2];
|
|
pu1_v_dst += (ps_codec->i4_strd * PAD_TOP) / 4 + (PAD_LEFT / 2);
|
|
break;
|
|
}
|
|
}
|
|
ps_dec_op->s_disp_frm_buf.pv_u_buf = pu1_u_dst;
|
|
ps_dec_op->s_disp_frm_buf.pv_v_buf = pu1_v_dst;
|
|
}
|
|
ps_dec_op->s_disp_frm_buf.u4_y_strd = ps_codec->i4_strd;
|
|
}
|
|
else
|
|
{
|
|
ps_dec_op->s_disp_frm_buf.pv_y_buf =
|
|
ps_dec_ip->s_out_buffer.pu1_bufs[0];
|
|
ps_dec_op->s_disp_frm_buf.pv_u_buf =
|
|
ps_dec_ip->s_out_buffer.pu1_bufs[1];
|
|
ps_dec_op->s_disp_frm_buf.pv_v_buf =
|
|
ps_dec_ip->s_out_buffer.pu1_bufs[2];
|
|
ps_dec_op->s_disp_frm_buf.u4_y_strd = ps_codec->i4_disp_strd;
|
|
}
|
|
|
|
if((IV_YUV_420SP_VU == ps_codec->e_chroma_fmt)
|
|
|| (IV_YUV_420SP_UV == ps_codec->e_chroma_fmt))
|
|
{
|
|
ps_dec_op->s_disp_frm_buf.u4_u_strd =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_strd;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_strd = 0;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_wd =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_wd;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_wd = 0;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_ht =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_ht / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_ht = 0;
|
|
}
|
|
else if(IV_YUV_420P == ps_codec->e_chroma_fmt)
|
|
{
|
|
ps_dec_op->s_disp_frm_buf.u4_u_strd =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_strd / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_strd =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_strd / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_wd =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_wd / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_wd =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_wd / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_ht =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_ht / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_ht =
|
|
ps_dec_op->s_disp_frm_buf.u4_y_ht / 2;
|
|
}
|
|
|
|
}
|
|
else if(ps_codec->i4_flush_mode)
|
|
{
|
|
ps_dec_op->u4_error_code = IHEVCD_END_OF_SEQUENCE;
|
|
/* Come out of flush mode */
|
|
ps_codec->i4_flush_mode = 0;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
*******************************************************************************
|
|
*
|
|
* @brief
|
|
* Codec process call
|
|
*
|
|
* @par Description:
|
|
* Codec process call Tests for few error checks Handle flush and decode
|
|
* header related code Parse bitstream for start codes For each NAL unit
|
|
* call decode NAL function Once a complete frame is decoded (in frame
|
|
* decode mode) Fill output arguments and return
|
|
*
|
|
* @param[in] ps_codec_obj
|
|
* Pointer to codec object at API level
|
|
*
|
|
* @param[in] pv_api_ip
|
|
* Pointer to input argument structure
|
|
*
|
|
* @param[in] pv_api_op
|
|
* Pointer to output argument structure
|
|
*
|
|
* @returns Status
|
|
*
|
|
* @remarks
|
|
*
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
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;
|
|
/* Initialize bytes remaining */
|
|
ps_codec->i4_bytes_remaining = 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*/
|
|
//arm_dsb();
|
|
/* 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_ip->s_out_buffer.u4_num_bufs > IVD_VIDDEC_MAX_IO_BUFFERS))
|
|
{
|
|
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);
|
|
/* If there is no start code found, consume the data and break */
|
|
if(nal_ofst == ps_codec->i4_bytes_remaining)
|
|
{
|
|
ps_codec->pu1_inp_bitsbuf += nal_ofst;
|
|
ps_codec->i4_bytes_remaining -= nal_ofst;
|
|
break;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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(1 == ps_codec->i4_pic_present && 0 == ps_codec->s_parse.i4_end_of_frame)
|
|
{
|
|
slice_header_t *ps_slice_hdr_next;
|
|
ps_codec->i4_slice_error = 1;
|
|
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 = -1;
|
|
ps_slice_hdr_next->i2_ctb_y = -1;
|
|
|
|
ihevcd_parse_slice_data(ps_codec);
|
|
ASSERT(ps_codec->s_parse.i4_end_of_frame != 0);
|
|
}
|
|
|
|
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])
|
|
{
|
|
#ifdef KEEP_THREADS_ACTIVE
|
|
ret = ithread_mutex_lock(ps_codec->apv_proc_done_mutex[i]);
|
|
RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
|
|
|
|
while(!ps_codec->ai4_process_done[i])
|
|
{
|
|
ithread_cond_wait(ps_codec->apv_proc_done_condition[i],
|
|
ps_codec->apv_proc_done_mutex[i]);
|
|
}
|
|
ps_codec->ai4_process_done[i] = 0;
|
|
ret = ithread_mutex_unlock(ps_codec->apv_proc_done_mutex[i]);
|
|
RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
|
|
#else
|
|
ithread_join(ps_codec->apv_process_thread_handle[i], NULL);
|
|
ps_codec->ai4_process_thread_created[i] = 0;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|