libhevc-mirror/decoder/ihevcd_nal.c
Naveen Kumar Ponnusamy 9663ae2116 Few bug fixes in loop filter
Removed few unused functions
Fixed an issue in 420P output in shared mdoe
Few bug fixes in handling loop filter corner cases in multi-tile multi-slice clips
Renamed few elements in mv_buf_t for consistency

Change-Id: I8d179b9ad3c7ee3ad27972ee02ea2658fd2c3c25
2015-07-30 18:14:32 +05:30

464 lines
13 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_nal.c
*
* @brief
* Contains functions for NAL level such as search start code etc
*
* @author
* Harish
*
* @par List of Functions:
*
* @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 "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 "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_parse_headers.h"
#include "ihevcd_parse_slice.h"
#include "ihevcd_debug.h"
/*****************************************************************************/
/* Function Prototypes */
/*****************************************************************************/
/**
*******************************************************************************
*
* @brief
* Search start code from the given buffer pointer
*
* @par Description:
* Search for start code Return the offset of start code if start code is
* found If no start code is found till end of given bitstream then treat
* it as invalid NAL and return end of buffer as offset
*
* @param[in] pu1_buf
* Pointer to bitstream
*
* @param[in] bytes_remaining
* Number of bytes remaining in the buffer
*
* @returns Offset to the first byte in NAL after start code
*
* @remarks
* Incomplete start code at the end of input bitstream is not handled. This
* has to be taken care outside this func
*
*******************************************************************************
*/
WORD32 ihevcd_nal_search_start_code(UWORD8 *pu1_buf, WORD32 bytes_remaining)
{
WORD32 ofst;
WORD32 zero_byte_cnt;
WORD32 start_code_found;
ofst = -1;
zero_byte_cnt = 0;
start_code_found = 0;
while(ofst < (bytes_remaining - 1))
{
ofst++;
if(pu1_buf[ofst] != 0)
{
zero_byte_cnt = 0;
continue;
}
zero_byte_cnt++;
if((pu1_buf[ofst + 1] == START_CODE_PREFIX_BYTE) &&
(zero_byte_cnt >= NUM_ZEROS_BEFORE_START_CODE))
{
/* Found the start code */
ofst++;
start_code_found = 1;
break;
}
}
if(0 == start_code_found)
{
if((START_CODE_PREFIX_BYTE == pu1_buf[ofst]) &&
(zero_byte_cnt >= NUM_ZEROS_BEFORE_START_CODE))
{
/* Found a start code at the end*/
ofst++;
}
}
/* Since ofst started at -1, increment it by 1 */
ofst++;
return ofst;
}
/**
*******************************************************************************
*
* @brief
* Remove emulation prevention byte present in the bitstream till next start
* code is found. Emulation prevention byte removed data is stored in a
* different buffer
*
* @par Description:
* Assumption is first start code is already found and pu1_buf is pointing
* to a byte after the start code Search for Next NAL's start code Return
* if start code is found Remove any emulation prevention byte present Copy
* data to new buffer If no start code is found, then treat complete buffer
* as one nal.
*
* @param[in] pu1_src
* Pointer to bitstream (excludes the initial the start code)
*
* @param[in] pu1_dst
* Pointer to destination buffer
*
* @param[in] bytes_remaining
* Number of bytes remaining
*
* @param[out] pi4_nal_len
* NAL length (length of bitstream parsed)
*
* @param[out] pi4_dst_len
* Destination bitstream size (length of bitstream parsed with emulation bytes
* removed)
*
* @returns Error code from IHEVCD_ERROR_T
*
* @remarks
* Incomplete start code at the end of input bitstream is not handled. This
* has to be taken care outside this func
*
*******************************************************************************
*/
IHEVCD_ERROR_T ihevcd_nal_remv_emuln_bytes(UWORD8 *pu1_src,
UWORD8 *pu1_dst,
WORD32 bytes_remaining,
WORD32 *pi4_nal_len,
WORD32 *pi4_dst_len)
{
WORD32 src_cnt;
WORD32 dst_cnt;
WORD32 zero_byte_cnt;
WORD32 start_code_found;
UWORD8 u1_src;
IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
src_cnt = 0;
dst_cnt = 0;
zero_byte_cnt = 0;
start_code_found = 0;
while(src_cnt < (bytes_remaining - 1))
{
u1_src = pu1_src[src_cnt++];
pu1_dst[dst_cnt++] = u1_src;
if(u1_src != 0)
{
zero_byte_cnt = 0;
continue;
}
zero_byte_cnt++;
if(zero_byte_cnt >= NUM_ZEROS_BEFORE_START_CODE)
{
u1_src = pu1_src[src_cnt];
if(START_CODE_PREFIX_BYTE == u1_src)
{
/* Found the start code */
src_cnt -= zero_byte_cnt;
dst_cnt -= zero_byte_cnt;
start_code_found = 1;
break;
}
else if(EMULATION_PREVENT_BYTE == u1_src)
{
/* Found the emulation prevention byte */
src_cnt++;
zero_byte_cnt = 0;
/* Decrement dst_cnt so that the next byte overwrites
* the emulation prevention byte already copied to dst above
*/
}
}
}
if(0 == start_code_found)
{
u1_src = pu1_src[src_cnt++];
if(zero_byte_cnt >= NUM_ZEROS_BEFORE_START_CODE)
{
if(START_CODE_PREFIX_BYTE == u1_src)
{
/* Found a start code at the end*/
src_cnt -= zero_byte_cnt;
}
else if(EMULATION_PREVENT_BYTE == u1_src)
{
/* Found the emulation prevention byte at the end*/
src_cnt++;
/* Decrement dst_cnt so that the next byte overwrites
* the emulation prevention byte already copied to dst above
*/
dst_cnt--;
}
}
else
{
pu1_dst[dst_cnt++] = u1_src;
}
}
*pi4_nal_len = src_cnt;
*pi4_dst_len = dst_cnt;
return ret;
}
/**
*******************************************************************************
*
* @brief
* Decode given NAL unit's header
*
* @par Description:
* Call NAL unit's header decode Section: 7.3.1.2
*
* @param[in] ps_bitstrm
* Pointer to bitstream context
*
* @param[out] ps_nal
* Pointer to NAL header
*
* @returns Error code from IHEVCD_ERROR_T
*
* @remarks
*
*
*******************************************************************************
*/
IHEVCD_ERROR_T ihevcd_nal_unit_header(bitstrm_t *ps_bitstrm, nal_header_t *ps_nal)
{
WORD32 unused;
IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
UNUSED(unused);
/* Syntax : forbidden_zero_bit */
unused = ihevcd_bits_get(ps_bitstrm, 1);
/* Syntax : nal_unit_type */
ps_nal->i1_nal_unit_type = ihevcd_bits_get(ps_bitstrm, 6);
/* Syntax : nuh_reserved_zero_6bits */
unused = ihevcd_bits_get(ps_bitstrm, 6);
/* Syntax : nuh_temporal_id_plus1 */
ps_nal->i1_nuh_temporal_id = ihevcd_bits_get(ps_bitstrm, 3) - 1;
return ret;
}
/**
*******************************************************************************
*
* @brief
* Decode given NAL
*
* @par Description:
* Based on the NAL type call appropriate decode function Section: 7.3.1.1
*
*
* @param[in,out] ps_codec
* Pointer to codec context (Functions called within will modify contents of
* ps_codec)
*
* @returns Error code from IHEVCD_ERROR_T
*
* @remarks
*
*
*******************************************************************************
*/
IHEVCD_ERROR_T ihevcd_nal_unit(codec_t *ps_codec)
{
IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
/* NAL Header */
nal_header_t s_nal;
ret = ihevcd_nal_unit_header(&ps_codec->s_parse.s_bitstrm, &s_nal);
RETURN_IF((ret != (IHEVCD_ERROR_T)IHEVCD_SUCCESS), ret);
if(ps_codec->i4_slice_error)
s_nal.i1_nal_unit_type = ps_codec->s_parse.ps_slice_hdr->i1_nal_unit_type;
/* Setting RASL Output flag */
switch(s_nal.i1_nal_unit_type)
{
case NAL_BLA_W_LP :
case NAL_BLA_W_DLP :
case NAL_BLA_N_LP :
ps_codec->i4_rasl_output_flag = 0;
break;
//TODO: After IDR, there is no case of open GOP
//To be fixed appropriately by ignoring RASL only if the
// required references are not found
case NAL_IDR_W_LP :
case NAL_IDR_N_LP :
ps_codec->i4_rasl_output_flag = 1;
break;
case NAL_CRA :
ps_codec->i4_rasl_output_flag = (0 != ps_codec->i4_cra_as_first_pic) ? 0 : 1;
break;
default:
break;
}
switch(s_nal.i1_nal_unit_type)
{
case NAL_BLA_W_LP :
case NAL_BLA_W_DLP :
case NAL_BLA_N_LP :
case NAL_IDR_W_LP :
case NAL_IDR_N_LP :
case NAL_CRA :
case NAL_TRAIL_N :
case NAL_TRAIL_R :
case NAL_TSA_N :
case NAL_TSA_R :
case NAL_STSA_N :
case NAL_STSA_R :
case NAL_RADL_N :
case NAL_RADL_R :
case NAL_RASL_N :
case NAL_RASL_R :
if(ps_codec->i4_header_mode)
return IHEVCD_SLICE_IN_HEADER_MODE;
if((0 == ps_codec->i4_sps_done) ||
(0 == ps_codec->i4_pps_done))
{
return IHEVCD_INVALID_HEADER;
}
ps_codec->i4_header_in_slice_mode = 0;
ps_codec->i4_cra_as_first_pic = 0;
ret = ihevcd_parse_slice_header(ps_codec, &s_nal);
DEBUG_PRINT_NAL_INFO(ps_codec, s_nal.i1_nal_unit_type);
if(ret == (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
{
if((s_nal.i1_nal_unit_type != NAL_RASL_N && s_nal.i1_nal_unit_type != NAL_RASL_R) ||
ps_codec->i4_rasl_output_flag ||
ps_codec->i4_slice_error)
ret = ihevcd_parse_slice_data(ps_codec);
}
break;
case NAL_VPS :
// ret = ihevcd_parse_vps(ps_codec);
DEBUG_PRINT_NAL_INFO(ps_codec, s_nal.i1_nal_unit_type);
break;
case NAL_SPS :
if(0 == ps_codec->i4_header_mode)
{
ps_codec->i4_header_in_slice_mode = 1;
if(ps_codec->i4_sps_done &&
ps_codec->i4_pic_present)
break;
}
ret = ihevcd_parse_sps(ps_codec);
if(ret == (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
{
sps_t *ps_sps = ps_codec->ps_sps_base + MAX_SPS_CNT - 1;
ihevcd_copy_sps(ps_codec, ps_sps->i1_sps_id, MAX_SPS_CNT - 1);
}
ps_codec->i4_error_code = ret;
DEBUG_PRINT_NAL_INFO(ps_codec, s_nal.i1_nal_unit_type);
break;
case NAL_PPS :
if(0 == ps_codec->i4_header_mode)
{
ps_codec->i4_header_in_slice_mode = 1;
if(ps_codec->i4_pps_done &&
ps_codec->i4_pic_present)
break;
}
ret = ihevcd_parse_pps(ps_codec);
if(ret == (IHEVCD_ERROR_T)IHEVCD_SUCCESS)
{
pps_t *ps_pps = ps_codec->ps_pps_base + MAX_PPS_CNT - 1;
ihevcd_copy_pps(ps_codec, ps_pps->i1_pps_id, MAX_PPS_CNT - 1);
}
ps_codec->i4_error_code = ret;
DEBUG_PRINT_NAL_INFO(ps_codec, s_nal.i1_nal_unit_type);
break;
case NAL_EOS :
ps_codec->i4_cra_as_first_pic = 1;
break;
default:
DEBUG_PRINT_NAL_INFO(ps_codec, s_nal.i1_nal_unit_type);
break;
}
return ret;
}