msm: vidc: Adds VUI timing info support for AVC encoding.
Poor video quality is observed as VUI fps information is not present in
the encoded bit stream. Add support for VUI timing info in video driver
and an additional V4L2 control to set from user space.
Change-Id: I3594903cb897920ea2ef93208644ac8c6ca5d5d9
CRs-Fixed: 399017
Signed-off-by: Srinu Gorle <sgorle@codeaurora.org>
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index 45532a9..21fc719 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -40,6 +40,7 @@
int secure;
struct mem_region unqueued_op_bufs;
bool streaming;
+ enum venc_framerate_modes framerate_mode;
};
struct venc {
@@ -301,6 +302,8 @@
inst->cbdata = vmops->cbdata;
inst->secure = vmops->secure;
inst->streaming = false;
+ inst->framerate_mode = VENC_MODE_VFR;
+
if (vmops->secure) {
WFD_MSG_ERR("OPENING SECURE SESSION\n");
flags |= VCD_CP_SESSION;
@@ -1123,6 +1126,14 @@
return rc;
}
+static long venc_set_framerate_mode(struct v4l2_subdev *sd,
+ void *arg)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ inst->framerate_mode = *(enum venc_framerate_modes *)arg;
+ return 0;
+}
+
static long venc_set_qp_value(struct video_client_ctx *client_ctx,
__s32 frametype, __s32 qp)
{
@@ -1400,6 +1411,51 @@
return rc;
}
+static long venc_set_vui_timing_info(struct video_client_ctx *client_ctx,
+ struct venc_inst *inst, __s32 flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_vui_timing_info_enable vui_timing_info_enable;
+
+ if (!client_ctx)
+ return -EINVAL;
+ if (inst->framerate_mode == VENC_MODE_VFR) {
+ WFD_MSG_ERR("VUI timing info not suported in VFR mode ");
+ return -EINVAL;
+ }
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_VUI_TIMING_INFO;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_vui_timing_info_enable);
+ vui_timing_info_enable.vui_timing_info = flag;
+ return vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vui_timing_info_enable);
+}
+
+static long venc_get_vui_timing_info(struct video_client_ctx *client_ctx,
+ __s32 *flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_vui_timing_info_enable vui_timing_info_enable;
+ int rc = 0;
+
+ if (!client_ctx || !flag)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_VUI_TIMING_INFO;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_vui_timing_info_enable);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vui_timing_info_enable);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Failed getting property for VUI timing info");
+ return rc;
+ }
+
+ *flag = vui_timing_info_enable.vui_timing_info;
+ return rc;
+}
+
static long venc_set_header_mode(struct video_client_ctx *client_ctx,
__s32 mode)
{
@@ -2285,6 +2341,9 @@
case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
rc = venc_set_avc_delimiter(client_ctx, ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+ rc = venc_set_vui_timing_info(client_ctx, inst, ctrl->value);
+ break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
rc = venc_set_entropy_mode(client_ctx, ctrl->value);
break;
@@ -2359,6 +2418,9 @@
case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
rc = venc_get_avc_delimiter(client_ctx, &ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+ rc = venc_get_vui_timing_info(client_ctx, &ctrl->value);
+ break;
default:
WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
rc = -ENOTSUPP;
@@ -2503,6 +2565,9 @@
case ENC_MUNMAP:
rc = venc_munmap(sd, arg);
break;
+ case SET_FRAMERATE_MODE:
+ rc = venc_set_framerate_mode(sd, arg);
+ break;
default:
rc = -1;
break;
diff --git a/drivers/media/video/msm_wfd/enc-subdev.h b/drivers/media/video/msm_wfd/enc-subdev.h
index c6c854e..25373e4 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.h
+++ b/drivers/media/video/msm_wfd/enc-subdev.h
@@ -20,6 +20,11 @@
#include <media/videobuf2-core.h>
#define VENC_MAGIC_IOCTL 'V'
+enum venc_framerate_modes {
+ VENC_MODE_CFR,
+ VENC_MODE_VFR,
+};
+
struct mem_region {
struct list_head list;
u8 *kvaddr;
@@ -101,6 +106,7 @@
#define ENCODE_FLUSH _IO('V', 24)
#define ENC_MMAP _IOWR('V', 25, struct mem_region_map *)
#define ENC_MUNMAP _IOWR('V', 26, struct mem_region_map *)
+#define SET_FRAMERATE_MODE _IO('V', 27)
extern int venc_init(struct v4l2_subdev *sd, u32 val);
extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 5f67a96..003eeb8 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -1047,7 +1047,8 @@
struct v4l2_qcom_frameskip frameskip;
int64_t frame_interval, max_frame_interval;
void *extendedmode = NULL;
- enum vsg_modes mode = VSG_MODE_VFR;
+ enum vsg_modes vsg_mode = VSG_MODE_VFR;
+ enum venc_framerate_modes venc_mode = VENC_MODE_VFR;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1069,6 +1070,7 @@
rc = -EINVAL;
goto set_parm_fail;
}
+ venc_mode = VENC_MODE_CFR;
frame_interval =
a->parm.capture.timeperframe.numerator * NSEC_PER_SEC /
a->parm.capture.timeperframe.denominator;
@@ -1097,7 +1099,7 @@
goto set_parm_fail;
max_frame_interval = (int64_t)frameskip.maxframeinterval;
- mode = VSG_MODE_VFR;
+ vsg_mode = VSG_MODE_VFR;
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
ioctl, VSG_SET_MAX_FRAME_INTERVAL,
@@ -1107,19 +1109,23 @@
goto set_parm_fail;
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
- ioctl, VSG_SET_MODE, &mode);
+ ioctl, VSG_SET_MODE, &vsg_mode);
if (rc)
goto set_parm_fail;
} else {
- mode = VSG_MODE_CFR;
+ vsg_mode = VSG_MODE_CFR;
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
- ioctl, VSG_SET_MODE, &mode);
+ ioctl, VSG_SET_MODE, &vsg_mode);
if (rc)
goto set_parm_fail;
}
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+ ioctl, SET_FRAMERATE_MODE,
+ &venc_mode);
+
set_parm_fail:
return rc;
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 2a850d8..7a1d521 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -293,6 +293,7 @@
struct vcd_property_slice_delivery_info slice_delivery_info;
struct ddl_batch_frame_data batch_frame;
u32 avc_delimiter_enable;
+ u32 vui_timinginfo_enable;
};
struct ddl_decoder_data {
struct ddl_codec_data_hdr hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index d6558c3..332497f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1061,6 +1061,20 @@
}
break;
}
+ case VCD_I_ENABLE_VUI_TIMING_INFO:
+ {
+ struct vcd_property_vui_timing_info_enable *vui_timing_enable =
+ (struct vcd_property_vui_timing_info_enable *)
+ property_value;
+ if (sizeof(struct vcd_property_vui_timing_info_enable) ==
+ property_hdr->sz &&
+ encoder->codec.codec == VCD_CODEC_H264) {
+ encoder->vui_timinginfo_enable =
+ vui_timing_enable->vui_timing_info;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
+ }
default:
DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1553,6 +1567,15 @@
vcd_status = VCD_S_SUCCESS;
}
break;
+ case VCD_I_ENABLE_VUI_TIMING_INFO:
+ if (sizeof(struct vcd_property_vui_timing_info_enable) ==
+ property_hdr->sz) {
+ ((struct vcd_property_vui_timing_info_enable *)
+ property_value)->vui_timing_info =
+ encoder->vui_timinginfo_enable;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
default:
vcd_status = VCD_ERR_ILLEGAL_OP;
break;
@@ -1715,6 +1738,7 @@
encoder->slice_delivery_info.num_slices = 0;
encoder->slice_delivery_info.num_slices_enc = 0;
encoder->avc_delimiter_enable = 0;
+ encoder->vui_timinginfo_enable = 0;
}
static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 40dc2aa..7bdb3b9 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -83,6 +83,8 @@
#define VIDC_SM_ENC_EXT_CTRL_ADDR 0x0028
#define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK 0xffff0000
#define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT 16
+#define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK 0x00004000
+#define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT 14
#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK 0x00000800
#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT 11
#define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK 0x80
@@ -176,6 +178,13 @@
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_ADDR 0x01d0
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_BMSK 0xffffffff
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_SHFT 0
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_ADDR 0x01dc
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_VALUE_BMSK 0xffffffff
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_VALUE_SHFT 0
+#define VIDC_SM_ENC_TIME_SCALE_ADDR 0x01e0
+#define VIDC_SM_ENC_TIME_SCALE_VALUE_BMSK 0xffffffff
+#define VIDC_SM_ENC_TIME_SCALE_VALUE_SHFT 0
+
#define VIDC_SM_ALLOCATED_LUMA_DPB_SIZE_ADDR 0x0064
#define VIDC_SM_ALLOCATED_CHROMA_DPB_SIZE_ADDR 0x0068
@@ -449,7 +458,8 @@
enum VIDC_SM_frame_skip frame_skip_mode,
u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
u32 sps_pps_control, u32 closed_gop_enable,
- u32 au_delim_enable)
+ u32 au_delim_enable,
+ u32 vui_timing_info_enable)
{
u32 enc_ctrl;
enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
@@ -475,7 +485,10 @@
VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK) |
VIDC_SETFIELD((au_delim_enable) ? 1 : 0,
VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT,
- VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK);
+ VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK) |
+ VIDC_SETFIELD((vui_timing_info_enable) ? 1 : 0,
+ VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT,
+ VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK);
DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
}
@@ -1139,3 +1152,15 @@
VIDC_SM_MP2_DATA_DUMP_BUFFER_SIZE_ADDR,
mp2datadumpsize);
}
+
+void vidc_sm_set_h264_encoder_timing_info(struct ddl_buf_addr *shared_mem,
+ u32 num_units_in_tick, u32 time_scale)
+{
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_ENC_NUM_UNITS_IN_TICK_ADDR,
+ num_units_in_tick);
+
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_ENC_TIME_SCALE_ADDR,
+ time_scale);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index c4d577b..2eef99d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,7 +106,7 @@
struct ddl_buf_addr *shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode, u32 seq_hdr_in_band,
u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
- u32 closed_gop_enable, u32 au_delim_enable);
+ u32 closed_gop_enable, u32 au_delim_enable, u32 vui_timing_info_enable);
void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
@@ -198,6 +198,8 @@
void vidc_sm_set_mp2datadump_enable(struct ddl_buf_addr *shared_mem,
struct ddl_mp2_datadumpenabletype *ddl_mp2_datadump_enable);
void vidc_sm_set_mp2datadumpbuffer(struct ddl_buf_addr *shared_mem,
- u32 mp2datadumpaddr, u32 mp2datadumpsize);
+ u32 mp2datadumpaddr, u32 mp2datadumpsize);
+void vidc_sm_set_h264_encoder_timing_info(struct ddl_buf_addr *shared_mem,
+ u32 num_units_in_tick, u32 time_scale);
#endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index bbde7ae..6817101 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -62,7 +62,8 @@
#define DDL_GET_ALIGNED_VITUAL(x) ((x).align_virtual_addr)
#define DDL_KILO_BYTE(x) ((x)*1024)
#define DDL_MEGA_BYTE(x) ((x)*1024*1024)
-#define DDL_FRAMERATE_SCALE(x) ((x) * 1000)
+#define DDL_FRAMERATE_SCALE_FACTOR (1000)
+#define DDL_FRAMERATE_SCALE(x) ((x) * DDL_FRAMERATE_SCALE_FACTOR)
#define DDL_MIN(x, y) ((x < y) ? x : y)
#define DDL_MAX(x, y) ((x > y) ? x : y)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 5eed305..76972ca 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -370,6 +370,15 @@
(u32)(DDL_FRAMERATE_SCALE(encoder->\
frame_rate.fps_numerator) /
encoder->frame_rate.fps_denominator));
+ if (encoder->vui_timinginfo_enable &&
+ encoder->frame_rate.fps_denominator) {
+ vidc_sm_set_h264_encoder_timing_info(
+ &ddl->shared_mem[ddl->command_channel],
+ DDL_FRAMERATE_SCALE_FACTOR,
+ (u32)(DDL_FRAMERATE_SCALE(encoder->\
+ frame_rate.fps_numerator) / encoder->\
+ frame_rate.fps_denominator) << 1);
+ }
encoder->dynamic_prop_change &=
~(DDL_ENC_CHANGE_FRAMERATE);
}
@@ -596,7 +605,14 @@
[ddl->command_channel], hdr_ext_control,
r_cframe_skip, false, 0,
h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
- encoder->closed_gop, encoder->avc_delimiter_enable);
+ encoder->closed_gop, encoder->avc_delimiter_enable,
+ encoder->vui_timinginfo_enable);
+ if (encoder->vui_timinginfo_enable) {
+ vidc_sm_set_h264_encoder_timing_info(
+ &ddl->shared_mem[ddl->command_channel],
+ DDL_FRAMERATE_SCALE_FACTOR,
+ scaled_frame_rate << 1);
+ }
vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
[ddl->command_channel],
encoder->target_bit_rate.target_bitrate);
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b1f534d..e5e0bb4 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1833,6 +1833,12 @@
V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM,
V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 180b38d..545dcd2 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -56,6 +56,8 @@
#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
#define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29)
#define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A)
+#define VCD_I_ENABLE_VUI_TIMING_INFO (VCD_START_BASE + 0x2B)
+
#define VCD_START_REQ (VCD_START_BASE + 0x1000)
#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
@@ -378,4 +380,8 @@
u32 avc_delimiter_enable_flag;
};
+struct vcd_property_vui_timing_info_enable {
+ u32 vui_timing_info;
+};
+
#endif