2663 lines
101 KiB
C
Executable File
2663 lines
101 KiB
C
Executable File
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*
|
|
* This source code is subject to the terms and conditions defined in below
|
|
* which is part of this source code package.
|
|
*
|
|
* Description:
|
|
*/
|
|
|
|
// Copyright (C) 2019 Amlogic, Inc. All rights reserved.
|
|
//
|
|
// All information contained herein is Amlogic confidential.
|
|
//
|
|
// This software is provided to you pursuant to Software License
|
|
// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
|
|
// used only in accordance with the terms of this agreement.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification is strictly prohibited without prior written permission
|
|
// from Amlogic.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
// #define LOG_NDEBUG 0
|
|
#define LOG_TAG "AMLVENC_MULTI"
|
|
#ifdef MAKEANDROID
|
|
#include <utils/Log.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include "AML_MultiEncoder.h"
|
|
#include "vpuapi.h"
|
|
#include "vpuconfig.h"
|
|
#include "vdi_osal.h"
|
|
#include "debug.h"
|
|
#include "vpuapifunc.h"
|
|
#include <sys/time.h>
|
|
|
|
#ifndef min
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
#ifndef max
|
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#define ENCODE_TIME_STATISTICS 0
|
|
|
|
#if ENCODE_TIME_STATISTICS
|
|
static unsigned long encode_time_per_frame;
|
|
static unsigned long long total_encode_time;
|
|
static unsigned long long total_encode_frames;
|
|
static struct timeval start_test;
|
|
static struct timeval end_test;
|
|
#endif
|
|
|
|
#define SUPPORT_SCALE 1
|
|
|
|
#if SUPPORT_SCALE
|
|
#include <ge2d_port.h>
|
|
#include <aml_ge2d.h>
|
|
#endif
|
|
|
|
#define MULTI_ENC_MAGIC ('A' << 24| 'M' <<16 | 'L' << 8 |'G')
|
|
/* timeout in ms */
|
|
#define VPU_WAIT_TIME_OUT_CQ 100
|
|
/* extra source frame buffer required.*/
|
|
#define EXTRA_SRC_BUFFER_NUM 0
|
|
|
|
// user scaling list
|
|
#define SL_NUM_MATRIX (6)
|
|
|
|
#define vp_align4(a) ((((a)+3)>>2)<<2)
|
|
#define vp_align8(a) ((((a)+7)>>3)<<3)
|
|
#define vp_align16(a) ((((a)+15)>>4)<<4)
|
|
#define vp_align32(a) ((((a)+31)>>5)<<5)
|
|
#define vp_align64(a) ((((a)+63)>>6)<<6)
|
|
#define vp_align128(a) ((((a)+127)>>7)<<7)
|
|
#define vp_align256(a) ((((a)+255)>>8)<<8)
|
|
|
|
typedef union {
|
|
struct {
|
|
Uint32 ctu_force_mode : 2; //[ 1: 0]
|
|
Uint32 ctu_coeff_drop : 1; //[ 2]
|
|
Uint32 reserved : 5; //[ 7: 3]
|
|
Uint32 sub_ctu_qp_0 : 6; //[13: 8]
|
|
Uint32 sub_ctu_qp_1 : 6; //[19:14]
|
|
Uint32 sub_ctu_qp_2 : 6; //[25:20]
|
|
Uint32 sub_ctu_qp_3 : 6; //[31:26]
|
|
|
|
Uint32 lambda_sad_0 : 8; //[39:32]
|
|
Uint32 lambda_sad_1 : 8; //[47:40]
|
|
Uint32 lambda_sad_2 : 8; //[55:48]
|
|
Uint32 lambda_sad_3 : 8; //[63:56]
|
|
} field;
|
|
} EncCustomMap; // for vp5xx custom map (1 CTU = 64bits)
|
|
|
|
typedef union {
|
|
struct {
|
|
Uint8 mb_force_mode : 2; //[ 1: 0]
|
|
Uint8 mb_qp : 6; //[ 7: 2]
|
|
} field;
|
|
} AvcEncCustomMap; // for AVC custom map on vp (1 MB = 8bits)
|
|
|
|
typedef struct
|
|
{
|
|
Uint8 s4[SL_NUM_MATRIX][16]; // [INTRA_Y/U/V,INTER_Y/U/V][NUM_COEFF]
|
|
Uint8 s8[SL_NUM_MATRIX][64];
|
|
Uint8 s16[SL_NUM_MATRIX][64];
|
|
Uint8 s32[SL_NUM_MATRIX][64];
|
|
Uint8 s16dc[SL_NUM_MATRIX];
|
|
Uint8 s32dc[2];
|
|
}UserScalingList;
|
|
|
|
typedef struct
|
|
{
|
|
Uint32 CustMeanY;
|
|
Uint32 CustMeadCb;
|
|
Uint32 CustMeadCr;
|
|
Uint32 CustSigmaY;
|
|
Uint32 CustSigmaCb;
|
|
Uint32 CustSigmaCr;
|
|
} WeigtedPredInfo;
|
|
|
|
typedef enum {
|
|
ENC_INT_STATUS_NONE, // Interrupt not asserted yet
|
|
ENC_INT_STATUS_FULL, // Need more buffer
|
|
ENC_INT_STATUS_DONE, // Interrupt asserted
|
|
ENC_INT_STATUS_LOW_LATENCY,
|
|
ENC_INT_STATUS_TIMEOUT, // Interrupt not asserted during given time.
|
|
} ENC_INT_STATUS;
|
|
|
|
typedef enum {
|
|
ENCODER_STATE_OPEN,
|
|
ENCODER_STATE_INIT_SEQ,
|
|
ENCODER_STATE_REGISTER_FB,
|
|
ENCODER_STATE_ENCODE_HEADER,
|
|
ENCODER_STATE_ENCODING,
|
|
} EncoderState;
|
|
|
|
static CustomGopPicParam AML_svc1[2] = {
|
|
{PIC_TYPE_P, 1, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 2, 0, 1, 0,-1, 0},
|
|
};
|
|
|
|
static CustomGopPicParam AML_svc2[3] = {
|
|
{PIC_TYPE_P, 1, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 2, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 3, 0, 1, 0,-1, 0},
|
|
};
|
|
|
|
static CustomGopPicParam AML_svc3[4] = {
|
|
{PIC_TYPE_P, 1, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 2, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 3, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 4, 0, 1, 0,-1, 0},
|
|
};
|
|
|
|
static CustomGopPicParam AML_svc4[5] = {
|
|
{PIC_TYPE_P, 1, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 2, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 3, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 4, 1, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 5, 0, 1, 0,-1, 0},
|
|
};
|
|
|
|
static CustomGopPicParam AML_custp[2] = {
|
|
{PIC_TYPE_P, 1, 0, 2, 0,-1, 0},
|
|
{PIC_TYPE_P, 2, 0, 2, 1, 0, 0},
|
|
};
|
|
//hoan mdf ref
|
|
static CustomGopPicParam AML_custp_ref_one[1] =
|
|
{
|
|
{PIC_TYPE_P, 1, 0, 1, 0,-1, 0},
|
|
};
|
|
//end
|
|
|
|
|
|
//hoan add svc for tencent
|
|
static CustomGopPicParam AML_svc5[4] = {
|
|
{PIC_TYPE_P, 1, 0, 1, 0,-1, 2},//type, POC, Qp, num_ref_L0, Ref_L0_POC, Ref_L1_POC, temporalLayer
|
|
{PIC_TYPE_P, 2, 0, 1, 0,-1, 1},
|
|
{PIC_TYPE_P, 3, 0, 1, 2,-1, 2},
|
|
{PIC_TYPE_P, 4, 0, 1, 0,-1, 0},
|
|
};
|
|
//end
|
|
|
|
typedef struct AMVEncContext_s {
|
|
uint32 magic_num;
|
|
uint32 instance_id;
|
|
uint32 src_idx;
|
|
uint32 src_count;
|
|
uint32 enc_width;
|
|
uint32 temp_enc_width;
|
|
uint32 enc_height;
|
|
uint32 bitrate; /* target encoding bit rate in bits/second */
|
|
uint32 frame_rate; /* frame rate */
|
|
int32 idrPeriod; /* IDR period in number of frames */
|
|
uint32 op_flag;
|
|
uint32 averageQP;
|
|
|
|
uint32 src_num; /*total src_frame buffer needed */
|
|
uint32 fb_num; /* total reconstuction frame buffer encoder needed */
|
|
|
|
uint32 enc_counter;
|
|
uint frame_delay;
|
|
|
|
AMVEncFrameFmt fmt;
|
|
|
|
bool mPrependSPSPPSToIDRFrames;
|
|
uint32 initQP; /* initial QP */
|
|
//AVCNalUnitType nal_unit_type;
|
|
bool rcEnable; /* rate control enable, on: RC on, off: constant QP */
|
|
AMVEncInitParams mInitParams; //copy of initial set up from upper layer
|
|
/* VPU API interfaces */
|
|
EncHandle enchandle; /*VPU encoder handler */
|
|
EncOpenParam encOpenParam; /* api open param */
|
|
EncChangeParam changeParam;
|
|
Uint32 param_change_flag;
|
|
Uint32 frameIdx;
|
|
vpu_buffer_t vbCustomLambda;
|
|
vpu_buffer_t vbScalingList;
|
|
Uint32 customLambda[NUM_CUSTOM_LAMBDA];
|
|
UserScalingList scalingList;
|
|
vpu_buffer_t vbCustomMap[MAX_REG_FRAME];
|
|
EncoderState state;
|
|
EncInitialInfo initialInfo;
|
|
EncParam encParam;
|
|
Int32 encodedSrcFrmIdxArr[ENC_SRC_BUF_NUM];
|
|
Int32 encMEMSrcFrmIdxArr[ENC_SRC_BUF_NUM];
|
|
vpu_buffer_t bsBuffer[ENC_SRC_BUF_NUM];
|
|
BOOL fullInterrupt;
|
|
Uint32 changedCount;
|
|
Uint64 startTimeout;
|
|
Uint32 cyclePerTick;
|
|
|
|
|
|
Uint32 reconFbStride;
|
|
Uint32 reconFbHeight;
|
|
Uint32 srcFbStride;
|
|
Uint32 srcFbSize;
|
|
FrameBufferAllocInfo srcFbAllocInfo;
|
|
BOOL fbAllocated;
|
|
FrameBuffer pFbRecon[MAX_REG_FRAME];
|
|
vpu_buffer_t pFbReconMem[MAX_REG_FRAME];
|
|
FrameBuffer pFbSrc[ENC_SRC_BUF_NUM];
|
|
vpu_buffer_t pFbSrcMem[ENC_SRC_BUF_NUM];
|
|
AMVMultiEncFrameIO FrameIO[ENC_SRC_BUF_NUM];
|
|
|
|
|
|
|
|
vpu_buffer_t work_vb;
|
|
vpu_buffer_t temp_vb;
|
|
vpu_buffer_t fbc_ltable_vb;
|
|
vpu_buffer_t fbc_ctable_vb;
|
|
vpu_buffer_t fbc_mv_vb;
|
|
vpu_buffer_t subsample_vb;
|
|
|
|
uint32 debugEnable;
|
|
BOOL force_terminate;
|
|
unsigned long long mNumInputFrames;
|
|
AMVEncBufferType bufType;
|
|
uint32 mNumPlanes;
|
|
|
|
uint8 *CustomRoiMapBuf; // store the latest value
|
|
uint8 *CustomLambdaMapBuf;
|
|
uint8 *CustomModeMapBuf;
|
|
uint32 CustomMapSize; // this is the max value
|
|
uint32 CustomUpdateID; //store the update count
|
|
uint32 CustomMapUpdatedId[MAX_REG_FRAME]; // updated ID cnt
|
|
WeigtedPredInfo wp_para;
|
|
int pic_type;
|
|
#if SUPPORT_SCALE
|
|
uint32 ge2d_initial_done;
|
|
aml_ge2d_t amlge2d;
|
|
bool INIT_GE2D;
|
|
#endif
|
|
} AMVMultiCtx;
|
|
|
|
|
|
#if SUPPORT_SCALE
|
|
static int SRC1_PIXFORMAT = PIXEL_FORMAT_YCrCb_420_SP;
|
|
static int SRC2_PIXFORMAT = PIXEL_FORMAT_YCrCb_420_SP;
|
|
static int DST_PIXFORMAT = PIXEL_FORMAT_YCrCb_420_SP;
|
|
|
|
static GE2DOP OP = AML_GE2D_STRETCHBLIT;
|
|
|
|
static int do_strechblit(aml_ge2d_info_t* pge2dinfo, AMVMultiEncFrameIO* input) {
|
|
int ret = -1;
|
|
char code = 0;
|
|
VLOG(INFO, "do_strechblit test case:\n");
|
|
pge2dinfo->src_info[0].memtype = GE2D_CANVAS_ALLOC;
|
|
pge2dinfo->dst_info.memtype = GE2D_CANVAS_ALLOC;
|
|
pge2dinfo->src_info[0].canvas_w = input->pitch; // SX_SRC1;
|
|
pge2dinfo->src_info[0].canvas_h = input->height; // SY_SRC1;
|
|
pge2dinfo->src_info[0].format = SRC1_PIXFORMAT;
|
|
if ((input->scale_width != 0) && (input->scale_height != 0)) {
|
|
pge2dinfo->dst_info.canvas_w = input->scale_width; // SX_DST;
|
|
pge2dinfo->dst_info.canvas_h = input->scale_height; // SY_DST;
|
|
} else {
|
|
pge2dinfo->dst_info.canvas_w =
|
|
vp_align32(input->pitch) - input->crop_left - input->crop_right;
|
|
pge2dinfo->dst_info.canvas_h =
|
|
input->height - input->crop_top - input->crop_bottom;
|
|
}
|
|
pge2dinfo->dst_info.format = DST_PIXFORMAT;
|
|
|
|
pge2dinfo->src_info[0].rect.x = input->crop_left;
|
|
pge2dinfo->src_info[0].rect.y = input->crop_top;
|
|
pge2dinfo->src_info[0].rect.w =
|
|
input->pitch - input->crop_left - input->crop_right;
|
|
pge2dinfo->src_info[0].rect.h =
|
|
input->height - input->crop_top - input->crop_bottom;
|
|
pge2dinfo->dst_info.rect.x = 0;
|
|
pge2dinfo->dst_info.rect.y = 0;
|
|
if ((input->scale_width != 0) && (input->scale_height != 0)) {
|
|
pge2dinfo->dst_info.rect.w = input->scale_width; // SX_DST;
|
|
pge2dinfo->dst_info.rect.h = input->scale_height; // SY_DST;
|
|
} else {
|
|
pge2dinfo->dst_info.rect.w =
|
|
vp_align32(input->pitch) - input->crop_left - input->crop_right;
|
|
pge2dinfo->dst_info.rect.h =
|
|
input->height - input->crop_top - input->crop_bottom;
|
|
}
|
|
pge2dinfo->dst_info.rotation = GE2D_ROTATION_0;
|
|
ret = aml_ge2d_process(pge2dinfo);
|
|
return ret;
|
|
}
|
|
|
|
static void set_ge2dinfo(aml_ge2d_info_t* pge2dinfo,
|
|
AMVEncInitParams* encParam) {
|
|
pge2dinfo->src_info[0].memtype = GE2D_CANVAS_ALLOC;
|
|
pge2dinfo->src_info[0].canvas_w = encParam->src_width; // SX_SRC1;
|
|
pge2dinfo->src_info[0].canvas_h = encParam->src_height; // SY_SRC1;
|
|
pge2dinfo->src_info[0].format = SRC1_PIXFORMAT;
|
|
//pge2dinfo->src_info[0].plane_number = 1;
|
|
pge2dinfo->src_info[1].memtype = GE2D_CANVAS_TYPE_INVALID;
|
|
pge2dinfo->src_info[1].canvas_w = 0;
|
|
pge2dinfo->src_info[1].canvas_h = 0;
|
|
pge2dinfo->src_info[1].format = SRC2_PIXFORMAT;
|
|
//pge2dinfo->src_info[1].plane_number = 1;
|
|
pge2dinfo->dst_info.memtype = GE2D_CANVAS_ALLOC;
|
|
pge2dinfo->dst_info.canvas_w = vp_align32(encParam->width);//encParam->width; // SX_DST;
|
|
pge2dinfo->dst_info.canvas_h = encParam->height; // SY_DST;
|
|
pge2dinfo->dst_info.format = DST_PIXFORMAT;
|
|
pge2dinfo->dst_info.rotation = GE2D_ROTATION_0;
|
|
//pge2dinfo->dst_info.plane_number = 1;
|
|
pge2dinfo->offset = 0;
|
|
pge2dinfo->ge2d_op = OP;
|
|
pge2dinfo->blend_mode = BLEND_MODE_PREMULTIPLIED;
|
|
}
|
|
#endif
|
|
|
|
int64_t GetNowUs() {
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
return (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec;
|
|
}
|
|
|
|
void static yuv_plane_memcpy(int coreIdx, int dst, char *src, uint32 width,
|
|
uint32 height, uint32 stride, uint32 src_stride,
|
|
bool aligned, EndianMode endian) {
|
|
unsigned i;
|
|
if (dst == 0 || src == NULL) {
|
|
VLOG(ERR, "yuv_plane_memcpy error ptr\n");
|
|
return;
|
|
}
|
|
if (!aligned) {
|
|
for (i = 0; i < height; i++) {
|
|
vdi_write_memory(coreIdx, dst, (Uint8 *)src, width, endian);
|
|
dst += stride;
|
|
src += src_stride;
|
|
}
|
|
} else {
|
|
vdi_write_memory(coreIdx, dst, (Uint8 *)src, stride * height, endian);
|
|
}
|
|
}
|
|
|
|
static BOOL SetupEncoderOpenParam(EncOpenParam *pEncOP, AMVEncInitParams* InitParam)
|
|
{
|
|
int i;
|
|
CustomGopPicParam *GopParam = NULL;
|
|
EncVpParam *param = &pEncOP->EncStdParam.vpParam;
|
|
/*basic settings */
|
|
if (InitParam->stream_type == AMV_AVC)
|
|
pEncOP->bitstreamFormat = STD_AVC;
|
|
else if (InitParam->stream_type == AMV_HEVC)
|
|
pEncOP->bitstreamFormat = STD_HEVC;
|
|
else {
|
|
VLOG(ERR, "[ERROR] Not supported format (%d)\n", InitParam->stream_type);
|
|
return FALSE;
|
|
}
|
|
pEncOP->picWidth = InitParam->width;
|
|
pEncOP->picHeight = InitParam->height;
|
|
pEncOP->frameRateInfo = InitParam->frame_rate;
|
|
pEncOP->bitRate = InitParam->bitrate;
|
|
pEncOP->rcEnable = InitParam->rate_control;
|
|
/* default */
|
|
pEncOP->srcBitDepth = InitParam->srcBitDepth; /*pCfg->SrcBitDepth; */
|
|
param->level = 0;
|
|
param->tier = 0;
|
|
param->internalBitDepth = InitParam->internalBitDepth;; /*pCfg->vpCfg.internalBitDepth;*/
|
|
|
|
if ( param->internalBitDepth == 10 ) {
|
|
pEncOP->outputFormat = FORMAT_420_P10_16BIT_MSB;
|
|
if (pEncOP->bitstreamFormat == STD_HEVC) {
|
|
param->profile = HEVC_PROFILE_MAIN10;
|
|
} else {
|
|
param->profile = AVC_PROFILE_HIGH10;
|
|
}
|
|
} else if ( param->internalBitDepth == 8 ) {
|
|
pEncOP->outputFormat = FORMAT_420;
|
|
if (pEncOP->bitstreamFormat == STD_HEVC) {
|
|
param->profile = HEVC_PROFILE_MAIN;
|
|
} else {//AVC
|
|
if (InitParam->profile < AVC_PROFILE_HIGH10)
|
|
param->profile = InitParam->profile;
|
|
else
|
|
param->profile = 0;
|
|
}
|
|
}
|
|
param->losslessEnable = 0;
|
|
param->constIntraPredFlag = 0;
|
|
param->lfCrossSliceBoundaryEnable = 1;
|
|
param->useLongTerm = InitParam->longterm_ref_enable;
|
|
|
|
/* for CMD_ENC_SEQ_GOP_PARAM */
|
|
//param->gopPresetIdx = pCfg->vpCfg.gopPresetIdx;
|
|
if (InitParam->GopPreset == GOP_OPT_NONE)
|
|
{
|
|
if (InitParam->idr_period == 1)
|
|
param->gopPresetIdx = PRESET_IDX_ALL_I; //all I frame
|
|
else
|
|
param->gopPresetIdx = PRESET_IDX_IPP ;//PRESET_IDX_IPP PRESET_IDX_IPP_SINGLE
|
|
}
|
|
else if (InitParam->GopPreset == GOP_ALL_I)
|
|
{
|
|
param->gopPresetIdx = PRESET_IDX_ALL_I;
|
|
}
|
|
else if (InitParam->GopPreset == GOP_IP) {
|
|
param->gopPresetIdx = PRESET_IDX_IPP;//ori
|
|
|
|
}
|
|
else if (InitParam->GopPreset == GOP_IBBBP) {
|
|
param->gopPresetIdx = PRESET_IDX_IBBBP;
|
|
}
|
|
|
|
|
|
else if (InitParam->GopPreset == GOP_IP_CUSTP_REF_ONE)
|
|
{
|
|
param->gopPresetIdx = PRESET_IDX_IPP_SINGLE;//ori
|
|
VLOG(TRACE, "InitParam->GopPreset == GOP_IP_CUSTP_REF_ONE\n");
|
|
}
|
|
|
|
|
|
else if (InitParam->GopPreset == GOP_IP_SVC1) {
|
|
param->gopPresetIdx = PRESET_IDX_CUSTOM_GOP;
|
|
param->gopParam.customGopSize = 2;
|
|
GopParam = AML_svc1;
|
|
}
|
|
else if (InitParam->GopPreset == GOP_IP_SVC2) {
|
|
param->gopPresetIdx = PRESET_IDX_CUSTOM_GOP;
|
|
param->gopParam.customGopSize = 3;
|
|
GopParam = AML_svc2;
|
|
}
|
|
else if (InitParam->GopPreset == GOP_IP_SVC3) {
|
|
param->gopPresetIdx = PRESET_IDX_CUSTOM_GOP;
|
|
param->gopParam.customGopSize = 4;
|
|
GopParam = AML_svc3;
|
|
}
|
|
else if (InitParam->GopPreset == GOP_IP_SVC4) {
|
|
param->gopPresetIdx = PRESET_IDX_CUSTOM_GOP;
|
|
param->gopParam.customGopSize = 5;
|
|
GopParam = AML_svc4;
|
|
}
|
|
else if (InitParam->GopPreset == GOP_IP_CUSTP) {
|
|
param->gopPresetIdx = PRESET_IDX_CUSTOM_GOP;
|
|
param->gopParam.customGopSize = 2;
|
|
GopParam = AML_custp;
|
|
|
|
VLOG(TRACE, "InitParam->GopPreset == GOP_IP_CUSTP,param->gopParam.customGopSize %d\n",
|
|
param->gopParam.customGopSize);
|
|
}
|
|
//hoan add for tencent
|
|
else if (InitParam->GopPreset == GOP_IP_SVC5) {
|
|
param->gopPresetIdx = PRESET_IDX_CUSTOM_GOP;
|
|
param->gopParam.customGopSize = 4;
|
|
GopParam = AML_svc5;
|
|
VLOG(TRACE, "AML_svc5!!!!!!!!!!!\n");
|
|
}
|
|
//end
|
|
else {
|
|
VLOG(ERR, "[ERROR] Not supported GOP format (%d)\n", InitParam->GopPreset);
|
|
return FALSE;
|
|
}
|
|
/* for CMD_ENC_SEQ_INTRA_PARAM */
|
|
param->decodingRefreshType = 1; //pCfg->vpCfg.decodingRefreshType;
|
|
param->intraPeriod = InitParam->idr_period;//pCfg->vpCfg.intraPeriod;
|
|
if (InitParam->idr_period == 0) { // only one I then all P
|
|
param->gopPresetIdx = PRESET_IDX_IPP;
|
|
param->intraPeriod = 0;
|
|
} else if (InitParam ->idr_period == 1) {
|
|
param->gopPresetIdx = PRESET_IDX_ALL_I;
|
|
param->intraPeriod = InitParam ->idr_period;
|
|
} else
|
|
param->intraPeriod = InitParam ->idr_period;
|
|
|
|
VLOG(INFO, "GopPreset GOP format (%d) period %d LongTermRef %d\n",
|
|
param->gopPresetIdx, param->intraPeriod, param->useLongTerm);
|
|
|
|
param->intraQP = InitParam ->initQP; //pCfg->vpCfg.intraQP;
|
|
param->forcedIdrHeaderEnable = 0; //pCfg->vpCfg.forcedIdrHeaderEnable;
|
|
|
|
/* for CMD_ENC_SEQ_CONF_WIN_TOP_BOT/LEFT_RIGHT */
|
|
param->confWinTop = 0; //pCfg->vpCfg.confWinTop;
|
|
param->confWinBot = 0; //pCfg->vpCfg.confWinBot;
|
|
param->confWinLeft = 0; //pCfg->vpCfg.confWinLeft;
|
|
param->confWinRight = 0; //pCfg->vpCfg.confWinRight;
|
|
|
|
if ((pEncOP->picHeight % 16) && param->confWinBot == 0
|
|
&& pEncOP->bitstreamFormat == STD_AVC) {
|
|
/* need set the drop flag */
|
|
if (InitParam->rotate_angle != 90 && InitParam->rotate_angle != 270)
|
|
{ // except rotation
|
|
param->confWinBot = 16 - (pEncOP->picHeight % 16);
|
|
}
|
|
}
|
|
if ((pEncOP->picWidth % 16) && param->confWinRight == 0
|
|
&& pEncOP->bitstreamFormat == STD_AVC) {
|
|
/* need set the drop flag for width*/
|
|
if (InitParam->rotate_angle != 90 && InitParam->rotate_angle != 270)
|
|
{ // except rotation
|
|
param->confWinRight = 16 - (pEncOP->picWidth % 16);
|
|
}
|
|
}
|
|
|
|
if ((pEncOP->picHeight % 8) && param->confWinBot == 0
|
|
&& pEncOP->bitstreamFormat == STD_HEVC) {
|
|
/* need set the drop flag */
|
|
if (InitParam->rotate_angle != 90 && InitParam->rotate_angle != 270)
|
|
{ // except rotation
|
|
param->confWinBot = 8 - (pEncOP->picHeight % 8);
|
|
}
|
|
}
|
|
|
|
/* for CMD_ENC_SEQ_INDEPENDENT_SLICE */
|
|
if (InitParam->slice_mode &&
|
|
InitParam->slice_mode <= 2 &&
|
|
InitParam->slice_arg &&
|
|
pEncOP->bitstreamFormat == STD_HEVC) {
|
|
param->independSliceMode = 1;
|
|
param->independSliceModeArg = InitParam->slice_arg & 0xffff;
|
|
VLOG(INFO, "HEVC:independSliceMode %d , independSliceModeArg %d\n",
|
|
param->independSliceMode, param->independSliceModeArg);
|
|
} else {
|
|
param->independSliceMode = 0; //pCfg->vpCfg.independSliceMode;
|
|
param->independSliceModeArg = 0; //pCfg->vpCfg.independSliceModeArg;
|
|
}
|
|
|
|
/* for CMD_ENC_SEQ_DEPENDENT_SLICE */
|
|
if (InitParam->slice_mode ==2 &&
|
|
InitParam->slice_arg &&
|
|
pEncOP->bitstreamFormat == STD_HEVC) {
|
|
param->dependSliceMode = 2; //pCfg->vpCfg.dependSliceMode;
|
|
param->dependSliceModeArg = (InitParam->slice_arg >>16) & 0xffff; //pCfg->vpCfg.dependSliceModeArg;
|
|
VLOG(INFO, "HEVC:dependSliceMode %d , dependSliceModeArg %d\n",
|
|
param->dependSliceMode, param->dependSliceModeArg);
|
|
} else {
|
|
param->dependSliceMode = 0; //pCfg->vpCfg.dependSliceMode;
|
|
param->dependSliceModeArg = 0; //pCfg->vpCfg.dependSliceModeArg;
|
|
}
|
|
|
|
/* for CMD_ENC_SEQ_INTRA_REFRESH_PARAM */
|
|
if (InitParam->IntraRefreshMode &&
|
|
InitParam->IntraRefreshMode <= 4 &&
|
|
InitParam->IntraRefreshArg &&
|
|
pEncOP->bitstreamFormat == STD_HEVC) {
|
|
param->intraRefreshMode = InitParam->IntraRefreshMode;
|
|
param->intraRefreshArg = InitParam->IntraRefreshArg;
|
|
VLOG(INFO, "HEVC:intraRefreshMode %d, intraRefreshArg %d\n",
|
|
param->intraRefreshMode, param->intraRefreshArg);
|
|
} else {
|
|
param->intraRefreshMode = 0; //pCfg->vpCfg.intraRefreshMode;
|
|
param->intraRefreshArg = 0; //pCfg->vpCfg.intraRefreshArg;
|
|
}
|
|
param->useRecommendEncParam = 0; //pCfg->vpCfg.useRecommendEncParam;
|
|
|
|
/* for CMD_ENC_PARAM */
|
|
param->scalingListEnable = 0; //pCfg->vpCfg.scalingListEnable;
|
|
param->cuSizeMode = 0x7; // always set cu8x8/16x16/32x32 enable to 1.
|
|
param->tmvpEnable = 1; //pCfg->vpCfg.tmvpEnable;
|
|
param->wppEnable = 0; //pCfg->vpCfg.wppenable;
|
|
param->maxNumMerge = 2; //pCfg->vpCfg.maxNumMerge;
|
|
|
|
param->disableDeblk = 0; //pCfg->vpCfg.disableDeblk;
|
|
|
|
param->lfCrossSliceBoundaryEnable = 1; //pCfg->vpCfg.lfCrossSliceBoundaryEnable;
|
|
param->betaOffsetDiv2 = 0;//pCfg->vpCfg.betaOffsetDiv2;
|
|
param->tcOffsetDiv2 = 0; //pCfg->vpCfg.tcOffsetDiv2;
|
|
param->skipIntraTrans = 1;//pCfg->vpCfg.skipIntraTrans;
|
|
param->saoEnable = 1;//pCfg->vpCfg.saoEnable;
|
|
param->intraNxNEnable = 1; //pCfg->vpCfg.intraNxNEnable;
|
|
|
|
/* for CMD_ENC_RC_PARAM */
|
|
//pEncOP->rcEnable = InitParam -> rate_control;
|
|
pEncOP->vbvBufferSize = 3000;//pCfg->VbvBufferSize;
|
|
|
|
param->cuLevelRCEnable = 1; //pCfg->vpCfg.cuLevelRCEnable;
|
|
param->hvsQPEnable = 1;//pCfg->vpCfg.hvsQPEnable;
|
|
param->hvsQpScale = 2;//pCfg->vpCfg.hvsQpScale;
|
|
|
|
param->bitAllocMode = 0; //pCfg->vpCfg.bitAllocMode;
|
|
for (i = 0; i < MAX_GOP_NUM; i++) {
|
|
param->fixedBitRatio[i] = 1;//pCfg->vpCfg.fixedBitRatio[i];
|
|
}
|
|
|
|
if (InitParam->qp_mode == 1) {
|
|
param->minQpI = InitParam->minQP;
|
|
param->minQpP = InitParam->minQP_P;
|
|
param->minQpB = InitParam->minQP_B;
|
|
param->maxQpI = InitParam->maxQP;
|
|
param->maxQpP = InitParam->maxQP_P;
|
|
param->maxQpB = InitParam->maxQP_B;
|
|
param->hvsMaxDeltaQp = InitParam->maxDeltaQP;
|
|
} else {
|
|
param->minQpI = 8;
|
|
param->minQpP = 8;
|
|
param->minQpB = 8;
|
|
param->maxQpI = 51;
|
|
param->maxQpP = 51;
|
|
param->maxQpB = 51;
|
|
param->hvsMaxDeltaQp = 10;
|
|
}
|
|
if (param->maxQpI < param->maxQpP && param->gopPresetIdx != PRESET_IDX_ALL_I)
|
|
param->QpModify = 1;
|
|
|
|
if (param->gopPresetIdx == PRESET_IDX_CUSTOM_GOP) {
|
|
/* for CMD_ENC_CUSTOM_GOP_PARAM */
|
|
if (param->intraPeriod % param->gopParam.customGopSize) {
|
|
VLOG(ERR, "[ERROR] Gop length %d have to be multiple of %d\n",
|
|
param->intraPeriod, param->gopParam.customGopSize);
|
|
return FALSE;
|
|
}
|
|
|
|
for (i= 0; i<param->gopParam.customGopSize; i++) {
|
|
param->gopParam.picParam[i].picType = GopParam->picType;
|
|
param->gopParam.picParam[i].pocOffset = GopParam->pocOffset;
|
|
param->gopParam.picParam[i].picQp = GopParam->picQp + param->intraQP +
|
|
InitParam->cust_qp_delta;
|
|
if (param->gopParam.picParam[i].picQp > 63)
|
|
param->gopParam.picParam[i].picQp = 63;
|
|
param->gopParam.picParam[i].refPocL0 = GopParam->refPocL0;
|
|
param->gopParam.picParam[i].refPocL1 = GopParam->refPocL1;
|
|
param->gopParam.picParam[i].temporalId = GopParam->temporalId;
|
|
param->gopParam.picParam[i].numRefPicL0 = GopParam->numRefPicL0;
|
|
GopParam++;
|
|
VLOG(INFO, "CustGop%d type %d offset %d, Qp %d, ref %d, %d, temp %d refn %d \n",
|
|
i, param->gopParam.picParam[i].picType, param->gopParam.picParam[i].pocOffset,
|
|
param->gopParam.picParam[i].picQp, param->gopParam.picParam[i].refPocL0,
|
|
param->gopParam.picParam[i].refPocL1, param->gopParam.picParam[i].temporalId,
|
|
param->gopParam.picParam[i].numRefPicL0);
|
|
}
|
|
}
|
|
param->roiEnable = InitParam->roi_enable; //pCfg->vpCfg.roiEnable;
|
|
// VPS & VUI
|
|
param->numUnitsInTick = 1000;//pCfg->vpCfg.numUnitsInTick;
|
|
if (pEncOP->bitstreamFormat == STD_AVC)
|
|
param->timeScale = pEncOP->frameRateInfo * 2000;
|
|
else
|
|
param->timeScale = pEncOP->frameRateInfo * 1000; //pCfg->vpCfg.timeScale;
|
|
param->numTicksPocDiffOne = 0;//pCfg->vpCfg.numTicksPocDiffOne;
|
|
|
|
param->chromaCbQpOffset = 0; //pCfg->vpCfg.chromaCbQpOffset;
|
|
param->chromaCrQpOffset = 0; //pCfg->vpCfg.chromaCrQpOffset;
|
|
param->initialRcQp = -1; //63//pCfg->vpCfg.initialRcQp;
|
|
|
|
param->nrYEnable = 1; //pCfg->vpCfg.nrYEnable;
|
|
param->nrCbEnable = 1; //pCfg->vpCfg.nrCbEnable;
|
|
param->nrCrEnable = 1; //pCfg->vpCfg.nrCrEnable;
|
|
param->nrNoiseEstEnable = 1;// pCfg->vpCfg.nrNoiseEstEnable;
|
|
param->nrNoiseSigmaY = 0; //pCfg->vpCfg.nrNoiseSigmaY;
|
|
param->nrNoiseSigmaCb = 0; //pCfg->vpCfg.nrNoiseSigmaCb;
|
|
param->nrNoiseSigmaCr = 0; //pCfg->vpCfg.nrNoiseSigmaCr;
|
|
param->nrIntraWeightY = 7; //pCfg->vpCfg.nrIntraWeightY;
|
|
param->nrIntraWeightCb = 7; //pCfg->vpCfg.nrIntraWeightCb;
|
|
param->nrIntraWeightCr = 7; //pCfg->vpCfg.nrIntraWeightCr;
|
|
param->nrInterWeightY = 4; //pCfg->vpCfg.nrInterWeightY;
|
|
param->nrInterWeightCb = 4; //pCfg->vpCfg.nrInterWeightCb;
|
|
param->nrInterWeightCr = 4; //pCfg->vpCfg.nrInterWeightCr;
|
|
|
|
param->monochromeEnable = 0; //pCfg->vpCfg.monochromeEnable;
|
|
param->strongIntraSmoothEnable = 1; //pCfg->vpCfg.strongIntraSmoothEnable;
|
|
param->weightPredEnable = InitParam->weight_pred_enable; //pCfg->vpCfg.weightPredEnable;
|
|
param->bgDetectEnable = 0; //pCfg->vpCfg.bgDetectEnable;
|
|
param->bgThrDiff = 8; //pCfg->vpCfg.bgThrDiff;
|
|
param->bgThrMeanDiff = 1;//pCfg->vpCfg.bgThrMeanDiff;
|
|
param->bgLambdaQp = 32 ; //pCfg->vpCfg.bgLambdaQp;
|
|
param->bgDeltaQp = 3; //pCfg->vpCfg.bgDeltaQp;
|
|
param->customLambdaEnable = 0; //pCfg->vpCfg.customLambdaEnable;
|
|
param->customMDEnable = 0; //pCfg->vpCfg.customMDEnable;
|
|
param->pu04DeltaRate = 0; //pCfg->vpCfg.pu04DeltaRate;
|
|
param->pu08DeltaRate = 0; //pCfg->vpCfg.pu08DeltaRate;
|
|
param->pu16DeltaRate = 0; //pCfg->vpCfg.pu16DeltaRate;
|
|
param->pu32DeltaRate = 0; //pCfg->vpCfg.pu32DeltaRate;
|
|
param->pu04IntraPlanarDeltaRate = 0; //pCfg->vpCfg.pu04IntraPlanarDeltaRate;
|
|
param->pu04IntraDcDeltaRate = 0; //pCfg->vpCfg.pu04IntraDcDeltaRate;
|
|
param->pu04IntraAngleDeltaRate = 0; //pCfg->vpCfg.pu04IntraAngleDeltaRate;
|
|
param->pu08IntraPlanarDeltaRate = 0; //pCfg->vpCfg.pu08IntraPlanarDeltaRate;
|
|
param->pu08IntraDcDeltaRate = 0; //pCfg->vpCfg.pu08IntraDcDeltaRate;
|
|
param->pu08IntraAngleDeltaRate = 0; //pCfg->vpCfg.pu08IntraAngleDeltaRate;
|
|
param->pu16IntraPlanarDeltaRate = 0; //pCfg->vpCfg.pu16IntraPlanarDeltaRate;
|
|
param->pu16IntraDcDeltaRate = 0; //pCfg->vpCfg.pu16IntraDcDeltaRate;
|
|
param->pu16IntraAngleDeltaRate = 0; //pCfg->vpCfg.pu16IntraAngleDeltaRate;
|
|
param->pu32IntraPlanarDeltaRate = 0; // pCfg->vpCfg.pu32IntraPlanarDeltaRate;
|
|
param->pu32IntraDcDeltaRate = 0; //pCfg->vpCfg.pu32IntraDcDeltaRate;
|
|
param->pu32IntraAngleDeltaRate = 0; //pCfg->vpCfg.pu32IntraAngleDeltaRate;
|
|
param->cu08IntraDeltaRate = 0; //pCfg->vpCfg.cu08IntraDeltaRate;
|
|
param->cu08InterDeltaRate = 0; //pCfg->vpCfg.cu08InterDeltaRate;
|
|
param->cu08MergeDeltaRate = 0; //pCfg->vpCfg.cu08MergeDeltaRate;
|
|
param->cu16IntraDeltaRate = 0; //pCfg->vpCfg.cu16IntraDeltaRate;
|
|
param->cu16InterDeltaRate = 0; //pCfg->vpCfg.cu16InterDeltaRate;
|
|
param->cu16MergeDeltaRate = 0; //pCfg->vpCfg.cu16MergeDeltaRate;
|
|
param->cu32IntraDeltaRate = 0; // pCfg->vpCfg.cu32IntraDeltaRate;
|
|
param->cu32InterDeltaRate = 0; //pCfg->vpCfg.cu32InterDeltaRate;
|
|
param->cu32MergeDeltaRate = 0; //pCfg->vpCfg.cu32MergeDeltaRate;
|
|
param->coefClearDisable = 0; //pCfg->vpCfg.coefClearDisable;
|
|
|
|
param->rcWeightParam = 16; //pCfg->vpCfg.rcWeightParam;
|
|
param->rcWeightBuf = 128; //pCfg->vpCfg.rcWeightBuf;
|
|
|
|
param->s2fmeDisable = 0; //pCfg->vpCfg.s2fmeDisable;
|
|
// for H.264 on VP
|
|
if (pEncOP->bitstreamFormat == STD_AVC)
|
|
param->avcIdrPeriod = param->intraPeriod;
|
|
else
|
|
param->avcIdrPeriod = 0; //pCfg->vpCfg.idrPeriod;
|
|
|
|
param->rdoSkip = 1; //pCfg->vpCfg.rdoSkip;
|
|
param->lambdaScalingEnable = 1; //pCfg->vpCfg.lambdaScalingEnable;
|
|
if (pEncOP->bitstreamFormat == STD_AVC &&
|
|
(param->profile == AVC_PROFILE_BASE ||
|
|
param->profile == AVC_PROFILE_MAIN)) {
|
|
param->transform8x8Enable = 0; //pCfg->vpCfg.transform8x8;
|
|
} else {
|
|
param->transform8x8Enable = 1; //pCfg->vpCfg.transform8x8;
|
|
}
|
|
|
|
if (InitParam->slice_mode &&
|
|
InitParam->slice_mode <= 1 &&
|
|
InitParam->slice_arg &&
|
|
pEncOP->bitstreamFormat == STD_AVC) {
|
|
param->avcSliceMode = InitParam->slice_mode;
|
|
param->avcSliceArg = InitParam->slice_arg & 0xffff;
|
|
VLOG(INFO, "AVC:avcSliceMode %d , avcSliceArg %d\n",
|
|
param->avcSliceMode, param->avcSliceArg);
|
|
} else {
|
|
param->avcSliceMode = 0; //pCfg->vpCfg.avcSliceMode;
|
|
param->avcSliceArg = 0; //pCfg->vpCfg.avcSliceArg;
|
|
}
|
|
if (InitParam->IntraRefreshMode &&
|
|
InitParam->IntraRefreshMode <= 3 &&
|
|
InitParam->IntraRefreshArg &&
|
|
pEncOP->bitstreamFormat == STD_AVC) {
|
|
param->intraMbRefreshMode = InitParam->IntraRefreshMode;
|
|
param->intraMbRefreshArg = InitParam->IntraRefreshArg;
|
|
VLOG(INFO, "AVC:intraMbRefreshMode %d , intraMbRefreshArg %d\n",
|
|
param->intraMbRefreshMode, param->intraMbRefreshArg);
|
|
} else {
|
|
param->intraMbRefreshMode = 0; //pCfg->vpCfg.intraMbRefreshMode;
|
|
param->intraMbRefreshArg = 1; //pCfg->vpCfg.intraMbRefreshArg;
|
|
}
|
|
param->mbLevelRcEnable = 0; //pCfg->vpCfg.mbLevelRc;
|
|
|
|
if (pEncOP->bitstreamFormat == STD_AVC &&
|
|
param->profile == AVC_PROFILE_BASE) {
|
|
param->entropyCodingMode = 0; //pCfg->vpCfg.entropyCodingMode;
|
|
} else {
|
|
param->entropyCodingMode = 1; //pCfg->vpCfg.entropyCodingMode;
|
|
}
|
|
|
|
pEncOP->streamBufCount = ENC_STREAM_BUF_COUNT;
|
|
|
|
if (InitParam->es_buf_sz)
|
|
pEncOP->streamBufSize = InitParam->es_buf_sz;
|
|
else
|
|
pEncOP->streamBufSize = ENC_STREAM_BUF_SIZE;
|
|
|
|
if (pEncOP->streamBufCount < COMMAND_QUEUE_DEPTH )
|
|
pEncOP->streamBufCount = COMMAND_QUEUE_DEPTH; //for encoder->numSinkPortQueue
|
|
if (InitParam->srcBitDepth == 10)
|
|
pEncOP->srcFormat = FORMAT_420_P10_16BIT_MSB;
|
|
else
|
|
pEncOP->srcFormat = FORMAT_420;
|
|
if (InitParam->fmt == AMVENC_NV21)
|
|
pEncOP->nv21 = 1;
|
|
else
|
|
pEncOP->nv21 = 0;
|
|
pEncOP->packedFormat = 0;
|
|
|
|
if (InitParam->fmt == AMVENC_NV21 || InitParam->fmt == AMVENC_NV12)
|
|
pEncOP->cbcrInterleave = 1;
|
|
else
|
|
pEncOP->cbcrInterleave = 0;
|
|
pEncOP->frameEndian = VPU_FRAME_ENDIAN;
|
|
pEncOP->streamEndian = VPU_STREAM_ENDIAN;
|
|
pEncOP->sourceEndian = VPU_SOURCE_ENDIAN;
|
|
pEncOP->lineBufIntEn = 1;
|
|
pEncOP->coreIdx = 0;
|
|
pEncOP->cbcrOrder = CBCR_ORDER_NORMAL;
|
|
pEncOP->lowLatencyMode = 0; // 2bits lowlatency mode setting. bit[1]: low latency interrupt enable, bit[0]: fast bitstream-packing enable.
|
|
return TRUE;
|
|
}
|
|
|
|
static ENC_INT_STATUS HandlingInterruptFlag(AMVMultiCtx* ctx)
|
|
{
|
|
EncHandle handle = ctx->enchandle;
|
|
Int32 interruptFlag = 0;
|
|
Uint32 interruptWaitTime = VPU_WAIT_TIME_OUT_CQ;
|
|
Uint32 interruptTimeout = VPU_ENC_TIMEOUT;
|
|
ENC_INT_STATUS status = ENC_INT_STATUS_NONE;
|
|
|
|
if (ctx->startTimeout == 0ULL) {
|
|
ctx->startTimeout = osal_gettime();
|
|
}
|
|
do {
|
|
interruptFlag = VPU_WaitInterruptEx(handle, interruptWaitTime);
|
|
if (INTERRUPT_TIMEOUT_VALUE == interruptFlag) {
|
|
Uint64 currentTimeout = osal_gettime();
|
|
if ((currentTimeout - ctx->startTimeout) > interruptTimeout) {
|
|
VLOG(ERR, "startTimeout(%ld) currentTime(%ld) diff(%d)\n",
|
|
ctx->startTimeout, currentTimeout, (Uint32)(currentTimeout - ctx->startTimeout));
|
|
status = ENC_INT_STATUS_TIMEOUT;
|
|
break;
|
|
}
|
|
interruptFlag = 0;
|
|
}
|
|
if (interruptFlag < 0)
|
|
VLOG(ERR, "interruptFlag is negative value! %08x\n", interruptFlag);
|
|
|
|
if (interruptFlag > 0) {
|
|
VPU_ClearInterruptEx(handle, interruptFlag);
|
|
ctx->startTimeout = 0ULL;
|
|
|
|
if (interruptFlag & (1<<INT_VP5_ENC_SET_PARAM)) {
|
|
status = ENC_INT_STATUS_DONE;
|
|
break;
|
|
}
|
|
|
|
if (interruptFlag & (1<<INT_VP5_ENC_PIC)) {
|
|
status = ENC_INT_STATUS_DONE;
|
|
break;
|
|
}
|
|
|
|
if (interruptFlag & (1<<INT_VP5_BSBUF_FULL)) {
|
|
status = ENC_INT_STATUS_FULL;
|
|
break;
|
|
}
|
|
|
|
if (interruptFlag & (1<<INT_VP5_ENC_LOW_LATENCY)) {
|
|
status = ENC_INT_STATUS_LOW_LATENCY;
|
|
break;
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
|
|
return status;
|
|
}
|
|
|
|
static void DisplayEncodedInformation(
|
|
EncHandle handle,
|
|
CodStd codec,
|
|
Uint32 frameNo,
|
|
EncOutputInfo* encodedInfo,
|
|
Int32 srcEndFlag,
|
|
Int32 srcFrameIdx,
|
|
Int32 performance
|
|
)
|
|
{
|
|
QueueStatusInfo queueStatus;
|
|
|
|
VPU_EncGiveCommand(handle, ENC_GET_QUEUE_STATUS, &queueStatus);
|
|
|
|
if (encodedInfo == NULL) {
|
|
if (performance == TRUE ) {
|
|
VLOG(DEBUG, "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
|
|
VLOG(DEBUG, " USEDSRC | FRAME | HOST | PREP_S PREP_E PREP | PROCE_S PROCE_E PROCE | ENC_S ENC_E ENC |\n");
|
|
VLOG(DEBUG, "I NO T RECON RD_PTR WR_PTR BYTES SRCIDX IDX IDC Vcore | CYCLE | TICK | TICK TICK CYCLE | TICK TICK CYCLE | TICK TICK CYCLE | RQ IQ\n");
|
|
VLOG(DEBUG, "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
|
|
}
|
|
else {
|
|
VLOG(DEBUG, "---------------------------------------------------------------------------------------------------------------------------\n");
|
|
VLOG(DEBUG, " USEDSRC | CYCLE\n");
|
|
VLOG(DEBUG, "I NO T RECON RD_PTR WR_PTR BYTES SRCIDX IDX IDC Vcore | FRAME PREPARING PROCESSING ENCODING | RQ IQ\n");
|
|
VLOG(DEBUG, "---------------------------------------------------------------------------------------------------------------------------\n");
|
|
}
|
|
} else {
|
|
if (performance == TRUE) {
|
|
VLOG(INFO, "%02d %5d %5d %5d %08x %08x %8x %2d %2d %08x %2d %8u %8u (%8u,%8u,%8u) (%8u,%8u,%8u) (%8u,%8u,%8u) %d %d\n",
|
|
handle->instIndex, encodedInfo->encPicCnt, encodedInfo->picType, encodedInfo->reconFrameIndex, encodedInfo->rdPtr, encodedInfo->wrPtr,
|
|
encodedInfo->bitstreamSize, (srcEndFlag == 1 ? -1 : srcFrameIdx), encodedInfo->encSrcIdx,
|
|
encodedInfo->releaseSrcFlag,
|
|
0,
|
|
encodedInfo->frameCycle, encodedInfo->encHostCmdTick,
|
|
encodedInfo->encPrepareStartTick, encodedInfo->encPrepareEndTick, encodedInfo->prepareCycle,
|
|
encodedInfo->encProcessingStartTick, encodedInfo->encProcessingEndTick, encodedInfo->processing,
|
|
encodedInfo->encEncodeStartTick, encodedInfo->encEncodeEndTick, encodedInfo->EncodedCycle,
|
|
queueStatus.reportQueueCount, queueStatus.instanceQueueCount);
|
|
}
|
|
else {
|
|
VLOG(INFO, "%02d %5d %5d %5d %08x %08x %8x %2d %2d %04x %d %8d %8d %8d %8d %d %d\n",
|
|
handle->instIndex, encodedInfo->encPicCnt, encodedInfo->picType, encodedInfo->reconFrameIndex, encodedInfo->rdPtr, encodedInfo->wrPtr,
|
|
encodedInfo->bitstreamSize, (srcEndFlag == 1 ? -1 : srcFrameIdx), encodedInfo->encSrcIdx,
|
|
encodedInfo->releaseSrcFlag,
|
|
0,
|
|
encodedInfo->frameCycle, encodedInfo->prepareCycle, encodedInfo->processing, encodedInfo->EncodedCycle,
|
|
queueStatus.reportQueueCount, queueStatus.instanceQueueCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
static BOOL SetSequenceInfo (AMVMultiCtx* ctx)
|
|
{
|
|
EncHandle handle = ctx->enchandle;
|
|
RetCode ret = RETCODE_SUCCESS;
|
|
EncInitialInfo* initialInfo = &ctx->initialInfo;
|
|
ENC_INT_STATUS status;
|
|
int retry_cnt = 0;
|
|
do {
|
|
ret = VPU_EncIssueSeqInit(handle);
|
|
retry_cnt++;
|
|
} while (ret == RETCODE_QUEUEING_FAILURE && retry_cnt < 10);
|
|
if (ret != RETCODE_SUCCESS) {
|
|
VLOG(ERR, "Failed to VPU_EncIssueSeqInit() ret(%d)\n", ret);
|
|
ChekcAndPrintDebugInfo(handle, TRUE, ret);
|
|
return FALSE;
|
|
}
|
|
VLOG(INFO, "Encoder issue VPU_EncIssueSeq \n");
|
|
retry_cnt = 0;
|
|
while (retry_cnt++ < 100) {
|
|
if ((status = HandlingInterruptFlag(ctx)) == ENC_INT_STATUS_DONE) {
|
|
break;
|
|
}
|
|
else if (status == ENC_INT_STATUS_NONE) {
|
|
Uint32 intr_usr = 0;
|
|
VPU_CheckInterrupt(ctx->enchandle, &intr_usr);
|
|
VLOG(DEBUG, "Check interrupt status inst #%d retry %d result %d\n",
|
|
ctx->enchandle->instIndex, retry_cnt, intr_usr);
|
|
if (intr_usr) {
|
|
VLOG(DEBUG, "Check and cleared interrupt inst #%d go ahead\n",
|
|
ctx->enchandle->instIndex);
|
|
break;
|
|
}
|
|
usleep(1000);
|
|
}
|
|
else if (status == ENC_INT_STATUS_TIMEOUT) {
|
|
VLOG(INFO, "INSTANCE #%d INTERRUPT TIMEOUT\n", handle->instIndex);
|
|
HandleEncoderError(ctx->enchandle, ctx->frameIdx, NULL);
|
|
return FALSE;
|
|
}
|
|
else {
|
|
VLOG(INFO, "Unknown interrupt status: %d\n", status);
|
|
return FALSE;
|
|
}
|
|
usleep(1000);
|
|
}
|
|
|
|
if ((ret=VPU_EncCompleteSeqInit(handle, initialInfo)) != RETCODE_SUCCESS) {
|
|
VLOG(ERR, "FAILED TO ENC_PIC_HDR: ret(%d), SEQERR(%08x)\n", ret, initialInfo->seqInitErrReason);
|
|
ChekcAndPrintDebugInfo(handle, TRUE, ret);
|
|
return FALSE;
|
|
}
|
|
ctx->fb_num = initialInfo->minFrameBufferCount;
|
|
ctx->src_num = initialInfo->minSrcFrameCount + 2
|
|
+ EXTRA_SRC_BUFFER_NUM;
|
|
|
|
if (ctx->encOpenParam.sourceBufCount > ctx->src_num)
|
|
ctx->src_num = ctx->encOpenParam.sourceBufCount;
|
|
|
|
VLOG(TRACE, "Required buffer fb_num=%d, src_num=%d, actual src=%d %dx%d\n",
|
|
ctx->fb_num, initialInfo->minSrcFrameCount,
|
|
ctx->src_num, ctx->encOpenParam.picWidth, ctx->encOpenParam.picHeight);
|
|
|
|
VLOG(INFO, "Done sequence init can setup BW and performance Monitor here\n");
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL AllocateReconFrameBuffer(AMVMultiCtx* ctx)
|
|
{
|
|
Uint32 i;
|
|
Uint32 reconFbSize;
|
|
Uint32 reconFbStride;
|
|
Uint32 reconFbWidth;
|
|
Uint32 reconFbHeight;
|
|
EncOpenParam encOpenParam = ctx->encOpenParam;
|
|
|
|
|
|
if (ctx->encOpenParam.bitstreamFormat == STD_AVC) {
|
|
reconFbWidth = VPU_ALIGN16(encOpenParam.picWidth);
|
|
reconFbHeight = VPU_ALIGN16(encOpenParam.picHeight);
|
|
} else {
|
|
reconFbWidth = VPU_ALIGN8(encOpenParam.picWidth);
|
|
reconFbHeight = VPU_ALIGN8(encOpenParam.picHeight);
|
|
}
|
|
|
|
if ((ctx->mInitParams.rotate_angle != 0 || ctx->mInitParams.mirror != 0)
|
|
&& !(ctx->mInitParams.rotate_angle == 180
|
|
&& ctx->mInitParams.mirror == MIRDIR_HOR_VER)) {
|
|
reconFbWidth = VPU_ALIGN32(encOpenParam.picWidth);
|
|
reconFbHeight = VPU_ALIGN32(encOpenParam.picHeight);
|
|
}
|
|
|
|
if (ctx->mInitParams.rotate_angle == 90
|
|
|| ctx->mInitParams.rotate_angle== 270) {
|
|
reconFbWidth = VPU_ALIGN32(encOpenParam.picHeight);
|
|
reconFbHeight = VPU_ALIGN32(encOpenParam.picWidth);
|
|
}
|
|
|
|
/* Allocate framebuffers for recon. */
|
|
reconFbStride = CalcStride(reconFbWidth, reconFbHeight,
|
|
(FrameBufferFormat)encOpenParam.outputFormat,
|
|
encOpenParam.cbcrInterleave,
|
|
COMPRESSED_FRAME_MAP, FALSE);
|
|
reconFbSize = VPU_GetFrameBufSize(ctx->enchandle, encOpenParam.coreIdx,
|
|
reconFbStride, reconFbHeight, COMPRESSED_FRAME_MAP,
|
|
(FrameBufferFormat)encOpenParam.outputFormat,
|
|
encOpenParam.cbcrInterleave, NULL);
|
|
|
|
for (i = 0; i < ctx->fb_num; i++) {
|
|
ctx->pFbReconMem[i].size = reconFbSize;
|
|
if (vdi_allocate_dma_memory(encOpenParam.coreIdx, &ctx->pFbReconMem[i], ENC_FBC, ctx->enchandle->instIndex) < 0) {
|
|
ctx->pFbReconMem[i].size = 0;
|
|
VLOG(ERR, "fail to allocate recon buffer\n");
|
|
return FALSE;
|
|
}
|
|
ctx->pFbRecon[i].bufY = ctx->pFbReconMem[i].phys_addr;
|
|
ctx->pFbRecon[i].bufCb = (PhysicalAddress) - 1;
|
|
ctx->pFbRecon[i].bufCr = (PhysicalAddress) - 1;
|
|
ctx->pFbRecon[i].size = reconFbSize;
|
|
ctx->pFbRecon[i].updateFbInfo = TRUE;
|
|
ctx->pFbRecon[i].dma_buf_planes = 0;
|
|
}
|
|
|
|
ctx->reconFbStride = reconFbStride;
|
|
ctx->reconFbHeight = reconFbHeight;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL AllocateYuvBufferHeader(AMVMultiCtx* ctx)
|
|
{
|
|
Uint32 i;
|
|
FrameBufferAllocInfo srcFbAllocInfo;
|
|
Uint32 srcFbSize;
|
|
Uint32 srcFbStride;
|
|
EncOpenParam encOpenParam = ctx->encOpenParam;
|
|
Uint32 srcFbWidth = VPU_ALIGN8(encOpenParam.picWidth);
|
|
Uint32 srcFbHeight = VPU_ALIGN8(encOpenParam.picHeight);
|
|
|
|
memset(&srcFbAllocInfo, 0x00, sizeof(FrameBufferAllocInfo));
|
|
|
|
/* calculate sourec buffer stride and size */
|
|
srcFbStride = CalcStride(srcFbWidth, srcFbHeight,
|
|
(FrameBufferFormat)encOpenParam.srcFormat,
|
|
encOpenParam.cbcrInterleave, LINEAR_FRAME_MAP, FALSE);
|
|
srcFbSize = VPU_GetFrameBufSize(ctx->enchandle, encOpenParam.coreIdx, srcFbStride,
|
|
srcFbHeight, LINEAR_FRAME_MAP,
|
|
(FrameBufferFormat)encOpenParam.srcFormat,
|
|
encOpenParam.cbcrInterleave, NULL);
|
|
|
|
srcFbAllocInfo.mapType = LINEAR_FRAME_MAP;
|
|
srcFbAllocInfo.format = (FrameBufferFormat)encOpenParam.srcFormat;
|
|
srcFbAllocInfo.cbcrInterleave = encOpenParam.cbcrInterleave;
|
|
srcFbAllocInfo.stride = srcFbStride;
|
|
srcFbAllocInfo.height = srcFbHeight;
|
|
srcFbAllocInfo.endian = encOpenParam.sourceEndian;
|
|
srcFbAllocInfo.type = FB_TYPE_PPU;
|
|
srcFbAllocInfo.num = ctx->src_num;
|
|
srcFbAllocInfo.nv21 = encOpenParam.nv21;
|
|
|
|
#if 0 //allocat later when use input buffer, in case DMA buffer no need copy.
|
|
for (i = 0; i < ctx->src_num; i++) {
|
|
ctx->pFbSrcMem[i].size = srcFbSize;
|
|
if (vdi_allocate_dma_memory(encOpenParam.coreIdx, &ctx->pFbSrcMem[i],
|
|
ENC_SRC, ctx->enchandle->instIndex) < 0) {
|
|
VLOG(ERR, "fail to allocate src buffer\n");
|
|
ctx->pFbSrcMem[i].size = 0;
|
|
return FALSE;
|
|
}
|
|
ctx->pFbSrc[i].bufY = ctx->pFbSrcMem[i].phys_addr;
|
|
ctx->pFbSrc[i].bufCb = (PhysicalAddress) - 1;
|
|
ctx->pFbSrc[i].bufCr = (PhysicalAddress) - 1;
|
|
ctx->pFbSrc[i].updateFbInfo = TRUE;
|
|
}
|
|
#else
|
|
for (i = 0; i < ctx->src_num; i++) {
|
|
ctx->pFbSrc[i].bufY = (PhysicalAddress) 0;
|
|
ctx->pFbSrc[i].bufCb = (PhysicalAddress) - 1;
|
|
ctx->pFbSrc[i].bufCr = (PhysicalAddress) - 1;
|
|
ctx->pFbSrc[i].updateFbInfo = TRUE;
|
|
}
|
|
#endif
|
|
ctx->srcFbStride = srcFbStride;
|
|
ctx->srcFbSize = srcFbSize;
|
|
ctx->srcFbAllocInfo = srcFbAllocInfo;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL RegisterFrameBuffers(AMVMultiCtx *ctx)
|
|
{
|
|
FrameBuffer *pReconFb;
|
|
FrameBuffer *pSrcFb;
|
|
FrameBufferAllocInfo srcFbAllocInfo;
|
|
Uint32 reconFbStride;
|
|
Uint32 reconFbHeight;
|
|
RetCode result;
|
|
Uint32 idx;
|
|
|
|
pReconFb = ctx->pFbRecon;
|
|
reconFbStride = ctx->reconFbStride;
|
|
reconFbHeight = ctx->reconFbHeight;
|
|
result = VPU_EncRegisterFrameBuffer(ctx->enchandle, pReconFb,
|
|
ctx->fb_num, reconFbStride, reconFbHeight, COMPRESSED_FRAME_MAP);
|
|
if (result != RETCODE_SUCCESS) {
|
|
VLOG(ERR, "Failed to VPU_EncRegisterFrameBuffer(%d)\n", result);
|
|
ChekcAndPrintDebugInfo(ctx->enchandle, TRUE, result);
|
|
return FALSE;
|
|
}
|
|
VLOG(INFO, " finish register frame buffer \n");
|
|
|
|
pSrcFb = ctx->pFbSrc;
|
|
srcFbAllocInfo = ctx->srcFbAllocInfo;
|
|
if (VPU_EncAllocateFrameBuffer(ctx->enchandle, srcFbAllocInfo, pSrcFb) != RETCODE_SUCCESS) {
|
|
VLOG(ERR, "VPU_EncAllocateFrameBuffer fail to allocate source frame buffer\n");
|
|
ChekcAndPrintDebugInfo(ctx->enchandle, TRUE, result);
|
|
return FALSE;
|
|
}
|
|
|
|
if (ctx->mInitParams.roi_enable
|
|
|| ctx->mInitParams.lambda_map_enable
|
|
|| ctx->mInitParams.mode_map_enable) {
|
|
ctx->CustomMapSize = (ctx->encOpenParam.bitstreamFormat == STD_AVC) ?
|
|
MAX_MB_NUM : MAX_CTU_NUM * 8;
|
|
if (ctx->mInitParams.roi_enable) {
|
|
ctx->CustomRoiMapBuf = (unsigned char *)malloc(ctx->CustomMapSize);
|
|
//set default qp value to 30;
|
|
memset(ctx->CustomRoiMapBuf, 0x1e , ctx->CustomMapSize);
|
|
}
|
|
if (ctx->mInitParams.mode_map_enable) {
|
|
ctx->CustomModeMapBuf = (unsigned char *)malloc(ctx->CustomMapSize);
|
|
memset(ctx->CustomModeMapBuf, 0x0 , ctx->CustomMapSize);
|
|
}
|
|
|
|
if (ctx->mInitParams.lambda_map_enable &&
|
|
ctx->encOpenParam.bitstreamFormat == STD_HEVC) {
|
|
ctx->CustomLambdaMapBuf = (unsigned char *)malloc(ctx->CustomMapSize);
|
|
memset(ctx->CustomLambdaMapBuf, 0x0 , ctx->CustomMapSize);
|
|
}
|
|
ctx->CustomUpdateID ++; // force the first update
|
|
for (idx = 0; idx < ctx->src_num; idx++) {
|
|
ctx->vbCustomMap[idx].size = ctx->CustomMapSize;
|
|
if (vdi_allocate_dma_memory(ctx->encOpenParam.coreIdx, &ctx->vbCustomMap[idx],
|
|
ENC_ETC, ctx->enchandle->instIndex) < 0) {
|
|
ctx->vbCustomMap[idx].size = 0;
|
|
VLOG(ERR, "fail to allocate ROI buffer\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void SetCustMapData(AMVMultiCtx *ctx, EncParam *encParam, unsigned long addrCustomMap)
|
|
{
|
|
Uint8 *roiMapBuf;
|
|
int sumQp = 0;
|
|
int h, w, bufSize;
|
|
|
|
if (ctx->encOpenParam.bitstreamFormat == STD_AVC) {
|
|
//AvcEncCustomMap customMapBuf[MAX_MB_NUM];
|
|
/*For stack optimization*/
|
|
AvcEncCustomMap *customMapBuf = (AvcEncCustomMap *)osal_malloc(MAX_MB_NUM * sizeof(AvcEncCustomMap));
|
|
if (customMapBuf == NULL) {
|
|
VLOG(ERR, "fail to allocate customMapBuf\n");
|
|
return;
|
|
}
|
|
int MbWidth = VPU_ALIGN16(ctx->encOpenParam.picWidth) >> 4;
|
|
int MbHeight = VPU_ALIGN16(ctx->encOpenParam.picHeight) >> 4;
|
|
int mbAddr;
|
|
//osal_memset(&customMapBuf[0], 0x00, MAX_MB_NUM);
|
|
osal_memset(customMapBuf, 0x00, MAX_MB_NUM * sizeof(AvcEncCustomMap));
|
|
roiMapBuf = ctx->CustomRoiMapBuf;
|
|
if (encParam->customMapOpt.customRoiMapEnable == 1) {
|
|
bufSize = MbWidth*MbHeight;
|
|
for (h = 0; h < MbHeight; h++) {
|
|
for (w = 0; w < MbWidth; w++) {
|
|
mbAddr = w + h*MbWidth;
|
|
customMapBuf[mbAddr].field.mb_qp = MAX(MIN(roiMapBuf[mbAddr]&0x3f, 51), 0);
|
|
sumQp += customMapBuf[mbAddr].field.mb_qp;
|
|
}
|
|
}
|
|
encParam->customMapOpt.roiAvgQp = (sumQp + (bufSize>>1)) / bufSize; // round off.
|
|
}
|
|
|
|
if (encParam->customMapOpt.customModeMapEnable == 1) {
|
|
bufSize = MbWidth*MbHeight;
|
|
for (h = 0; h < MbHeight; h++) {
|
|
for (w = 0; w < MbWidth; w++) {
|
|
mbAddr = w + h*MbWidth;
|
|
customMapBuf[mbAddr].field.mb_force_mode = ctx->CustomModeMapBuf[mbAddr] & 0x3;
|
|
}
|
|
}
|
|
}
|
|
|
|
encParam->customMapOpt.addrCustomMap = addrCustomMap;
|
|
vdi_write_memory(ctx->encOpenParam.coreIdx,
|
|
encParam->customMapOpt.addrCustomMap,
|
|
(unsigned char*)customMapBuf,
|
|
MAX_MB_NUM, VDI_LITTLE_ENDIAN);
|
|
if (customMapBuf)
|
|
osal_free(customMapBuf);
|
|
}
|
|
else {
|
|
// for HEVC custom map.
|
|
//EncCustomMap customMapBuf[MAX_CTU_NUM];// custom map 1 CTU data = 64bits
|
|
/*For stack optimization*/
|
|
EncCustomMap *customMapBuf = (EncCustomMap *)osal_malloc(MAX_MB_NUM * sizeof(EncCustomMap));
|
|
if (customMapBuf == NULL) {
|
|
VLOG(ERR, "fail to allocate customMapBuf\n");
|
|
return;
|
|
}
|
|
int ctuMapWidthCnt = VPU_ALIGN64(ctx->encOpenParam.picWidth) >> 6;
|
|
int ctuMapHeightCnt = VPU_ALIGN64(ctx->encOpenParam.picHeight) >> 6;
|
|
int ctuMapStride = VPU_ALIGN64(ctx->encOpenParam.picWidth) >> 6;
|
|
int subCtuMapStride = VPU_ALIGN64(ctx->encOpenParam.picWidth) >> 5;
|
|
int ctuPos;
|
|
Uint8* src;
|
|
|
|
//osal_memset(&customMapBuf[0], 0x00, MAX_CTU_NUM * 8);
|
|
osal_memset(customMapBuf, 0x00, MAX_MB_NUM * sizeof(EncCustomMap));
|
|
roiMapBuf = ctx->CustomRoiMapBuf;
|
|
if (encParam->customMapOpt.customRoiMapEnable == 1) {
|
|
bufSize = subCtuMapStride*(VPU_ALIGN64(ctx->encOpenParam.picHeight) >> 5);
|
|
|
|
for (h = 0; h < ctuMapHeightCnt; h++) {
|
|
src = &roiMapBuf[subCtuMapStride * h * 2];
|
|
for (w = 0; w < ctuMapWidthCnt; w++, src += 2) {
|
|
ctuPos = (h * ctuMapStride + w);
|
|
// store in the order of sub-ctu.
|
|
customMapBuf[ctuPos].field.sub_ctu_qp_0 = MAX(MIN(*src, 51), 0);
|
|
customMapBuf[ctuPos].field.sub_ctu_qp_1 = MAX(MIN(*(src + 1), 51), 0);
|
|
customMapBuf[ctuPos].field.sub_ctu_qp_2 = MAX(MIN(*(src + subCtuMapStride), 51), 0);
|
|
customMapBuf[ctuPos].field.sub_ctu_qp_3 = MAX(MIN(*(src + subCtuMapStride + 1), 51), 0);
|
|
sumQp += (customMapBuf[ctuPos].field.sub_ctu_qp_0 +
|
|
customMapBuf[ctuPos].field.sub_ctu_qp_1 +
|
|
customMapBuf[ctuPos].field.sub_ctu_qp_2 +
|
|
customMapBuf[ctuPos].field.sub_ctu_qp_3);
|
|
}
|
|
}
|
|
encParam->customMapOpt.roiAvgQp = (sumQp + (bufSize>>1)) / bufSize; // round off.
|
|
}
|
|
|
|
if (encParam->customMapOpt.customLambdaMapEnable == 1) {
|
|
// bufSize = subCtuMapStride*(VPU_ALIGN64(ctx->encOpenParam.picHeight) >> 5);
|
|
for (h = 0; h < ctuMapHeightCnt; h++) {
|
|
src = &(ctx->CustomLambdaMapBuf[subCtuMapStride * 2 * h]);
|
|
for (w = 0; w < ctuMapWidthCnt; w++, src += 2) {
|
|
ctuPos = (h * ctuMapStride + w);
|
|
// store in the order of sub-ctu.
|
|
customMapBuf[ctuPos].field.lambda_sad_0 = *src;
|
|
customMapBuf[ctuPos].field.lambda_sad_1 = *(src + 1);
|
|
customMapBuf[ctuPos].field.lambda_sad_2 = *(src + subCtuMapStride);
|
|
customMapBuf[ctuPos].field.lambda_sad_3 = *(src + subCtuMapStride + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((encParam->customMapOpt.customModeMapEnable == 1)
|
|
|| (encParam->customMapOpt.customCoefDropEnable == 1)) {
|
|
// bufSize = ctuMapWidthCnt * ctuMapHeightCnt;
|
|
for (h = 0; h < ctuMapHeightCnt; h++) {
|
|
src = &(ctx->CustomModeMapBuf[ctuMapStride * h]);
|
|
for (w = 0; w < ctuMapWidthCnt; w++, src++) {
|
|
ctuPos = (h * ctuMapStride + w);
|
|
customMapBuf[ctuPos].field.ctu_force_mode = (*src) & 0x3;
|
|
customMapBuf[ctuPos].field.ctu_coeff_drop = ((*src) >> 2) & 0x1;
|
|
}
|
|
}
|
|
}
|
|
|
|
encParam->customMapOpt.addrCustomMap = addrCustomMap;
|
|
vdi_write_memory(ctx->encOpenParam.coreIdx,
|
|
encParam->customMapOpt.addrCustomMap,
|
|
(unsigned char*)customMapBuf,
|
|
MAX_CTU_NUM * 8, VDI_LITTLE_ENDIAN);
|
|
if (customMapBuf)
|
|
osal_free(customMapBuf);
|
|
}
|
|
}
|
|
|
|
#if SUPPORT_SCALE
|
|
AMVEnc_Status ge2d_colorFormat(AMVEncFrameFmt format) {
|
|
switch (format) {
|
|
case AMVENC_RGB888:
|
|
SRC1_PIXFORMAT = PIXEL_FORMAT_RGB_888;
|
|
SRC2_PIXFORMAT = PIXEL_FORMAT_RGB_888;
|
|
return AMVENC_SUCCESS;
|
|
case AMVENC_RGBA8888:
|
|
SRC1_PIXFORMAT = PIXEL_FORMAT_RGBA_8888;
|
|
SRC2_PIXFORMAT = PIXEL_FORMAT_RGBA_8888;
|
|
return AMVENC_SUCCESS;
|
|
default:
|
|
VLOG(ERR, "not support color format!");
|
|
return AMVENC_FAIL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
amv_enc_handle_t AML_MultiEncInitialize(AMVEncInitParams* encParam)
|
|
{
|
|
|
|
RetCode retCode;
|
|
VpuAttr productInfo;
|
|
SecAxiUse secAxiUse;
|
|
Uint32 coreIdx, idx;
|
|
RetCode result;
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* )malloc(sizeof(AMVMultiCtx));
|
|
|
|
if (ctx == NULL) {
|
|
VLOG(ERR, "ctx == NULL");
|
|
return (amv_enc_handle_t) ctx;
|
|
}
|
|
|
|
memset(ctx, 0, sizeof(AMVMultiCtx));
|
|
ctx->magic_num = MULTI_ENC_MAGIC;
|
|
|
|
ctx->instance_id = 0;
|
|
ctx->src_idx = 0;
|
|
ctx->enc_counter = 0;
|
|
ctx->enc_width = encParam->width;
|
|
ctx->enc_height = encParam->height;
|
|
// copy a backup on initial parameter
|
|
memcpy((char *)&ctx->mInitParams, encParam, sizeof(AMVEncInitParams));
|
|
if (encParam->idr_period == -1) {
|
|
ctx->idrPeriod = 0;
|
|
} else {
|
|
ctx->idrPeriod = encParam->idr_period;
|
|
}
|
|
|
|
VLOG(INFO, "ctx->idrPeriod: %d\n", ctx->idrPeriod);
|
|
|
|
ctx->bitrate = encParam->bitrate;
|
|
ctx->frame_rate = encParam->frame_rate;
|
|
ctx->mPrependSPSPPSToIDRFrames = encParam->prepend_spspps_to_idr_frames;
|
|
ctx->mNumPlanes = 0;
|
|
if (SetupEncoderOpenParam(&(ctx->encOpenParam), encParam) == FALSE)
|
|
goto fail_exit;
|
|
coreIdx = ctx->encOpenParam.coreIdx;
|
|
retCode = VPU_Init(coreIdx);
|
|
if (retCode != RETCODE_SUCCESS && retCode != RETCODE_CALLED_BEFORE) {
|
|
VLOG(INFO, "Failed to VPU_Init, ret(%08x)\n", retCode);
|
|
goto fail_exit;
|
|
}
|
|
retCode = PrintVpuProductInfo(coreIdx, &productInfo);
|
|
if (retCode == RETCODE_VPU_RESPONSE_TIMEOUT ) {
|
|
VLOG(INFO, "Failed to PrintVpuProductInfo()\n");
|
|
HandleEncoderError(ctx->enchandle, 0, NULL);
|
|
goto fail_exit;
|
|
}
|
|
ctx->cyclePerTick = 32768;
|
|
if (TRUE == productInfo.supportNewTimer)
|
|
ctx->cyclePerTick = 256;
|
|
/* prepare stream buffers */
|
|
if (encParam->es_buf_sz)
|
|
ctx->bsBuffer[0].size = encParam->es_buf_sz; //ENC_STREAM_BUF_SIZE;
|
|
else
|
|
ctx->bsBuffer[0].size = ENC_STREAM_BUF_SIZE; // default value
|
|
if (vdi_allocate_dma_memory(coreIdx, &ctx->bsBuffer[0], ENC_BS, 0) < 0) {
|
|
VLOG(ERR, "fail to allocate bitstream buffer\n");
|
|
ctx->bsBuffer[0].size = 0;
|
|
goto fail_exit;
|
|
}
|
|
|
|
ctx->encOpenParam.bitstreamBuffer = ctx->bsBuffer[0].phys_addr;
|
|
ctx->encOpenParam.bitstreamBufferSize = ctx->bsBuffer[0].size;
|
|
|
|
VLOG(DEBUG, "ctx->encOpenParam.bitstreamBuffer %0x, ctx->encOpenParam.bitstreamBufferSiz %0x",
|
|
ctx->encOpenParam.bitstreamBuffer, ctx->encOpenParam.bitstreamBufferSize);
|
|
|
|
// real open the encoder with OpenParam
|
|
if ((result = VPU_EncOpen(&ctx->enchandle, &ctx->encOpenParam)) != RETCODE_SUCCESS) {
|
|
VLOG(ERR, "VPU_EncOpen failed Error code is 0x%x \n", result);
|
|
ctx->enchandle = NULL;
|
|
goto fail_exit;
|
|
}
|
|
if (VPU_EncInstParamSync(ctx->enchandle,encParam->GopPreset,
|
|
encParam->cust_qp_delta,NULL) != RETCODE_SUCCESS) {
|
|
VLOG(ERR, "VPU instance param sync with open param failed\n");
|
|
}
|
|
|
|
// customer buffers allocat and settins
|
|
/* Allocate Buffer and Set Data as needed*/
|
|
if (ctx->encOpenParam.EncStdParam.vpParam.scalingListEnable) {
|
|
ctx->vbScalingList.size = 0x1000;
|
|
if (vdi_allocate_dma_memory(coreIdx, &ctx->vbScalingList, ENC_ETC, ctx->enchandle->instIndex) < 0) {
|
|
VLOG(ERR, "fail to allocate scaling list buffer\n");
|
|
ctx->vbScalingList.size = 0;
|
|
goto fail_exit;
|
|
}
|
|
ctx->encOpenParam.EncStdParam.vpParam.userScalingListAddr = ctx->vbScalingList.phys_addr;
|
|
// fill the scaling list data here, configure APIs to be added
|
|
//parse_user_scaling_list(&ctx->scalingList, testEncConfig.scaling_list_file, testEncConfig.stdMode);
|
|
vdi_write_memory(coreIdx, ctx->vbScalingList.phys_addr,
|
|
(unsigned char*)&ctx->scalingList,
|
|
ctx->vbScalingList.size,
|
|
VDI_LITTLE_ENDIAN);
|
|
}
|
|
|
|
if (ctx->encOpenParam.EncStdParam.vpParam.customLambdaEnable) {
|
|
ctx->vbCustomLambda.size = 0x200;
|
|
if (vdi_allocate_dma_memory(coreIdx, &ctx->vbCustomLambda, ENC_ETC, ctx->enchandle->instIndex) < 0) {
|
|
VLOG(ERR, "fail to allocate Lambda map buffer\n");
|
|
ctx->vbCustomLambda.size = 0;
|
|
goto fail_exit;
|
|
}
|
|
ctx->encOpenParam.EncStdParam.vpParam.customLambdaAddr = ctx->vbCustomLambda.phys_addr;
|
|
// fill the customLambda buffer,API to be add as needed.
|
|
//parse_custom_lambda(ctx->customLambda, testEncConfig.custom_lambda_file);
|
|
vdi_write_memory(coreIdx, ctx->vbCustomLambda.phys_addr, (unsigned char*)&ctx->customLambda[0], ctx->vbCustomLambda.size, VDI_LITTLE_ENDIAN);
|
|
}
|
|
|
|
// set rotate and mirror
|
|
//VPU_EncGiveCommand(ctx->enchandle, ENABLE_LOGGING, 0);
|
|
if (encParam->rotate_angle != 0 || encParam->mirror != 0) {
|
|
VLOG(DEBUG, "set rotate and mirror, angle:%d, mirror:%d\n",
|
|
ctx->mInitParams.rotate_angle, ctx->mInitParams.mirror);
|
|
VPU_EncGiveCommand(ctx->enchandle, ENABLE_ROTATION, 0);
|
|
VPU_EncGiveCommand(ctx->enchandle, ENABLE_MIRRORING, 0);
|
|
VPU_EncGiveCommand(ctx->enchandle, SET_ROTATION_ANGLE, &ctx->mInitParams.rotate_angle);
|
|
VPU_EncGiveCommand(ctx->enchandle, SET_MIRROR_DIRECTION, &ctx->mInitParams.mirror);
|
|
}
|
|
memset(&secAxiUse, 0x00, sizeof(SecAxiUse));
|
|
secAxiUse.u.vp.useEncRdoEnable =0; //USE_RDO_INTERNAL_BUF
|
|
secAxiUse.u.vp.useEncLfEnable = 0; //USE_LF_INTERNAL_BUF
|
|
VPU_EncGiveCommand(ctx->enchandle, SET_SEC_AXI, &secAxiUse);
|
|
VPU_EncGiveCommand(ctx->enchandle, SET_CYCLE_PER_TICK, (void*)&ctx->cyclePerTick);
|
|
// get the seqence buffer requirement info
|
|
if (SetSequenceInfo(ctx) == FALSE)
|
|
goto fail_exit;
|
|
// Allocate and register encoder frame buffer
|
|
if (AllocateReconFrameBuffer(ctx) == FALSE)
|
|
goto fail_exit;
|
|
if (AllocateYuvBufferHeader(ctx) == FALSE)
|
|
goto fail_exit;
|
|
if (RegisterFrameBuffers(ctx) == FALSE)
|
|
goto fail_exit;
|
|
|
|
#if SUPPORT_SCALE
|
|
if ((encParam->width != encParam->src_width) || (encParam->height != encParam->src_height) || true) {
|
|
memset(&ctx->amlge2d,0x0,sizeof(aml_ge2d_t));
|
|
aml_ge2d_info_t *pge2dinfo = &ctx->amlge2d.ge2dinfo;
|
|
memset(pge2dinfo, 0, sizeof(aml_ge2d_info_t));
|
|
memset(&(pge2dinfo->src_info[0]), 0, sizeof(buffer_info_t));
|
|
memset(&(pge2dinfo->src_info[1]), 0, sizeof(buffer_info_t));
|
|
memset(&(pge2dinfo->dst_info), 0, sizeof(buffer_info_t));
|
|
|
|
set_ge2dinfo(pge2dinfo, encParam);
|
|
|
|
int ret = aml_ge2d_init(&ctx->amlge2d);
|
|
if (ret < 0) {
|
|
VLOG(ERR, "encode open ge2d failed, ret=0x%x", ret);
|
|
return AMVENC_FAIL;
|
|
}
|
|
ctx->ge2d_initial_done = 1;
|
|
ctx->INIT_GE2D = true;
|
|
}
|
|
#endif
|
|
return (amv_enc_handle_t) ctx;
|
|
fail_exit:
|
|
if (ctx->enchandle) {
|
|
if (ctx->vbCustomLambda.size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->vbCustomLambda, ENC_ETC, ctx->enchandle->instIndex);
|
|
if (ctx->vbScalingList.size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->vbScalingList, ENC_ETC, ctx->enchandle->instIndex);
|
|
}
|
|
if (ctx->bsBuffer[0].size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->bsBuffer[0], ENC_BS, 0);
|
|
if (ctx->enchandle) {
|
|
for (idx = 0; idx < MAX_REG_FRAME; idx++) {
|
|
if (ctx->pFbReconMem[idx].size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->pFbReconMem[idx], ENC_FBC, ctx->enchandle->instIndex);
|
|
if (ctx->vbCustomMap[idx].size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->vbCustomMap[idx], ENC_ETC, ctx->enchandle->instIndex);
|
|
}
|
|
}
|
|
if (ctx->CustomRoiMapBuf)
|
|
{
|
|
free(ctx->CustomRoiMapBuf);
|
|
ctx->CustomRoiMapBuf = NULL;
|
|
}
|
|
if (ctx->CustomLambdaMapBuf)
|
|
{
|
|
free(ctx->CustomLambdaMapBuf);
|
|
ctx->CustomLambdaMapBuf = NULL;
|
|
}
|
|
if (ctx->CustomModeMapBuf)
|
|
{
|
|
free(ctx->CustomModeMapBuf);
|
|
ctx->CustomModeMapBuf = NULL;
|
|
}
|
|
if (ctx->enchandle) {
|
|
for (idx = 0; idx < ENC_SRC_BUF_NUM; idx++) {
|
|
if (ctx->pFbSrcMem[idx].size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->pFbSrcMem[idx],
|
|
ENC_SRC, ctx->enchandle->instIndex);
|
|
}
|
|
}
|
|
if (ctx->enchandle)
|
|
VPU_EncClose(ctx->enchandle);
|
|
#if SUPPORT_SCALE
|
|
if (ctx->ge2d_initial_done) {
|
|
aml_ge2d_exit(&ctx->amlge2d);
|
|
}
|
|
#endif
|
|
free(ctx);
|
|
return (amv_enc_handle_t) NULL;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncSetInput(amv_enc_handle_t ctx_handle,
|
|
AMVMultiEncFrameIO* input) {
|
|
Uint32 src_stride;
|
|
Uint32 luma_stride, chroma_stride;
|
|
Uint32 size_src_luma;
|
|
// Uint32 size_src_chroma;
|
|
char *y_dst = NULL;
|
|
char *src = NULL;
|
|
int idx, idx_1, endian;
|
|
bool width32alinged = true; //width is multiple of 32 or not
|
|
Uint32 is_DMA_buffer = 0;
|
|
EncParam * param;
|
|
int64_t total_cost = 0;
|
|
int64_t t1, t2, t3, t4, t5, t6, t7;
|
|
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* )ctx_handle;
|
|
|
|
VLOG(NONE, "AML_MultiEncSetInput, canvas=%u, input fmt=%d, num_planes=%d, type=%d",
|
|
input->canvas, input->fmt, input->num_planes, input->type);
|
|
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC) return AMVENC_FAIL;
|
|
|
|
ctx->pic_type = input->pic_type;
|
|
if (input->type == CANVAS_BUFFER) {
|
|
VLOG(INFO, "set fmt to nv21 for canvas buffer mode as default");
|
|
input->fmt = AMVENC_NV21;
|
|
}
|
|
|
|
if (ctx->enc_width % 32) {
|
|
width32alinged = false;
|
|
}
|
|
if ((input->num_planes >0) && (input->type == DMA_BUFF)) { /* DMA buffer, no need allocate */
|
|
is_DMA_buffer = 1;
|
|
}
|
|
param = &(ctx->encParam);
|
|
|
|
ctx->op_flag = input->op_flag;
|
|
ctx->fmt = input->fmt;
|
|
if (ctx->fmt != AMVENC_NV12 && ctx->fmt != AMVENC_NV21 && ctx->fmt != AMVENC_YUV420P) {
|
|
#if SUPPORT_SCALE
|
|
if (ctx->INIT_GE2D) {
|
|
if (ge2d_colorFormat(ctx->fmt) == AMVENC_SUCCESS) {
|
|
VLOG(DEBUG, "The %d of color format that HEVC need ge2d to change!", ctx->fmt);
|
|
} else
|
|
{
|
|
VLOG(INFO, "Encoder only support NV12/NV21, not support %d", ctx->fmt);
|
|
return AMVENC_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
#else
|
|
VLOG(INFO, "Encoder only support NV12/NV21, not support %d", ctx->fmt);
|
|
return AMVENC_NOT_SUPPORTED;
|
|
#endif
|
|
}
|
|
|
|
VLOG(INFO, "fmt %d , is dma %d \n", ctx->fmt, is_DMA_buffer);
|
|
|
|
if (is_DMA_buffer) {
|
|
if (!input->pitch) {
|
|
src_stride = vp_align32(ctx->enc_width);
|
|
} else {
|
|
src_stride = input->pitch;
|
|
if (ctx->fmt == AMVENC_NV12 || ctx->fmt == AMVENC_NV21 || ctx->fmt == AMVENC_YUV420P) {
|
|
if (src_stride % 16) {
|
|
VLOG(ERR, "DMA buffer stride %d to 16 byte align\n", src_stride);
|
|
return AMVENC_FAIL;
|
|
}
|
|
} else {
|
|
src_stride = vp_align32(input->pitch);
|
|
}
|
|
}
|
|
} else {
|
|
src_stride = vp_align32(ctx->enc_width);
|
|
}
|
|
if (src_stride != input->pitch) {
|
|
width32alinged = false;
|
|
}
|
|
luma_stride = src_stride * (ctx->encOpenParam.srcBitDepth == 10 ? 2 : 1);
|
|
chroma_stride = src_stride * (ctx->encOpenParam.srcBitDepth == 10 ? 2 : 1);
|
|
// Pick a no used src frame buffer descriptor
|
|
idx_1 = -1;
|
|
for (idx = 0; idx< ENC_SRC_BUF_NUM; idx++) {
|
|
if(ctx->encodedSrcFrmIdxArr[idx] == 0
|
|
&& ctx->pFbSrcMem[idx].size) break; // free and located mem
|
|
if(ctx->encodedSrcFrmIdxArr[idx] == 0
|
|
&& idx_1 == -1) idx_1 = idx;
|
|
}
|
|
if (idx == ENC_SRC_BUF_NUM) { //no found, just get a free header
|
|
if(idx_1 >= 0 ) idx = idx_1;
|
|
else {
|
|
VLOG(ERR, "can not find a free src buffer\n");
|
|
return AMVENC_FAIL;
|
|
}
|
|
}
|
|
if (idx >= ctx->src_num) {
|
|
VLOG(ERR, "Too many src buffer request\n");
|
|
return AMVENC_FAIL;
|
|
}
|
|
|
|
if (is_DMA_buffer == 0 && input->type != CANVAS_BUFFER) {
|
|
// need allocate buffer and copy
|
|
ctx->pFbSrc[idx].dma_buf_planes = 0; //clean the DMA buffer
|
|
if(ctx->pFbSrcMem[idx].size == 0) { // allocate buffer
|
|
ctx->pFbSrcMem[idx].size = ctx->srcFbSize;
|
|
if (vdi_allocate_dma_memory(ctx->encOpenParam.coreIdx, &ctx->pFbSrcMem[idx],
|
|
ENC_SRC, ctx->enchandle->instIndex) < 0) {
|
|
VLOG(ERR, "fail to allocate src buffer, short of memory\n");
|
|
ctx->pFbSrcMem[idx].size = 0;
|
|
return AMVENC_FAIL;
|
|
}
|
|
ctx->pFbSrc[idx].bufY = ctx->pFbSrcMem[idx].phys_addr;
|
|
if (ctx->pFbSrc[idx].bufCb != -1)
|
|
ctx->pFbSrc[idx].bufCb += ctx->pFbSrc[idx].bufY;
|
|
if (ctx->pFbSrc[idx].bufCr != -1)
|
|
ctx->pFbSrc[idx].bufCr += ctx->pFbSrc[idx].bufY;
|
|
VLOG(INFO, "New allocate frame idx %d address y:0x%x cb:0x%x cr:0x%x\n",
|
|
idx, ctx->pFbSrc[idx].bufY, ctx->pFbSrc[idx].bufCb,ctx->pFbSrc[idx].bufCr);
|
|
}
|
|
#if SUPPORT_SCALE
|
|
if ((input->scale_width !=0 && input->scale_height !=0) || input->crop_left != 0 ||
|
|
input->crop_right != 0 || input->crop_top != 0 || input->crop_bottom != 0 ||
|
|
(ctx->fmt != AMVENC_NV12 && ctx->fmt != AMVENC_NV21 && ctx->fmt != AMVENC_YUV420P)) {
|
|
if (ctx->INIT_GE2D) {
|
|
ctx->INIT_GE2D = false;
|
|
|
|
ctx->amlge2d.ge2dinfo.src_info[0].format = SRC1_PIXFORMAT;
|
|
ctx->amlge2d.ge2dinfo.src_info[1].format = SRC2_PIXFORMAT;
|
|
ctx->amlge2d.ge2dinfo.src_info[0].plane_number = 1;
|
|
ctx->amlge2d.ge2dinfo.dst_info.plane_number = 1;
|
|
int ret = aml_ge2d_mem_alloc(&ctx->amlge2d);
|
|
if (ret < 0) {
|
|
VLOG(ERR, "encode ge2di mem alloc failed, ret=0x%x", ret);
|
|
return AMVENC_FAIL;
|
|
}
|
|
VLOG(DEBUG, "ge2d init successful!");
|
|
}
|
|
VLOG(DEBUG, "HEVC TEST sclale, enc_width:%d enc_height:%d pitch:%d height:%d",
|
|
ctx->enc_width, ctx->enc_height, input->pitch, input->height);
|
|
if (ctx->fmt == AMVENC_NV12 || ctx->fmt == AMVENC_NV21 || ctx->fmt == AMVENC_YUV420P) {
|
|
if (input->pitch % 32) {
|
|
VLOG(ERR, "HEVC crop and scale must be 32bit aligned");
|
|
return AMVENC_FAIL;
|
|
}
|
|
}
|
|
else {
|
|
width32alinged = true;
|
|
}
|
|
|
|
if (ctx->fmt == AMVENC_RGBA8888) {
|
|
memcpy((void *)ctx->amlge2d.ge2dinfo.src_info[0].vaddr[0], (void *)input->YCbCr[0], 4 * input->pitch * input->height);
|
|
} else if (ctx->fmt == AMVENC_NV12 || ctx->fmt == AMVENC_NV21) {
|
|
//memcpy((void *)ctx->amlge2d.ge2dinfo.src_info[0].vaddr[0], (void *)input->YCbCr[0], input->pitch * input->height);
|
|
//memcpy((void *) ((char *)ctx->amlge2d.ge2dinfo.src_info[0].vaddr[0] + input->pitch * input->height), (void *)input->YCbCr[1], input->pitch * input->height / 2);
|
|
} else if (ctx->fmt == AMVENC_YUV420P) {
|
|
//memcpy((void *)ctx->amlge2d.ge2dinfo.src_info[0].vaddr[0], (void *)input->YCbCr[0], input->pitch * input->height);
|
|
//memcpy((void *) ((char *)ctx->amlge2d.ge2dinfo.src_info[0].vaddr[0] + input->pitch * input->height), (void *)input->YCbCr[1], input->pitch * input->height / 4);
|
|
//memcpy((void *) ((char *)ctx->amlge2d.ge2dinfo.src_info[0].vaddr[0] + (input->pitch * input->height * 5) /4), (void *)input->YCbCr[2], input->pitch * input->height / 4);
|
|
} else if (ctx->fmt == AMVENC_RGB888) {
|
|
memcpy((void *)ctx->amlge2d.ge2dinfo.src_info[0].vaddr[0], (void *)input->YCbCr[0], input->pitch * input->height * 3);
|
|
}
|
|
|
|
do_strechblit(&ctx->amlge2d.ge2dinfo, input);
|
|
aml_ge2d_invalid_cache(&ctx->amlge2d.ge2dinfo);
|
|
size_src_luma = luma_stride * vp_align32(ctx->enc_height);
|
|
// size_src_chroma = luma_stride * (vp_align16(ctx->enc_height) / 2);
|
|
endian = ctx->pFbSrc[idx].endian;
|
|
y_dst = (char *) ctx->pFbSrcMem[idx].virt_addr;
|
|
src = (char *) ctx->amlge2d.ge2dinfo.dst_info.vaddr[0];
|
|
yuv_plane_memcpy(ctx->encOpenParam.coreIdx, ctx->pFbSrc[idx].bufY, src,
|
|
ctx->enc_width, ctx->enc_height, luma_stride,
|
|
input->pitch, width32alinged, endian);
|
|
src = (char *) ctx->amlge2d.ge2dinfo.dst_info.vaddr[0] + luma_stride * ctx->enc_height;
|
|
yuv_plane_memcpy(ctx->encOpenParam.coreIdx, ctx->pFbSrc[idx].bufCb,
|
|
src, ctx->enc_width, ctx->enc_height / 2,
|
|
chroma_stride, input->pitch, width32alinged,endian);
|
|
} else
|
|
#endif
|
|
{
|
|
// set frame buffers
|
|
// calculate required buffer size
|
|
size_src_luma = luma_stride * vp_align32(ctx->enc_height);
|
|
// size_src_chroma = luma_stride * (vp_align16(ctx->enc_height) / 2);
|
|
endian = ctx->pFbSrc[idx].endian;
|
|
|
|
y_dst = (char *) ctx->pFbSrcMem[idx].virt_addr;
|
|
|
|
//for (idx_1 = 0; idx_1 < size_src_luma; idx_1++) *(y_dst + idx_1) = 0;
|
|
//for (idx_1 = 0; idx_1 < size_src_chroma; idx_1++) *(y_dst + size_src_luma + idx_1) = 0x80;
|
|
//memset(y_dst, 0x0, size_src_luma);
|
|
//memset(y_dst + size_src_luma, 0x80, size_src_chroma);
|
|
|
|
src = (char *) input->YCbCr[0];
|
|
VLOG(INFO, "idx %d luma %d src %p dst %p width %d, height %d \n",
|
|
idx, size_src_luma, src, y_dst, ctx->enc_width, ctx->enc_height);
|
|
|
|
ctx->temp_enc_width = ctx->enc_width;
|
|
input->temp_pitch = input->pitch;
|
|
if (!width32alinged && ctx->encOpenParam.srcBitDepth == 10) {
|
|
ctx->temp_enc_width *= 2;
|
|
input->temp_pitch *= 2;
|
|
}
|
|
|
|
yuv_plane_memcpy(ctx->encOpenParam.coreIdx, ctx->pFbSrc[idx].bufY, src,
|
|
ctx->temp_enc_width, ctx->enc_height, luma_stride,
|
|
input->temp_pitch, width32alinged, endian);
|
|
|
|
if (ctx->fmt == AMVENC_NV12 || ctx->fmt == AMVENC_NV21) {
|
|
src = (char *)input->YCbCr[1];
|
|
yuv_plane_memcpy(ctx->encOpenParam.coreIdx, ctx->pFbSrc[idx].bufCb,
|
|
src, ctx->enc_width, ctx->enc_height / 2,
|
|
chroma_stride, input->pitch, width32alinged,endian);
|
|
} else if (ctx->fmt == AMVENC_YUV420P) {
|
|
src = (char *)input->YCbCr[1];
|
|
yuv_plane_memcpy(ctx->encOpenParam.coreIdx, ctx->pFbSrc[idx].bufCb,
|
|
src, ctx->temp_enc_width /2, ctx->enc_height/ 2,
|
|
chroma_stride / 2, input->temp_pitch / 2, width32alinged,
|
|
endian);
|
|
// v_dst = (char *)(ctx->pFbSrcMem[idx].virt_addr + size_src_luma + size_src_luma / 4);
|
|
src = (char *)input->YCbCr[2];
|
|
yuv_plane_memcpy(ctx->encOpenParam.coreIdx, ctx->pFbSrc[idx].bufCr,
|
|
src, ctx->temp_enc_width/2, ctx->enc_height/ 2,
|
|
chroma_stride / 2, input->temp_pitch / 2, width32alinged,
|
|
endian);
|
|
}
|
|
}
|
|
vdi_flush_memory(ctx->encOpenParam.coreIdx, &ctx->pFbSrcMem[idx]);
|
|
VLOG(INFO,"frame %d stride %d address Y 0x%x cb 0x%x cr 0x%x \n",
|
|
idx, size_src_luma, ctx->pFbSrc[idx].bufY, ctx->pFbSrc[idx].bufCb,ctx->pFbSrc[idx].bufCr);
|
|
#if 0
|
|
if (ctx->fmt == AMVENC_NV12 || ctx->fmt == AMVENC_NV21) {
|
|
ctx->pFbSrc[idx].bufCb = (PhysicalAddress) (ctx->pFbSrc[idx].bufY + size_src_luma);
|
|
ctx->pFbSrc[idx].bufCr = (PhysicalAddress) - 1;
|
|
ctx->pFbSrc[idx].cbcrInterleave = 1;
|
|
} else if (ctx->fmt == AMVENC_YUV420P) {
|
|
ctx->pFbSrc[idx].bufCb = (PhysicalAddress) (ctx->pFbSrc[idx].bufY + size_src_luma);
|
|
ctx->pFbSrc[idx].bufCr = (PhysicalAddress) (ctx->pFbSrc[idx].bufY + size_src_luma + size_src_luma / 4);
|
|
}
|
|
#endif
|
|
VLOG(INFO,"frame %d stride %d address Y 0x%x cb 0x%x cr 0x%x \n",
|
|
idx, size_src_luma, ctx->pFbSrc[idx].bufY,
|
|
ctx->pFbSrc[idx].bufCb,ctx->pFbSrc[idx].bufCr);
|
|
}
|
|
else if (input->type == CANVAS_BUFFER) {
|
|
|
|
} else { //DMA buffer
|
|
#if SUPPORT_SCALE
|
|
if (ctx->fmt != AMVENC_NV12 && ctx->fmt != AMVENC_NV21 && ctx->fmt != AMVENC_YUV420P) {
|
|
if (ctx->INIT_GE2D) {
|
|
ctx->INIT_GE2D = false;
|
|
ctx->amlge2d.ge2dinfo.src_info[0].format = SRC1_PIXFORMAT;
|
|
ctx->amlge2d.ge2dinfo.src_info[1].format = SRC2_PIXFORMAT;
|
|
ctx->amlge2d.ge2dinfo.dst_info.plane_number = 1;
|
|
int ret = aml_ge2d_mem_alloc(&ctx->amlge2d);
|
|
if (ret < 0) {
|
|
VLOG(ERR, "encode ge2di mem alloc failed, ret=0x%x", ret);
|
|
return AMVENC_FAIL;
|
|
}
|
|
VLOG(DEBUG, "ge2d init successful!");
|
|
}
|
|
ctx->amlge2d.ge2dinfo.src_info[0].shared_fd[0] = input->shared_fd[0];
|
|
|
|
do_strechblit(&ctx->amlge2d.ge2dinfo, input);
|
|
aml_ge2d_invalid_cache(&ctx->amlge2d.ge2dinfo);
|
|
|
|
ctx->pFbSrc[idx].dma_shared_fd[0] = ctx->amlge2d.ge2dinfo.dst_info.shared_fd[0];
|
|
ctx->pFbSrc[idx].dma_buf_planes = 1;
|
|
ctx->amlge2d.ge2dinfo.src_info[0].shared_fd[0] = -1;
|
|
VLOG(INFO,"Set DMA buffer index %d planes %d fd[%d]\n", idx, ctx->pFbSrc[idx].dma_buf_planes,
|
|
ctx->pFbSrc[idx].dma_shared_fd[0]);
|
|
} else
|
|
#endif
|
|
{
|
|
ctx->pFbSrc[idx].dma_buf_planes = input->num_planes;
|
|
ctx->pFbSrc[idx].dma_shared_fd[0] = input->shared_fd[0];
|
|
ctx->pFbSrc[idx].dma_shared_fd[1] = input->shared_fd[1];
|
|
ctx->pFbSrc[idx].dma_shared_fd[2] = input->shared_fd[2];
|
|
VLOG(INFO,"Set DMA buffer index %d planes %d fd[%d, %d, %d]\n", idx, input->num_planes,
|
|
input->shared_fd[0], input->shared_fd[1], input->shared_fd[2]);
|
|
}
|
|
}
|
|
ctx->FrameIO[idx] = *input;
|
|
ctx->encodedSrcFrmIdxArr[idx] = 1; // occupic the frames.
|
|
ctx->encMEMSrcFrmIdxArr[param->srcIdx] = idx; //indirect link due to reodering. srcIdx increase linear.
|
|
ctx->pFbSrc[idx].stride = src_stride * (ctx->encOpenParam.srcBitDepth == 10 ? 2 : 1); /**< A horizontal stride for given frame buffer */
|
|
ctx->pFbSrc[idx].height = input->height; /**< A height for given frame buffer */
|
|
|
|
VLOG(INFO, "Assign src buffer,input idx %d poolidx %d stride %d \n",param->srcIdx, idx, src_stride);
|
|
if (ctx->bsBuffer[idx].size == 0) { // allocate buffer
|
|
ctx->bsBuffer[idx].size = ctx->bsBuffer[0].size; //ENC_STREAM_BUF_SIZE;
|
|
if (vdi_allocate_dma_memory(ctx->encOpenParam.coreIdx, &ctx->bsBuffer[idx], ENC_BS, 0) < 0) {
|
|
VLOG(ERR, "fail to allocate bitstream buffer\n");
|
|
ctx->bsBuffer[idx].size = 0;
|
|
ctx->encodedSrcFrmIdxArr[idx] = 0;
|
|
return AMVENC_FAIL;
|
|
}
|
|
}
|
|
|
|
//hoan add for canvas
|
|
ctx->pFbSrc[idx].canvas_index = input->canvas;
|
|
VLOG(NONE, "[canvas_u] >> input->canvas = 0x%x.\n", input->canvas);
|
|
//end
|
|
param->canvas = input->canvas;
|
|
param->sourceFrame = &ctx->pFbSrc[idx];
|
|
param->picStreamBufferAddr = ctx->bsBuffer[idx].phys_addr;
|
|
param->picStreamBufferSize = ctx->bsBuffer[idx].size;
|
|
|
|
VLOG(INFO, "Assign stream buffer, idx %d address 0x%x size %d\n",
|
|
idx, param->picStreamBufferAddr, param->picStreamBufferSize);
|
|
|
|
// param->srcIdx = param->srcIdx;
|
|
param->srcEndFlag = 0; //in->last;
|
|
// encParam->sourceFrame = &in->fb;
|
|
param->sourceFrame->sourceLBurstEn = 0;
|
|
|
|
if (ctx->op_flag & AMVEncFrameIO_FORCE_SKIP_FLAG) {
|
|
param->skipPicture = 1;
|
|
} else {
|
|
param->skipPicture = 0;
|
|
}
|
|
|
|
param->forceAllCtuCoefDropEnable = 0;
|
|
|
|
param->forcePicQpEnable = ctx->mInitParams.forcePicQpEnable;
|
|
param->forcePicQpI = ctx->mInitParams.forcePicQpI;
|
|
param->forcePicQpP = ctx->mInitParams.forcePicQpP;
|
|
param->forcePicQpB = ctx->mInitParams.forcePicQpB;
|
|
|
|
if (ctx->op_flag & AMVEncFrameIO_FORCE_IDR_FLAG) {
|
|
param->forcePicTypeEnable = 1;
|
|
param->forcePicType = 3; // 0 for I frame. 3 for IDR
|
|
} else {
|
|
param->forcePicTypeEnable = 0;
|
|
param->forcePicType = 0;
|
|
}
|
|
if (ctx->op_flag & AMVEncFrameIO_USE_AS_LTR_FLAG) {
|
|
VLOG(INFO, "Update seCurSrcAsLongtermPic\n");
|
|
param->useCurSrcAsLongtermPic = 1;
|
|
} else {
|
|
param->useCurSrcAsLongtermPic = 0;
|
|
}
|
|
if (ctx->op_flag & AMVEncFrameIO_USE_LTR_FLAG) {
|
|
VLOG(INFO, "Update useLongtermRef\n");
|
|
param->useLongtermRef = 1;
|
|
} else {
|
|
param->useLongtermRef = 0;
|
|
}
|
|
// FW will encode header data implicitly when changing the header syntaxes
|
|
param->codeOption.implicitHeaderEncode = 1;
|
|
param->codeOption.encodeAUD = 0;
|
|
param->codeOption.encodeEOS = 0;
|
|
param->codeOption.encodeEOB = 0;
|
|
|
|
// set custom map param
|
|
param->customMapOpt.customLambdaMapEnable = ctx->mInitParams.lambda_map_enable;
|
|
param->customMapOpt.customModeMapEnable = ctx->mInitParams.mode_map_enable & 0x1;
|
|
param->customMapOpt.customCoefDropEnable = (ctx->mInitParams.mode_map_enable & 0x2) >> 1;
|
|
param->customMapOpt.customRoiMapEnable = ctx->mInitParams.roi_enable;
|
|
|
|
if (param->customMapOpt.customRoiMapEnable
|
|
|| param->customMapOpt.customLambdaMapEnable
|
|
|| param->customMapOpt.customModeMapEnable
|
|
|| param->customMapOpt.customCoefDropEnable) {
|
|
|
|
if (ctx->CustomMapUpdatedId[idx] != ctx->CustomUpdateID) {
|
|
// the custom map changed refresh the data
|
|
// packaging roi/lambda/mode data to custom map buffer
|
|
ctx->CustomMapUpdatedId[idx] = ctx->CustomUpdateID;
|
|
SetCustMapData(ctx, param, ctx->vbCustomMap[idx].phys_addr);
|
|
VLOG(INFO, "ROI updted buffer addr %x \n",
|
|
param->customMapOpt.addrCustomMap);
|
|
} else {
|
|
param->customMapOpt.addrCustomMap = ctx->vbCustomMap[idx].phys_addr;
|
|
VLOG(INFO, "ROI no updte use old buffer addr %x \n",
|
|
param->customMapOpt.addrCustomMap);
|
|
}
|
|
}
|
|
|
|
// weighted prediction
|
|
if ((ctx->mInitParams.weight_pred_enable & 0x1)) {
|
|
Uint32 meanY, meanCb, meanCr, sigmaY, sigmaCb, sigmaCr;
|
|
Uint32 maxMean = (ctx->encOpenParam.bitstreamFormat == STD_AVC) ? 0xffff :
|
|
((1 << ctx->encOpenParam.EncStdParam.vpParam.internalBitDepth) - 1);
|
|
Uint32 maxSigma = (ctx->encOpenParam.bitstreamFormat == STD_AVC) ? 0xffff :
|
|
((1 << (ctx->encOpenParam.EncStdParam.vpParam.internalBitDepth + 6)) - 1);
|
|
|
|
meanY = ctx->wp_para.CustMeanY;
|
|
meanCb = ctx->wp_para.CustMeadCb;
|
|
meanCr = ctx->wp_para.CustMeadCr;
|
|
sigmaY = ctx->wp_para.CustSigmaY;
|
|
sigmaCb = ctx->wp_para.CustSigmaCb;
|
|
sigmaCr = ctx->wp_para.CustSigmaCr;
|
|
|
|
meanY = max(min(maxMean, meanY), 0);
|
|
meanCb = max(min(maxMean, meanCb), 0);
|
|
meanCr = max(min(maxMean, meanCr), 0);
|
|
sigmaY = max(min(maxSigma, sigmaY), 0);
|
|
sigmaCb = max(min(maxSigma, sigmaCb), 0);
|
|
sigmaCr = max(min(maxSigma, sigmaCr), 0);
|
|
|
|
// set weighted prediction param.
|
|
param->wpPixSigmaY = sigmaY;
|
|
param->wpPixSigmaCb = sigmaCb;
|
|
param->wpPixSigmaCr = sigmaCr;
|
|
param->wpPixMeanY = meanY;
|
|
param->wpPixMeanCb = meanCb;
|
|
param->wpPixMeanCr = meanCr;
|
|
}
|
|
|
|
return AMVENC_SUCCESS;
|
|
}
|
|
|
|
|
|
AMVEnc_Status AML_MultiEncUpdateRoi(amv_enc_handle_t ctx_handle,
|
|
unsigned char* buffer,
|
|
int size)
|
|
{
|
|
int required_size;
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
VLOG(INFO, "Update Roi table update cur update ID %d size %d\n",
|
|
ctx->CustomUpdateID, size);
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC)
|
|
return AMVENC_FAIL;
|
|
if (ctx->mInitParams.roi_enable == 0)
|
|
return AMVENC_FAIL;
|
|
if (ctx->encOpenParam.bitstreamFormat == STD_AVC)
|
|
required_size = ((ctx->enc_width + 15)/16)*((ctx->enc_height + 15)/16);
|
|
else //HEVC
|
|
required_size = ((ctx->enc_width + 31)/32)*((ctx->enc_height + 31)/32);
|
|
VLOG(INFO, "Update Roi table update cur update ID %d size %d required %d \n",
|
|
ctx->CustomUpdateID, size, required_size);
|
|
if (size < required_size)
|
|
return AMVENC_FAIL;
|
|
memcpy(ctx->CustomRoiMapBuf, buffer, required_size);
|
|
ctx->CustomUpdateID ++;
|
|
if (ctx->CustomUpdateID > 256) ctx->CustomUpdateID = 1;
|
|
return AMVENC_SUCCESS;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncChangeBitRate(amv_enc_handle_t ctx_handle,
|
|
int BitRate)
|
|
{
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
EncChangeParam *ChgParam;
|
|
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC)
|
|
return AMVENC_FAIL;
|
|
if (ctx->mInitParams.param_change_enable == 0)
|
|
return AMVENC_FAIL;
|
|
VLOG(INFO, "Change bit rate to %d Count %d\n", BitRate, ctx->changedCount);
|
|
|
|
ChgParam = &ctx->changeParam;
|
|
|
|
ChgParam->bitRate = BitRate;
|
|
ChgParam->enable_option |= ENC_SET_CHANGE_PARAM_RC_TARGET_RATE;
|
|
ctx->param_change_flag ++;
|
|
|
|
return AMVENC_SUCCESS;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncChangeFrameRate(amv_enc_handle_t ctx_handle,
|
|
int FrameRate,int BitRate)
|
|
{
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
EncChangeParam *ChgParam;
|
|
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC)
|
|
return AMVENC_FAIL;
|
|
if (ctx->mInitParams.param_change_enable == 0)
|
|
return AMVENC_FAIL;
|
|
VLOG(INFO, "Change frame rate to %d Count %d\n", FrameRate, ctx->changedCount);
|
|
|
|
ChgParam = &ctx->changeParam;
|
|
|
|
ChgParam->frameRate = FrameRate;
|
|
ChgParam->bitRate = BitRate * ctx->encOpenParam.frameRateInfo / FrameRate;
|
|
|
|
ChgParam->enable_option |= ENC_SET_CHANGE_PARAM_RC_TARGET_RATE;
|
|
ctx->param_change_flag ++;
|
|
|
|
return AMVENC_SUCCESS;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncChangeQPMinMax(amv_enc_handle_t ctx_handle,
|
|
int minQpI, int maxQpI, int maxDeltaQp,
|
|
int minQpP, int maxQpP,
|
|
int minQpB, int maxQpB)
|
|
{
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
EncChangeParam *ChgParam;
|
|
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC)
|
|
return AMVENC_FAIL;
|
|
if (ctx->mInitParams.param_change_enable == 0)
|
|
return AMVENC_FAIL;
|
|
|
|
VLOG(INFO, "Change MinMax QP Count %d to I:%d-%d delta %d P:%d-%d B:%d-%d\n",
|
|
ctx->changedCount, minQpI, maxQpI, maxDeltaQp,
|
|
minQpP, maxQpP, minQpB, maxQpB);
|
|
|
|
ChgParam = &ctx->changeParam;
|
|
|
|
ChgParam->minQpI = minQpI;
|
|
ChgParam->maxQpI = maxQpI;
|
|
ChgParam->hvsMaxDeltaQp = maxDeltaQp;
|
|
ChgParam->minQpP = minQpP;
|
|
ChgParam->maxQpP = maxQpP;
|
|
ChgParam->minQpB = minQpB;
|
|
ChgParam->maxQpB = maxQpB;
|
|
ChgParam->enable_option |= ENC_SET_CHANGE_PARAM_RC_MIN_MAX_QP;
|
|
ChgParam->enable_option |= ENC_SET_CHANGE_PARAM_RC_INTER_MIN_MAX_QP;
|
|
ctx->param_change_flag ++;
|
|
|
|
return AMVENC_SUCCESS;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncChangeIntraPeriod(amv_enc_handle_t ctx_handle,
|
|
int IntraQP, int IntraPeriod)
|
|
{
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
EncChangeParam *ChgParam;
|
|
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC)
|
|
return AMVENC_FAIL;
|
|
if (ctx->mInitParams.param_change_enable == 0)
|
|
return AMVENC_FAIL;
|
|
|
|
VLOG(INFO, "Change IntraPeriod to %d, intraQP %d, count %d\n",
|
|
IntraPeriod, IntraQP, ctx->changedCount);
|
|
|
|
ChgParam = &ctx->changeParam;
|
|
|
|
ChgParam->intraQP = IntraQP;
|
|
ChgParam->intraPeriod = IntraPeriod;
|
|
if (ctx->encOpenParam.bitstreamFormat == STD_AVC)
|
|
ChgParam->avcIdrPeriod = IntraPeriod;
|
|
else
|
|
ChgParam->avcIdrPeriod = 0;
|
|
|
|
ChgParam->enable_option |= ENC_SET_CHANGE_PARAM_INTRA_PARAM;
|
|
ctx->param_change_flag ++;
|
|
|
|
return AMVENC_SUCCESS;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncChangeMutiSlice(amv_enc_handle_t ctx_handle,
|
|
int multi_slice_mode, int multi_slice_para)
|
|
{
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
EncChangeParam *ChgParam;
|
|
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC)
|
|
return AMVENC_FAIL;
|
|
if (ctx->mInitParams.param_change_enable == 0)
|
|
return AMVENC_FAIL;
|
|
|
|
VLOG(INFO, "Change Multislice to mode %d, para %d, count %d\n",
|
|
multi_slice_mode, multi_slice_para, ctx->changedCount);
|
|
|
|
ChgParam = &ctx->changeParam;
|
|
|
|
if (ctx->encOpenParam.bitstreamFormat == STD_AVC) {
|
|
if (multi_slice_mode < 0 || multi_slice_mode >1)
|
|
return AMVENC_FAIL;
|
|
ChgParam->avcSliceMode = multi_slice_mode;
|
|
ChgParam->avcSliceArg = multi_slice_para;
|
|
} else { //HEVC
|
|
if (multi_slice_mode < 0 || multi_slice_mode >2)
|
|
return AMVENC_FAIL;
|
|
if (multi_slice_mode == 2) {
|
|
ChgParam->dependSliceMode = multi_slice_mode;
|
|
ChgParam->dependSliceModeArg = (multi_slice_para>>16) & 0xffff;
|
|
ChgParam->independSliceMode = 1;
|
|
} else {
|
|
ChgParam->dependSliceMode = 0;
|
|
ChgParam->dependSliceModeArg = 0;
|
|
ChgParam->independSliceMode = multi_slice_mode;
|
|
}
|
|
ChgParam->enable_option |= ENC_SET_CHANGE_PARAM_DEPEND_SLICE;
|
|
ChgParam->independSliceModeArg = multi_slice_para & 0xffff;
|
|
}
|
|
ChgParam->enable_option |= ENC_SET_CHANGE_PARAM_INDEPEND_SLICE;
|
|
ctx->param_change_flag ++;
|
|
|
|
return AMVENC_SUCCESS;
|
|
}
|
|
|
|
|
|
AMVEnc_Status AML_MultiEncHeader(amv_enc_handle_t ctx_handle,
|
|
unsigned char* buffer,
|
|
unsigned int* buf_nal_size)
|
|
{
|
|
EncHeaderParam encHeaderParam;
|
|
EncOutputInfo encOutputInfo;
|
|
QueueStatusInfo queueStatus;
|
|
ENC_INT_STATUS status;
|
|
PhysicalAddress paRdPtr = 0;
|
|
PhysicalAddress paWrPtr = 0;
|
|
int header_size = 0;
|
|
int retry = 0;
|
|
RetCode result= RETCODE_SUCCESS;
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
ENC_QUERY_WRPTR_SEL encWrPtrSel = GET_ENC_PIC_DONE_WRPTR;
|
|
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC) return AMVENC_FAIL;
|
|
//EncHandle handle = ctx->enchandle;
|
|
memset(&encHeaderParam, 0x00, sizeof(EncHeaderParam));
|
|
|
|
/*Just reuse bitstream buffer or allocat a new one*/
|
|
encHeaderParam.buf = ctx->bsBuffer[0].phys_addr;
|
|
encHeaderParam.size = ctx->bsBuffer[0].size;
|
|
|
|
|
|
if (ctx->encOpenParam.bitstreamFormat == STD_HEVC) {
|
|
encHeaderParam.headerType = CODEOPT_ENC_VPS | CODEOPT_ENC_SPS | CODEOPT_ENC_PPS;
|
|
}
|
|
else {
|
|
// H.264
|
|
encHeaderParam.headerType = CODEOPT_ENC_SPS | CODEOPT_ENC_PPS;
|
|
}
|
|
|
|
#if ENCODE_TIME_STATISTICS
|
|
gettimeofday(&start_test, NULL);
|
|
#endif
|
|
|
|
retry_point:
|
|
result = VPU_EncGiveCommand(ctx->enchandle, ENC_PUT_VIDEO_HEADER, &encHeaderParam);
|
|
if (result != RETCODE_SUCCESS) {
|
|
retry ++;
|
|
if (result == RETCODE_QUEUEING_FAILURE ) {
|
|
VLOG(DEBUG, "Instance %d HEADER Queue fail\n",
|
|
ctx->enchandle->instIndex);
|
|
|
|
} else {
|
|
VLOG(ERR, "HEADER fail instance %d reason %d\n",
|
|
ctx->enchandle->instIndex, result);
|
|
}
|
|
if (retry > 100)
|
|
{
|
|
VLOG(ERR, "INSTANCE #%d HEADER retry failed\n", ctx->enchandle->instIndex);
|
|
HandleEncoderError(ctx->enchandle, ctx->frameIdx, NULL);
|
|
return AMVENC_TIMEOUT;
|
|
}
|
|
usleep(1000);
|
|
goto retry_point;
|
|
}
|
|
while (1) {
|
|
// wait interrupt */
|
|
if ((status = HandlingInterruptFlag(ctx)) == ENC_INT_STATUS_DONE) {
|
|
break;
|
|
}
|
|
else if (status == ENC_INT_STATUS_NONE) { // no interrupt yet
|
|
Uint32 intr_usr = 0;
|
|
VPU_CheckInterrupt(ctx->enchandle, &intr_usr);
|
|
VLOG(DEBUG, "Check interrupt status inst #%d retry %d result %d\n",
|
|
ctx->enchandle->instIndex, retry, intr_usr);
|
|
if (intr_usr) {
|
|
VLOG(DEBUG, "Check and cleared interrupt inst #%d go ahead\n",
|
|
ctx->enchandle->instIndex);
|
|
break;
|
|
}
|
|
VLOG(DEBUG, "INSTANCE #%d INT timeout \n", ctx->enchandle->instIndex);
|
|
VPU_EncGiveCommand(ctx->enchandle, ENC_GET_QUEUE_STATUS, &queueStatus);
|
|
VLOG(DEBUG, "INSTANCE #%d queuedCmd %d allQueued %d \n",
|
|
ctx->enchandle->instIndex, queueStatus.instanceQueueCount,
|
|
queueStatus.reportQueueCount);
|
|
retry++;
|
|
if (retry > 20) break;
|
|
}
|
|
else if (status == ENC_INT_STATUS_TIMEOUT) {
|
|
if (retry++ < 20) break;
|
|
VLOG(ERR, "INSTANCE #%d INTERRUPT TIMEOUT\n", ctx->enchandle->instIndex);
|
|
HandleEncoderError(ctx->enchandle, ctx->frameIdx, NULL);
|
|
VPU_SWReset(ctx->encOpenParam.coreIdx, SW_RESET_SAFETY, ctx->enchandle);
|
|
return AMVENC_TIMEOUT;
|
|
} else {
|
|
VLOG(ERR, "Unknown interrupt status: %d\n",status);
|
|
return AMVENC_FAIL;
|
|
}
|
|
usleep(1000); //osal_msleep(1);
|
|
}
|
|
|
|
if (retry) {
|
|
VLOG(DEBUG, "INSTANCE #%d Possible INT lost rety %d\n",
|
|
ctx->enchandle->instIndex, retry);
|
|
}
|
|
|
|
DisplayEncodedInformation(ctx->enchandle, ctx->encOpenParam.bitstreamFormat, 0, NULL, 0, 0, 1);
|
|
|
|
VPU_EncGiveCommand(ctx->enchandle, ENC_WRPTR_SEL, &encWrPtrSel);
|
|
encOutputInfo.result = VPU_EncGetOutputInfo(ctx->enchandle, &encOutputInfo);
|
|
|
|
if (encOutputInfo.result == RETCODE_REPORT_NOT_READY) {
|
|
VPU_EncGiveCommand(ctx->enchandle, ENC_GET_QUEUE_STATUS, &queueStatus);
|
|
VLOG(DEBUG, "HEADER encode ready queue = %d %d\n",
|
|
queueStatus.instanceQueueCount, queueStatus.reportQueueCount);
|
|
if (retry++ < 100)
|
|
{
|
|
VLOG(DEBUG, "HEADER NO command in queue, retry\n");
|
|
goto retry_point;
|
|
} else {
|
|
VLOG(DEBUG, "HEADER retry FAILED\n");
|
|
return AMVENC_SPS_FAIL; /* Not encoded yet */
|
|
}
|
|
}
|
|
else if (encOutputInfo.result == RETCODE_VLC_BUF_FULL) {
|
|
VLOG(ERR, "VLC BUFFER FULL!!! ALLOCATE MORE TASK BUFFER(%d)!!!\n", ONE_TASKBUF_SIZE_FOR_CQ);
|
|
}
|
|
else if (encOutputInfo.result != RETCODE_SUCCESS) {
|
|
/* ERROR */
|
|
VLOG(ERR, "Failed to encode error = %d\n", encOutputInfo.result);
|
|
if ( retry++ >100) {
|
|
VLOG(ERR, "HEADER RETRY failed reset\n");
|
|
HandleEncoderError(ctx->enchandle, encOutputInfo.encPicCnt, &encOutputInfo);
|
|
VPU_SWReset(ctx->encOpenParam.coreIdx, SW_RESET_SAFETY, ctx->enchandle);
|
|
return AMVENC_SPS_FAIL;
|
|
}
|
|
goto retry_point;
|
|
}
|
|
else {
|
|
if (retry) {
|
|
VLOG(DEBUG, "INSTANCE #%d INT lost recovered %d\n",
|
|
ctx->enchandle->instIndex, retry);
|
|
};/* SUCCESS */
|
|
}
|
|
paRdPtr = encOutputInfo.rdPtr;
|
|
paWrPtr = encOutputInfo.wrPtr;
|
|
header_size = encOutputInfo.bitstreamSize;
|
|
VLOG(DEBUG, "header_size %d paWrPtr-paRdPtr %d", header_size, paWrPtr-paRdPtr);
|
|
if (paRdPtr != ctx->bsBuffer[0].phys_addr) {
|
|
VLOG(ERR, "BS buffer no match!! expect %x acutual %x size %d\n",
|
|
ctx->bsBuffer[0].phys_addr, paRdPtr, header_size);
|
|
}
|
|
|
|
#if ENCODE_TIME_STATISTICS
|
|
gettimeofday(&end_test, NULL);
|
|
encode_time_per_frame = end_test.tv_sec - start_test.tv_sec;
|
|
encode_time_per_frame = encode_time_per_frame * 1000000 + end_test.tv_usec - start_test.tv_usec;
|
|
total_encode_frames++;
|
|
total_encode_time += encode_time_per_frame;
|
|
VLOG(WARN, "%p#Encode header spent time : %lu us, frame_number : %llu",
|
|
ctx_handle, encode_time_per_frame, total_encode_frames);
|
|
#endif
|
|
|
|
VLOG(INFO, "Enc HEADER size %d\n",header_size);
|
|
*buf_nal_size = header_size;
|
|
// cache invalid to read out by CPU
|
|
//vdi_invalitate_memory(ctx->encOpenParam.coreIdx, &ctx->bsBuffer[0]);
|
|
vdi_read_memory(ctx->encOpenParam.coreIdx,
|
|
ctx->bsBuffer[0].phys_addr, buffer, header_size,
|
|
ctx->encOpenParam.streamEndian);
|
|
|
|
return AMVENC_SUCCESS;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncGetAvgQp(amv_enc_handle_t ctx_handle, int *avgqp) {
|
|
AMVEnc_Status ret = AMVENC_FAIL;
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
|
|
if (ctx->averageQP) {
|
|
*avgqp = ctx->averageQP;
|
|
ret = AMVENC_SUCCESS;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncNAL(amv_enc_handle_t ctx_handle,
|
|
unsigned char* buffer,
|
|
unsigned int* buf_nal_size,
|
|
AMVMultiEncFrameIO *Retframe) {
|
|
RetCode result;
|
|
EncParam* encParam;
|
|
EncVpParam* VpParam;
|
|
EncOutputInfo encOutputInfo;
|
|
ENC_INT_STATUS intStatus;
|
|
ENC_QUERY_WRPTR_SEL encWrPtrSel = GET_ENC_PIC_DONE_WRPTR;
|
|
int retry_cnt = 0;
|
|
int idx;
|
|
QueueStatusInfo qStatus;
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
if (ctx == NULL) return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC) return AMVENC_FAIL;
|
|
|
|
ctx->mNumInputFrames++;
|
|
VpParam = &ctx->encOpenParam.EncStdParam.vpParam;
|
|
|
|
#if ENCODE_TIME_STATISTICS
|
|
gettimeofday(&start_test, NULL);
|
|
#endif
|
|
|
|
retry_point:
|
|
if (VpParam->QpModify) {
|
|
ctx->param_change_flag = 1;
|
|
ctx->changeParam.enable_option |= ENC_SET_CHANGE_PARAM_RC_MIN_MAX_QP;
|
|
ctx->changeParam.enable_option |= ENC_SET_CHANGE_PARAM_RC_INTER_MIN_MAX_QP;
|
|
ctx->changeParam.intraPeriod = VpParam->intraPeriod;
|
|
ctx->changeParam.pic_type = ctx->pic_type;
|
|
if ((ctx->mNumInputFrames % ctx->changeParam.intraPeriod == 1) || ctx->changeParam.pic_type == 3) {
|
|
ctx->changeParam.maxQpI = VpParam->maxQpI;
|
|
ctx->changeParam.maxQpP = VpParam->maxQpP;
|
|
ctx->changeParam.hvsMaxDeltaQp = VpParam->hvsMaxDeltaQp;
|
|
}
|
|
else {
|
|
ctx->changeParam.maxQpI = VpParam->maxQpP;
|
|
ctx->changeParam.maxQpP = VpParam->maxQpP;
|
|
ctx->changeParam.hvsMaxDeltaQp = VpParam->hvsMaxDeltaQp;
|
|
}
|
|
}
|
|
if(ctx ->param_change_flag) {
|
|
result = VPU_EncGiveCommand(ctx->enchandle, ENC_SET_PARA_CHANGE, &ctx->changeParam);
|
|
if (result == RETCODE_SUCCESS) {
|
|
VLOG(INFO, "ENC_SET_PARA_CHANGE queue success option 0x%x\n",
|
|
ctx->changeParam.enable_option);
|
|
|
|
if (VPU_EncInstParamSync(ctx->enchandle,0,0,&ctx->changeParam) != RETCODE_SUCCESS) {
|
|
VLOG(ERR, "VPU instance param sync with change param failed!\n");
|
|
}
|
|
|
|
osal_memset(&ctx->changeParam, 0x00, sizeof(EncChangeParam));
|
|
ctx->param_change_flag = 0;
|
|
ctx->changedCount ++;
|
|
}
|
|
else if (result == RETCODE_QUEUEING_FAILURE) { // Just retry
|
|
VLOG(INFO, "ENC_SET_PARA_CHANGE Queue Full\n");
|
|
goto retry_point;
|
|
}
|
|
else { // Error
|
|
VLOG(ERR, "ENC_SET_PARA_CHANGE failed Error code is 0x%x \n", result);
|
|
ChekcAndPrintDebugInfo(ctx->enchandle, TRUE, result);
|
|
return AMVENC_FAIL;
|
|
}
|
|
|
|
}
|
|
encParam = &ctx->encParam;
|
|
|
|
result = VPU_EncStartOneFrame(ctx->enchandle, encParam);
|
|
if (result == RETCODE_SUCCESS) {
|
|
ctx->frameIdx++;
|
|
encParam -> srcIdx++;
|
|
if(encParam -> srcIdx >= ctx->src_num) encParam -> srcIdx = 0;
|
|
VLOG(INFO, "VPU_EncStartOneFrame sucesss frameIdx %d srcIdx %d \n", ctx->frameIdx, encParam -> srcIdx);
|
|
}
|
|
else if (result == RETCODE_QUEUEING_FAILURE) { // Just retry
|
|
VLOG(ERR, "VPU_EncStartOneFrame retry code is 0x%x \n", result);
|
|
// Just retry
|
|
VPU_EncGiveCommand(ctx->enchandle, ENC_GET_QUEUE_STATUS, (void*)&qStatus);
|
|
if (qStatus.instanceQueueCount == 0) {
|
|
VLOG(ERR, "<%s:%d> The queue is empty but it can't add a command\n", __FUNCTION__, __LINE__);
|
|
goto retry_point;//return TRUE;
|
|
}
|
|
}
|
|
else { // Error
|
|
VLOG(ERR, "VPU_EncStartOneFrame failed Error code is 0x%x \n", result);
|
|
ChekcAndPrintDebugInfo(ctx->enchandle, TRUE, result);
|
|
idx = ctx->encMEMSrcFrmIdxArr[encParam->srcIdx];
|
|
ctx->encodedSrcFrmIdxArr[idx] = 0; //free slot as failed to start
|
|
return AMVENC_FAIL;
|
|
}
|
|
|
|
retry_pointB:
|
|
while (retry_cnt++ < 100) {
|
|
if ((intStatus=HandlingInterruptFlag(ctx)) == ENC_INT_STATUS_TIMEOUT) {
|
|
VPU_SWReset(ctx->encOpenParam.coreIdx, SW_RESET_SAFETY, ctx->enchandle);
|
|
VLOG(ERR, "Timeout of encoder interrupt reset \n");
|
|
return AMVENC_FAIL;
|
|
}
|
|
else if (intStatus == ENC_INT_STATUS_FULL || intStatus == ENC_INT_STATUS_LOW_LATENCY) {
|
|
PhysicalAddress paRdPtr;
|
|
PhysicalAddress paWrPtr;
|
|
int size;
|
|
encWrPtrSel = (intStatus==ENC_INT_STATUS_FULL) ? GET_ENC_BSBUF_FULL_WRPTR : GET_ENC_LOW_LATENCY_WRPTR;
|
|
VPU_EncGiveCommand(ctx->enchandle, ENC_WRPTR_SEL, &encWrPtrSel);
|
|
VPU_EncGetBitstreamBuffer(ctx->enchandle, &paRdPtr, &paWrPtr, &size);
|
|
VLOG(TRACE, "INT_BSBUF_FULL %d, %d\n", paRdPtr, paWrPtr);
|
|
ctx->fullInterrupt = TRUE;
|
|
return AMVENC_FAIL; //return TRUE;
|
|
}
|
|
else if (intStatus == ENC_INT_STATUS_NONE) {
|
|
Uint32 intr_usr = 0;
|
|
VPU_CheckInterrupt(ctx->enchandle, &intr_usr);
|
|
VLOG(DEBUG, "Check interrupt status inst #%d retry %d result %d\n",
|
|
ctx->enchandle->instIndex, retry_cnt, intr_usr);
|
|
if (intr_usr) {
|
|
VLOG(DEBUG, "Check and cleared interrupt inst #%d go ahead\n",
|
|
ctx->enchandle->instIndex);
|
|
break;
|
|
}
|
|
usleep(1000); //osal_msleep(1);
|
|
}
|
|
else if (intStatus == ENC_INT_STATUS_DONE) break; //success get done intr
|
|
}
|
|
// get the interrupt
|
|
// get result andc output */
|
|
VPU_EncGiveCommand(ctx->enchandle, ENC_WRPTR_SEL, &encWrPtrSel);
|
|
osal_memset(&encOutputInfo, 0x00, sizeof(EncOutputInfo));
|
|
encOutputInfo.result = VPU_EncGetOutputInfo(ctx->enchandle, &encOutputInfo);
|
|
if (encOutputInfo.result == RETCODE_REPORT_NOT_READY) {
|
|
VLOG(ERR, "no encode yet !!!\n");
|
|
return AMVENC_FAIL; //return TRUE; /* Not encoded yet */
|
|
}
|
|
else if (encOutputInfo.result == RETCODE_VLC_BUF_FULL) {
|
|
VLOG(ERR, "VLC BUFFER FULL!!! ALLOCATE MORE TASK BUFFER(%d)!!!\n", ONE_TASKBUF_SIZE_FOR_CQ);
|
|
}
|
|
else if (encOutputInfo.result != RETCODE_SUCCESS) {
|
|
/* ERROR */
|
|
VLOG(ERR, "Failed to encode error = %d 0x%x\n", encOutputInfo.result, encOutputInfo.errorReason);
|
|
ChekcAndPrintDebugInfo(ctx->enchandle, TRUE, encOutputInfo.result);
|
|
HandleEncoderError(ctx->enchandle, encOutputInfo.encPicCnt, &encOutputInfo);
|
|
VPU_SWReset(ctx->encOpenParam.coreIdx, SW_RESET_SAFETY, ctx->enchandle);
|
|
return AMVENC_FAIL;
|
|
}
|
|
else {
|
|
;/* SUCCESS */
|
|
VLOG(INFO, "Success one = %d\n", encOutputInfo.result);
|
|
}
|
|
ctx->averageQP = encOutputInfo.avgCtuQp;
|
|
|
|
if (encOutputInfo.reconFrameIndex == RECON_IDX_FLAG_CHANGE_PARAM) {
|
|
VLOG(INFO, "CHANGE PARAMETER!\n");
|
|
retry_cnt = 0;
|
|
goto retry_pointB; //return TRUE; /* Try again */
|
|
}
|
|
else if (encOutputInfo.reconFrameIndex == RECON_IDX_FLAG_HEADER_ONLY) {
|
|
VLOG(INFO, "Only have encoded headers !\n");
|
|
retry_cnt = 0;
|
|
goto retry_pointB; //return TRUE; /* Try again */
|
|
}
|
|
else {
|
|
// out put frame info
|
|
DisplayEncodedInformation(ctx->enchandle,
|
|
ctx->encOpenParam.bitstreamFormat,
|
|
ctx->frameIdx, &encOutputInfo,
|
|
encParam->srcEndFlag,
|
|
encParam->srcIdx,
|
|
1);
|
|
}
|
|
|
|
if ( encOutputInfo.result != RETCODE_SUCCESS ) {
|
|
VLOG(ERR, "output info result error \n");
|
|
return AMVENC_FAIL;
|
|
}
|
|
|
|
VLOG(INFO, "encOutputInfo.encSrcIdx %d reconFrameIndex %d \n",
|
|
encOutputInfo.encSrcIdx, encOutputInfo.reconFrameIndex);
|
|
if (encOutputInfo.reconFrameIndex == RECON_IDX_FLAG_CHANGE_PARAM) {
|
|
VLOG(ERR, "CHANGE PARAMETER!\n");
|
|
// return TRUE; /* Try again */
|
|
}
|
|
if (encOutputInfo.reconFrameIndex == RECON_IDX_FLAG_HEADER_ONLY) {
|
|
VLOG(ERR, "ENCODED HEADER ONLY!\n");
|
|
}
|
|
|
|
#if 0 //release flag
|
|
for (i = 0; i < ctx->fbCount.srcFbNum; i++) {
|
|
if ( (encOutputInfo.releaseSrcFlag >> i) & 0x01) {
|
|
ctx->encodedSrcFrmIdxArr[i] = 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( encOutputInfo.encSrcIdx >= 0) {
|
|
idx = ctx->encMEMSrcFrmIdxArr[encOutputInfo.encSrcIdx];
|
|
ctx->encodedSrcFrmIdxArr[idx] = 0;
|
|
ctx->fullInterrupt = FALSE;
|
|
// copy frames
|
|
|
|
VLOG(INFO, "Enc bitstream size %d pic_type %d avgQP %d\n",
|
|
encOutputInfo.bitstreamSize, encOutputInfo.picType,
|
|
encOutputInfo.avgCtuQp);
|
|
*buf_nal_size = encOutputInfo.bitstreamSize;
|
|
vdi_read_memory(ctx->encOpenParam.coreIdx,
|
|
encOutputInfo.bitstreamBuffer,
|
|
buffer, encOutputInfo.bitstreamSize,
|
|
ctx->encOpenParam.streamEndian);
|
|
|
|
*Retframe= ctx->FrameIO[idx];
|
|
Retframe->encoded_frame_type = encOutputInfo.picType;
|
|
Retframe->enc_average_qp = encOutputInfo.avgCtuQp;
|
|
Retframe->enc_intra_blocks = encOutputInfo.numOfIntra;
|
|
Retframe->enc_merged_blocks = encOutputInfo.numOfMerge;
|
|
Retframe->enc_skipped_blocks = encOutputInfo.numOfSkipBlock;
|
|
|
|
} else if ( encOutputInfo.encSrcIdx == 0xfffffffe) {
|
|
VLOG(INFO, "delay frame delay %d \n", ctx->frame_delay);
|
|
ctx->frame_delay ++;
|
|
*buf_nal_size = 0;
|
|
Retframe ->YCbCr[0] = 0;
|
|
} else if (encOutputInfo.encSrcIdx == 0xfffffffb) {
|
|
VLOG(INFO, "non-reference picture !! \n");
|
|
*buf_nal_size = 0;
|
|
Retframe->YCbCr[0] = 0;
|
|
}
|
|
|
|
#if ENCODE_TIME_STATISTICS
|
|
gettimeofday(&end_test, NULL);
|
|
encode_time_per_frame = end_test.tv_sec - start_test.tv_sec;
|
|
encode_time_per_frame = encode_time_per_frame * 1000000 + end_test.tv_usec - start_test.tv_usec;
|
|
total_encode_frames++;
|
|
total_encode_time += encode_time_per_frame;
|
|
VLOG(WARN, "%p#Encode slice time : %lu us, frame index : %llu",
|
|
ctx_handle, encode_time_per_frame, total_encode_frames);
|
|
#endif
|
|
|
|
VLOG(INFO, "Done one picture !! \n");
|
|
return AMVENC_PICTURE_READY;
|
|
}
|
|
|
|
AMVEnc_Status AML_MultiEncRelease(amv_enc_handle_t ctx_handle) {
|
|
AMVEnc_Status ret = AMVENC_SUCCESS;
|
|
RetCode result;
|
|
EncParam* encParam;
|
|
AMVMultiCtx * ctx = (AMVMultiCtx* ) ctx_handle;
|
|
ENC_INT_STATUS intStatus;
|
|
Uint32 coreIdx;
|
|
int idx;
|
|
|
|
if (ctx == NULL)
|
|
return AMVENC_FAIL;
|
|
if (ctx->magic_num != MULTI_ENC_MAGIC)
|
|
return AMVENC_FAIL;
|
|
|
|
#if ENCODE_TIME_STATISTICS
|
|
VLOG(WARN, "%p#Total encode time : %llu us, Total encode frames : %llu",
|
|
ctx_handle, total_encode_time, total_encode_frames);
|
|
#endif
|
|
coreIdx = ctx->encOpenParam.coreIdx;
|
|
|
|
if (ctx->frameIdx ) {
|
|
flush_retry_point:
|
|
encParam = &ctx->encParam;
|
|
encParam->srcEndFlag = 1; // flush out frame
|
|
result = VPU_EncStartOneFrame(ctx->enchandle, encParam);
|
|
if (result == RETCODE_SUCCESS) {
|
|
// Queue_Dequeue(ctx->encOutQ);
|
|
ctx->frameIdx++;
|
|
}
|
|
else if (result == RETCODE_QUEUEING_FAILURE) { // Just retry
|
|
QueueStatusInfo qStatus;
|
|
// Just retry
|
|
VPU_EncGiveCommand(ctx->enchandle, ENC_GET_QUEUE_STATUS, (void*)&qStatus);
|
|
if (qStatus.instanceQueueCount == 0) {
|
|
goto flush_retry_point;//return TRUE;
|
|
}
|
|
}
|
|
else { // Error
|
|
VLOG(ERR, "VPU_EncStartOneFrame failed Error code is 0x%x \n", result);
|
|
//return AMVENC_FAIL;
|
|
}
|
|
}
|
|
while (VPU_EncClose(ctx->enchandle) == RETCODE_VPU_STILL_RUNNING) {
|
|
if ((intStatus = HandlingInterruptFlag(ctx)) == ENC_INT_STATUS_TIMEOUT) {
|
|
HandleEncoderError(ctx->enchandle, ctx->frameIdx, NULL);
|
|
VLOG(ERR, "NO RESPONSE FROM VPU_EncClose2()\n");
|
|
ret = AMVENC_TIMEOUT;
|
|
break;
|
|
}
|
|
else if (intStatus == ENC_INT_STATUS_DONE) {
|
|
EncOutputInfo outputInfo;
|
|
VLOG(INFO, "VPU_EncClose() : CLEAR REMAIN INTERRUPT\n");
|
|
VPU_EncGetOutputInfo(ctx->enchandle, &outputInfo);
|
|
continue;
|
|
}
|
|
|
|
osal_msleep(10);
|
|
}
|
|
|
|
if (ctx->vbCustomLambda.size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->vbCustomLambda, ENC_ETC, ctx->enchandle->instIndex);
|
|
if (ctx->vbScalingList.size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->vbScalingList, ENC_ETC, ctx->enchandle->instIndex);
|
|
|
|
for (idx = 0; idx < MAX_REG_FRAME; idx++) {
|
|
if (ctx->pFbReconMem[idx].size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->pFbReconMem[idx], ENC_FBC, ctx->enchandle->instIndex);
|
|
if (ctx->vbCustomMap[idx].size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->vbCustomMap[idx], ENC_ETC, ctx->enchandle->instIndex);
|
|
}
|
|
for (idx = 0; idx < ENC_SRC_BUF_NUM; idx++) {
|
|
if (ctx->pFbSrcMem[idx].size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->pFbSrcMem[idx], ENC_SRC, ctx->enchandle->instIndex);
|
|
if (ctx->bsBuffer[idx].size)
|
|
vdi_free_dma_memory(coreIdx, &ctx->bsBuffer[idx], ENC_BS, 0);
|
|
}
|
|
if (ctx->CustomRoiMapBuf)
|
|
{
|
|
free(ctx->CustomRoiMapBuf);
|
|
ctx->CustomRoiMapBuf = NULL;
|
|
}
|
|
if (ctx->CustomLambdaMapBuf)
|
|
{
|
|
free(ctx->CustomLambdaMapBuf);
|
|
ctx->CustomLambdaMapBuf = NULL;
|
|
}
|
|
if (ctx->CustomModeMapBuf)
|
|
{
|
|
free(ctx->CustomModeMapBuf);
|
|
ctx->CustomModeMapBuf = NULL;
|
|
}
|
|
|
|
#if SUPPORT_SCALE
|
|
if (ctx->ge2d_initial_done) {
|
|
aml_ge2d_mem_free(&ctx->amlge2d);
|
|
aml_ge2d_exit(&ctx->amlge2d);
|
|
VLOG(DEBUG, "ge2d exit!!!\n");
|
|
}
|
|
#endif
|
|
VPU_DeInit(ctx->encOpenParam.coreIdx);
|
|
|
|
free(ctx);
|
|
VLOG(INFO, "AML_HEVCRelease succeed\n");
|
|
return ret;
|
|
}
|