/*
|
*
|
* Copyright 2015 Rockchip Electronics Co. LTD
|
*
|
* 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.
|
*/
|
|
#define MODULE_TAG "h264d_parse"
|
|
#include <string.h>
|
#include <stdlib.h>
|
|
#include "mpp_mem.h"
|
#include "mpp_packet_impl.h"
|
#include "hal_dec_task.h"
|
|
#include "h264d_global.h"
|
#include "h264d_parse.h"
|
#include "h264d_slice.h"
|
#include "h264d_sps.h"
|
#include "h264d_pps.h"
|
#include "h264d_sei.h"
|
#include "h264d_init.h"
|
#include "h264d_fill.h"
|
|
#define HEAD_SYNTAX_MAX_SIZE (12800)
|
#define NALU_TYPE_NORMAL_LENGTH (1)
|
#define NALU_TYPE_EXT_LENGTH (5)
|
|
static const RK_U8 g_start_precode[3] = {0, 0, 1};
|
|
typedef struct h264d_nalu_head_t {
|
RK_U16 is_frame_end;
|
RK_U16 nalu_type;
|
RK_U32 sodb_len;
|
} H264dNaluHead_t;
|
|
|
static RK_U16 U16_AT(const RK_U8 *ptr)
|
{
|
return ptr[0] << 8 | ptr[1];
|
}
|
|
static RK_U32 U32_AT(const RK_U8 *ptr)
|
{
|
return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
|
}
|
|
static RK_U32 parse_nal_size(RK_U8 nal_size, RK_U8 *data)
|
{
|
switch (nal_size) {
|
case 1:
|
return *data;
|
case 2:
|
return U16_AT(data);
|
case 3:
|
return ((RK_U64)data[0] << 16) | U16_AT(&data[1]);
|
case 4:
|
return U32_AT(data);
|
}
|
return 0;
|
}
|
|
static void reset_slice(H264dVideoCtx_t *p_Vid)
|
{
|
RK_U32 i = 0, j = 0;
|
H264_SLICE_t *currSlice = &p_Vid->p_Cur->slice;
|
|
memset(currSlice, 0, sizeof(H264_SLICE_t));
|
//-- re-init parameters
|
currSlice->view_id = -1;
|
currSlice->p_Vid = p_Vid;
|
currSlice->p_Dec = p_Vid->p_Dec;
|
currSlice->p_Cur = p_Vid->p_Cur;
|
currSlice->p_Inp = p_Vid->p_Inp;
|
currSlice->active_sps = p_Vid->active_sps;
|
currSlice->active_pps = p_Vid->active_pps;
|
//--- reset listP listB
|
for (i = 0; i < MAX_NUM_DPB_LAYERS; i++) {
|
currSlice->listP[i] = p_Vid->p_Cur->listP[i];
|
currSlice->listB[i] = p_Vid->p_Cur->listB[i];
|
for (j = 0; j < MAX_LIST_SIZE; j++) {
|
currSlice->listP[i][j] = NULL;
|
currSlice->listB[i][j] = NULL;
|
}
|
currSlice->listXsizeP[i] = 0;
|
currSlice->listXsizeB[i] = 0;
|
}
|
reset_cur_slice(p_Vid->p_Cur, currSlice);
|
}
|
|
static MPP_RET realloc_buffer(RK_U8 **buf, RK_U32 *max_size, RK_U32 add_size)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
if ((*buf) == NULL) {
|
H264D_ERR("[realloc_buffer] pointer is null, %p \n", (*buf));
|
ret = MPP_ERR_MALLOC;
|
goto __FAILED;
|
}
|
|
add_size = MPP_ALIGN(add_size, 16);
|
|
(*buf) = mpp_realloc((*buf), RK_U8, ((*max_size) + add_size));
|
if ((*buf) == NULL) {
|
H264D_ERR("[realloc_buffer] ERROR: max_size=%d, add_size=%d \n", (*max_size), add_size);
|
ret = MPP_ERR_MALLOC;
|
goto __FAILED;
|
}
|
(*max_size) += add_size;
|
|
return ret = MPP_OK;
|
__FAILED:
|
return ret;
|
}
|
|
static void reset_nalu(H264dCurStream_t *p_strm)
|
{
|
if (p_strm->endcode_found) {
|
p_strm->startcode_found = p_strm->endcode_found;
|
p_strm->nalu_len = 0;
|
p_strm->nalu_type = H264_NALU_TYPE_NULL;
|
p_strm->endcode_found = 0;
|
}
|
}
|
|
static void find_prefix_code(RK_U8 *p_data, H264dCurStream_t *p_strm)
|
{
|
(void)p_data;
|
|
if ((p_strm->prefixdata & 0x00FFFFFF) == 0x00000001) {
|
if (p_strm->startcode_found) {
|
p_strm->endcode_found = 1;
|
} else {
|
p_strm->startcode_found = 1;
|
}
|
}
|
}
|
|
static MPP_RET parser_nalu_header(H264_SLICE_t *currSlice)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
|
H264dCurCtx_t *p_Cur = currSlice->p_Cur;
|
BitReadCtx_t *p_bitctx = &p_Cur->bitctx;
|
H264_Nalu_t *cur_nal = &p_Cur->nalu;
|
|
mpp_set_bitread_ctx(p_bitctx, cur_nal->sodb_buf, cur_nal->sodb_len);
|
mpp_set_pre_detection(p_bitctx);
|
|
READ_BITS(p_bitctx, 1, &cur_nal->forbidden_bit);
|
ASSERT(cur_nal->forbidden_bit == 0);
|
{
|
RK_S32 *ptmp = NULL;
|
ptmp = (RK_S32 *)&cur_nal->nal_reference_idc;
|
READ_BITS(p_bitctx, 2, ptmp); //!< nal_ref_idc
|
ptmp = (RK_S32 *)&cur_nal->nalu_type;
|
READ_BITS(p_bitctx, 5, ptmp); //!< nalu_type
|
}
|
cur_nal->ualu_header_bytes = 1;
|
currSlice->svc_extension_flag = -1; //!< initialize to -1
|
if (cur_nal->nalu_type == H264_NALU_TYPE_PREFIX
|
|| cur_nal->nalu_type == H264_NALU_TYPE_SLC_EXT) {
|
READ_ONEBIT(p_bitctx, &currSlice->svc_extension_flag);
|
if (currSlice->svc_extension_flag) {
|
currSlice->svcExt.valid = 1;
|
p_Cur->p_Dec->svc_valid = 1;
|
READ_ONEBIT(p_bitctx, &currSlice->svcExt.idr_flag);
|
READ_BITS(p_bitctx, 6, &currSlice->svcExt.priority_id);
|
READ_ONEBIT(p_bitctx, &currSlice->svcExt.no_inter_layer_pred_flag);
|
READ_BITS(p_bitctx, 3, &currSlice->svcExt.dependency_id);
|
READ_BITS(p_bitctx, 4, &currSlice->svcExt.quality_id);
|
READ_BITS(p_bitctx, 3, &currSlice->svcExt.temporal_id);
|
READ_ONEBIT(p_bitctx, &currSlice->svcExt.use_ref_base_pic_flag);
|
READ_ONEBIT(p_bitctx, &currSlice->svcExt.discardable_flag);
|
READ_ONEBIT(p_bitctx, &currSlice->svcExt.output_flag);
|
|
ASSERT(currSlice->svcExt.no_inter_layer_pred_flag == 1);
|
ASSERT(currSlice->svcExt.dependency_id == 0);
|
ASSERT(currSlice->svcExt.quality_id == 0);
|
ASSERT(currSlice->svcExt.use_ref_base_pic_flag == 0);
|
} else { //!< MVC
|
currSlice->mvcExt.valid = 1;
|
p_Cur->p_Dec->mvc_valid = 1;
|
READ_ONEBIT(p_bitctx, &currSlice->mvcExt.non_idr_flag);
|
READ_BITS(p_bitctx, 6, &currSlice->mvcExt.priority_id);
|
READ_BITS(p_bitctx, 10, &currSlice->mvcExt.view_id);
|
READ_BITS(p_bitctx, 3, &currSlice->mvcExt.temporal_id);
|
READ_ONEBIT(p_bitctx, &currSlice->mvcExt.anchor_pic_flag);
|
READ_ONEBIT(p_bitctx, &currSlice->mvcExt.inter_view_flag);
|
READ_ONEBIT(p_bitctx, &currSlice->mvcExt.reserved_one_bit);
|
ASSERT(currSlice->mvcExt.reserved_one_bit == 1);
|
currSlice->mvcExt.iPrefixNALU = (cur_nal->nalu_type == H264_NALU_TYPE_PREFIX) ? 1 : 0;
|
//!< combine H264_NALU_TYPE_SLC_EXT into H264_NALU_TYPE_SLICE
|
if (cur_nal->nalu_type == H264_NALU_TYPE_SLC_EXT) {
|
cur_nal->nalu_type = H264_NALU_TYPE_SLICE;
|
}
|
}
|
cur_nal->ualu_header_bytes += 3;
|
}
|
/* Move forward the bitread offset */
|
mpp_set_bitread_ctx(p_bitctx,
|
cur_nal->sodb_buf + cur_nal->ualu_header_bytes,
|
cur_nal->sodb_len - cur_nal->ualu_header_bytes);
|
mpp_set_pre_detection(p_bitctx);
|
p_Cur->p_Dec->nalu_ret = StartofNalu;
|
|
return ret = MPP_OK;
|
__BITREAD_ERR:
|
p_Cur->p_Dec->nalu_ret = ReadNaluError;
|
return ret = p_bitctx->ret;
|
}
|
|
static MPP_RET parser_one_nalu(H264_SLICE_t *currSlice)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
|
FUN_CHECK(ret = parser_nalu_header(currSlice));
|
//!< nalu_parse
|
switch (currSlice->p_Cur->nalu.nalu_type) {
|
case H264_NALU_TYPE_SLICE:
|
case H264_NALU_TYPE_IDR:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "nalu_type=SLICE.");
|
FUN_CHECK(ret = process_slice(currSlice));
|
currSlice->p_Dec->nalu_ret = StartOfPicture;
|
if (currSlice->layer_id && currSlice->p_Inp->mvc_disable)
|
currSlice->p_Dec->nalu_ret = MvcDisAble;
|
break;
|
case H264_NALU_TYPE_SPS:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "nalu_type=SPS");
|
FUN_CHECK(ret = process_sps(currSlice));
|
currSlice->p_Dec->nalu_ret = NALU_SPS;
|
break;
|
case H264_NALU_TYPE_PPS:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "nalu_type=PPS");
|
FUN_CHECK(ret = process_pps(currSlice));
|
currSlice->p_Dec->nalu_ret = NALU_PPS;
|
break;
|
case H264_NALU_TYPE_SUB_SPS:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "nalu_type=SUB_SPS");
|
FUN_CHECK(ret = process_subsps(currSlice));
|
currSlice->p_Dec->nalu_ret = NALU_SubSPS;
|
break;
|
case H264_NALU_TYPE_SEI:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "nalu_type=SEI");
|
ret = process_sei(currSlice);
|
currSlice->p_Dec->nalu_ret = NALU_SEI;
|
break;
|
case H264_NALU_TYPE_SLC_EXT:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "Found H264_NALU_TYPE_SLC_EXT.");
|
currSlice->p_Dec->nalu_ret = SkipNALU;
|
break;
|
case H264_NALU_TYPE_PREFIX:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "Found H264_NALU_TYPE_PREFIX.");
|
process_prefix(currSlice);
|
break;
|
case H264_NALU_TYPE_AUD:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "Found H264_NALU_TYPE_AUD.");
|
currSlice->p_Dec->nalu_ret = SkipNALU;
|
break;
|
case H264_NALU_TYPE_EOSEQ:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "Found H264_NALU_TYPE_EOSEQ.");
|
currSlice->p_Dec->nalu_ret = SkipNALU;
|
break;
|
case H264_NALU_TYPE_EOSTREAM:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "Found H264_NALU_TYPE_EOSTREAM.");
|
currSlice->p_Dec->nalu_ret = SkipNALU;
|
break;
|
case H264_NALU_TYPE_FILL:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "Found H264_NALU_TYPE_FILL.");
|
currSlice->p_Dec->nalu_ret = SkipNALU;
|
break;
|
case H264_NALU_TYPE_VDRD:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "Found H264_NALU_TYPE_VDRD.");
|
currSlice->p_Dec->nalu_ret = SkipNALU;
|
break;
|
case H264_NALU_TYPE_DPA:
|
case H264_NALU_TYPE_DPB:
|
case H264_NALU_TYPE_DPC:
|
H264D_DBG(H264D_DBG_PARSE_NALU,
|
"Found H264_NALU_TYPE_DPA DPB DPC, and not supported.");
|
currSlice->p_Dec->nalu_ret = NaluNotSupport;
|
break;
|
default:
|
currSlice->p_Dec->nalu_ret = SkipNALU;
|
break;
|
}
|
|
return ret = MPP_OK;
|
__FAILED:
|
H264D_DBG(H264D_DBG_PARSE_NALU, "parser_one_nalu error.");
|
currSlice->p_Dec->nalu_ret = ReadNaluError;
|
return ret;
|
}
|
|
static MPP_RET add_empty_nalu(H264dCurStream_t *p_strm)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
RK_U8 *p_des = NULL;
|
RK_U32 add_size = sizeof(H264dNaluHead_t);
|
|
if ((p_strm->head_offset + add_size) >= p_strm->head_max_size) {
|
FUN_CHECK(ret = realloc_buffer(&p_strm->head_buf, &p_strm->head_max_size, HEAD_BUF_ADD_SIZE));
|
}
|
p_des = &p_strm->head_buf[p_strm->head_offset];
|
((H264dNaluHead_t *)p_des)->is_frame_end = 1;
|
((H264dNaluHead_t *)p_des)->nalu_type = 0;
|
((H264dNaluHead_t *)p_des)->sodb_len = 0;
|
p_strm->head_offset += add_size;
|
|
return ret = MPP_OK;
|
__FAILED:
|
return ret;
|
}
|
|
static MPP_RET store_cur_nalu(H264dCurCtx_t *p_Cur, H264dCurStream_t *p_strm, H264dDxvaCtx_t *dxva_ctx)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
RK_U8 *p_des = NULL;
|
|
//!< fill head buffer
|
if ( (p_strm->nalu_type == H264_NALU_TYPE_SLICE)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_IDR)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_SPS)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_PPS)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_SUB_SPS)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_SEI)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_PREFIX)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_SLC_EXT)) {
|
|
RK_U32 head_size = MPP_MIN(HEAD_SYNTAX_MAX_SIZE, p_strm->nalu_len);
|
RK_U32 add_size = head_size + sizeof(H264dNaluHead_t);
|
|
if ((p_strm->head_offset + add_size) >= p_strm->head_max_size) {
|
FUN_CHECK(ret = realloc_buffer(&p_strm->head_buf, &p_strm->head_max_size, add_size));
|
}
|
p_des = &p_strm->head_buf[p_strm->head_offset];
|
((H264dNaluHead_t *)p_des)->is_frame_end = 0;
|
((H264dNaluHead_t *)p_des)->nalu_type = p_strm->nalu_type;
|
((H264dNaluHead_t *)p_des)->sodb_len = head_size;
|
memcpy(p_des + sizeof(H264dNaluHead_t), p_strm->nalu_buf, head_size);
|
p_strm->head_offset += add_size;
|
} //!< fill sodb buffer
|
if ((p_strm->nalu_type == H264_NALU_TYPE_SLICE)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_IDR)) {
|
|
RK_U32 add_size = p_strm->nalu_len + sizeof(g_start_precode);
|
|
if ((dxva_ctx->strm_offset + add_size) >= dxva_ctx->max_strm_size) {
|
FUN_CHECK(ret = realloc_buffer(&dxva_ctx->bitstream, &dxva_ctx->max_strm_size, add_size));
|
}
|
|
p_des = &dxva_ctx->bitstream[dxva_ctx->strm_offset];
|
memcpy(p_des, g_start_precode, sizeof(g_start_precode));
|
memcpy(p_des + sizeof(g_start_precode), p_strm->nalu_buf, p_strm->nalu_len);
|
dxva_ctx->strm_offset += add_size;
|
}
|
if (rkv_h264d_parse_debug & H264D_DBG_WRITE_ES_EN) {
|
H264dInputCtx_t *p_Inp = p_Cur->p_Inp;
|
if ((p_strm->nalu_type == H264_NALU_TYPE_SPS)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_PPS)) {
|
if (p_Inp->spspps_update_flag) {
|
p_des = &p_Inp->spspps_buf[p_Inp->spspps_offset];
|
memcpy(p_des, g_start_precode, sizeof(g_start_precode));
|
memcpy(p_des + sizeof(g_start_precode), p_strm->nalu_buf, p_strm->nalu_len);
|
p_Inp->spspps_offset += p_strm->nalu_len + sizeof(g_start_precode);
|
p_Inp->spspps_len = p_Inp->spspps_offset;
|
}
|
} else if ((p_strm->nalu_type == H264_NALU_TYPE_SLICE)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_IDR)) {
|
p_Cur->p_Inp->spspps_update_flag = 1;
|
p_Inp->spspps_offset = 0;
|
}
|
}
|
|
return ret = MPP_OK;
|
__FAILED:
|
return ret;
|
}
|
|
static MPP_RET judge_is_new_frame(H264dCurCtx_t *p_Cur, H264dCurStream_t *p_strm)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
RK_U32 nalu_header_bytes = 0;
|
|
BitReadCtx_t *p_bitctx = &p_Cur->bitctx;
|
memset(p_bitctx, 0, sizeof(BitReadCtx_t));
|
{
|
RK_U32 forbidden_bit = -1;
|
RK_U32 nal_reference_idc = -1;
|
mpp_set_bitread_ctx(p_bitctx, p_strm->nalu_buf, 4);
|
mpp_set_pre_detection(p_bitctx);
|
|
READ_BITS(p_bitctx, 1, &forbidden_bit);
|
ASSERT(forbidden_bit == 0);
|
READ_BITS(p_bitctx, 2, &nal_reference_idc);
|
READ_BITS(p_bitctx, 5, &p_strm->nalu_type);
|
|
nalu_header_bytes = 1;
|
if ((p_strm->nalu_type == H264_NALU_TYPE_PREFIX)
|
|| (p_strm->nalu_type == H264_NALU_TYPE_SLC_EXT)) {
|
if (p_strm->nalu_type == H264_NALU_TYPE_SLC_EXT) {
|
p_strm->nalu_type = H264_NALU_TYPE_SLICE;
|
}
|
nalu_header_bytes += 3;
|
}
|
}
|
if ((p_strm->nalu_len == 1)
|
&& (p_strm->nalu_type == H264_NALU_TYPE_SEI
|
|| p_strm->nalu_type == H264_NALU_TYPE_SPS
|
|| p_strm->nalu_type == H264_NALU_TYPE_PPS
|
|| p_strm->nalu_type == H264_NALU_TYPE_AUD
|
/*|| p_strm->nalu_type == H264_NALU_TYPE_PREFIX*/)) { // prefix may insert in slices of one frame
|
if (p_Cur->p_Dec->have_slice_data) {
|
p_Cur->p_Dec->is_new_frame = 1;
|
}
|
p_Cur->p_Dec->have_slice_data = 0;
|
} else if ((p_strm->nalu_len > 1)
|
&& (p_strm->nalu_type == H264_NALU_TYPE_SLICE
|
|| p_strm->nalu_type == H264_NALU_TYPE_IDR)) {
|
RK_U32 first_mb_in_slice = 0;
|
mpp_set_bitread_ctx(p_bitctx, (p_strm->nalu_buf + nalu_header_bytes), 4); // reset
|
mpp_set_pre_detection(p_bitctx);
|
READ_UE(p_bitctx, &first_mb_in_slice);
|
if (first_mb_in_slice == 0) {
|
p_Cur->last_dts = p_Cur->curr_dts;
|
p_Cur->last_pts = p_Cur->curr_pts;
|
p_Cur->curr_dts = p_Cur->p_Inp->in_dts;
|
p_Cur->curr_pts = p_Cur->p_Inp->in_pts;
|
if (p_Cur->p_Dec->have_slice_data) {
|
p_Cur->p_Dec->is_new_frame = 1;
|
}
|
p_Cur->p_Dec->have_slice_data = 1;
|
}
|
}
|
|
return ret = MPP_OK;
|
__BITREAD_ERR:
|
return ret = p_bitctx->ret;
|
}
|
|
#define MAX_ES_FILE_SIZE (100*1024*1024)
|
static RK_U32 global_file_fid = 0;
|
static RK_U64 global_flie_size = 0;
|
/*!
|
***********************************************************************
|
* \brief
|
* open stream file to store packet
|
***********************************************************************
|
*/
|
MPP_RET open_stream_file(H264dInputCtx_t *p_Inp, char *path)
|
{
|
if (rkv_h264d_parse_debug & H264D_DBG_WRITE_ES_EN) {
|
|
sprintf(p_Inp->fname[0], "%s/rkv_h264d_file_00.h264", path);
|
sprintf(p_Inp->fname[1], "%s/rkv_h264d_file_01.h264", path);
|
|
p_Inp->fp = fopen(p_Inp->fname[global_file_fid], "ab"); {
|
if (p_Inp->fp == NULL) {
|
H264D_WARNNING("[open_stream_file] can not open stream file, %s.", p_Inp->fname[global_file_fid]);
|
}
|
}
|
}
|
|
return MPP_OK;
|
}
|
/*!
|
***********************************************************************
|
* \brief
|
* write stream file
|
***********************************************************************
|
*/
|
MPP_RET fwrite_stream_to_file(H264dInputCtx_t *p_Inp, RK_U8 *pdata, RK_U32 len)
|
{
|
if (p_Inp->fp && (rkv_h264d_parse_debug & H264D_DBG_WRITE_ES_EN)) {
|
if (p_Inp->fp) {
|
fwrite(pdata, sizeof(RK_U8), len, p_Inp->fp);
|
fflush(p_Inp->fp);
|
}
|
global_flie_size += len;
|
if (global_flie_size > MAX_ES_FILE_SIZE) {
|
MPP_FCLOSE(p_Inp->fp);
|
global_file_fid = 1 - global_file_fid;
|
global_flie_size = 0;
|
p_Inp->fp = fopen(p_Inp->fname[global_file_fid], "wb");
|
if (p_Inp->fp == NULL) {
|
H264D_WARNNING("[open_stream_file] can not open stream file, %s", p_Inp->fname[global_file_fid]);
|
} else {
|
fwrite(p_Inp->spspps_buf, sizeof(RK_U8), p_Inp->spspps_len, p_Inp->fp);
|
fflush(p_Inp->fp);
|
}
|
}
|
}
|
|
return MPP_OK;
|
}
|
/*!
|
***********************************************************************
|
* \brief
|
* close stream file
|
***********************************************************************
|
*/
|
MPP_RET close_stream_file(H264dInputCtx_t *p_Inp)
|
{
|
if (rkv_h264d_parse_debug & H264D_DBG_WRITE_ES_EN) {
|
if (p_Inp->fp) {
|
fflush(p_Inp->fp);
|
MPP_FCLOSE(p_Inp->fp);
|
}
|
}
|
|
return MPP_OK;
|
}
|
/*!
|
***********************************************************************
|
* \brief
|
* prepare function for parser
|
***********************************************************************
|
*/
|
MPP_RET parse_prepare(H264dInputCtx_t *p_Inp, H264dCurCtx_t *p_Cur)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
|
H264_DecCtx_t *p_Dec = p_Inp->p_Dec;
|
H264dCurStream_t *p_strm = &p_Cur->strm;
|
MppPacketImpl *pkt_impl = (MppPacketImpl *)p_Inp->in_pkt;
|
|
p_Dec->nalu_ret = NALU_NULL;
|
p_Inp->task_valid = 0;
|
|
//!< check eos
|
if (p_Inp->pkt_eos && !p_Inp->in_length) {
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Dec->dxva_ctx));
|
FUN_CHECK(ret = add_empty_nalu(p_strm));
|
p_Dec->p_Inp->task_valid = 1;
|
p_Dec->p_Inp->task_eos = 1;
|
H264D_LOG("----- end of stream ----");
|
goto __RETURN;
|
}
|
//!< check input
|
if (!p_Inp->in_length) {
|
p_Dec->nalu_ret = HaveNoStream;
|
goto __RETURN;
|
}
|
|
while (pkt_impl->length > 0) {
|
p_strm->curdata = &p_Inp->in_buf[p_strm->nalu_offset++];
|
pkt_impl->length--;
|
p_strm->prefixdata = (p_strm->prefixdata << 8) | (*p_strm->curdata);
|
if (p_strm->startcode_found) {
|
if (p_strm->nalu_len >= p_strm->nalu_max_size) {
|
FUN_CHECK(ret = realloc_buffer(&p_strm->nalu_buf, &p_strm->nalu_max_size, NALU_BUF_ADD_SIZE));
|
}
|
p_strm->nalu_buf[p_strm->nalu_len++] = *p_strm->curdata;
|
if ((p_strm->nalu_len == NALU_TYPE_NORMAL_LENGTH)
|
|| (p_strm->nalu_len == NALU_TYPE_EXT_LENGTH)) {
|
FUN_CHECK(ret = judge_is_new_frame(p_Cur, p_strm));
|
if (p_Cur->p_Dec->is_new_frame) {
|
FUN_CHECK(ret = add_empty_nalu(p_strm));
|
p_strm->head_offset = 0;
|
p_Cur->p_Inp->task_valid = 1;
|
p_Cur->p_Dec->is_new_frame = 0;
|
break;
|
}
|
}
|
}
|
|
find_prefix_code(p_strm->curdata, p_strm);
|
|
if (p_strm->endcode_found) {
|
p_strm->nalu_len -= START_PREFIX_3BYTE;
|
if (p_strm->nalu_len > START_PREFIX_3BYTE) {
|
while ((p_strm->nalu_len > 0) &&
|
(p_strm->nalu_buf[p_strm->nalu_len - 1] == 0x00)) {
|
p_strm->nalu_len--;
|
}
|
}
|
p_Dec->nalu_ret = EndOfNalu;
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Dec->dxva_ctx));
|
reset_nalu(p_strm);
|
break;
|
}
|
}
|
p_Inp->in_length = pkt_impl->length;
|
//!< check input
|
if (!p_Inp->in_length) {
|
p_strm->nalu_offset = 0;
|
p_Dec->nalu_ret = HaveNoStream;
|
}
|
|
if (p_Inp->pkt_eos) {
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Dec->dxva_ctx));
|
FUN_CHECK(ret = add_empty_nalu(p_strm));
|
p_Dec->p_Inp->task_valid = 1;
|
p_Dec->p_Inp->task_eos = 1;
|
}
|
|
__RETURN:
|
|
return ret = MPP_OK;
|
__FAILED:
|
return ret;
|
}
|
|
/*!
|
***********************************************************************
|
* \brief
|
* prepare function for parser
|
***********************************************************************
|
*/
|
MPP_RET parse_prepare_fast(H264dInputCtx_t *p_Inp, H264dCurCtx_t *p_Cur)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
|
H264_DecCtx_t *p_Dec = p_Inp->p_Dec;
|
H264dCurStream_t *p_strm = &p_Cur->strm;
|
MppPacketImpl *pkt_impl = (MppPacketImpl *)p_Inp->in_pkt;
|
|
p_Dec->nalu_ret = NALU_NULL;
|
p_Inp->task_valid = 0;
|
|
while (pkt_impl->length > 0) {
|
p_strm->curdata = &p_Inp->in_buf[p_strm->nalu_offset++];
|
pkt_impl->length--;
|
p_strm->prefixdata = (p_strm->prefixdata << 8) | (*p_strm->curdata);
|
if (p_strm->startcode_found) {
|
if (p_strm->nalu_len >= p_strm->nalu_max_size) {
|
FUN_CHECK(ret = realloc_buffer(&p_strm->nalu_buf, &p_strm->nalu_max_size, NALU_BUF_ADD_SIZE));
|
}
|
p_strm->nalu_buf[p_strm->nalu_len++] = *p_strm->curdata;
|
if (p_strm->nalu_len == 1) {
|
p_strm->nalu_type = p_strm->nalu_buf[0] & 0x1F;
|
|
if (p_strm->nalu_type == H264_NALU_TYPE_SLICE
|
|| p_strm->nalu_type == H264_NALU_TYPE_IDR || p_strm->nalu_type == H264_NALU_TYPE_SLC_EXT) {
|
p_strm->nalu_len += (RK_U32)pkt_impl->length;
|
if (p_strm->nalu_len >= p_strm->nalu_max_size) {
|
RK_U32 add_size = pkt_impl->length + 1 - p_strm->nalu_max_size;
|
FUN_CHECK(ret = realloc_buffer(&p_strm->nalu_buf, &p_strm->nalu_max_size, MPP_MAX(NALU_BUF_ADD_SIZE, add_size)));
|
}
|
memcpy(&p_strm->nalu_buf[0], p_strm->curdata, pkt_impl->length + 1);
|
pkt_impl->length = 0;
|
p_Cur->p_Inp->task_valid = 1;
|
break;
|
}
|
}
|
}
|
|
find_prefix_code(p_strm->curdata, p_strm);
|
|
if (p_strm->endcode_found) {
|
p_strm->nalu_len -= START_PREFIX_3BYTE;
|
while (p_strm->nalu_len > 0 && p_strm->nalu_buf[p_strm->nalu_len - 1] == 0x00) {
|
p_strm->nalu_len--;
|
}
|
p_Dec->nalu_ret = EndOfNalu;
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Dec->dxva_ctx));
|
reset_nalu(p_strm);
|
break;
|
}
|
}
|
if (p_Cur->p_Inp->task_valid) {
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Dec->dxva_ctx));
|
FUN_CHECK(ret = add_empty_nalu(p_strm));
|
p_strm->head_offset = 0;
|
p_Cur->last_dts = p_Cur->p_Inp->in_dts;
|
p_Cur->last_pts = p_Cur->p_Inp->in_pts;
|
}
|
p_Inp->in_length = pkt_impl->length;
|
//!< check input
|
if (!p_Inp->in_length) {
|
if (!p_Cur->p_Inp->task_valid) {
|
p_Dec->nalu_ret = EndOfNalu;
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Dec->dxva_ctx));
|
} else {
|
p_Dec->nalu_ret = HaveNoStream;
|
}
|
p_strm->nalu_offset = 0;
|
p_strm->endcode_found = 1;
|
|
reset_nalu(p_strm);
|
p_strm->startcode_found = 0;
|
}
|
|
return ret = MPP_OK;
|
__FAILED:
|
return ret;
|
}
|
/*!
|
***********************************************************************
|
* \brief
|
* main function for parser avcC header
|
***********************************************************************
|
*/
|
MPP_RET parse_prepare_avcC_header(H264dInputCtx_t *p_Inp, H264dCurCtx_t *p_Cur)
|
{
|
RK_S32 i = 0;
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
|
H264dCurStream_t *p_strm = &p_Cur->strm;
|
RK_U8 *pdata = p_Inp->in_buf;
|
RK_U64 extrasize = p_Inp->in_length;
|
MppPacketImpl *pkt_impl = (MppPacketImpl *)p_Inp->in_pkt;
|
|
//!< free nalu_buffer
|
MPP_FREE(p_strm->nalu_buf);
|
if (p_Inp->in_length < 7) {
|
H264D_ERR("avcC too short, len=%d \n", p_Inp->in_length);
|
goto __FAILED;
|
}
|
if (pdata[0] != 1) {
|
goto __FAILED;
|
}
|
p_Inp->profile = pdata[1];
|
p_Inp->level = pdata[3];
|
p_Inp->nal_size = 1 + (pdata[4] & 3);
|
p_Inp->sps_num = pdata[5] & 31;
|
|
pdata += 6;
|
extrasize -= 6;
|
for (i = 0; i < p_Inp->sps_num; ++i) {
|
p_strm->nalu_len = U16_AT(pdata);
|
pdata += 2;
|
extrasize -= 2;
|
p_strm->nalu_type = H264_NALU_TYPE_SPS;
|
p_strm->nalu_buf = pdata;
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Cur->p_Dec->dxva_ctx));
|
pdata += p_strm->nalu_len;
|
extrasize -= p_strm->nalu_len;
|
}
|
p_strm->nalu_buf = NULL;
|
p_Inp->pps_num = *pdata;
|
++pdata;
|
--extrasize;
|
for (i = 0; i < p_Inp->pps_num; ++i) {
|
p_strm->nalu_len = U16_AT(pdata);
|
pdata += 2;
|
extrasize -= 2;
|
p_strm->nalu_type = H264_NALU_TYPE_PPS;
|
p_strm->nalu_buf = pdata;
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Cur->p_Dec->dxva_ctx));
|
pdata += p_strm->nalu_len;
|
extrasize -= p_strm->nalu_len;
|
}
|
pkt_impl->length = 0;
|
p_strm->nalu_buf = NULL;
|
p_strm->startcode_found = 1;
|
|
ret = MPP_OK;
|
__FAILED:
|
return ret;
|
}
|
/*!
|
***********************************************************************
|
* \brief
|
* main function for parser avcC data
|
***********************************************************************
|
*/
|
MPP_RET parse_prepare_avcC_data(H264dInputCtx_t *p_Inp, H264dCurCtx_t *p_Cur)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
|
H264dCurStream_t *p_strm = &p_Cur->strm;
|
MppPacketImpl *pkt_impl = (MppPacketImpl *)p_Inp->in_pkt;
|
|
p_strm->nalu_buf = NULL;
|
p_Inp->task_valid = 0;
|
if (p_Inp->pkt_eos) {
|
p_Inp->task_eos = 1;
|
p_Inp->task_valid = 1;
|
return MPP_OK;
|
}
|
VAL_CHECK(ret, (p_Inp->nal_size > 0));
|
p_strm->curdata = &p_Inp->in_buf[p_strm->nalu_offset];
|
while (p_Inp->in_length > 0) {
|
if (p_strm->startcode_found) {
|
p_strm->nalu_len = parse_nal_size(p_Inp->nal_size, p_strm->curdata);
|
if (p_strm->nalu_len <= 0 || p_strm->nalu_len >= p_Inp->in_length) {
|
p_Cur->p_Dec->is_new_frame = 1;
|
p_Cur->p_Dec->have_slice_data = 0;
|
pkt_impl->length = 0;
|
p_Inp->in_length = 0;
|
p_strm->nalu_len = 0;
|
p_strm->nalu_offset = 0;
|
p_strm->startcode_found = 1;
|
p_strm->endcode_found = 0;
|
p_strm->nalu_buf = NULL;
|
goto __FAILED;
|
}
|
|
p_strm->nalu_buf = p_strm->curdata + p_Inp->nal_size;
|
judge_is_new_frame(p_Cur, p_strm);
|
if (p_Cur->p_Dec->is_new_frame) {
|
p_Cur->p_Dec->have_slice_data = 0;
|
p_strm->startcode_found = 1;
|
p_strm->endcode_found = 0;
|
break;
|
}
|
|
p_strm->curdata += p_Inp->nal_size;
|
p_strm->nalu_offset += p_Inp->nal_size;
|
pkt_impl->length -= p_Inp->nal_size;
|
p_Inp->in_length -= p_Inp->nal_size;
|
|
p_strm->nalu_buf = p_strm->curdata;
|
p_strm->nalu_type = p_strm->nalu_buf[0] & 0x1F;
|
p_strm->startcode_found = 0;
|
p_strm->endcode_found = 1;
|
|
FUN_CHECK(ret = store_cur_nalu(p_Cur, p_strm, p_Cur->p_Dec->dxva_ctx));
|
p_strm->curdata += p_strm->nalu_len;
|
p_strm->nalu_offset += p_strm->nalu_len;
|
pkt_impl->length -= p_strm->nalu_len;
|
p_Inp->in_length -= p_strm->nalu_len;
|
p_strm->startcode_found = 1;
|
p_strm->endcode_found = 0;
|
p_strm->nalu_len = 0;
|
}
|
|
if (p_Inp->in_length < p_Inp->nal_size) {
|
p_Cur->p_Dec->is_new_frame = 1;
|
p_Cur->p_Dec->have_slice_data = 0;
|
pkt_impl->length = 0;
|
p_Inp->in_length = 0;
|
p_strm->nalu_len = 0;
|
p_strm->nalu_offset = 0;
|
p_strm->startcode_found = 1;
|
p_strm->endcode_found = 0;
|
p_strm->nalu_buf = NULL;
|
break;
|
}
|
}
|
//!< one frame end
|
if (p_Cur->p_Dec->is_new_frame) {
|
//!< add an empty nalu to tell frame end
|
FUN_CHECK(ret = add_empty_nalu(p_strm));
|
//!< reset curstream parameters
|
p_strm->head_offset = 0;
|
p_Cur->p_Inp->task_valid = 1;
|
p_Cur->p_Dec->is_new_frame = 0;
|
|
p_Cur->last_dts = p_Inp->in_dts;
|
p_Cur->last_pts = p_Inp->in_pts;
|
}
|
p_strm->nalu_buf = NULL;
|
ret = MPP_OK;
|
__FAILED:
|
//p_strm->nalu_len = 0;
|
p_Cur->last_dts = p_Inp->in_dts;
|
p_Cur->last_pts = p_Inp->in_pts;
|
p_Inp->p_Dec->nalu_ret = HaveNoStream;
|
|
return ret;
|
}
|
|
|
|
/*!
|
***********************************************************************
|
* \brief
|
* main function for parser
|
***********************************************************************
|
*/
|
MPP_RET parse_loop(H264_DecCtx_t *p_Dec)
|
{
|
MPP_RET ret = MPP_ERR_UNKNOW;
|
RK_U8 *p_curdata = NULL;
|
RK_U8 while_loop_flag = 1;
|
H264dNaluHead_t *p_head = NULL;
|
|
INP_CHECK(ret, !p_Dec);
|
//!< ==== loop ====
|
p_Dec->next_state = SliceSTATE_ResetSlice;
|
p_curdata = p_Dec->p_Cur->strm.head_buf;
|
|
while (while_loop_flag) {
|
switch (p_Dec->next_state) {
|
case SliceSTATE_ResetSlice:
|
reset_slice(p_Dec->p_Vid);
|
p_Dec->next_state = SliceSTATE_ReadNalu;
|
H264D_DBG(H264D_DBG_LOOP_STATE, "SliceSTATE_ResetSlice");
|
break;
|
case SliceSTATE_ReadNalu:
|
p_head = (H264dNaluHead_t *)p_curdata;
|
if (p_head->is_frame_end) {
|
p_Dec->next_state = SliceSTATE_RegisterOneFrame;
|
p_Dec->nalu_ret = HaveNoStream;
|
} else {
|
p_curdata += sizeof(H264dNaluHead_t);
|
memset(&p_Dec->p_Cur->nalu, 0, sizeof(H264_Nalu_t));
|
p_Dec->p_Cur->nalu.sodb_buf = p_curdata;
|
p_Dec->p_Cur->nalu.sodb_len = p_head->sodb_len;
|
p_curdata += p_head->sodb_len;
|
p_Dec->nalu_ret = EndOfNalu;
|
p_Dec->next_state = SliceSTATE_ParseNalu;
|
}
|
H264D_DBG(H264D_DBG_LOOP_STATE, "SliceSTATE_ReadNalu");
|
break;
|
case SliceSTATE_ParseNalu:
|
FUN_CHECK(ret = parser_one_nalu(&p_Dec->p_Cur->slice));
|
if (p_Dec->nalu_ret == StartOfSlice) {
|
p_Dec->next_state = SliceSTATE_GetSliceData;
|
} else if (p_Dec->nalu_ret == StartOfPicture) {
|
p_Dec->next_state = SliceSTATE_InitPicture;
|
} else if (p_Dec->nalu_ret == MvcDisAble) {
|
H264D_LOG("xxxxxxxx MVC disable");
|
goto __FAILED;
|
} else {
|
p_Dec->next_state = SliceSTATE_ReadNalu;
|
}
|
H264D_DBG(H264D_DBG_LOOP_STATE, "SliceSTATE_ParseNalu");
|
break;
|
case SliceSTATE_InitPicture:
|
if (!p_Dec->p_Vid->iNumOfSlicesDecoded) {
|
FUN_CHECK(ret = init_picture(&p_Dec->p_Cur->slice));
|
p_Dec->is_parser_end = 1;
|
}
|
p_Dec->next_state = SliceSTATE_GetSliceData;
|
H264D_DBG(H264D_DBG_LOOP_STATE, "SliceSTATE_InitPicture");
|
break;
|
case SliceSTATE_GetSliceData:
|
FUN_CHECK(ret = fill_slice_syntax(&p_Dec->p_Cur->slice, p_Dec->dxva_ctx));
|
p_Dec->p_Vid->iNumOfSlicesDecoded++;
|
if (p_Dec->is_parser_end) {
|
p_Dec->next_state = SliceSTATE_RegisterOneFrame;
|
} else {
|
p_Dec->next_state = SliceSTATE_ResetSlice;
|
}
|
H264D_DBG(H264D_DBG_LOOP_STATE, "SliceSTATE_GetSliceData");
|
break;
|
case SliceSTATE_RegisterOneFrame:
|
if (!p_Dec->is_parser_end) {
|
ret = MPP_NOK;
|
goto __FAILED;
|
}
|
commit_buffer(p_Dec->dxva_ctx);
|
while_loop_flag = 0;
|
p_Dec->next_state = SliceSTATE_ReadNalu;
|
H264D_DBG(H264D_DBG_LOOP_STATE, "SliceSTATE_RegisterOneFrame");
|
break;
|
default:
|
ret = MPP_NOK;
|
break;
|
}
|
}
|
|
__RETURN:
|
return ret = MPP_OK;
|
__FAILED:
|
p_Dec->nalu_ret = NALU_NULL;
|
p_Dec->dxva_ctx->slice_count = 0;
|
p_Dec->dxva_ctx->strm_offset = 0;
|
p_Dec->p_Vid->iNumOfSlicesDecoded = 0;
|
p_Dec->p_Vid->exit_picture_flag = 0;
|
|
return ret;
|
}
|