610 lines
17 KiB
C
610 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2018 MediaTek Inc.
|
|
* Author: Longfei Wang <longfei.wang@mediatek.com>
|
|
*/
|
|
|
|
#include <linux/interrupt.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "../mtk_vcodec_drv.h"
|
|
#include "../mtk_vcodec_util.h"
|
|
#include "../mtk_vcodec_enc.h"
|
|
#include "../venc_drv_base.h"
|
|
#include "../venc_ipi_msg.h"
|
|
#include "../venc_vcu_if.h"
|
|
#include "mtk_vcodec_enc_pm.h"
|
|
#include "mtk_vcodec_intr.h"
|
|
#include "mtk_vcu.h"
|
|
|
|
|
|
|
|
static unsigned int venc_h265_get_profile(struct venc_inst *inst,
|
|
unsigned int profile)
|
|
{
|
|
switch (profile) {
|
|
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
|
|
return 1;
|
|
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10:
|
|
return 2;
|
|
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
|
|
return 4;
|
|
default:
|
|
mtk_vcodec_debug(inst, "unsupported profile %d", profile);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static unsigned int venc_h265_get_level(struct venc_inst *inst,
|
|
unsigned int level, unsigned int tier)
|
|
{
|
|
switch (level) {
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 2 : 3;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 8 : 9;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 10 : 11;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 13 : 14;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 15 : 16;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 18 : 19;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 20 : 21;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 23 : 24;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 25 : 26;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 27 : 28;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_6:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 29 : 30;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 31 : 32;
|
|
case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2:
|
|
return (tier == V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) ? 33 : 34;
|
|
default:
|
|
mtk_vcodec_debug(inst, "unsupported level %d", level);
|
|
return 25;
|
|
}
|
|
}
|
|
|
|
static unsigned int venc_mpeg4_get_profile(struct venc_inst *inst,
|
|
unsigned int profile)
|
|
{
|
|
switch (profile) {
|
|
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
|
|
return 0;
|
|
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
|
|
return 1;
|
|
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE:
|
|
return 2;
|
|
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE:
|
|
return 3;
|
|
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY:
|
|
return 4;
|
|
default:
|
|
mtk_vcodec_debug(inst, "unsupported mpeg4 profile %d", profile);
|
|
return 100;
|
|
}
|
|
}
|
|
|
|
static unsigned int venc_mpeg4_get_level(struct venc_inst *inst,
|
|
unsigned int level)
|
|
{
|
|
switch (level) {
|
|
case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
|
|
return 0;
|
|
case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
|
|
return 1;
|
|
case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
|
|
return 2;
|
|
case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
|
|
return 3;
|
|
case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
|
|
return 4;
|
|
case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B:
|
|
return 5;
|
|
case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
|
|
return 6;
|
|
case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
|
|
return 7;
|
|
default:
|
|
mtk_vcodec_debug(inst, "unsupported mpeg4 level %d", level);
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
static int venc_encode_header(struct venc_inst *inst,
|
|
struct mtk_vcodec_mem *bs_buf,
|
|
unsigned int *bs_size)
|
|
{
|
|
int ret = 0;
|
|
|
|
mtk_vcodec_debug_enter(inst);
|
|
if (bs_buf == NULL)
|
|
inst->vsi->venc.venc_bs_va = 0;
|
|
else
|
|
inst->vsi->venc.venc_bs_va = (u64)(bs_buf->index + 1);
|
|
|
|
inst->vsi->venc.venc_fb_va = 0;
|
|
|
|
mtk_vcodec_debug(inst, "vsi venc_bs_va %lld",
|
|
inst->vsi->venc.venc_bs_va);
|
|
|
|
ret = vcu_enc_encode(&inst->vcu_inst, VENC_BS_MODE_SEQ_HDR, NULL,
|
|
bs_buf, bs_size);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int venc_encode_frame(struct venc_inst *inst,
|
|
struct venc_frm_buf *frm_buf,
|
|
struct mtk_vcodec_mem *bs_buf,
|
|
unsigned int *bs_size)
|
|
{
|
|
int ret = 0;
|
|
unsigned int fm_fourcc = inst->ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc;
|
|
unsigned int bs_fourcc = inst->ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc;
|
|
|
|
mtk_vcodec_debug_enter(inst);
|
|
|
|
if (bs_buf == NULL)
|
|
inst->vsi->venc.venc_bs_va = 0;
|
|
else
|
|
inst->vsi->venc.venc_bs_va = (u64)(bs_buf->index + 1);
|
|
|
|
if (frm_buf == NULL)
|
|
inst->vsi->venc.venc_fb_va = 0;
|
|
else {
|
|
inst->vsi->venc.venc_fb_va = (u64)(frm_buf->index + 1);
|
|
inst->vsi->venc.timestamp = frm_buf->timestamp;
|
|
}
|
|
ret = vcu_enc_encode(&inst->vcu_inst, VENC_BS_MODE_FRAME, frm_buf,
|
|
bs_buf, bs_size);
|
|
if (ret)
|
|
return ret;
|
|
|
|
++inst->frm_cnt;
|
|
mtk_vcodec_debug(inst,
|
|
"Format: frame_va %lld (%c%c%c%c) bs_va:%lld (%c%c%c%c)",
|
|
inst->vsi->venc.venc_fb_va,
|
|
fm_fourcc & 0xFF, (fm_fourcc >> 8) & 0xFF,
|
|
(fm_fourcc >> 16) & 0xFF, (fm_fourcc >> 24) & 0xFF,
|
|
inst->vsi->venc.venc_bs_va,
|
|
bs_fourcc & 0xFF, (bs_fourcc >> 8) & 0xFF,
|
|
(bs_fourcc >> 16) & 0xFF, (bs_fourcc >> 24) & 0xFF);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int venc_encode_frame_final(struct venc_inst *inst,
|
|
struct venc_frm_buf *frm_buf,
|
|
struct mtk_vcodec_mem *bs_buf,
|
|
unsigned int *bs_size)
|
|
{
|
|
int ret = 0;
|
|
|
|
mtk_v4l2_debug(0, "check inst->vsi %p +", inst->vsi);
|
|
if (inst == NULL || inst->vsi == NULL)
|
|
return -EINVAL;
|
|
|
|
if (bs_buf == NULL)
|
|
inst->vsi->venc.venc_bs_va = 0;
|
|
else
|
|
inst->vsi->venc.venc_bs_va = (u64)(bs_buf->index + 1);
|
|
if (frm_buf == NULL)
|
|
inst->vsi->venc.venc_fb_va = 0;
|
|
else
|
|
inst->vsi->venc.venc_fb_va = (u64)(frm_buf->index + 1);
|
|
|
|
ret = vcu_enc_encode(&inst->vcu_inst, VENC_BS_MODE_FRAME_FINAL, frm_buf,
|
|
bs_buf, bs_size);
|
|
if (ret)
|
|
return ret;
|
|
|
|
*bs_size = inst->vcu_inst.bs_size;
|
|
mtk_vcodec_debug(inst, "bs size %d <-", *bs_size);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int venc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle)
|
|
{
|
|
int ret = 0;
|
|
struct venc_inst *inst;
|
|
struct vcu_v4l2_callback_func cb;
|
|
|
|
inst = kzalloc(sizeof(*inst), GFP_KERNEL);
|
|
if (!inst) {
|
|
*handle = (unsigned long)NULL;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
inst->ctx = ctx;
|
|
inst->vcu_inst.ctx = ctx;
|
|
inst->vcu_inst.dev = VCU_FPTR(vcu_get_plat_device)(ctx->dev->plat_dev);
|
|
inst->vcu_inst.id = IPI_VENC_COMMON;
|
|
inst->hw_base = mtk_vcodec_get_enc_reg_addr(inst->ctx, VENC_SYS);
|
|
inst->vcu_inst.handler = vcu_enc_ipi_handler;
|
|
(*handle) = (unsigned long)inst;
|
|
|
|
mtk_vcodec_debug_enter(inst);
|
|
|
|
mtk_vcodec_add_ctx_list(ctx);
|
|
|
|
ret = vcu_enc_init(&inst->vcu_inst);
|
|
|
|
inst->vsi = (struct venc_vsi *)inst->vcu_inst.vsi;
|
|
|
|
memset(&cb, 0, sizeof(struct vcu_v4l2_callback_func));
|
|
cb.enc_prepare = venc_encode_prepare;
|
|
cb.enc_unprepare = venc_encode_unprepare;
|
|
cb.enc_pmqos_gce_begin = venc_encode_pmqos_gce_begin;
|
|
cb.enc_pmqos_gce_end = venc_encode_pmqos_gce_end;
|
|
cb.gce_timeout_dump = mtk_vcodec_gce_timeout_dump;
|
|
VCU_FPTR(vcu_set_v4l2_callback)(inst->vcu_inst.dev, &cb);
|
|
|
|
mtk_vcodec_debug_leave(inst);
|
|
|
|
if (ret) {
|
|
mtk_vcodec_del_ctx_list(ctx);
|
|
kfree(inst);
|
|
(*handle) = (unsigned long)NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int venc_encode(unsigned long handle,
|
|
enum venc_start_opt opt,
|
|
struct venc_frm_buf *frm_buf,
|
|
struct mtk_vcodec_mem *bs_buf,
|
|
struct venc_done_result *result)
|
|
{
|
|
int ret = 0;
|
|
struct venc_inst *inst = (struct venc_inst *)handle;
|
|
|
|
if (inst == NULL || inst->vsi == NULL)
|
|
return -EINVAL;
|
|
|
|
mtk_vcodec_debug(inst, "opt %d ->", opt);
|
|
|
|
switch (opt) {
|
|
case VENC_START_OPT_ENCODE_SEQUENCE_HEADER: {
|
|
unsigned int bs_size_hdr = 0;
|
|
|
|
ret = venc_encode_header(inst, bs_buf, &bs_size_hdr);
|
|
if (ret)
|
|
goto encode_err;
|
|
|
|
result->bs_size = bs_size_hdr;
|
|
result->is_key_frm = false;
|
|
break;
|
|
}
|
|
|
|
case VENC_START_OPT_ENCODE_FRAME: {
|
|
/* only run @ worker then send ipi
|
|
* VPU flush cmd binding ctx & handle
|
|
* or cause cmd calllback ctx error
|
|
*/
|
|
ret = venc_encode_frame(inst, frm_buf, bs_buf,
|
|
&result->bs_size);
|
|
if (ret)
|
|
goto encode_err;
|
|
result->is_key_frm = inst->vcu_inst.is_key_frm;
|
|
break;
|
|
}
|
|
|
|
case VENC_START_OPT_ENCODE_FRAME_FINAL: {
|
|
ret = venc_encode_frame_final(inst,
|
|
frm_buf, bs_buf, &result->bs_size);
|
|
if (ret)
|
|
goto encode_err;
|
|
result->is_key_frm = inst->vcu_inst.is_key_frm;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
mtk_vcodec_err(inst, "venc_start_opt %d not supported", opt);
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
encode_err:
|
|
mtk_vcodec_debug(inst, "opt %d <-", opt);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void venc_get_free_buffers(struct venc_inst *inst,
|
|
struct ring_input_list *list,
|
|
struct venc_done_result *pResult)
|
|
{
|
|
u64 bs_index, fb_index;
|
|
|
|
if (list->count < 0 || list->count >= VENC_MAX_FB_NUM) {
|
|
mtk_vcodec_err(inst, "list count %d invalid ! (write_idx %d, read_idx %d)",
|
|
list->count, list->write_idx, list->read_idx);
|
|
if (list->write_idx < 0 || list->write_idx >= VENC_MAX_FB_NUM ||
|
|
list->read_idx < 0 || list->read_idx >= VENC_MAX_FB_NUM)
|
|
list->write_idx = list->read_idx = 0;
|
|
if (list->write_idx >= list->read_idx)
|
|
list->count = list->write_idx - list->read_idx;
|
|
else
|
|
list->count = list->write_idx + VENC_MAX_FB_NUM - list->read_idx;
|
|
}
|
|
if (list->count == 0) {
|
|
mtk_vcodec_debug(inst, "[FB] there is no free buffers");
|
|
pResult->bs_va = 0;
|
|
pResult->frm_va = 0;
|
|
pResult->is_key_frm = false;
|
|
pResult->bs_size = 0;
|
|
return;
|
|
}
|
|
|
|
pResult->bs_size = list->bs_size[list->read_idx];
|
|
pResult->is_key_frm = list->is_key_frm[list->read_idx];
|
|
bs_index = list->venc_bs_va_list[list->read_idx];
|
|
pResult->bs_va = (unsigned long)inst->ctx->bs_list[bs_index];
|
|
fb_index = list->venc_fb_va_list[list->read_idx];
|
|
pResult->frm_va = (unsigned long)inst->ctx->fb_list[fb_index];
|
|
pResult->is_last_slc = list->is_last_slice[list->read_idx];
|
|
pResult->flags = list->flags[list->read_idx];
|
|
|
|
mtk_vcodec_debug(inst, "read_idx=%d bsva %lx %lld frva %lx %lld bssize %d iskey %d is_last_slc=%d flags 0x%x",
|
|
list->read_idx,
|
|
pResult->bs_va, bs_index,
|
|
pResult->frm_va, fb_index,
|
|
pResult->bs_size,
|
|
pResult->is_key_frm,
|
|
pResult->is_last_slc,
|
|
pResult->flags);
|
|
|
|
list->read_idx = (list->read_idx == VENC_MAX_FB_NUM - 1U) ?
|
|
0U : list->read_idx + 1U;
|
|
list->count--;
|
|
}
|
|
|
|
static void venc_get_resolution_change(struct venc_inst *inst,
|
|
struct venc_vcu_config *Config,
|
|
struct venc_resolution_change *pResChange)
|
|
{
|
|
pResChange->width = Config->pic_w;
|
|
pResChange->height = Config->pic_h;
|
|
pResChange->framerate = Config->framerate;
|
|
pResChange->resolutionchange = Config->resolutionChange;
|
|
|
|
if (Config->resolutionChange)
|
|
Config->resolutionChange = 0;
|
|
|
|
mtk_vcodec_debug(inst, "get reschange %d %d %d %d\n",
|
|
pResChange->width,
|
|
pResChange->height,
|
|
pResChange->framerate,
|
|
pResChange->resolutionchange);
|
|
}
|
|
|
|
|
|
static int venc_get_param(unsigned long handle,
|
|
enum venc_get_param_type type,
|
|
void *out)
|
|
{
|
|
int ret = 0;
|
|
struct venc_inst *inst = (struct venc_inst *)handle;
|
|
|
|
if (inst == NULL)
|
|
return -EINVAL;
|
|
|
|
mtk_vcodec_debug(inst, "%s: %d", __func__, type);
|
|
inst->vcu_inst.ctx = inst->ctx;
|
|
|
|
switch (type) {
|
|
case GET_PARAM_VENC_CAP_FRAME_SIZES:
|
|
case GET_PARAM_VENC_CAP_SUPPORTED_FORMATS:
|
|
vcu_enc_query_cap(&inst->vcu_inst, type, out);
|
|
break;
|
|
case GET_PARAM_FREE_BUFFERS:
|
|
if (inst->vsi == NULL)
|
|
return -EINVAL;
|
|
venc_get_free_buffers(inst, &inst->vsi->list_free, out);
|
|
break;
|
|
case GET_PARAM_ROI_RC_QP: {
|
|
if (inst->vsi == NULL || out == NULL)
|
|
return -EINVAL;
|
|
*(int *)out = inst->vsi->config.roi_rc_qp;
|
|
break;
|
|
}
|
|
case GET_PARAM_RESOLUTION_CHANGE:
|
|
if (inst->vsi == NULL)
|
|
return -EINVAL;
|
|
venc_get_resolution_change(inst, &inst->vsi->config, out);
|
|
break;
|
|
case GET_PARAM_VENC_VCU_VPUD_LOG:
|
|
VCU_FPTR(vcu_get_log)(out, LOG_PROPERTY_SIZE);
|
|
break;
|
|
default:
|
|
mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int venc_set_param(unsigned long handle,
|
|
enum venc_set_param_type type,
|
|
struct venc_enc_param *enc_prm)
|
|
{
|
|
int i;
|
|
int ret = 0;
|
|
struct venc_inst *inst = (struct venc_inst *)handle;
|
|
unsigned int fmt = 0;
|
|
|
|
if (inst == NULL)
|
|
return -EINVAL;
|
|
|
|
mtk_vcodec_debug(inst, "->type=%d", type);
|
|
|
|
switch (type) {
|
|
case VENC_SET_PARAM_ENC:
|
|
if (inst->vsi == NULL)
|
|
return -EINVAL;
|
|
inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt;
|
|
inst->vsi->config.bitrate = enc_prm->bitrate;
|
|
inst->vsi->config.pic_w = enc_prm->width;
|
|
inst->vsi->config.pic_h = enc_prm->height;
|
|
inst->vsi->config.buf_w = enc_prm->buf_width;
|
|
inst->vsi->config.buf_h = enc_prm->buf_height;
|
|
inst->vsi->config.gop_size = enc_prm->gop_size;
|
|
inst->vsi->config.framerate = enc_prm->frm_rate;
|
|
inst->vsi->config.intra_period = enc_prm->intra_period;
|
|
inst->vsi->config.operationrate = enc_prm->operationrate;
|
|
inst->vsi->config.bitratemode = enc_prm->bitratemode;
|
|
inst->vsi->config.roion = enc_prm->roion;
|
|
inst->vsi->config.scenario = enc_prm->scenario;
|
|
inst->vsi->config.prependheader = enc_prm->prependheader;
|
|
inst->vsi->config.heif_grid_size = enc_prm->heif_grid_size;
|
|
inst->vsi->config.max_w = enc_prm->max_w;
|
|
inst->vsi->config.max_h = enc_prm->max_h;
|
|
inst->vsi->config.num_b_frame = enc_prm->num_b_frame;
|
|
inst->vsi->config.slbc_ready = enc_prm->slbc_ready;
|
|
inst->vsi->config.slbc_addr = enc_prm->slbc_addr;
|
|
inst->vsi->config.i_qp = enc_prm->i_qp;
|
|
inst->vsi->config.p_qp = enc_prm->p_qp;
|
|
inst->vsi->config.b_qp = enc_prm->b_qp;
|
|
inst->vsi->config.svp_mode = enc_prm->svp_mode;
|
|
inst->vsi->config.highquality = enc_prm->highquality;
|
|
inst->vsi->config.max_qp = enc_prm->max_qp;
|
|
inst->vsi->config.min_qp = enc_prm->min_qp;
|
|
inst->vsi->config.i_p_qp_delta = enc_prm->ip_qpdelta;
|
|
inst->vsi->config.qp_control_mode = enc_prm->qp_control_mode;
|
|
inst->vsi->config.frame_level_qp = enc_prm->framelvl_qp;
|
|
inst->vsi->config.dummynal = enc_prm->dummynal;
|
|
inst->vsi->config.hier_ref_layer = enc_prm->hier_ref_layer;
|
|
inst->vsi->config.hier_ref_type = enc_prm->hier_ref_type;
|
|
inst->vsi->config.temporal_layer_pcount = enc_prm->temporal_layer_pcount;
|
|
inst->vsi->config.temporal_layer_bcount = enc_prm->temporal_layer_bcount;
|
|
inst->vsi->config.max_ltr_num = enc_prm->max_ltr_num;
|
|
inst->vsi->config.cb_qp_offset = enc_prm->cb_qp_offset;
|
|
inst->vsi->config.cr_qp_offset = enc_prm->cr_qp_offset;
|
|
|
|
if (enc_prm->color_desc) {
|
|
memcpy(&inst->vsi->config.color_desc,
|
|
enc_prm->color_desc,
|
|
sizeof(struct mtk_color_desc));
|
|
}
|
|
|
|
if (enc_prm->multi_ref) {
|
|
memcpy(&inst->vsi->config.multi_ref,
|
|
enc_prm->multi_ref,
|
|
sizeof(struct mtk_venc_multi_ref));
|
|
}
|
|
|
|
if (enc_prm->vui_info) {
|
|
memcpy(&inst->vsi->config.vui_info,
|
|
enc_prm->vui_info,
|
|
sizeof(struct mtk_venc_vui_info));
|
|
}
|
|
|
|
inst->vsi->config.slice_header_spacing =
|
|
enc_prm->slice_header_spacing;
|
|
|
|
fmt = inst->ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc;
|
|
mtk_vcodec_debug(inst, "fmt:%u", fmt);
|
|
|
|
if (fmt == V4L2_PIX_FMT_H264) {
|
|
inst->vsi->config.profile = enc_prm->profile;
|
|
inst->vsi->config.level = enc_prm->level;
|
|
} else if (fmt == V4L2_PIX_FMT_H265 ||
|
|
fmt == V4L2_PIX_FMT_HEIF) {
|
|
inst->vsi->config.profile =
|
|
venc_h265_get_profile(inst, enc_prm->profile);
|
|
inst->vsi->config.level =
|
|
venc_h265_get_level(inst, enc_prm->level,
|
|
enc_prm->tier);
|
|
} else if (fmt == V4L2_PIX_FMT_MPEG4) {
|
|
inst->vsi->config.profile =
|
|
venc_mpeg4_get_profile(inst, enc_prm->profile);
|
|
inst->vsi->config.level =
|
|
venc_mpeg4_get_level(inst, enc_prm->level);
|
|
}
|
|
inst->vsi->config.wfd = 0;
|
|
ret = vcu_enc_set_param(&inst->vcu_inst, type, enc_prm);
|
|
if (ret)
|
|
break;
|
|
|
|
for (i = 0; i < MTK_VCODEC_MAX_PLANES; i++) {
|
|
enc_prm->sizeimage[i] =
|
|
inst->vsi->sizeimage[i];
|
|
mtk_vcodec_debug(inst, "sizeimage[%d] size=0x%x", i,
|
|
enc_prm->sizeimage[i]);
|
|
}
|
|
inst->ctx->async_mode = !(inst->vsi->sync_mode);
|
|
|
|
break;
|
|
case VENC_SET_PARAM_PREPEND_HEADER:
|
|
inst->prepend_hdr = 1;
|
|
ret = vcu_enc_set_param(&inst->vcu_inst, type, enc_prm);
|
|
break;
|
|
case VENC_SET_PARAM_COLOR_DESC:
|
|
if (inst->vsi == NULL)
|
|
return -EINVAL;
|
|
memcpy(&inst->vsi->config.color_desc, enc_prm->color_desc,
|
|
sizeof(struct mtk_color_desc));
|
|
ret = vcu_enc_set_param(&inst->vcu_inst, type, enc_prm);
|
|
break;
|
|
case VENC_SET_PARAM_PROPERTY:
|
|
mtk_vcodec_err(inst, "VCU not support SET_PARAM_VDEC_PROPERTY\n");
|
|
break;
|
|
case VENC_SET_PARAM_VCU_VPUD_LOG:
|
|
ret = VCU_FPTR(vcu_set_log)(enc_prm->log);
|
|
break;
|
|
default:
|
|
if (inst->vsi == NULL)
|
|
return -EINVAL;
|
|
ret = vcu_enc_set_param(&inst->vcu_inst, type, enc_prm);
|
|
inst->ctx->async_mode = !(inst->vsi->sync_mode);
|
|
break;
|
|
}
|
|
|
|
mtk_vcodec_debug_leave(inst);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int venc_deinit(unsigned long handle)
|
|
{
|
|
int ret = 0;
|
|
struct venc_inst *inst = (struct venc_inst *)handle;
|
|
|
|
mtk_vcodec_debug_enter(inst);
|
|
|
|
ret = vcu_enc_deinit(&inst->vcu_inst);
|
|
|
|
mtk_vcodec_del_ctx_list(inst->ctx);
|
|
|
|
mtk_vcodec_debug_leave(inst);
|
|
kfree(inst);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct venc_common_if venc_if = {
|
|
.init = venc_init,
|
|
.encode = venc_encode,
|
|
.get_param = venc_get_param,
|
|
.set_param = venc_set_param,
|
|
.deinit = venc_deinit,
|
|
};
|
|
|
|
const struct venc_common_if *get_enc_vcu_if(void);
|
|
|
|
const struct venc_common_if *get_enc_vcu_if(void)
|
|
{
|
|
return &venc_if;
|
|
}
|