mirror of
https://github.com/ittiam-systems/libhevc.git
synced 2026-08-13 22:32:34 +07:00
This is the initial version and doesn't enable SIMD functions yet. Has not been tested extensively yet. This is not ready to be merged into main branch yet.
1070 lines
40 KiB
C
1070 lines
40 KiB
C
/******************************************************************************
|
|
*
|
|
* 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(e_error)
|
|
{
|
|
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,
|
|
void *pv_api_ip,
|
|
void *pv_api_op)
|
|
{
|
|
WORD32 i4_bit_depth_luma, i4_bit_depth_chroma;
|
|
|
|
ihevcd_cxa_video_decode_ip_t *ps_hevcd_dec_ip;
|
|
ihevcd_cxa_video_decode_op_t *ps_hevcd_dec_op;
|
|
ivd_video_decode_ip_t *ps_dec_ip;
|
|
ivd_video_decode_op_t *ps_dec_op;
|
|
|
|
ps_hevcd_dec_ip = (ihevcd_cxa_video_decode_ip_t *)pv_api_ip;
|
|
ps_hevcd_dec_op = (ihevcd_cxa_video_decode_op_t *)pv_api_op;
|
|
ps_dec_ip = &ps_hevcd_dec_ip->s_ivd_video_decode_ip_t;
|
|
ps_dec_op = &ps_hevcd_dec_op->s_ivd_video_decode_op_t;
|
|
|
|
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;
|
|
i4_bit_depth_luma = ps_codec->i4_bit_depth_luma;
|
|
i4_bit_depth_chroma = ps_codec->i4_bit_depth_chroma;
|
|
}
|
|
else
|
|
{
|
|
ps_dec_op->u4_pic_wd = 0;
|
|
ps_dec_op->u4_pic_ht = 0;
|
|
i4_bit_depth_luma = 0;
|
|
i4_bit_depth_chroma = 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;
|
|
|
|
}
|
|
ps_dec_op->s_disp_frm_buf.u4_y_bit_depth = i4_bit_depth_luma;
|
|
ps_dec_op->s_disp_frm_buf.u4_uv_bit_depth = i4_bit_depth_chroma;
|
|
|
|
/* If there is a display buffer */
|
|
if(ps_codec->ps_disp_buf)
|
|
{
|
|
pic_buf_t *ps_disp_buf = ps_codec->ps_disp_buf;
|
|
#ifndef DISABLE_SEI
|
|
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;
|
|
}
|
|
}
|
|
#endif
|
|
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;
|
|
// ps_dec_op->s_disp_frm_buf.u4_y_bit_depth = i4_bit_depth_luma;
|
|
// ps_dec_op->s_disp_frm_buf.u4_uv_bit_depth = i4_bit_depth_chroma;
|
|
|
|
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 = ALIGN2(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 = ALIGN2(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 + 1) / 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 + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_strd = (ps_dec_op->s_disp_frm_buf.u4_y_strd + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_wd = (ps_dec_op->s_disp_frm_buf.u4_y_wd + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_wd = (ps_dec_op->s_disp_frm_buf.u4_y_wd + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_ht = (ps_dec_op->s_disp_frm_buf.u4_y_ht + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_ht = (ps_dec_op->s_disp_frm_buf.u4_y_ht + 1) / 2;
|
|
}
|
|
else if(IV_YUV_444P == 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 = ps_dec_op->s_disp_frm_buf.u4_y_strd;
|
|
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 = ps_dec_op->s_disp_frm_buf.u4_y_wd;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_ht = ps_dec_op->s_disp_frm_buf.u4_y_ht;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_ht = ps_dec_op->s_disp_frm_buf.u4_y_ht;
|
|
}
|
|
else if(IV_GRAY == ps_codec->e_chroma_fmt)
|
|
{
|
|
ps_dec_op->s_disp_frm_buf.u4_u_strd = 0;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_strd = 0;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_wd = 0;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_wd = 0;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_ht = 0;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_ht = 0;
|
|
}
|
|
else if(IV_YUV_422P == 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 + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_strd = (ps_dec_op->s_disp_frm_buf.u4_y_strd + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_wd = (ps_dec_op->s_disp_frm_buf.u4_y_wd + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_wd = (ps_dec_op->s_disp_frm_buf.u4_y_wd + 1) / 2;
|
|
ps_dec_op->s_disp_frm_buf.u4_u_ht = ps_dec_op->s_disp_frm_buf.u4_y_ht;
|
|
ps_dec_op->s_disp_frm_buf.u4_v_ht = ps_dec_op->s_disp_frm_buf.u4_y_ht;
|
|
}
|
|
|
|
}
|
|
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;
|
|
}
|
|
|
|
if(ps_codec->u1_enable_cu_info && ps_dec_op->u4_output_present)
|
|
{
|
|
WORD32 info_map_dst_strd = ALIGN8(ps_codec->i4_wd) >> 3;
|
|
WORD32 info_map_src_strd = ALIGN64(ps_codec->i4_wd) >> 3;
|
|
WORD32 info_map_ht = ALIGN8(ps_codec->i4_ht);
|
|
UWORD32 info_map_size = (ALIGN8(ps_codec->i4_wd) * info_map_ht) >> 6;
|
|
WORD32 vert_8x8;
|
|
UWORD8 *pu1_out_qp_map, *pu1_qp_map;
|
|
UWORD8 *pu1_out_blk_type_map, *pu1_type_map;
|
|
|
|
if(ps_hevcd_dec_ip->pu1_8x8_blk_qp_map)
|
|
{
|
|
ps_hevcd_dec_op->pu1_8x8_blk_qp_map = ps_hevcd_dec_ip->pu1_8x8_blk_qp_map;
|
|
ps_hevcd_dec_op->u4_8x8_blk_qp_map_size = info_map_size;
|
|
|
|
pu1_out_qp_map = ps_hevcd_dec_op->pu1_8x8_blk_qp_map;
|
|
pu1_qp_map = ps_codec->as_buf_id_info_map[ps_codec->i4_disp_buf_id].pu1_qp_map;
|
|
for(vert_8x8 = 0; vert_8x8 < info_map_ht; vert_8x8++)
|
|
{
|
|
memcpy(pu1_out_qp_map, pu1_qp_map, info_map_dst_strd);
|
|
pu1_out_qp_map += info_map_dst_strd;
|
|
pu1_qp_map += info_map_src_strd;
|
|
}
|
|
}
|
|
|
|
if(ps_hevcd_dec_ip->pu1_8x8_blk_type_map)
|
|
{
|
|
ps_hevcd_dec_op->pu1_8x8_blk_type_map = ps_hevcd_dec_ip->pu1_8x8_blk_type_map;
|
|
ps_hevcd_dec_op->u4_8x8_blk_type_map_size = info_map_size;
|
|
|
|
pu1_out_blk_type_map = ps_hevcd_dec_op->pu1_8x8_blk_type_map;
|
|
pu1_type_map =
|
|
ps_codec->as_buf_id_info_map[ps_codec->i4_disp_buf_id].pu1_cu_type_map;
|
|
for(vert_8x8 = 0; vert_8x8 < info_map_ht; vert_8x8++)
|
|
{
|
|
memcpy(pu1_out_blk_type_map, pu1_type_map, info_map_dst_strd);
|
|
pu1_out_blk_type_map += info_map_dst_strd;
|
|
pu1_type_map += info_map_src_strd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*******************************************************************************
|
|
*
|
|
* @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);
|
|
ihevcd_cxa_video_decode_ip_t s_hevcd_dec_ip = {};
|
|
ihevcd_cxa_video_decode_ip_t *ps_hevcd_dec_ip;
|
|
ihevcd_cxa_video_decode_op_t *ps_hevcd_dec_op;
|
|
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;
|
|
memcpy(&s_hevcd_dec_ip, ps_dec_ip, ps_dec_ip->u4_size);
|
|
s_hevcd_dec_ip.s_ivd_video_decode_ip_t.u4_size = sizeof(ihevcd_cxa_video_decode_ip_t);
|
|
|
|
ps_hevcd_dec_ip = &s_hevcd_dec_ip;
|
|
ps_dec_ip = &ps_hevcd_dec_ip->s_ivd_video_decode_ip_t;
|
|
|
|
ps_hevcd_dec_op = (ihevcd_cxa_video_decode_op_t *)pv_api_op;
|
|
ps_dec_op = &ps_hevcd_dec_op->s_ivd_video_decode_op_t;
|
|
|
|
{
|
|
UWORD32 u4_size = ps_dec_op->u4_size;
|
|
memset(ps_hevcd_dec_op, 0, u4_size);
|
|
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(ps_codec->u1_enable_cu_info && ps_codec->i4_sps_done)
|
|
{
|
|
UWORD32 blk_qp_map_size = ps_hevcd_dec_ip->u4_8x8_blk_qp_map_size;
|
|
UWORD32 blk_type_map_size = ps_hevcd_dec_ip->u4_8x8_blk_type_map_size;
|
|
UWORD32 blk_8x8_map_size = (ALIGN8(ps_codec->i4_wd) * ALIGN8(ps_codec->i4_ht)) >> 6;
|
|
|
|
if ((ps_hevcd_dec_ip->pu1_8x8_blk_qp_map && blk_qp_map_size < blk_8x8_map_size) ||
|
|
(ps_hevcd_dec_ip->pu1_8x8_blk_type_map && blk_type_map_size < blk_8x8_map_size))
|
|
{
|
|
ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;
|
|
ps_dec_op->u4_error_code |= IHEVCD_INSUFFICIENT_METADATA_BUFFER;
|
|
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_hevcd_dec_ip, ps_hevcd_dec_op);
|
|
|
|
if(1 == ps_dec_op->u4_output_present)
|
|
{
|
|
WORD32 ypos = ps_codec->i4_disp_ht - 64 - LOGO_HT;
|
|
|
|
if(ypos < 0)
|
|
ypos = 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,
|
|
32 ,
|
|
ps_codec->i4_disp_ht - 32 - LOGO_HT,
|
|
ps_codec->e_chroma_fmt,
|
|
ps_codec->i4_bit_depth_luma,
|
|
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)
|
|
{
|
|
|
|
/* If format conversion jobs were not issued in pic_init() add them here */
|
|
/* 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 */
|
|
#if ENABLE_FMT_CONV_AHEAD
|
|
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) && (ps_codec->i4_disp_buf_id == ps_proc->i4_cur_pic_buf_id) &&
|
|
((0 == ps_codec->i4_share_disp_buf) || (IV_YUV_420P == ps_codec->e_chroma_fmt)))
|
|
#else
|
|
if((ps_codec->ps_disp_buf) &&
|
|
((0 == ps_codec->i4_share_disp_buf) || (IV_YUV_420P == ps_codec->e_chroma_fmt)))
|
|
#endif
|
|
{
|
|
|
|
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_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_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])
|
|
{
|
|
if(ps_codec->i4_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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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_hevcd_dec_ip, ps_hevcd_dec_op);
|
|
|
|
if(1 == ps_dec_op->u4_output_present)
|
|
{
|
|
WORD32 ypos = ps_codec->i4_disp_ht - 64 - LOGO_HT;
|
|
|
|
if(ypos < 0)
|
|
ypos = 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,
|
|
32 ,
|
|
ypos,
|
|
ps_codec->e_chroma_fmt,
|
|
ps_codec->i4_bit_depth_luma,
|
|
ps_codec->i4_disp_wd,
|
|
ps_codec->i4_disp_ht);
|
|
}
|
|
|
|
|
|
return ret;
|
|
}
|
|
|