/*
|
*
|
* 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.
|
*/
|
|
/*
|
* @file h265_refs.c
|
* @brief
|
* @author csy(csy@rock-chips.com)
|
|
* @version 1.0.0
|
* @history
|
* 2015.7.15 : Create
|
*/
|
|
#define MODULE_TAG "H265_PARSER_REF"
|
|
#include "mpp_compat_impl.h"
|
|
#include "h265d_parser.h"
|
|
#define HEVC_ALIGN(value, x) ((value + (x-1)) & (~(x-1)))
|
|
void mpp_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
|
{
|
/* frame->frame can be NULL if context init failed */
|
if (!frame->frame || (frame->slot_index == 0xff))
|
return;
|
|
frame->flags &= ~flags;
|
if (!frame->flags) {
|
frame->refPicList = NULL;
|
frame->collocated_ref = NULL;
|
if (frame->slot_index <= 0x7f) {
|
h265d_dbg(H265D_DBG_REF, "poc %d clr ref index %d", frame->poc, frame->slot_index);
|
mpp_buf_slot_clr_flag(s->slots, frame->slot_index, SLOT_CODEC_USE);
|
}
|
h265d_dbg(H265D_DBG_REF, "unref_frame poc %d frame->slot_index %d \n", frame->poc, frame->slot_index);
|
frame->poc = INT_MAX;
|
frame->slot_index = 0xff;
|
frame->error_flag = 0;
|
}
|
}
|
|
|
void mpp_hevc_clear_refs(HEVCContext *s)
|
{
|
RK_U32 i;
|
for (i = 0; i < MPP_ARRAY_ELEMS(s->DPB); i++) {
|
mpp_hevc_unref_frame(s, &s->DPB[i],
|
HEVC_FRAME_FLAG_SHORT_REF |
|
HEVC_FRAME_FLAG_LONG_REF);
|
}
|
}
|
|
void mpp_hevc_flush_dpb(HEVCContext *s)
|
{
|
RK_U32 i;
|
for (i = 0; i < MPP_ARRAY_ELEMS(s->DPB); i++) {
|
mpp_hevc_unref_frame(s, &s->DPB[i], ~0);
|
}
|
}
|
|
static RK_U32 hor_align_64(RK_U32 val)
|
{
|
return MPP_ALIGN(val, 64);
|
}
|
|
static HEVCFrame *alloc_frame(HEVCContext *s)
|
{
|
RK_U32 i;
|
MPP_RET ret = MPP_OK;
|
for (i = 0; i < MPP_ARRAY_ELEMS(s->DPB); i++) {
|
HEVCFrame *frame = &s->DPB[i];
|
if (frame->slot_index != 0xff) {
|
continue;
|
}
|
|
h265d_dbg(H265D_DBG_GLOBAL, "width = %d height = %d", s->h265dctx->width, s->h265dctx->height);
|
mpp_frame_set_width(frame->frame, s->h265dctx->width);
|
mpp_frame_set_height(frame->frame, s->h265dctx->height);
|
mpp_frame_set_hor_stride(frame->frame,
|
(MPP_ALIGN(s->h265dctx->coded_width, 64) * s->h265dctx->nBitDepth) >> 3);
|
mpp_frame_set_ver_stride(frame->frame, s->h265dctx->coded_height);
|
mpp_frame_set_fmt(frame->frame, s->h265dctx->pix_fmt);
|
|
if (MPP_FRAME_FMT_IS_FBC(s->h265dctx->pix_fmt)) {
|
mpp_slots_set_prop(s->slots, SLOTS_HOR_ALIGN, hor_align_64);
|
mpp_frame_set_offset_x(frame->frame, 0);
|
mpp_frame_set_offset_y(frame->frame, 4);
|
|
if (*compat_ext_fbc_buf_size)
|
mpp_frame_set_ver_stride(frame->frame, s->h265dctx->coded_height + 16);
|
|
mpp_frame_set_fbc_hdr_stride(frame->frame, MPP_ALIGN(s->h265dctx->width, 64));
|
}
|
|
mpp_frame_set_errinfo(frame->frame, 0);
|
mpp_frame_set_pts(frame->frame, s->pts);
|
mpp_frame_set_poc(frame->frame, s->poc);
|
mpp_frame_set_color_range(frame->frame, s->h265dctx->color_range);
|
mpp_frame_set_color_primaries(frame->frame, s->sps->vui.colour_primaries);
|
mpp_frame_set_color_trc(frame->frame, s->sps->vui.transfer_characteristic);
|
mpp_frame_set_colorspace(frame->frame, s->h265dctx->colorspace);
|
mpp_frame_set_mastering_display(frame->frame, s->mastering_display);
|
mpp_frame_set_content_light(frame->frame, s->content_light);
|
h265d_dbg(H265D_DBG_GLOBAL, "w_stride %d h_stride %d\n", s->h265dctx->coded_width, s->h265dctx->coded_height);
|
ret = mpp_buf_slot_get_unused(s->slots, &frame->slot_index);
|
mpp_assert(ret == MPP_OK);
|
return frame;
|
}
|
mpp_err( "Error allocating frame, DPB full.\n");
|
return NULL;
|
}
|
|
int mpp_hevc_set_new_ref(HEVCContext *s, MppFrame *mframe, int poc)
|
{
|
|
HEVCFrame *ref = NULL;
|
RK_U32 i;
|
|
/* check that this POC doesn't already exist */
|
for (i = 0; i < MPP_ARRAY_ELEMS(s->DPB); i++) {
|
HEVCFrame *frame = &s->DPB[i];
|
|
if ((frame->slot_index != 0xff) && frame->sequence == s->seq_decode &&
|
frame->poc == poc && !s->nuh_layer_id) {
|
mpp_err( "Duplicate POC in a sequence: %d.\n",
|
poc);
|
return MPP_ERR_STREAM;
|
}
|
}
|
|
ref = alloc_frame(s);
|
if (!ref) {
|
mpp_err( "alloc_frame error\n");
|
return MPP_ERR_NOMEM;
|
}
|
|
*mframe = ref->frame;
|
s->ref = ref;
|
ref->poc = poc;
|
h265d_dbg(H265D_DBG_REF, "alloc frame poc %d slot_index %d", poc, ref->slot_index);
|
ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF;
|
mpp_buf_slot_set_flag(s->slots, ref->slot_index, SLOT_CODEC_USE);
|
mpp_buf_slot_set_flag(s->slots, ref->slot_index, SLOT_HAL_OUTPUT);
|
s->task->output = ref->slot_index;
|
|
ref->sequence = s->seq_decode;
|
ref->window = s->sps->output_window;
|
return 0;
|
}
|
|
static HEVCFrame *find_ref_idx(HEVCContext *s, int poc)
|
{
|
RK_U32 i;
|
RK_S32 LtMask = (1 << s->sps->log2_max_poc_lsb) - 1;
|
|
for (i = 0; i < MPP_ARRAY_ELEMS(s->DPB); i++) {
|
HEVCFrame *ref = &s->DPB[i];
|
if ((ref->slot_index != 0xff) && (ref->sequence == s->seq_decode)) {
|
if ((ref->poc & LtMask) == poc)
|
return ref;
|
}
|
}
|
|
for (i = 0; i < MPP_ARRAY_ELEMS(s->DPB); i++) {
|
HEVCFrame *ref = &s->DPB[i];
|
if ((ref->slot_index != 0xff) && ref->sequence == s->seq_decode) {
|
if (ref->poc == poc || (ref->poc & LtMask) == poc)
|
return ref;
|
}
|
}
|
mpp_err("Could not find ref with POC %d\n", poc);
|
return NULL;
|
}
|
|
|
|
static void mark_ref(HEVCFrame *frame, int flag)
|
{
|
frame->flags &= ~(HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF);
|
frame->flags |= flag;
|
}
|
|
static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc)
|
{
|
HEVCFrame *frame;
|
h265d_dbg(H265D_DBG_REF, "generate_missing_ref in \n");
|
frame = alloc_frame(s);
|
if (!frame)
|
return NULL;
|
frame->poc = poc;
|
|
mpp_frame_set_errinfo(frame->frame, 1);
|
mpp_buf_slot_set_prop(s->slots, frame->slot_index, SLOT_FRAME, frame->frame);
|
mpp_buf_slot_set_flag(s->slots, frame->slot_index, SLOT_CODEC_READY);
|
mpp_buf_slot_set_flag(s->slots, frame->slot_index, SLOT_CODEC_USE);
|
h265d_dbg(H265D_DBG_REF, "generate_missing_ref frame poc %d slot_index %d", poc, frame->slot_index);
|
frame->sequence = s->seq_decode;
|
frame->flags = 0;
|
return frame;
|
}
|
|
/* add a reference with the given poc to the list and mark it as used in DPB */
|
static int add_candidate_ref(HEVCContext *s, RefPicList *list,
|
int poc, int ref_flag)
|
{
|
HEVCFrame *ref = find_ref_idx(s, poc);
|
|
if (!ref) {
|
ref = generate_missing_ref(s, poc);
|
if (!ref)
|
return MPP_ERR_NOMEM;
|
ref->error_flag = 1;
|
}
|
|
list->list[list->nb_refs] = ref->poc;
|
list->ref[list->nb_refs] = ref;
|
list->nb_refs++;
|
if (ref_flag) {
|
h265d_dbg(H265D_DBG_REF, "set ref poc = %d ref->slot_index %d", ref->poc, ref->slot_index);
|
mpp_buf_slot_set_flag(s->slots, ref->slot_index, SLOT_CODEC_USE);
|
}
|
mark_ref(ref, ref_flag);
|
if (ref->error_flag) {
|
s->miss_ref_flag = 1;
|
}
|
return 0;
|
}
|
|
RK_S32 mpp_hevc_frame_rps(HEVCContext *s)
|
{
|
|
const ShortTermRPS *short_rps = s->sh.short_term_rps;
|
const LongTermRPS *long_rps = &s->sh.long_term_rps;
|
RefPicList *rps = s->rps;
|
RK_S32 ret;
|
RK_U32 i;
|
|
if (!short_rps) {
|
rps[0].nb_refs = rps[1].nb_refs = 0;
|
return 0;
|
}
|
|
/* clear the reference flags on all frames except the current one */
|
for (i = 0; i < MPP_ARRAY_ELEMS(s->DPB); i++) {
|
HEVCFrame *frame = &s->DPB[i];
|
mark_ref(frame, 0);
|
}
|
|
for (i = 0; i < NB_RPS_TYPE; i++)
|
rps[i].nb_refs = 0;
|
|
/* add the short refs */
|
for (i = 0; short_rps && (RK_S32)i < short_rps->num_delta_pocs; i++) {
|
int poc = s->poc + short_rps->delta_poc[i];
|
int list;
|
|
if (!short_rps->used[i])
|
list = ST_FOLL;
|
else if (i < short_rps->num_negative_pics)
|
list = ST_CURR_BEF;
|
else
|
list = ST_CURR_AFT;
|
|
ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_SHORT_REF);
|
if (ret < 0)
|
return ret;
|
}
|
|
/* add the long refs */
|
for (i = 0; long_rps && i < long_rps->nb_refs; i++) {
|
int poc = long_rps->poc[i];
|
int list = long_rps->used[i] ? LT_CURR : LT_FOLL;
|
|
ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_LONG_REF);
|
if (ret < 0)
|
return ret;
|
}
|
/* release any frames that are now unused */
|
for (i = 0; i < MPP_ARRAY_ELEMS(s->DPB); i++) {
|
mpp_hevc_unref_frame(s, &s->DPB[i], 0);
|
}
|
|
return 0;
|
}
|
|
int mpp_hevc_compute_poc(HEVCContext *s, int poc_lsb)
|
{
|
RK_S32 max_poc_lsb = 1 << s->sps->log2_max_poc_lsb;
|
RK_S32 prev_poc_lsb = s->pocTid0 % max_poc_lsb;
|
RK_S32 prev_poc_msb = s->pocTid0 - prev_poc_lsb;
|
RK_S32 poc_msb;
|
|
if (poc_lsb < prev_poc_lsb && prev_poc_lsb - poc_lsb >= max_poc_lsb / 2)
|
poc_msb = prev_poc_msb + max_poc_lsb;
|
else if (poc_lsb > prev_poc_lsb && poc_lsb - prev_poc_lsb > max_poc_lsb / 2)
|
poc_msb = prev_poc_msb - max_poc_lsb;
|
else
|
poc_msb = prev_poc_msb;
|
|
// For BLA picture types, POCmsb is set to 0.
|
if (s->nal_unit_type == NAL_BLA_W_LP ||
|
s->nal_unit_type == NAL_BLA_W_RADL ||
|
s->nal_unit_type == NAL_BLA_N_LP)
|
poc_msb = 0;
|
|
return poc_msb + poc_lsb;
|
}
|
|
int mpp_hevc_frame_nb_refs(HEVCContext *s)
|
{
|
RK_S32 ret = 0;
|
RK_S32 i;
|
const ShortTermRPS *rps = s->sh.short_term_rps;
|
LongTermRPS *long_rps = &s->sh.long_term_rps;
|
|
if (s->sh.slice_type == I_SLICE) {
|
return 0;
|
}
|
if (rps) {
|
for (i = 0; (RK_U32)i < rps->num_negative_pics; i++)
|
ret += !!rps->used[i];
|
for (; i < rps->num_delta_pocs; i++)
|
ret += !!rps->used[i];
|
}
|
|
if (long_rps) {
|
for (i = 0; i < long_rps->nb_refs; i++)
|
ret += !!long_rps->used[i];
|
}
|
return ret;
|
}
|