
Latency property is set to firmware during streamon output port, if set as part of initial configuration by client. During runtime, the property is set as and when configured by client. 1. Make the latency property dynamic for decoder. 2. For encoder, the same gets set to firmware with regular v4l2 set properties. 3. For decoder, set the property explicitly during streamon output port. Change-Id: I35990614b95e57f113ddacfc2272cad6ae0dde82 Signed-off-by: Vikash Garodia <vgarodia@codeaurora.org>
2558 sor
67 KiB
C
2558 sor
67 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
|
*/
|
|
|
|
#include <media/v4l2_vidc_extensions.h>
|
|
#include "msm_media_info.h"
|
|
#include <linux/v4l2-common.h>
|
|
|
|
#include "msm_vdec.h"
|
|
#include "msm_vidc_core.h"
|
|
#include "msm_vidc_inst.h"
|
|
#include "msm_vidc_driver.h"
|
|
#include "msm_vidc_internal.h"
|
|
#include "msm_vidc_platform.h"
|
|
#include "msm_vidc_control.h"
|
|
#include "msm_vidc_debug.h"
|
|
#include "msm_vidc_power.h"
|
|
#include "msm_vidc_control.h"
|
|
#include "msm_vidc_memory.h"
|
|
#include "venus_hfi.h"
|
|
#include "hfi_packet.h"
|
|
/* TODO: update based on clips */
|
|
#define MAX_DEC_BATCH_SIZE 6
|
|
#define SKIP_BATCH_WINDOW 100
|
|
|
|
static const u32 msm_vdec_subscribe_for_psc_avc[] = {
|
|
HFI_PROP_BITSTREAM_RESOLUTION,
|
|
HFI_PROP_CROP_OFFSETS,
|
|
HFI_PROP_CODED_FRAMES,
|
|
HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
|
|
HFI_PROP_PIC_ORDER_CNT_TYPE,
|
|
HFI_PROP_PROFILE,
|
|
HFI_PROP_LEVEL,
|
|
HFI_PROP_SIGNAL_COLOR_INFO,
|
|
};
|
|
|
|
static const u32 msm_vdec_subscribe_for_psc_hevc[] = {
|
|
HFI_PROP_BITSTREAM_RESOLUTION,
|
|
HFI_PROP_CROP_OFFSETS,
|
|
HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
|
|
HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
|
|
HFI_PROP_PROFILE,
|
|
HFI_PROP_LEVEL,
|
|
HFI_PROP_TIER,
|
|
HFI_PROP_SIGNAL_COLOR_INFO,
|
|
};
|
|
|
|
static const u32 msm_vdec_subscribe_for_psc_vp9[] = {
|
|
HFI_PROP_BITSTREAM_RESOLUTION,
|
|
HFI_PROP_CROP_OFFSETS,
|
|
HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
|
|
HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
|
|
HFI_PROP_PROFILE,
|
|
HFI_PROP_LEVEL,
|
|
};
|
|
|
|
static const u32 msm_vdec_input_subscribe_for_properties[] = {
|
|
HFI_PROP_NO_OUTPUT,
|
|
};
|
|
|
|
static const u32 msm_vdec_output_subscribe_for_properties[] = {
|
|
HFI_PROP_WORST_COMPRESSION_RATIO,
|
|
HFI_PROP_WORST_COMPLEXITY_FACTOR,
|
|
HFI_PROP_PICTURE_TYPE,
|
|
HFI_PROP_DPB_LIST,
|
|
HFI_PROP_CABAC_SESSION,
|
|
};
|
|
|
|
static const u32 msm_vdec_internal_buffer_type[] = {
|
|
MSM_VIDC_BUF_BIN,
|
|
MSM_VIDC_BUF_COMV,
|
|
MSM_VIDC_BUF_NON_COMV,
|
|
MSM_VIDC_BUF_LINE,
|
|
};
|
|
|
|
struct msm_vdec_prop_type_handle {
|
|
u32 type;
|
|
int (*handle)(struct msm_vidc_inst *inst, enum msm_vidc_port_type port);
|
|
};
|
|
|
|
static int msm_vdec_codec_change(struct msm_vidc_inst *inst, u32 v4l2_codec)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (inst->codec && inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat == v4l2_codec)
|
|
return 0;
|
|
|
|
i_vpr_h(inst, "%s: codec changed from %#x to %#x\n",
|
|
__func__, inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat, v4l2_codec);
|
|
|
|
inst->codec = v4l2_codec_to_driver(v4l2_codec, __func__);
|
|
rc = msm_vidc_update_debug_str(inst);
|
|
if (rc)
|
|
goto exit;
|
|
|
|
rc = msm_vidc_get_inst_capability(inst);
|
|
if (rc)
|
|
goto exit;
|
|
|
|
rc = msm_vidc_ctrl_deinit(inst);
|
|
if (rc)
|
|
goto exit;
|
|
|
|
rc = msm_vidc_ctrl_init(inst);
|
|
if(rc)
|
|
goto exit;
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_bitstream_resolution(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 resolution;
|
|
|
|
resolution = inst->fmts[INPUT_PORT].fmt.pix_mp.width << 16 |
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.height;
|
|
i_vpr_h(inst, "%s: width: %d height: %d\n", __func__,
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.width,
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.height);
|
|
inst->subcr_params[port].bitstream_resolution = resolution;
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_BITSTREAM_RESOLUTION,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&resolution,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_linear_stride_scanline(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
u32 stride_y, scanline_y, stride_uv, scanline_uv;
|
|
u32 payload[2];
|
|
|
|
if (inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat !=
|
|
V4L2_PIX_FMT_NV12 &&
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat !=
|
|
V4L2_PIX_FMT_VIDC_P010)
|
|
return 0;
|
|
|
|
stride_y = inst->fmts[OUTPUT_PORT].fmt.pix_mp.width;
|
|
scanline_y = inst->fmts[OUTPUT_PORT].fmt.pix_mp.height;
|
|
stride_uv = stride_y;
|
|
scanline_uv = scanline_y / 2;
|
|
|
|
payload[0] = stride_y << 16 | scanline_y;
|
|
payload[1] = stride_uv << 16 | scanline_uv;
|
|
i_vpr_h(inst, "%s: stride_y: %d scanline_y: %d "
|
|
"stride_uv: %d, scanline_uv: %d", __func__,
|
|
stride_y, scanline_y, stride_uv, scanline_uv);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_LINEAR_STRIDE_SCANLINE,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, OUTPUT_PORT),
|
|
HFI_PAYLOAD_U64,
|
|
&payload,
|
|
sizeof(u64));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_crop_offsets(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 left_offset, top_offset, right_offset, bottom_offset;
|
|
u32 payload[2] = {0};
|
|
|
|
if (inst->fmts[INPUT_PORT].fmt.pix_mp.width <
|
|
inst->crop.width)
|
|
return -EINVAL;
|
|
|
|
if (inst->fmts[INPUT_PORT].fmt.pix_mp.height <
|
|
inst->crop.height)
|
|
return -EINVAL;
|
|
|
|
left_offset = inst->crop.left;
|
|
top_offset = inst->crop.top;
|
|
right_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.width -
|
|
inst->crop.width);
|
|
bottom_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.height -
|
|
inst->crop.height);
|
|
|
|
payload[0] = left_offset << 16 | top_offset;
|
|
payload[1] = right_offset << 16 | bottom_offset;
|
|
i_vpr_h(inst, "%s: left_offset: %d top_offset: %d "
|
|
"right_offset: %d bottom_offset: %d", __func__,
|
|
left_offset, top_offset, right_offset, bottom_offset);
|
|
inst->subcr_params[port].crop_offsets[0] = payload[0];
|
|
inst->subcr_params[port].crop_offsets[1] = payload[1];
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_CROP_OFFSETS,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_64_PACKED,
|
|
&payload,
|
|
sizeof(u64));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_bit_depth(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 colorformat;
|
|
u32 bitdepth = 8 << 16 | 8;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
colorformat = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat;
|
|
if (colorformat == V4L2_PIX_FMT_VIDC_P010 ||
|
|
colorformat == V4L2_PIX_FMT_VIDC_TP10C)
|
|
bitdepth = 10 << 16 | 10;
|
|
|
|
inst->subcr_params[port].bit_depth = bitdepth;
|
|
msm_vidc_update_cap_value(inst, BIT_DEPTH, bitdepth, __func__);
|
|
i_vpr_h(inst, "%s: bit depth: %#x", __func__, bitdepth);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&bitdepth,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
//todo: enable when needed
|
|
/*
|
|
static int msm_vdec_set_cabac(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 cabac = 0;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
cabac = inst->capabilities->cap[ENTROPY_MODE].value;
|
|
inst->subcr_params[port].cabac = cabac;
|
|
i_vpr_h(inst, "%s: entropy mode: %d", __func__, cabac);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_CABAC_SESSION,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&cabac,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
*/
|
|
static int msm_vdec_set_coded_frames(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 coded_frames = 0;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (inst->capabilities->cap[CODED_FRAMES].value ==
|
|
CODED_FRAMES_PROGRESSIVE)
|
|
coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG;
|
|
inst->subcr_params[port].coded_frames = coded_frames;
|
|
i_vpr_h(inst, "%s: coded frames: %d", __func__, coded_frames);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_CODED_FRAMES,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&coded_frames,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_min_output_count(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 min_output;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
min_output = inst->buffers.output.min_count;
|
|
inst->subcr_params[port].fw_min_count = min_output;
|
|
i_vpr_h(inst, "%s: firmware min output count: %d",
|
|
__func__, min_output);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&min_output,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_picture_order_count(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 poc = 0;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
inst->subcr_params[port].pic_order_cnt = poc;
|
|
i_vpr_h(inst, "%s: picture order count: %d", __func__, poc);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_PIC_ORDER_CNT_TYPE,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&poc,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_colorspace(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 primaries = MSM_VIDC_PRIMARIES_RESERVED;
|
|
u32 matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED;
|
|
u32 transfer_char = MSM_VIDC_TRANSFER_RESERVED;
|
|
u32 full_range = V4L2_QUANTIZATION_DEFAULT;
|
|
u32 colour_description_present_flag = 0;
|
|
u32 video_signal_type_present_flag = 0, color_info = 0;
|
|
/* Unspecified video format */
|
|
u32 video_format = 5;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (inst->codec != MSM_VIDC_H264 &&
|
|
inst->codec != MSM_VIDC_HEVC &&
|
|
inst->codec != MSM_VIDC_HEIC)
|
|
return 0;
|
|
|
|
if (inst->fmts[port].fmt.pix_mp.colorspace != V4L2_COLORSPACE_DEFAULT ||
|
|
inst->fmts[port].fmt.pix_mp.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT ||
|
|
inst->fmts[port].fmt.pix_mp.xfer_func != V4L2_XFER_FUNC_DEFAULT) {
|
|
colour_description_present_flag = 1;
|
|
video_signal_type_present_flag = 1;
|
|
primaries = v4l2_color_primaries_to_driver(inst,
|
|
inst->fmts[port].fmt.pix_mp.colorspace, __func__);
|
|
matrix_coeff = v4l2_matrix_coeff_to_driver(inst,
|
|
inst->fmts[port].fmt.pix_mp.ycbcr_enc, __func__);
|
|
transfer_char = v4l2_transfer_char_to_driver(inst,
|
|
inst->fmts[port].fmt.pix_mp.xfer_func, __func__);
|
|
}
|
|
|
|
if (inst->fmts[port].fmt.pix_mp.quantization !=
|
|
V4L2_QUANTIZATION_DEFAULT) {
|
|
video_signal_type_present_flag = 1;
|
|
full_range = inst->fmts[port].fmt.pix_mp.quantization ==
|
|
V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0;
|
|
}
|
|
|
|
color_info = (matrix_coeff & 0xFF) |
|
|
((transfer_char << 8) & 0xFF00) |
|
|
((primaries << 16) & 0xFF0000) |
|
|
((colour_description_present_flag << 24) & 0x1000000) |
|
|
((full_range << 25) & 0x2000000) |
|
|
((video_format << 26) & 0x1C000000) |
|
|
((video_signal_type_present_flag << 29) & 0x20000000);
|
|
|
|
inst->subcr_params[port].color_info = color_info;
|
|
i_vpr_h(inst, "%s: color info: %#x\n", __func__, color_info);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_SIGNAL_COLOR_INFO,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_32_PACKED,
|
|
&color_info,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_profile(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 profile;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
profile = inst->capabilities->cap[PROFILE].value;
|
|
inst->subcr_params[port].profile = profile;
|
|
i_vpr_h(inst, "%s: profile: %d", __func__, profile);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_PROFILE,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32_ENUM,
|
|
&profile,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_level(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 level;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
level = inst->capabilities->cap[LEVEL].value;
|
|
inst->subcr_params[port].level = level;
|
|
i_vpr_h(inst, "%s: level: %d", __func__, level);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_LEVEL,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32_ENUM,
|
|
&level,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_tier(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 tier;
|
|
|
|
if (port != INPUT_PORT && port != OUTPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
tier = inst->capabilities->cap[HEVC_TIER].value;
|
|
inst->subcr_params[port].tier = tier;
|
|
i_vpr_h(inst, "%s: tier: %d", __func__, tier);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_TIER,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32_ENUM,
|
|
&tier,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_colorformat(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
u32 pixelformat;
|
|
enum msm_vidc_colorformat_type colorformat;
|
|
u32 hfi_colorformat;
|
|
|
|
pixelformat = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat;
|
|
colorformat = v4l2_colorformat_to_driver(pixelformat, __func__);
|
|
hfi_colorformat = get_hfi_colorformat(inst, colorformat);
|
|
i_vpr_h(inst, "%s: hfi colorformat: %d",
|
|
__func__, hfi_colorformat);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_COLOR_FORMAT,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, OUTPUT_PORT),
|
|
HFI_PAYLOAD_U32,
|
|
&hfi_colorformat,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_pipe(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
u32 pipe;
|
|
struct msm_vidc_core *core = inst->core;
|
|
struct msm_vidc_inst_capability *capability = inst->capabilities;
|
|
|
|
rc = call_session_op(core, decide_work_route, inst);
|
|
if (rc) {
|
|
i_vpr_e(inst, "%s: decide_work_route failed\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pipe = capability->cap[PIPE].value;
|
|
i_vpr_h(inst, "%s: pipe: %d", __func__, pipe);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_PIPE,
|
|
HFI_HOST_FLAGS_NONE,
|
|
HFI_PORT_NONE,
|
|
HFI_PAYLOAD_U32,
|
|
&pipe,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_output_order(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 output_order = 0;
|
|
|
|
if (port != INPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (inst->capabilities->cap[DISPLAY_DELAY_ENABLE].value &&
|
|
!inst->capabilities->cap[DISPLAY_DELAY].value)
|
|
output_order = 1;
|
|
|
|
i_vpr_h(inst, "%s: output order: %d", __func__, output_order);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_DECODE_ORDER_OUTPUT,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&output_order,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_secure_mode(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 secure_mode;
|
|
|
|
secure_mode = inst->capabilities->cap[SECURE_MODE].value;
|
|
i_vpr_h(inst, "%s: secure mode: %d", __func__, secure_mode);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_SECURE,
|
|
HFI_HOST_FLAGS_NONE,
|
|
HFI_PORT_NONE,
|
|
HFI_PAYLOAD_U32,
|
|
&secure_mode,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_rap_frame(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 rap_frame = true;
|
|
|
|
if (port != INPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rap_frame = inst->capabilities->cap[RAP_FRAME].value;
|
|
i_vpr_h(inst, "%s: start from rap frame: %d", __func__, rap_frame);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_DEC_START_FROM_RAP_FRAME,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&rap_frame,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_thumbnail_mode(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 thumbnail_mode = 0;
|
|
|
|
if (port != INPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
thumbnail_mode = inst->capabilities->cap[THUMBNAIL_MODE].value;
|
|
i_vpr_h(inst, "%s: thumbnail mode: %d", __func__, thumbnail_mode);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_THUMBNAIL_MODE,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&thumbnail_mode,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_conceal_color_8bit(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 conceal_color_8bit;
|
|
|
|
if (port != INPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
conceal_color_8bit = inst->capabilities->cap[CONCEAL_COLOR_8BIT].value;
|
|
i_vpr_h(inst, "%s: conceal color 8bit: %#x",
|
|
__func__, conceal_color_8bit);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_CONCEAL_COLOR_8BIT,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_32_PACKED,
|
|
&conceal_color_8bit,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_conceal_color_10bit(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 conceal_color_10bit;
|
|
|
|
if (port != INPUT_PORT) {
|
|
i_vpr_e(inst, "%s: invalid port %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
conceal_color_10bit = inst->capabilities->cap[CONCEAL_COLOR_10BIT].value;
|
|
i_vpr_h(inst, "%s: conceal color 10bit: %#x",
|
|
__func__, conceal_color_10bit);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_CONCEAL_COLOR_10BIT,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_32_PACKED,
|
|
&conceal_color_10bit,
|
|
sizeof(u32));
|
|
if (rc)
|
|
i_vpr_e(inst, "%s: set property failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_host_max_buf_count(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 count = DEFAULT_MAX_HOST_BUF_COUNT;
|
|
|
|
if (is_image_session(inst))
|
|
count = DEFAULT_MAX_HOST_BURST_BUF_COUNT;
|
|
|
|
i_vpr_h(inst, "%s: count: %u port: %u\n", __func__, count, port);
|
|
rc = venus_hfi_session_property(inst,
|
|
HFI_PROP_BUFFER_HOST_MAX_COUNT,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
HFI_PAYLOAD_U32,
|
|
&count,
|
|
sizeof(u32));
|
|
if (rc)
|
|
return rc;
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_set_input_properties(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = msm_vdec_set_output_order(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_secure_mode(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_thumbnail_mode(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_rap_frame(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_conceal_color_8bit(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_conceal_color_10bit(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_host_max_buf_count(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_output_properties(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = msm_vdec_set_colorformat(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vidc_set_stage(inst, STAGE);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_pipe(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_linear_stride_scanline(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_host_max_buf_count(inst, OUTPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_get_input_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
u32 i = 0;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) {
|
|
rc = msm_vidc_get_internal_buffers(inst, msm_vdec_internal_buffer_type[i]);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_get_output_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = msm_vidc_get_internal_buffers(inst, MSM_VIDC_BUF_DPB);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_create_input_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
u32 i = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) {
|
|
rc = msm_vidc_create_internal_buffers(inst, msm_vdec_internal_buffer_type[i]);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_create_output_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_DPB);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_queue_input_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
u32 i = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) {
|
|
rc = msm_vidc_queue_internal_buffers(inst, msm_vdec_internal_buffer_type[i]);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_queue_output_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_DPB);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_release_input_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
u32 i = 0;
|
|
|
|
i_vpr_h(inst, "%s()\n",__func__);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) {
|
|
rc = msm_vidc_release_internal_buffers(inst, msm_vdec_internal_buffer_type[i]);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_subscribe_input_port_settings_change(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_core *core;
|
|
u32 payload[32] = {0};
|
|
u32 i, j;
|
|
u32 subscribe_psc_size;
|
|
const u32 *psc;
|
|
static const struct msm_vdec_prop_type_handle prop_type_handle_arr[] = {
|
|
{HFI_PROP_BITSTREAM_RESOLUTION, msm_vdec_set_bitstream_resolution },
|
|
{HFI_PROP_CROP_OFFSETS, msm_vdec_set_crop_offsets },
|
|
{HFI_PROP_LUMA_CHROMA_BIT_DEPTH, msm_vdec_set_bit_depth },
|
|
{HFI_PROP_CODED_FRAMES, msm_vdec_set_coded_frames },
|
|
{HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, msm_vdec_set_min_output_count },
|
|
{HFI_PROP_PIC_ORDER_CNT_TYPE, msm_vdec_set_picture_order_count },
|
|
{HFI_PROP_SIGNAL_COLOR_INFO, msm_vdec_set_colorspace },
|
|
{HFI_PROP_PROFILE, msm_vdec_set_profile },
|
|
{HFI_PROP_LEVEL, msm_vdec_set_level },
|
|
{HFI_PROP_TIER, msm_vdec_set_tier },
|
|
};
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
i_vpr_h(inst, "%s()\n", __func__);
|
|
|
|
payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
|
|
if (inst->codec == MSM_VIDC_H264) {
|
|
subscribe_psc_size = ARRAY_SIZE(msm_vdec_subscribe_for_psc_avc);
|
|
psc = msm_vdec_subscribe_for_psc_avc;
|
|
} else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) {
|
|
subscribe_psc_size = ARRAY_SIZE(msm_vdec_subscribe_for_psc_hevc);
|
|
psc = msm_vdec_subscribe_for_psc_hevc;
|
|
} else if (inst->codec == MSM_VIDC_VP9) {
|
|
subscribe_psc_size = ARRAY_SIZE(msm_vdec_subscribe_for_psc_vp9);
|
|
psc = msm_vdec_subscribe_for_psc_vp9;
|
|
} else {
|
|
i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec);
|
|
psc = NULL;
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!psc || !subscribe_psc_size) {
|
|
i_vpr_e(inst, "%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
|
|
for (i = 0; i < subscribe_psc_size; i++)
|
|
payload[i + 1] = psc[i];
|
|
rc = venus_hfi_session_command(inst,
|
|
HFI_CMD_SUBSCRIBE_MODE,
|
|
port,
|
|
HFI_PAYLOAD_U32_ARRAY,
|
|
&payload[0],
|
|
((subscribe_psc_size + 1) *
|
|
sizeof(u32)));
|
|
|
|
for (i = 0; i < subscribe_psc_size; i++) {
|
|
/* set session properties */
|
|
for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) {
|
|
if (prop_type_handle_arr[j].type == psc[i]) {
|
|
rc = prop_type_handle_arr[j].handle(inst, port);
|
|
if (rc)
|
|
goto exit;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* is property type unknown ? */
|
|
if (j == ARRAY_SIZE(prop_type_handle_arr))
|
|
i_vpr_e(inst, "%s: unknown property %#x\n", __func__, psc[i]);
|
|
}
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_subscribe_property(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_core *core;
|
|
u32 payload[32] = {0};
|
|
u32 i, count = 0;
|
|
bool allow = false;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
i_vpr_h(inst, "%s()\n", __func__);
|
|
|
|
payload[0] = HFI_MODE_PROPERTY;
|
|
|
|
if (port == INPUT_PORT) {
|
|
for (i = 0; i < ARRAY_SIZE(msm_vdec_input_subscribe_for_properties); i++) {
|
|
payload[count + 1] = msm_vdec_input_subscribe_for_properties[i];
|
|
count++;
|
|
}
|
|
} else if (port == OUTPUT_PORT) {
|
|
for (i = 0; i < ARRAY_SIZE(msm_vdec_output_subscribe_for_properties); i++) {
|
|
allow = msm_vidc_allow_property(inst,
|
|
msm_vdec_output_subscribe_for_properties[i]);
|
|
if (allow) {
|
|
payload[count + 1] = msm_vdec_output_subscribe_for_properties[i];
|
|
count++;
|
|
}
|
|
msm_vidc_update_property_cap(inst,
|
|
msm_vdec_output_subscribe_for_properties[i], allow);
|
|
}
|
|
} else {
|
|
i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = venus_hfi_session_command(inst,
|
|
HFI_CMD_SUBSCRIBE_MODE,
|
|
port,
|
|
HFI_PAYLOAD_U32_ARRAY,
|
|
&payload[0],
|
|
(count + 1) * sizeof(u32));
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_core *core;
|
|
u32 payload[32] = {0};
|
|
u32 i, count = 0;
|
|
struct msm_vidc_inst_capability *capability;
|
|
static const u32 metadata_list[] = {
|
|
META_DPB_MISR,
|
|
META_OPB_MISR,
|
|
META_INTERLACE,
|
|
META_TIMESTAMP,
|
|
META_CONCEALED_MB_CNT,
|
|
META_HIST_INFO,
|
|
META_SEI_MASTERING_DISP,
|
|
META_SEI_CLL,
|
|
META_HDR10PLUS,
|
|
META_BUF_TAG,
|
|
META_DPB_TAG_LIST,
|
|
META_SUBFRAME_OUTPUT,
|
|
};
|
|
|
|
if (!inst || !inst->core || !inst->capabilities) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
i_vpr_h(inst, "%s()\n", __func__);
|
|
|
|
capability = inst->capabilities;
|
|
payload[0] = HFI_MODE_METADATA;
|
|
for (i = 0; i < ARRAY_SIZE(metadata_list); i++) {
|
|
if (capability->cap[metadata_list[i]].value &&
|
|
msm_vidc_allow_metadata(inst, metadata_list[i])) {
|
|
payload[count + 1] =
|
|
capability->cap[metadata_list[i]].hfi_id;
|
|
count++;
|
|
}
|
|
};
|
|
|
|
rc = venus_hfi_session_command(inst,
|
|
HFI_CMD_SUBSCRIBE_MODE,
|
|
port,
|
|
HFI_PAYLOAD_U32_ARRAY,
|
|
&payload[0],
|
|
(count + 1) * sizeof(u32));
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_set_delivery_mode_metadata(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_core *core;
|
|
u32 payload[32] = {0};
|
|
u32 i, count = 0;
|
|
struct msm_vidc_inst_capability *capability;
|
|
static const u32 metadata_input_list[] = {
|
|
META_BUF_TAG,
|
|
};
|
|
static const u32 metadata_output_list[] = {
|
|
META_OUTPUT_BUF_TAG,
|
|
};
|
|
|
|
if (!inst || !inst->core || !inst->capabilities) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
i_vpr_h(inst, "%s()\n", __func__);
|
|
|
|
capability = inst->capabilities;
|
|
payload[0] = HFI_MODE_METADATA;
|
|
|
|
if (port == INPUT_PORT) {
|
|
for (i = 0; i < ARRAY_SIZE(metadata_input_list); i++) {
|
|
if (capability->cap[metadata_input_list[i]].value) {
|
|
payload[count + 1] =
|
|
capability->cap[metadata_input_list[i]].hfi_id;
|
|
count++;
|
|
}
|
|
}
|
|
} else if (port == OUTPUT_PORT) {
|
|
for (i = 0; i < ARRAY_SIZE(metadata_output_list); i++) {
|
|
if (capability->cap[metadata_output_list[i]].value &&
|
|
msm_vidc_allow_metadata(inst, metadata_output_list[i])) {
|
|
payload[count + 1] =
|
|
capability->cap[metadata_output_list[i]].hfi_id;
|
|
count++;
|
|
}
|
|
}
|
|
} else {
|
|
i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = venus_hfi_session_command(inst,
|
|
HFI_CMD_DELIVERY_MODE,
|
|
port,
|
|
HFI_PAYLOAD_U32_ARRAY,
|
|
&payload[0],
|
|
(count + 1) * sizeof(u32));
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_session_resume(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
|
|
i_vpr_h(inst, "%s()\n", __func__);
|
|
rc = venus_hfi_session_command(inst,
|
|
HFI_CMD_RESUME,
|
|
port,
|
|
HFI_PAYLOAD_NONE,
|
|
NULL,
|
|
0);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_init_input_subcr_params(struct msm_vidc_inst *inst)
|
|
{
|
|
struct msm_vidc_subscription_params *subsc_params;
|
|
struct msm_vidc_core *core;
|
|
u32 left_offset, top_offset, right_offset, bottom_offset;
|
|
u32 primaries, matrix_coeff, transfer_char;
|
|
u32 full_range = 0, video_format = 0;
|
|
u32 colour_description_present_flag = 0;
|
|
u32 video_signal_type_present_flag = 0;
|
|
|
|
if (!inst || !inst->core || !inst->capabilities) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
subsc_params = &inst->subcr_params[INPUT_PORT];
|
|
|
|
subsc_params->bitstream_resolution =
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.width << 16 |
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.height;
|
|
|
|
left_offset = inst->crop.left;
|
|
top_offset = inst->crop.top;
|
|
right_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.width -
|
|
inst->crop.width);
|
|
bottom_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.height -
|
|
inst->crop.height);
|
|
subsc_params->crop_offsets[0] =
|
|
left_offset << 16 | top_offset;
|
|
subsc_params->crop_offsets[1] =
|
|
right_offset << 16 | bottom_offset;
|
|
|
|
subsc_params->fw_min_count = inst->buffers.output.min_count;
|
|
|
|
primaries = v4l2_color_primaries_to_driver(inst,
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.colorspace, __func__);
|
|
matrix_coeff = v4l2_matrix_coeff_to_driver(inst,
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.ycbcr_enc, __func__);
|
|
transfer_char = v4l2_transfer_char_to_driver(inst,
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.xfer_func, __func__);
|
|
full_range = inst->fmts[OUTPUT_PORT].fmt.pix_mp.quantization ==
|
|
V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0;
|
|
subsc_params->color_info =
|
|
(matrix_coeff & 0xFF) |
|
|
((transfer_char << 8) & 0xFF00) |
|
|
((primaries << 16) & 0xFF0000) |
|
|
((colour_description_present_flag << 24) & 0x1000000) |
|
|
((full_range << 25) & 0x2000000) |
|
|
((video_format << 26) & 0x1C000000) |
|
|
((video_signal_type_present_flag << 29) & 0x20000000);
|
|
|
|
subsc_params->profile = inst->capabilities->cap[PROFILE].value;
|
|
subsc_params->level = inst->capabilities->cap[LEVEL].value;
|
|
subsc_params->tier = inst->capabilities->cap[HEVC_TIER].value;
|
|
subsc_params->pic_order_cnt = inst->capabilities->cap[POC].value;
|
|
subsc_params->bit_depth = inst->capabilities->cap[BIT_DEPTH].value;
|
|
if (inst->capabilities->cap[CODED_FRAMES].value ==
|
|
CODED_FRAMES_PROGRESSIVE)
|
|
subsc_params->coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG;
|
|
else
|
|
subsc_params->coded_frames = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_read_input_subcr_params(struct msm_vidc_inst *inst)
|
|
{
|
|
struct msm_vidc_subscription_params subsc_params;
|
|
struct msm_vidc_core *core;
|
|
u32 width, height;
|
|
u32 primaries, matrix_coeff, transfer_char;
|
|
u32 full_range = 0, video_format = 0;
|
|
u32 colour_description_present_flag = 0;
|
|
u32 video_signal_type_present_flag = 0;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
|
|
subsc_params = inst->subcr_params[INPUT_PORT];
|
|
width = (subsc_params.bitstream_resolution &
|
|
HFI_BITMASK_BITSTREAM_WIDTH) >> 16;
|
|
height = subsc_params.bitstream_resolution &
|
|
HFI_BITMASK_BITSTREAM_HEIGHT;
|
|
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.width = width;
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.height = height;
|
|
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.width = VIDEO_Y_STRIDE_PIX(
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, width);
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.height = VIDEO_Y_SCANLINES(
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, height);
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].bytesperline =
|
|
VIDEO_Y_STRIDE_BYTES(
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, width);
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage =
|
|
call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_OUTPUT);
|
|
//inst->buffers.output.size = inst->fmts[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage;
|
|
|
|
matrix_coeff = subsc_params.color_info & 0xFF;
|
|
transfer_char = (subsc_params.color_info & 0xFF00) >> 8;
|
|
primaries = (subsc_params.color_info & 0xFF0000) >> 16;
|
|
colour_description_present_flag =
|
|
(subsc_params.color_info & 0x1000000) >> 24;
|
|
full_range = (subsc_params.color_info & 0x2000000) >> 25;
|
|
video_signal_type_present_flag =
|
|
(subsc_params.color_info & 0x20000000) >> 29;
|
|
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
|
|
|
|
if (video_signal_type_present_flag) {
|
|
video_format = (subsc_params.color_info & 0x1C000000) >> 26;
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.quantization =
|
|
full_range ?
|
|
V4L2_QUANTIZATION_FULL_RANGE :
|
|
V4L2_QUANTIZATION_LIM_RANGE;
|
|
if (colour_description_present_flag) {
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.colorspace =
|
|
v4l2_color_primaries_from_driver(inst, primaries, __func__);
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.xfer_func =
|
|
v4l2_transfer_char_from_driver(inst, transfer_char, __func__);
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.ycbcr_enc =
|
|
v4l2_matrix_coeff_from_driver(inst, matrix_coeff, __func__);
|
|
} else {
|
|
i_vpr_h(inst,
|
|
"%s: color description flag is not present\n",
|
|
__func__);
|
|
}
|
|
} else {
|
|
i_vpr_h(inst, "%s: video_signal type is not present\n",
|
|
__func__);
|
|
}
|
|
|
|
inst->buffers.output.min_count = subsc_params.fw_min_count;
|
|
inst->buffers.output.extra_count = call_session_op(core,
|
|
extra_count, inst, MSM_VIDC_BUF_OUTPUT);
|
|
if (is_thumbnail_session(inst) && inst->codec != MSM_VIDC_VP9) {
|
|
if (inst->buffers.output.min_count != 1) {
|
|
i_vpr_e(inst, "%s: invalid min count %d in thumbnail case\n",
|
|
__func__, inst->buffers.output.min_count);
|
|
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__);
|
|
}
|
|
}
|
|
inst->crop.top = subsc_params.crop_offsets[0] & 0xFFFF;
|
|
inst->crop.left = (subsc_params.crop_offsets[0] >> 16) & 0xFFFF;
|
|
inst->crop.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height -
|
|
(subsc_params.crop_offsets[1] & 0xFFFF);
|
|
inst->crop.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width -
|
|
((subsc_params.crop_offsets[1] >> 16) & 0xFFFF);
|
|
|
|
msm_vidc_update_cap_value(inst, PROFILE, subsc_params.profile, __func__);
|
|
msm_vidc_update_cap_value(inst, LEVEL, subsc_params.level, __func__);
|
|
msm_vidc_update_cap_value(inst, HEVC_TIER, subsc_params.tier, __func__);
|
|
msm_vidc_update_cap_value(inst, POC, subsc_params.pic_order_cnt, __func__);
|
|
if (subsc_params.bit_depth == BIT_DEPTH_8)
|
|
msm_vidc_update_cap_value(inst, BIT_DEPTH, BIT_DEPTH_8, __func__);
|
|
else
|
|
msm_vidc_update_cap_value(inst, BIT_DEPTH, BIT_DEPTH_10, __func__);
|
|
if (subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG)
|
|
msm_vidc_update_cap_value(inst, CODED_FRAMES, CODED_FRAMES_PROGRESSIVE, __func__);
|
|
else
|
|
msm_vidc_update_cap_value(inst, CODED_FRAMES, CODED_FRAMES_INTERLACE, __func__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst)
|
|
{
|
|
u32 rc = 0;
|
|
struct v4l2_event event = {0};
|
|
|
|
if (!inst->vb2q[INPUT_PORT].streaming) {
|
|
i_vpr_e(inst, "%s: input port not streaming\n",
|
|
__func__);
|
|
return 0;
|
|
}
|
|
|
|
rc = msm_vdec_read_input_subcr_params(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
event.type = V4L2_EVENT_SOURCE_CHANGE;
|
|
event.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION;
|
|
v4l2_event_queue_fh(&inst->event_handler, &event);
|
|
|
|
rc = msm_vdec_get_input_internal_buffers(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_release_input_internal_buffers(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_create_input_internal_buffers(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_queue_input_internal_buffers(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_session_resume(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_output_port_settings_change(struct msm_vidc_inst *inst)
|
|
{
|
|
//todo
|
|
return 0;
|
|
}
|
|
|
|
int msm_vdec_streamoff_input(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = msm_vidc_session_streamoff(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int msm_vdec_streamon_input(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (is_input_meta_enabled(inst) &&
|
|
!inst->vb2q[INPUT_META_PORT].streaming) {
|
|
i_vpr_e(inst,
|
|
"%s: Meta port must be streamed on before data port\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = msm_vidc_check_session_supported(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vidc_check_scaling_supported(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vdec_set_input_properties(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
/* Decide bse vpp delay after work mode */
|
|
//msm_vidc_set_bse_vpp_delay(inst);
|
|
|
|
rc = msm_vdec_get_input_internal_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
/* check for memory after all buffers calculation */
|
|
//rc = msm_vidc_check_memory_supported(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vdec_create_input_internal_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vdec_queue_input_internal_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
if (!inst->ipsc_properties_set) {
|
|
rc = msm_vdec_subscribe_input_port_settings_change(
|
|
inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
inst->ipsc_properties_set = true;
|
|
}
|
|
|
|
rc = msm_vdec_subscribe_property(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_set_delivery_mode_metadata(inst, INPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vidc_session_streamon(inst, INPUT_PORT);
|
|
if (rc)
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
i_vpr_e(inst, "%s: failed\n", __func__);
|
|
msm_vdec_streamoff_input(inst);
|
|
return rc;
|
|
}
|
|
|
|
static int schedule_batch_work(struct msm_vidc_inst *inst)
|
|
{
|
|
struct msm_vidc_core *core;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
cancel_delayed_work(&inst->decode_batch.work);
|
|
queue_delayed_work(core->batch_workq, &inst->decode_batch.work,
|
|
msecs_to_jiffies(core->capabilities[DECODE_BATCH_TIMEOUT].value));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cancel_batch_work(struct msm_vidc_inst *inst)
|
|
{
|
|
if (!inst) {
|
|
d_vpr_e("%s: Invalid arguments\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
cancel_delayed_work(&inst->decode_batch.work);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int msm_vdec_streamoff_output(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* cancel pending batch work */
|
|
cancel_batch_work(inst);
|
|
rc = msm_vidc_session_streamoff(inst, OUTPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_subscribe_output_port_settings_change(struct msm_vidc_inst *inst,
|
|
enum msm_vidc_port_type port)
|
|
{
|
|
int rc = 0;
|
|
u32 payload[32] = {0};
|
|
u32 prop_type, payload_size, payload_type;
|
|
u32 i;
|
|
struct msm_vidc_subscription_params subsc_params;
|
|
u32 subscribe_psc_size = 0;
|
|
const u32 *psc = NULL;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
i_vpr_h(inst, "%s()\n", __func__);
|
|
|
|
payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
|
|
if (inst->codec == MSM_VIDC_H264) {
|
|
subscribe_psc_size = ARRAY_SIZE(msm_vdec_subscribe_for_psc_avc);
|
|
psc = msm_vdec_subscribe_for_psc_avc;
|
|
} else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) {
|
|
subscribe_psc_size = ARRAY_SIZE(msm_vdec_subscribe_for_psc_hevc);
|
|
psc = msm_vdec_subscribe_for_psc_hevc;
|
|
} else if (inst->codec == MSM_VIDC_VP9) {
|
|
subscribe_psc_size = ARRAY_SIZE(msm_vdec_subscribe_for_psc_vp9);
|
|
psc = msm_vdec_subscribe_for_psc_vp9;
|
|
} else {
|
|
i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec);
|
|
psc = NULL;
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!psc || !subscribe_psc_size) {
|
|
i_vpr_e(inst, "%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE;
|
|
for (i = 0; i < subscribe_psc_size; i++)
|
|
payload[i + 1] = psc[i];
|
|
|
|
rc = venus_hfi_session_command(inst,
|
|
HFI_CMD_SUBSCRIBE_MODE,
|
|
port,
|
|
HFI_PAYLOAD_U32_ARRAY,
|
|
&payload[0],
|
|
((subscribe_psc_size + 1) *
|
|
sizeof(u32)));
|
|
|
|
subsc_params = inst->subcr_params[port];
|
|
for (i = 0; i < subscribe_psc_size; i++) {
|
|
payload[0] = 0;
|
|
payload[1] = 0;
|
|
payload_size = 0;
|
|
payload_type = 0;
|
|
prop_type = psc[i];
|
|
switch (prop_type) {
|
|
case HFI_PROP_BITSTREAM_RESOLUTION:
|
|
payload[0] = subsc_params.bitstream_resolution;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
case HFI_PROP_CROP_OFFSETS:
|
|
payload[0] = subsc_params.crop_offsets[0];
|
|
payload[1] = subsc_params.crop_offsets[1];
|
|
payload_size = sizeof(u64);
|
|
payload_type = HFI_PAYLOAD_64_PACKED;
|
|
break;
|
|
case HFI_PROP_LUMA_CHROMA_BIT_DEPTH:
|
|
payload[0] = subsc_params.bit_depth;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
case HFI_PROP_CODED_FRAMES:
|
|
payload[0] = subsc_params.coded_frames;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT:
|
|
payload[0] = subsc_params.fw_min_count;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
case HFI_PROP_PIC_ORDER_CNT_TYPE:
|
|
payload[0] = subsc_params.pic_order_cnt;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
case HFI_PROP_SIGNAL_COLOR_INFO:
|
|
payload[0] = subsc_params.color_info;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
case HFI_PROP_PROFILE:
|
|
payload[0] = subsc_params.profile;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
case HFI_PROP_LEVEL:
|
|
payload[0] = subsc_params.level;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
case HFI_PROP_TIER:
|
|
payload[0] = subsc_params.tier;
|
|
payload_size = sizeof(u32);
|
|
payload_type = HFI_PAYLOAD_U32;
|
|
break;
|
|
default:
|
|
i_vpr_e(inst, "%s: unknown property %#x\n", __func__,
|
|
prop_type);
|
|
prop_type = 0;
|
|
rc = -EINVAL;
|
|
break;
|
|
}
|
|
if (prop_type) {
|
|
rc = venus_hfi_session_property(inst,
|
|
prop_type,
|
|
HFI_HOST_FLAGS_NONE,
|
|
get_hfi_port(inst, port),
|
|
payload_type,
|
|
&payload,
|
|
payload_size);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_streamon_output(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (is_output_meta_enabled(inst) &&
|
|
!inst->vb2q[OUTPUT_META_PORT].streaming) {
|
|
i_vpr_e(inst,
|
|
"%s: Meta port must be streamed on before data port\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = msm_vdec_set_output_properties(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
if (!inst->opsc_properties_set) {
|
|
memcpy(&inst->subcr_params[OUTPUT_PORT],
|
|
&inst->subcr_params[INPUT_PORT],
|
|
sizeof(inst->subcr_params[INPUT_PORT]));
|
|
rc = msm_vdec_subscribe_output_port_settings_change(inst, OUTPUT_PORT);
|
|
if (rc)
|
|
goto error;
|
|
inst->opsc_properties_set = true;
|
|
}
|
|
|
|
rc = msm_vdec_subscribe_property(inst, OUTPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_subscribe_metadata(inst, OUTPUT_PORT);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vdec_set_delivery_mode_metadata(inst, OUTPUT_PORT);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vdec_get_output_internal_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vdec_create_output_internal_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vidc_session_streamon(inst, OUTPUT_PORT);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vdec_queue_output_internal_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
i_vpr_e(inst, "%s: failed\n", __func__);
|
|
msm_vdec_streamoff_output(inst);
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_qbuf_batch(struct msm_vidc_inst *inst,
|
|
struct vb2_buffer *vb2)
|
|
{
|
|
struct msm_vidc_buffer *buf;
|
|
enum msm_vidc_allow allow;
|
|
int count, rc;
|
|
|
|
if (!inst || !vb2 || !inst->decode_batch.size) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
buf = msm_vidc_get_driver_buf(inst, vb2);
|
|
if (!buf)
|
|
return -EINVAL;
|
|
|
|
allow = msm_vidc_allow_qbuf(inst, vb2->type);
|
|
if (allow == MSM_VIDC_DISALLOW) {
|
|
i_vpr_e(inst, "%s: qbuf not allowed\n", __func__);
|
|
return -EINVAL;
|
|
} else if (allow == MSM_VIDC_DEFER) {
|
|
print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf);
|
|
return 0;
|
|
}
|
|
|
|
/* do not defer buffers initially to avoid latency issues */
|
|
if (inst->power.buffer_counter > SKIP_BATCH_WINDOW) {
|
|
count = msm_vidc_num_buffers(inst, MSM_VIDC_BUF_OUTPUT, MSM_VIDC_ATTR_DEFERRED);
|
|
if (count < inst->decode_batch.size) {
|
|
print_vidc_buffer(VIDC_LOW, "low ", "batch-qbuf deferred", inst, buf);
|
|
schedule_batch_work(inst);
|
|
return 0;
|
|
}
|
|
|
|
cancel_batch_work(inst);
|
|
}
|
|
|
|
rc = msm_vidc_queue_buffer_batch(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vdec_release_nonref_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
u32 fw_ro_count = 0, nonref_ro_count = 0;
|
|
struct msm_vidc_buffer *ro_buf, *rel_buf, *dummy;
|
|
int i = 0;
|
|
bool found = false;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* count num buffers in read_only list */
|
|
list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list)
|
|
fw_ro_count++;
|
|
|
|
if (fw_ro_count <= MAX_DPB_COUNT)
|
|
return 0;
|
|
|
|
/*
|
|
* Mark those buffers present in read_only list as non-reference
|
|
* if that buffer is not part of dpb_list_payload
|
|
* count such non-ref read only buffers as nonref_ro_count
|
|
* dpb_list_payload details:
|
|
* payload[0-1] : 64 bits base_address of DPB-1
|
|
* payload[2] : 32 bits addr_offset of DPB-1
|
|
* payload[3] : 32 bits data_offset of DPB-1
|
|
*/
|
|
list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) {
|
|
found = false;
|
|
for (i = 0; (i + 3) < MAX_DPB_LIST_ARRAY_SIZE; i = i + 4) {
|
|
if (ro_buf->device_addr == inst->dpb_list_payload[i] &&
|
|
ro_buf->data_offset == inst->dpb_list_payload[i + 3]) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
ro_buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY;
|
|
nonref_ro_count++;
|
|
}
|
|
}
|
|
|
|
if (nonref_ro_count <= inst->buffers.output.min_count)
|
|
return 0;
|
|
|
|
i_vpr_l(inst, "%s: fw ro buf count %d, non-ref ro count %d\n",
|
|
__func__, fw_ro_count, nonref_ro_count);
|
|
/*
|
|
* move non-ref read only buffers from read_only list to
|
|
* release list
|
|
*/
|
|
list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) {
|
|
if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY)) {
|
|
list_del(&ro_buf->list);
|
|
INIT_LIST_HEAD(&ro_buf->list);
|
|
list_add_tail(&ro_buf->list, &inst->buffers.release.list);
|
|
}
|
|
}
|
|
|
|
/* send release flag along with read only flag for release list bufs*/
|
|
list_for_each_entry(rel_buf, &inst->buffers.release.list, list) {
|
|
/* fw needs RO flag for FTB release buffer */
|
|
rel_buf->attr |= MSM_VIDC_ATTR_READ_ONLY;
|
|
print_vidc_buffer(VIDC_HIGH, "high", "release buf", inst, rel_buf);
|
|
rc = venus_hfi_release_buffer(inst, rel_buf);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_handle_release_buffer(struct msm_vidc_inst *inst,
|
|
struct msm_vidc_buffer *buf)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_map *map;
|
|
bool found;
|
|
|
|
if (!inst || !buf) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
print_vidc_buffer(VIDC_HIGH, "high", "release done", inst, buf);
|
|
|
|
found = false;
|
|
list_for_each_entry(map, &inst->mappings.output.list, list) {
|
|
if (map->device_addr == buf->device_addr) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found) {
|
|
/*
|
|
* finally remove mappings if no one using it.
|
|
* refcount will be more than 1 if anyone using it.
|
|
*/
|
|
if (map->refcount == 1) {
|
|
rc = msm_vidc_put_delayed_unmap(inst, map);
|
|
if (rc)
|
|
print_vidc_buffer(VIDC_ERR, "err ",
|
|
"delayed unmap failed", inst, buf);
|
|
}
|
|
}
|
|
|
|
/* delete the buffer from release list */
|
|
list_del(&buf->list);
|
|
msm_vidc_put_vidc_buffer(inst, buf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_unmap_excessive_mappings(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_map *map;
|
|
u32 refcount_one_bufs_count = 0;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* count entries from map list whose refcount is 1
|
|
* these are excess mappings present due to delayed
|
|
* unmap feature.
|
|
*/
|
|
list_for_each_entry(map, &inst->mappings.output.list, list) {
|
|
if (map->refcount == 1)
|
|
refcount_one_bufs_count++;
|
|
}
|
|
|
|
if (refcount_one_bufs_count <= MAX_MAPPED_OUTPUT_COUNT)
|
|
return 0;
|
|
|
|
/* unmap these buffers as they are stale entries */
|
|
list_for_each_entry(map, &inst->mappings.output.list, list) {
|
|
if (map->refcount == 1) {
|
|
d_vpr_h(
|
|
"%s: type %11s, device_addr %#x, refcount %d, region %d\n",
|
|
__func__, buf_name(map->type), map->device_addr, map->refcount,
|
|
map->region);
|
|
msm_vidc_memory_unmap(inst->core, map);
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst || !vb2 || !inst->capabilities) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (vb2->type == OUTPUT_MPLANE) {
|
|
if (inst->capabilities->cap[DPB_LIST].value) {
|
|
rc = msm_vdec_release_nonref_buffers(inst);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
rc = msm_vidc_unmap_excessive_mappings(inst);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
/* batch decoder output & meta buffer only */
|
|
if (inst->decode_batch.enable && vb2->type == OUTPUT_MPLANE)
|
|
rc = msm_vdec_qbuf_batch(inst, vb2);
|
|
else
|
|
rc = msm_vidc_queue_buffer_single(inst, vb2);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_process_cmd(struct msm_vidc_inst *inst, u32 cmd)
|
|
{
|
|
int rc = 0;
|
|
enum msm_vidc_allow allow = MSM_VIDC_DISALLOW;
|
|
enum msm_vidc_port_type port;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (cmd == V4L2_DEC_CMD_STOP) {
|
|
allow = msm_vidc_allow_stop(inst);
|
|
if (allow == MSM_VIDC_DISALLOW)
|
|
return -EBUSY;
|
|
else if (allow == MSM_VIDC_IGNORE)
|
|
return 0;
|
|
else if (allow != MSM_VIDC_ALLOW)
|
|
return -EINVAL;
|
|
rc = venus_hfi_session_command(inst,
|
|
HFI_CMD_DRAIN,
|
|
INPUT_PORT,
|
|
HFI_PAYLOAD_NONE,
|
|
NULL,
|
|
0);
|
|
if (rc)
|
|
return rc;
|
|
rc = msm_vidc_state_change_stop(inst);
|
|
if (rc)
|
|
return rc;
|
|
} else if (cmd == V4L2_DEC_CMD_START) {
|
|
if (!msm_vidc_allow_start(inst))
|
|
return -EBUSY;
|
|
port = (inst->state == MSM_VIDC_DRAIN_LAST_FLAG) ? INPUT_PORT : OUTPUT_PORT;
|
|
vb2_clear_last_buffer_dequeued(&inst->vb2q[OUTPUT_META_PORT]);
|
|
vb2_clear_last_buffer_dequeued(&inst->vb2q[OUTPUT_PORT]);
|
|
|
|
rc = msm_vidc_state_change_start(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
/* tune power features */
|
|
inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst);
|
|
msm_vidc_allow_dcvs(inst);
|
|
msm_vidc_power_data_reset(inst);
|
|
|
|
/* print final buffer counts & size details */
|
|
msm_vidc_print_buffer_info(inst);
|
|
|
|
rc = venus_hfi_session_command(inst,
|
|
HFI_CMD_RESUME,
|
|
port,
|
|
HFI_PAYLOAD_NONE,
|
|
NULL,
|
|
0);
|
|
if (rc)
|
|
return rc;
|
|
} else {
|
|
i_vpr_e(inst, "%s: unknown cmd %d\n", __func__, cmd);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_core *core;
|
|
struct v4l2_format *fmt;
|
|
u32 codec_align, pix_fmt;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
|
|
if (f->type == INPUT_MPLANE) {
|
|
if (inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat !=
|
|
f->fmt.pix_mp.pixelformat) {
|
|
i_vpr_h(inst,
|
|
"%s: codec changed from %#x to %#x\n", __func__,
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat,
|
|
f->fmt.pix_mp.pixelformat);
|
|
rc = msm_vdec_codec_change(inst, f->fmt.pix_mp.pixelformat);
|
|
if (rc)
|
|
goto err_invalid_fmt;
|
|
}
|
|
fmt = &inst->fmts[INPUT_PORT];
|
|
fmt->type = INPUT_MPLANE;
|
|
|
|
codec_align = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat ==
|
|
V4L2_PIX_FMT_HEVC ? 32 : 16;
|
|
fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align);
|
|
fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align);
|
|
fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat;
|
|
fmt->fmt.pix_mp.num_planes = 1;
|
|
fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
|
|
fmt->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core,
|
|
buffer_size, inst, MSM_VIDC_BUF_INPUT);
|
|
inst->buffers.input.min_count = call_session_op(core,
|
|
min_count, inst, MSM_VIDC_BUF_INPUT);
|
|
inst->buffers.input.extra_count = call_session_op(core,
|
|
extra_count, inst, MSM_VIDC_BUF_INPUT);
|
|
if (inst->buffers.input.actual_count <
|
|
inst->buffers.input.min_count +
|
|
inst->buffers.input.extra_count) {
|
|
inst->buffers.input.actual_count =
|
|
inst->buffers.input.min_count +
|
|
inst->buffers.input.extra_count;
|
|
}
|
|
inst->buffers.input.size =
|
|
fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
|
|
|
|
/* update crop dimensions */
|
|
inst->crop.left = inst->crop.top = 0;
|
|
inst->crop.width = f->fmt.pix_mp.width;
|
|
inst->crop.height = f->fmt.pix_mp.height;
|
|
i_vpr_h(inst,
|
|
"%s: input: codec %#x width %d height %d size %d min_count %d extra_count %d\n",
|
|
__func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width,
|
|
f->fmt.pix_mp.height,
|
|
fmt->fmt.pix_mp.plane_fmt[0].sizeimage,
|
|
inst->buffers.input.min_count,
|
|
inst->buffers.input.extra_count);
|
|
} else if (f->type == INPUT_META_PLANE) {
|
|
fmt = &inst->fmts[INPUT_META_PORT];
|
|
fmt->type = INPUT_META_PLANE;
|
|
fmt->fmt.meta.dataformat = V4L2_META_FMT_VIDC;
|
|
if (is_input_meta_enabled(inst)) {
|
|
fmt->fmt.meta.buffersize = call_session_op(core,
|
|
buffer_size, inst, MSM_VIDC_BUF_INPUT_META);
|
|
inst->buffers.input_meta.min_count =
|
|
inst->buffers.input.min_count;
|
|
inst->buffers.input_meta.extra_count =
|
|
inst->buffers.input.extra_count;
|
|
inst->buffers.input_meta.actual_count =
|
|
inst->buffers.input.actual_count;
|
|
inst->buffers.input_meta.size = fmt->fmt.meta.buffersize;
|
|
} else {
|
|
fmt->fmt.meta.buffersize = 0;
|
|
inst->buffers.input_meta.min_count = 0;
|
|
inst->buffers.input_meta.extra_count = 0;
|
|
inst->buffers.input_meta.actual_count = 0;
|
|
inst->buffers.input_meta.size = 0;
|
|
}
|
|
i_vpr_h(inst,
|
|
"%s: input meta: size %d min_count %d extra_count %d\n",
|
|
__func__, fmt->fmt.meta.buffersize,
|
|
inst->buffers.input_meta.min_count,
|
|
inst->buffers.input_meta.extra_count);
|
|
} else if (f->type == OUTPUT_MPLANE) {
|
|
fmt = &inst->fmts[OUTPUT_PORT];
|
|
fmt->type = OUTPUT_MPLANE;
|
|
if (inst->vb2q[INPUT_PORT].streaming) {
|
|
f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height;
|
|
f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width;
|
|
}
|
|
fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat;
|
|
fmt->fmt.pix_mp.width = VIDEO_Y_STRIDE_PIX(
|
|
fmt->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width);
|
|
fmt->fmt.pix_mp.height = VIDEO_Y_SCANLINES(
|
|
fmt->fmt.pix_mp.pixelformat,
|
|
f->fmt.pix_mp.height);
|
|
fmt->fmt.pix_mp.num_planes = 1;
|
|
fmt->fmt.pix_mp.plane_fmt[0].bytesperline =
|
|
VIDEO_Y_STRIDE_BYTES(
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat,
|
|
f->fmt.pix_mp.width);
|
|
fmt->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core,
|
|
buffer_size, inst, MSM_VIDC_BUF_OUTPUT);
|
|
|
|
if (!inst->vb2q[INPUT_PORT].streaming)
|
|
inst->buffers.output.min_count = call_session_op(core,
|
|
min_count, inst, MSM_VIDC_BUF_OUTPUT);
|
|
inst->buffers.output.extra_count = call_session_op(core,
|
|
extra_count, inst, MSM_VIDC_BUF_OUTPUT);
|
|
if (inst->buffers.output.actual_count <
|
|
inst->buffers.output.min_count +
|
|
inst->buffers.output.extra_count) {
|
|
inst->buffers.output.actual_count =
|
|
inst->buffers.output.min_count +
|
|
inst->buffers.output.extra_count;
|
|
}
|
|
inst->buffers.output.size =
|
|
fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
|
|
pix_fmt = v4l2_colorformat_to_driver(f->fmt.pix_mp.pixelformat, __func__);
|
|
msm_vidc_update_cap_value(inst, PIX_FMTS, pix_fmt, __func__);
|
|
i_vpr_h(inst,
|
|
"%s: output: format %#x width %d height %d size %d min_count %d extra_count %d\n",
|
|
__func__, fmt->fmt.pix_mp.pixelformat, fmt->fmt.pix_mp.width,
|
|
fmt->fmt.pix_mp.height,
|
|
fmt->fmt.pix_mp.plane_fmt[0].sizeimage,
|
|
inst->buffers.output.min_count,
|
|
inst->buffers.output.extra_count);
|
|
} else if (f->type == OUTPUT_META_PLANE) {
|
|
fmt = &inst->fmts[OUTPUT_META_PORT];
|
|
fmt->type = OUTPUT_META_PLANE;
|
|
fmt->fmt.meta.dataformat = V4L2_META_FMT_VIDC;
|
|
if (is_output_meta_enabled(inst)) {
|
|
fmt->fmt.meta.buffersize = call_session_op(core,
|
|
buffer_size, inst, MSM_VIDC_BUF_OUTPUT_META);
|
|
inst->buffers.output_meta.min_count =
|
|
inst->buffers.output.min_count;
|
|
inst->buffers.output_meta.extra_count =
|
|
inst->buffers.output.extra_count;
|
|
inst->buffers.output_meta.actual_count =
|
|
inst->buffers.output.actual_count;
|
|
inst->buffers.output_meta.size = fmt->fmt.meta.buffersize;
|
|
} else {
|
|
fmt->fmt.meta.buffersize = 0;
|
|
inst->buffers.output_meta.min_count = 0;
|
|
inst->buffers.output_meta.extra_count = 0;
|
|
inst->buffers.output_meta.actual_count = 0;
|
|
inst->buffers.output_meta.size = 0;
|
|
}
|
|
i_vpr_h(inst,
|
|
"%s: output meta: size %d min_count %d extra_count %d\n",
|
|
__func__, fmt->fmt.meta.buffersize,
|
|
inst->buffers.output_meta.min_count,
|
|
inst->buffers.output_meta.extra_count);
|
|
} else {
|
|
i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type);
|
|
goto err_invalid_fmt;
|
|
}
|
|
memcpy(f, fmt, sizeof(struct v4l2_format));
|
|
|
|
err_invalid_fmt:
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
|
|
{
|
|
int rc = 0;
|
|
int port;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
port = v4l2_type_to_driver_port(inst, f->type, __func__);
|
|
if (port < 0)
|
|
return -EINVAL;
|
|
|
|
memcpy(f, &inst->fmts[port], sizeof(struct v4l2_format));
|
|
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_s_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s)
|
|
{
|
|
if (!inst || !s) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
i_vpr_e(inst, "%s: unsupported\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
int msm_vdec_g_selection(struct msm_vidc_inst* inst, struct v4l2_selection* s)
|
|
{
|
|
if (!inst || !s) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (s->target) {
|
|
case V4L2_SEL_TGT_CROP_BOUNDS:
|
|
case V4L2_SEL_TGT_CROP_DEFAULT:
|
|
case V4L2_SEL_TGT_CROP:
|
|
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
|
|
case V4L2_SEL_TGT_COMPOSE_PADDED:
|
|
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
|
|
case V4L2_SEL_TGT_COMPOSE:
|
|
default:
|
|
s->r.left = inst->crop.left;
|
|
s->r.top = inst->crop.top;
|
|
s->r.width = inst->crop.width;
|
|
s->r.height = inst->crop.height;
|
|
break;
|
|
}
|
|
i_vpr_h(inst, "%s: type %d target %d, r [%d, %d, %d, %d]\n",
|
|
__func__, s->type, s->target, s->r.top, s->r.left,
|
|
s->r.width, s->r.height);
|
|
return 0;
|
|
}
|
|
|
|
int msm_vdec_s_param(struct msm_vidc_inst *inst,
|
|
struct v4l2_streamparm *s_parm)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_inst_capability *capability = NULL;
|
|
struct v4l2_fract *timeperframe = NULL;
|
|
u32 q16_rate, max_rate, default_rate;
|
|
u64 us_per_frame = 0, input_rate = 0;
|
|
bool is_frame_rate = false;
|
|
|
|
if (!inst || !s_parm) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
capability = inst->capabilities;
|
|
|
|
if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
timeperframe = &s_parm->parm.output.timeperframe;
|
|
max_rate = capability->cap[FRAME_RATE].max >> 16;
|
|
default_rate = capability->cap[FRAME_RATE].value >> 16;
|
|
is_frame_rate = true;
|
|
} else {
|
|
timeperframe = &s_parm->parm.capture.timeperframe;
|
|
max_rate = capability->cap[OPERATING_RATE].max;
|
|
default_rate = capability->cap[OPERATING_RATE].value >> 16;
|
|
}
|
|
|
|
if (!timeperframe->denominator || !timeperframe->numerator) {
|
|
i_vpr_e(inst,
|
|
"%s: invalid rate for type %u\n",
|
|
__func__, s_parm->type);
|
|
input_rate = default_rate;
|
|
goto set_default;
|
|
}
|
|
|
|
us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC;
|
|
do_div(us_per_frame, timeperframe->denominator);
|
|
|
|
if (!us_per_frame) {
|
|
i_vpr_e(inst, "%s: us_per_frame is zero\n",
|
|
__func__);
|
|
rc = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
input_rate = (u64)USEC_PER_SEC;
|
|
do_div(input_rate, us_per_frame);
|
|
|
|
/* Check max allowed rate */
|
|
if (input_rate > max_rate) {
|
|
i_vpr_e(inst,
|
|
"%s: Unsupported rate %llu, max_fps %u, type: %u\n",
|
|
__func__, input_rate, max_rate, s_parm->type);
|
|
rc = -ENOTSUPP;
|
|
goto exit;
|
|
}
|
|
|
|
set_default:
|
|
q16_rate = (u32)input_rate << 16;
|
|
i_vpr_h(inst, "%s: %s value %d\n",
|
|
__func__, is_frame_rate ? "frame rate" : "operating rate", input_rate);
|
|
|
|
msm_vidc_update_cap_value(inst,
|
|
is_frame_rate ? FRAME_RATE : OPERATING_RATE,
|
|
q16_rate, __func__);
|
|
|
|
if ((s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
|
|
inst->vb2q[INPUT_PORT].streaming) ||
|
|
(s_parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
|
|
inst->vb2q[OUTPUT_PORT].streaming)) {
|
|
if (msm_vidc_check_mbps_supported(inst)) {
|
|
i_vpr_e(inst,
|
|
"%s: Unsupported load with rate %d, setting default rate %d\n",
|
|
__func__, input_rate, default_rate);
|
|
msm_vidc_update_cap_value(inst,
|
|
is_frame_rate ? FRAME_RATE : OPERATING_RATE,
|
|
default_rate << 16, __func__);
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
if (!is_realtime_session(inst))
|
|
inst->priority_level = MSM_VIDC_PRIORITY_HIGH;
|
|
|
|
if (is_frame_rate)
|
|
capability->cap[FRAME_RATE].flags |= CAP_FLAG_CLIENT_SET;
|
|
else
|
|
capability->cap[OPERATING_RATE].flags |= CAP_FLAG_CLIENT_SET;
|
|
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_g_param(struct msm_vidc_inst *inst,
|
|
struct v4l2_streamparm *s_parm)
|
|
{
|
|
struct msm_vidc_inst_capability *capability = NULL;
|
|
struct v4l2_fract *timeperframe = NULL;
|
|
|
|
if (!inst || !s_parm) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
capability = inst->capabilities;
|
|
|
|
if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
|
timeperframe = &s_parm->parm.output.timeperframe;
|
|
timeperframe->numerator = 1;
|
|
timeperframe->denominator =
|
|
capability->cap[FRAME_RATE].value >> 16;
|
|
} else {
|
|
timeperframe = &s_parm->parm.capture.timeperframe;
|
|
timeperframe->numerator = 1;
|
|
timeperframe->denominator =
|
|
capability->cap[OPERATING_RATE].value >> 16;
|
|
}
|
|
|
|
i_vpr_h(inst, "%s: type %u, num %u denom %u\n",
|
|
__func__, s_parm->type, timeperframe->numerator,
|
|
timeperframe->denominator);
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vdec_check_colorformat_supported(struct msm_vidc_inst* inst,
|
|
enum msm_vidc_colorformat_type colorformat)
|
|
{
|
|
bool supported = true;
|
|
|
|
/* do not reject coloformats before streamon */
|
|
if (!inst->vb2q[INPUT_PORT].streaming)
|
|
return true;
|
|
|
|
/*
|
|
* bit_depth 8 bit supports 8 bit colorformats only
|
|
* bit_depth 10 bit supports 10 bit colorformats only
|
|
* interlace supports ubwc colorformats only
|
|
*/
|
|
if (inst->capabilities->cap[BIT_DEPTH].value == BIT_DEPTH_8 &&
|
|
!is_8bit_colorformat(colorformat))
|
|
supported = false;
|
|
if (inst->capabilities->cap[BIT_DEPTH].value == BIT_DEPTH_10 &&
|
|
!is_10bit_colorformat(colorformat))
|
|
supported = false;
|
|
if (inst->capabilities->cap[CODED_FRAMES].value ==
|
|
CODED_FRAMES_INTERLACE &&
|
|
!is_ubwc_colorformat(colorformat))
|
|
supported = false;
|
|
|
|
return supported;
|
|
}
|
|
|
|
int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_core *core;
|
|
u32 array[32] = {0};
|
|
u32 i = 0;
|
|
|
|
if (!inst || !inst->core || !inst->capabilities || !f ||
|
|
f->index >= ARRAY_SIZE(array)) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
|
|
if (f->type == INPUT_MPLANE) {
|
|
u32 codecs = core->capabilities[DEC_CODECS].value;
|
|
u32 idx = 0;
|
|
|
|
for (i = 0; i <= 31; i++) {
|
|
if (codecs & BIT(i)) {
|
|
if (idx >= ARRAY_SIZE(array))
|
|
break;
|
|
array[idx] = codecs & BIT(i);
|
|
idx++;
|
|
}
|
|
}
|
|
f->pixelformat = v4l2_codec_from_driver(array[f->index],
|
|
__func__);
|
|
if (!f->pixelformat)
|
|
return -EINVAL;
|
|
f->flags = V4L2_FMT_FLAG_COMPRESSED;
|
|
strlcpy(f->description, "codec", sizeof(f->description));
|
|
} else if (f->type == OUTPUT_MPLANE) {
|
|
u32 formats = inst->capabilities->cap[PIX_FMTS].step_or_mask;
|
|
u32 idx = 0;
|
|
|
|
for (i = 0; i <= 31; i++) {
|
|
if (formats & BIT(i)) {
|
|
if (idx >= ARRAY_SIZE(array))
|
|
break;
|
|
if (msm_vdec_check_colorformat_supported(inst,
|
|
formats & BIT(i))) {
|
|
array[idx] = formats & BIT(i);
|
|
idx++;
|
|
}
|
|
}
|
|
}
|
|
f->pixelformat = v4l2_colorformat_from_driver(array[f->index],
|
|
__func__);
|
|
if (!f->pixelformat)
|
|
return -EINVAL;
|
|
strlcpy(f->description, "colorformat", sizeof(f->description));
|
|
} else if (f->type == INPUT_META_PLANE || f->type == OUTPUT_META_PLANE) {
|
|
if (!f->index) {
|
|
f->pixelformat = V4L2_META_FMT_VIDC;
|
|
strlcpy(f->description, "metadata", sizeof(f->description));
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
memset(f->reserved, 0, sizeof(f->reserved));
|
|
|
|
i_vpr_h(inst, "%s: index %d, %s : %#x, flags %#x, driver colorfmt %#x\n",
|
|
__func__, f->index, f->description, f->pixelformat, f->flags,
|
|
v4l2_colorformat_to_driver(f->pixelformat, __func__));
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_inst_init(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_vidc_core *core;
|
|
struct v4l2_format *f;
|
|
|
|
if (!inst || !inst->core) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core = inst->core;
|
|
|
|
INIT_DELAYED_WORK(&inst->decode_batch.work, msm_vidc_batch_handler);
|
|
if (core->capabilities[DECODE_BATCH].value) {
|
|
inst->decode_batch.enable = true;
|
|
inst->decode_batch.size = MAX_DEC_BATCH_SIZE;
|
|
}
|
|
|
|
f = &inst->fmts[INPUT_PORT];
|
|
f->type = INPUT_MPLANE;
|
|
f->fmt.pix_mp.width = DEFAULT_WIDTH;
|
|
f->fmt.pix_mp.height = DEFAULT_HEIGHT;
|
|
f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
|
|
f->fmt.pix_mp.num_planes = 1;
|
|
f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
|
|
f->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core,
|
|
buffer_size, inst, MSM_VIDC_BUF_INPUT);
|
|
inst->buffers.input.min_count = call_session_op(core,
|
|
min_count, inst, MSM_VIDC_BUF_INPUT);
|
|
inst->buffers.input.extra_count = call_session_op(core,
|
|
extra_count, inst, MSM_VIDC_BUF_INPUT);
|
|
inst->buffers.input.actual_count =
|
|
inst->buffers.input.min_count +
|
|
inst->buffers.input.extra_count;
|
|
inst->buffers.input.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
|
|
|
|
inst->crop.left = inst->crop.top = 0;
|
|
inst->crop.width = f->fmt.pix_mp.width;
|
|
inst->crop.height = f->fmt.pix_mp.height;
|
|
|
|
f = &inst->fmts[INPUT_META_PORT];
|
|
f->type = INPUT_META_PLANE;
|
|
f->fmt.meta.dataformat = V4L2_META_FMT_VIDC;
|
|
f->fmt.meta.buffersize = 0;
|
|
inst->buffers.input_meta.min_count = 0;
|
|
inst->buffers.input_meta.extra_count = 0;
|
|
inst->buffers.input_meta.actual_count = 0;
|
|
inst->buffers.input_meta.size = 0;
|
|
|
|
f = &inst->fmts[OUTPUT_PORT];
|
|
f->type = OUTPUT_MPLANE;
|
|
f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_VIDC_NV12C;
|
|
f->fmt.pix_mp.width = VIDEO_Y_STRIDE_PIX(f->fmt.pix_mp.pixelformat,
|
|
DEFAULT_WIDTH);
|
|
f->fmt.pix_mp.height = VIDEO_Y_SCANLINES(f->fmt.pix_mp.pixelformat,
|
|
DEFAULT_HEIGHT);
|
|
f->fmt.pix_mp.num_planes = 1;
|
|
f->fmt.pix_mp.plane_fmt[0].bytesperline =
|
|
VIDEO_Y_STRIDE_BYTES(
|
|
inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat,
|
|
DEFAULT_WIDTH);
|
|
f->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core,
|
|
buffer_size, inst, MSM_VIDC_BUF_OUTPUT);
|
|
f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
|
|
f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
|
|
f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
|
|
f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
|
|
inst->buffers.output.min_count = call_session_op(core,
|
|
min_count, inst, MSM_VIDC_BUF_OUTPUT);
|
|
inst->buffers.output.extra_count = call_session_op(core,
|
|
extra_count, inst, MSM_VIDC_BUF_OUTPUT);
|
|
inst->buffers.output.actual_count =
|
|
inst->buffers.output.min_count +
|
|
inst->buffers.output.extra_count;
|
|
inst->buffers.output.size = f->fmt.pix_mp.plane_fmt[0].sizeimage;
|
|
|
|
f = &inst->fmts[OUTPUT_META_PORT];
|
|
f->type = OUTPUT_META_PLANE;
|
|
f->fmt.meta.dataformat = V4L2_META_FMT_VIDC;
|
|
f->fmt.meta.buffersize = 0;
|
|
inst->buffers.output_meta.min_count = 0;
|
|
inst->buffers.output_meta.extra_count = 0;
|
|
inst->buffers.output_meta.actual_count = 0;
|
|
inst->buffers.output_meta.size = 0;
|
|
|
|
rc = msm_vdec_codec_change(inst,
|
|
inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int msm_vdec_inst_deinit(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
/* cancel pending batch work */
|
|
cancel_batch_work(inst);
|
|
rc = msm_vidc_ctrl_deinit(inst);
|
|
|
|
return rc;
|
|
}
|