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.
476 lines
14 KiB
476 lines
14 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_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((ofst < (bytes_remaining - 1)) &&
|
|
(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) && (ofst < bytes_remaining))
|
|
{
|
|
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) && (src_cnt < bytes_remaining))
|
|
{
|
|
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 = (WORD32)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_PREFIX_SEI:
|
|
case NAL_SUFFIX_SEI:
|
|
if(IVD_DECODE_HEADER == ps_codec->i4_header_mode)
|
|
{
|
|
return IHEVCD_SLICE_IN_HEADER_MODE;
|
|
}
|
|
|
|
ret = ihevcd_parse_sei(ps_codec, &s_nal);
|
|
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;
|
|
}
|
|
|