@@ -330,6 +330,10 @@
#define S5P_FIMV_E_MVC_RC_RPARA_VIEW1_V6 0xfd50
#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON_V6 0xfd80
+#define S5P_FIMV_E_GOP_CONFIG_CHANGE_SHIFT_V6 0
+#define S5P_FIMV_E_FRAME_RATE_CHANGE_SHIFT_V6 1
+#define S5P_FIMV_E_BIT_RATE_CHANGE_SHIFT_V6 2
+
/* Codec numbers */
#define S5P_FIMV_CODEC_NONE_V6 -1
@@ -173,12 +173,35 @@ enum s5p_mfc_decode_arg {
MFC_DEC_RES_CHANGE,
};
+
+/**
+ * enum s5p_mfc_encoder_param_change - indicates runtime parameter change
+ */
+enum s5p_mfc_encode_param_change {
+ MFC_ENC_GOP_CONFIG_CHANGE,
+ MFC_ENC_FRAME_RATE_CHANGE,
+ MFC_ENC_BIT_RATE_CHANGE,
+ MFC_ENC_FRAME_INSERTION,
+};
+
#define MFC_BUF_FLAG_USED (1 << 0)
#define MFC_BUF_FLAG_EOS (1 << 1)
struct s5p_mfc_ctx;
/**
+ * struct s5p_mfc_enc_params - runtime modifiable encoding parameters
+ */
+struct s5p_mfc_runtime_enc_params {
+ u32 params_changed;
+ u16 gop_size;
+ u32 rc_framerate_num;
+ u32 rc_framerate_denom;
+ u32 rc_bitrate;
+ enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
+};
+
+/**
* struct s5p_mfc_buf - MFC buffer
*/
struct s5p_mfc_buf {
@@ -192,6 +215,7 @@ struct s5p_mfc_buf {
size_t stream;
} cookie;
int flags;
+ struct s5p_mfc_runtime_enc_params runtime_enc_params;
};
/**
@@ -433,7 +457,6 @@ struct s5p_mfc_enc_params {
u16 crop_top_offset;
u16 crop_bottom_offset;
- u16 gop_size;
enum v4l2_mpeg_video_multi_slice_mode slice_mode;
u16 slice_mb;
u32 slice_bit;
@@ -444,7 +467,6 @@ struct s5p_mfc_enc_params {
u8 pad_cr;
int rc_frame;
int rc_mb;
- u32 rc_bitrate;
u16 rc_reaction_coeff;
u16 vbv_size;
u32 vbv_delay;
@@ -454,15 +476,13 @@ struct s5p_mfc_enc_params {
int fixed_target_bit;
u8 num_b_frame;
- u32 rc_framerate_num;
- u32 rc_framerate_denom;
struct {
+ struct s5p_mfc_runtime_enc_params runtime;
struct s5p_mfc_h264_enc_params h264;
struct s5p_mfc_mpeg4_enc_params mpeg4;
struct s5p_mfc_vp8_enc_params vp8;
} codec;
-
};
/**
@@ -638,8 +658,6 @@ struct s5p_mfc_ctx {
size_t me_buffer_size;
size_t tmv_buffer_size;
- enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
-
struct list_head ref_queue;
unsigned int ref_queue_cnt;
@@ -1342,7 +1342,9 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- p->gop_size = ctrl->val;
+ p->codec.runtime.params_changed |=
+ (1 << MFC_ENC_GOP_CONFIG_CHANGE);
+ p->codec.runtime.gop_size = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
p->slice_mode = ctrl->val;
@@ -1368,13 +1370,17 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
p->rc_frame = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
- p->rc_bitrate = ctrl->val;
+ p->codec.runtime.params_changed |=
+ (1 << MFC_ENC_BIT_RATE_CHANGE);
+ p->codec.runtime.rc_bitrate = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
p->rc_reaction_coeff = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
- ctx->force_frame_type = ctrl->val;
+ p->codec.runtime.params_changed |=
+ (1 << MFC_ENC_FRAME_INSERTION);
+ p->codec.runtime.force_frame_type = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
p->vbv_size = ctrl->val;
@@ -1575,12 +1581,29 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *a)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ struct s5p_mfc_runtime_enc_params *runtime_params =
+ &ctx->enc_params.codec.runtime;
+ /*
+ * Note that MFC hardware specifies framerate but the V4L2 API specifies
+ * timeperframe. Take the reciprocal of one to get the other.
+ */
if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ctx->enc_params.rc_framerate_num =
- a->parm.output.timeperframe.denominator;
- ctx->enc_params.rc_framerate_denom =
- a->parm.output.timeperframe.numerator;
+ if ((runtime_params->rc_framerate_num !=
+ a->parm.output.timeperframe.denominator) ||
+ (runtime_params->rc_framerate_denom !=
+ a->parm.output.timeperframe.numerator)) {
+ if (a->parm.output.timeperframe.numerator == 0) {
+ mfc_err("Cannot set an infinite FPS\n");
+ return -EINVAL;
+ }
+ runtime_params->params_changed |=
+ (1 << MFC_ENC_FRAME_RATE_CHANGE);
+ runtime_params->rc_framerate_num =
+ a->parm.output.timeperframe.denominator;
+ runtime_params->rc_framerate_denom =
+ a->parm.output.timeperframe.numerator;
+ }
} else {
mfc_err("Setting FPS is only possible for the output queue\n");
return -EINVAL;
@@ -1595,9 +1618,9 @@ static int vidioc_g_parm(struct file *file, void *priv,
if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
a->parm.output.timeperframe.denominator =
- ctx->enc_params.rc_framerate_num;
+ ctx->enc_params.codec.runtime.rc_framerate_num;
a->parm.output.timeperframe.numerator =
- ctx->enc_params.rc_framerate_denom;
+ ctx->enc_params.codec.runtime.rc_framerate_denom;
} else {
mfc_err("Getting FPS is only possible for the output queue\n");
return -EINVAL;
@@ -1983,7 +2006,19 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
ctx->dst_queue_cnt++;
spin_unlock_irqrestore(&dev->irqlock, flags);
} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ struct s5p_mfc_runtime_enc_params *runtime_params =
+ &ctx->enc_params.codec.runtime;
mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+ /* Tag buffer with runtime encoding parameters */
+ memcpy(&mfc_buf->runtime_enc_params, runtime_params,
+ sizeof(mfc_buf->runtime_enc_params));
+ runtime_params->params_changed = 0;
+ /* force_frame_type needs to revert to 0 after being sent. */
+ if (runtime_params->force_frame_type != 0) {
+ v4l2_ctrl_s_ctrl(v4l2_ctrl_find(&ctx->ctrl_handler,
+ V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE),
+ V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED);
+ }
mfc_buf->flags &= ~MFC_BUF_FLAG_USED;
spin_lock_irqsave(&dev->irqlock, flags);
list_add_tail(&mfc_buf->list, &ctx->src_queue);
@@ -688,7 +688,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
reg |= (1 << 18);
reg &= ~(0xFFFF);
- reg |= p->gop_size;
+ reg |= p->codec.runtime.gop_size;
mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
/* multi-slice control */
@@ -736,7 +736,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
/* bit rate */
if (p->rc_frame)
- mfc_write(dev, p->rc_bitrate,
+ mfc_write(dev, p->codec.runtime.rc_bitrate,
S5P_FIMV_ENC_RC_BIT_RATE);
else
mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE);
@@ -831,9 +831,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
reg |= p_264->rc_frame_qp;
mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
/* frame rate */
- if (p->rc_frame && p->rc_framerate_denom)
- mfc_write(dev, p->rc_framerate_num * 1000
- / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+ if (p->rc_frame && p->codec.runtime.rc_framerate_denom)
+ mfc_write(dev, p->codec.runtime.rc_framerate_num * 1000
+ / p->codec.runtime.rc_framerate_denom,
+ S5P_FIMV_ENC_RC_FRAME_RATE);
else
mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
/* max & min value of QP */
@@ -950,16 +951,17 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
}
/* frame rate */
if (p->rc_frame) {
- if (p->rc_framerate_denom > 0) {
- framerate = p->rc_framerate_num * 1000 /
- p->rc_framerate_denom;
+ if (p->codec.runtime.rc_framerate_denom > 0) {
+ framerate = p->codec.runtime.rc_framerate_num * 1000 /
+ p->codec.runtime.rc_framerate_denom;
mfc_write(dev, framerate,
S5P_FIMV_ENC_RC_FRAME_RATE);
shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING);
shm &= ~(0xFFFFFFFF);
shm |= (1 << 31);
- shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
- shm |= (p->rc_framerate_denom & 0xFFFF);
+ shm |= ((p->codec.runtime.rc_framerate_num & 0x7FFF)
+ << 16);
+ shm |= (p->codec.runtime.rc_framerate_denom & 0xFFFF);
s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING);
}
} else {
@@ -1009,9 +1011,10 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP);
}
/* frame rate */
- if (p->rc_frame && p->rc_framerate_denom)
- mfc_write(dev, p->rc_framerate_num * 1000
- / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+ if (p->rc_frame && p->codec.runtime.rc_framerate_denom)
+ mfc_write(dev, p->codec.runtime.rc_framerate_num * 1000
+ / p->codec.runtime.rc_framerate_denom,
+ S5P_FIMV_ENC_RC_FRAME_RATE);
else
mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
/* rate control config. */
@@ -587,6 +587,52 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
return 0;
}
+static int s5p_mfc_set_runtime_enc_params(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_runtime_enc_params *runtime_p)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc_params *p = &ctx->enc_params;
+ unsigned int params_changed = 0;
+
+ if (runtime_p->params_changed & (1 << MFC_ENC_GOP_CONFIG_CHANGE)) {
+ params_changed |= (1 << S5P_FIMV_E_GOP_CONFIG_CHANGE_SHIFT_V6);
+ /* pictype: IDR period */
+ WRITEL((runtime_p->gop_size & 0xFFFF),
+ S5P_FIMV_E_GOP_CONFIG_V6);
+ }
+ if (runtime_p->params_changed & (1 << MFC_ENC_FRAME_RATE_CHANGE)) {
+ /* frame rate */
+ if (p->rc_frame && runtime_p->rc_framerate_num &&
+ runtime_p->rc_framerate_denom) {
+ params_changed |=
+ (1 << S5P_FIMV_E_FRAME_RATE_CHANGE_SHIFT_V6);
+ WRITEL((((runtime_p->rc_framerate_num & 0xFFFF) << 16) |
+ (runtime_p->rc_framerate_denom & 0xFFFF)),
+ S5P_FIMV_E_RC_FRAME_RATE_V6);
+ }
+ }
+ if (runtime_p->params_changed & (1 << MFC_ENC_BIT_RATE_CHANGE)) {
+ /* bit rate */
+ if (p->rc_frame) {
+ params_changed |=
+ (1 << S5P_FIMV_E_BIT_RATE_CHANGE_SHIFT_V6);
+ WRITEL(runtime_p->rc_bitrate,
+ S5P_FIMV_E_RC_BIT_RATE_V6);
+ }
+ }
+ if (runtime_p->params_changed & (1 << MFC_ENC_FRAME_INSERTION)) {
+ unsigned int reg = READL(S5P_FIMV_E_FRAME_INSERTION_V6);
+ reg &= ~0x3;
+ reg |= runtime_p->force_frame_type & 0x3;
+ WRITEL(reg, S5P_FIMV_E_FRAME_INSERTION_V6);
+ }
+
+ if (params_changed)
+ WRITEL(params_changed, S5P_FIMV_E_PARAM_CHANGE_V6);
+
+ return 0;
+}
+
static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -611,10 +657,10 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
(((p->crop_top_offset / 16) & 0x2FF) << 10),
S5P_FIMV_E_FRAME_CROP_OFFSET_V6);
- /* pictype : IDR period */
- reg = 0;
- reg |= p->gop_size & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6);
+ /* send all runtime encoder parameters. */
+ p->codec.runtime.params_changed = ~0;
+ s5p_mfc_set_runtime_enc_params(ctx, &p->codec.runtime);
+ p->codec.runtime.params_changed = 0;
/* multi-slice control */
/* multi-slice MB number or bit size */
@@ -700,13 +746,6 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
reg |= ((p->rc_frame & 0x1) << 9);
WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
- /* bit rate */
- if (p->rc_frame)
- WRITEL(p->rc_bitrate,
- S5P_FIMV_E_RC_BIT_RATE_V6);
- else
- WRITEL(1, S5P_FIMV_E_RC_BIT_RATE_V6);
-
/* reaction coefficient */
if (p->rc_frame) {
if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */
@@ -814,14 +853,6 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
}
- /* frame rate */
- if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
- reg = 0;
- reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
- reg |= p->rc_framerate_denom & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
- }
-
/* vbv buffer size */
if (p->frame_skip_mode ==
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
@@ -1089,14 +1120,6 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
}
- /* frame rate */
- if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
- reg = 0;
- reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
- reg |= p->rc_framerate_denom & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
- }
-
/* vbv buffer size */
if (p->frame_skip_mode ==
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
@@ -1161,14 +1184,6 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
}
- /* frame rate */
- if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
- reg = 0;
- reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
- reg |= p->rc_framerate_denom & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
- }
-
/* vbv buffer size */
if (p->frame_skip_mode ==
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
@@ -1214,14 +1229,6 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
reg |= ((p->rc_mb & 0x1) << 8);
WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
- /* frame rate */
- if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
- reg = 0;
- reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
- reg |= p->rc_framerate_denom & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
- }
-
/* vbv buffer size */
if (p->frame_skip_mode ==
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
@@ -1560,6 +1567,7 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr);
s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr);
+ s5p_mfc_set_runtime_enc_params(ctx, &src_mb->runtime_enc_params);
dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
dst_mb->flags |= MFC_BUF_FLAG_USED;
Add support for dynamic encoding parameter changes in MFCv6. Parameters set are applied with the next OUTPUT buffer queued to the device with VIDIOC_QBUF. Supported parameters are: * GOP size (V4L2_CID_MPEG_VIDEO_GOP_SIZE) * framerate (from VIDIOC_S_PARM) * VBR target bitrate (V4L2_CID_MPEG_VIDEO_BITRATE) * (h264) frame type (V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE) Signed-off-by: John Sheu <sheu@google.com> --- drivers/media/platform/s5p-mfc/regs-mfc-v6.h | 4 ++ drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 32 +++++++-- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 53 +++++++++++--- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 29 ++++---- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 94 ++++++++++++++----------- 5 files changed, 140 insertions(+), 72 deletions(-)