[PATCH v1 1/5] media: venus: handle video decoder resolution change

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add logic for below to handle resolution change during video decode.
- stream off support for video decoder OUTPUT plane and
  flush old resolution OUTPUT plane buffers.
- De-allocate and allocate video firmware internal buffers.
  And also ensures g_fmt for output plane populated
  only after SPS and PPS has parsed.

Signed-off-by: Srinu Gorle <sgorle@xxxxxxxxxxxxxx>
---
 drivers/media/platform/qcom/venus/helpers.c | 159 +++++++++++++++++++++++-----
 drivers/media/platform/qcom/venus/helpers.h |   3 +
 drivers/media/platform/qcom/venus/hfi.c     |   5 +-
 drivers/media/platform/qcom/venus/hfi.h     |   2 +-
 drivers/media/platform/qcom/venus/vdec.c    | 102 +++++++++++++++---
 drivers/media/platform/qcom/venus/venc.c    |  20 +++-
 6 files changed, 246 insertions(+), 45 deletions(-)

diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index e436385..822a853 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -180,6 +180,7 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst)
 		list_add_tail(&buf->list, &inst->dpbbufs);
 	}
 
+	venus_helper_queue_dpb_bufs(inst);
 	return 0;
 
 fail:
@@ -319,6 +320,65 @@ static int intbufs_free(struct venus_inst *inst)
 	return intbufs_unset_buffers(inst);
 }
 
+static int alloc_reconfig_buffers(struct venus_inst *inst)
+{
+	size_t arr_sz;
+	size_t i;
+	int ret;
+	unsigned int buf_type;
+
+	if (IS_V4(inst->core))
+		arr_sz = ARRAY_SIZE(intbuf_types_4xx);
+	else
+		arr_sz = ARRAY_SIZE(intbuf_types_1xx);
+
+	for (i = 0; i < arr_sz; i++) {
+		buf_type = IS_V4(inst->core) ? intbuf_types_4xx[i] :
+					intbuf_types_1xx[i];
+		if (buf_type == HFI_BUFFER_INTERNAL_PERSIST ||
+		    buf_type == HFI_BUFFER_INTERNAL_PERSIST_1)
+			continue;
+
+		ret = intbufs_set_buffer(inst, buf_type);
+		if (ret)
+			goto error;
+	}
+
+	return 0;
+
+error:
+	intbufs_unset_buffers(inst);
+	return ret;
+}
+
+static int unset_reconfig_buffers(struct venus_inst *inst)
+{
+	struct hfi_buffer_desc bd = {0};
+	struct intbuf *buf, *n;
+	int ret = 0;
+
+	list_for_each_entry_safe(buf, n, &inst->internalbufs, list) {
+		if (buf->type == HFI_BUFFER_INTERNAL_PERSIST ||
+		    buf->type == HFI_BUFFER_INTERNAL_PERSIST_1)
+			continue;
+
+		bd.buffer_size = buf->size;
+		bd.buffer_type = buf->type;
+		bd.num_buffers = 1;
+		bd.device_addr = buf->da;
+		bd.response_required = true;
+
+		ret = hfi_session_unset_buffers(inst, &bd);
+
+		list_del_init(&buf->list);
+		dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
+			       buf->attrs);
+		kfree(buf);
+	}
+
+	return ret;
+}
+
 static u32 load_per_instance(struct venus_inst *inst)
 {
 	u32 mbs;
@@ -969,14 +1029,26 @@ void venus_helper_vb2_buf_queue(struct vb2_buffer *vb)
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
 	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+	struct venus_core *core = inst->core;
+	struct device *dev = core->dev;
 	int ret;
+	bool is_plane_enabled;
 
 	mutex_lock(&inst->lock);
 
 	v4l2_m2m_buf_queue(m2m_ctx, vbuf);
 
-	if (!(inst->streamon_out & inst->streamon_cap))
+	is_plane_enabled = inst->streamon_out &&
+		vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	is_plane_enabled |= inst->streamon_cap &&
+		vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+
+	if (!is_plane_enabled) {
+		dev_info(dev, "%s: Yet to start_stream the Q",
+			 vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+			 "FTB" : "ETB");
 		goto unlock;
+	}
 
 	ret = is_buf_refed(inst, vbuf);
 	if (ret)
@@ -1009,37 +1081,72 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
 	struct venus_core *core = inst->core;
 	int ret;
 
-	mutex_lock(&inst->lock);
-
-	if (inst->streamon_out & inst->streamon_cap) {
-		ret = hfi_session_stop(inst);
-		ret |= hfi_session_unload_res(inst);
+	hfi_session_stop(inst);
+	ret = hfi_session_unload_res(inst);
+	if (inst->hfi_codec == HFI_VIDEO_CODEC_H264)
 		ret |= session_unregister_bufs(inst);
-		ret |= intbufs_free(inst);
-		ret |= hfi_session_deinit(inst);
-
-		if (inst->session_error || core->sys_error)
-			ret = -EIO;
+	ret |= intbufs_free(inst);
+	ret |= hfi_session_deinit(inst);
 
-		if (ret)
-			hfi_session_abort(inst);
+	if (inst->session_error || core->sys_error)
+		ret = -EIO;
 
-		venus_helper_free_dpb_bufs(inst);
+	if (IS_V3(core) && ret)
+		hfi_session_abort(inst);
 
-		load_scale_clocks(core);
-		INIT_LIST_HEAD(&inst->registeredbufs);
-	}
+	venus_helper_free_dpb_bufs(inst);
+	load_scale_clocks(core);
+	INIT_LIST_HEAD(&inst->registeredbufs);
 
 	venus_helper_buffers_done(inst, VB2_BUF_STATE_ERROR);
+}
+EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
 
-	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-		inst->streamon_out = 0;
-	else
-		inst->streamon_cap = 0;
+int venus_helper_alloc_intbufs(struct venus_inst *inst)
+{
+	int ret = 0;
 
-	mutex_unlock(&inst->lock);
+	ret = intbufs_free(inst);
+	ret |= intbufs_alloc(inst);
+
+	return ret;
 }
-EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
+EXPORT_SYMBOL_GPL(venus_helper_alloc_intbufs);
+
+int venus_helper_alloc_reconfig_bufs(struct venus_inst *inst)
+{
+	int ret = 0;
+
+	ret = unset_reconfig_buffers(inst);
+	ret |= alloc_reconfig_buffers(inst);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(venus_helper_alloc_reconfig_bufs);
+
+int venus_helper_queue_initial_bufs(struct venus_inst *inst, unsigned int type)
+{
+	struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+	struct v4l2_m2m_buffer *buf, *n;
+	int ret;
+
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)	{
+		v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n)	{
+			ret = session_process_buf(inst, &buf->vb);
+			if (ret)
+				return_buf_error(inst, &buf->vb);
+		}
+	}
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
+			ret = session_process_buf(inst, &buf->vb);
+			if (ret)
+				return_buf_error(inst, &buf->vb);
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(venus_helper_queue_initial_bufs);
 
 int venus_helper_vb2_start_streaming(struct venus_inst *inst)
 {
@@ -1064,14 +1171,8 @@ int venus_helper_vb2_start_streaming(struct venus_inst *inst)
 	if (ret)
 		goto err_unload_res;
 
-	ret = venus_helper_queue_dpb_bufs(inst);
-	if (ret)
-		goto err_session_stop;
-
 	return 0;
 
-err_session_stop:
-	hfi_session_stop(inst);
 err_unload_res:
 	hfi_session_unload_res(inst);
 err_unreg_bufs:
diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h
index 2475f284..3de0c44 100644
--- a/drivers/media/platform/qcom/venus/helpers.h
+++ b/drivers/media/platform/qcom/venus/helpers.h
@@ -31,6 +31,8 @@ void venus_helper_buffers_done(struct venus_inst *inst,
 int venus_helper_vb2_start_streaming(struct venus_inst *inst);
 void venus_helper_m2m_device_run(void *priv);
 void venus_helper_m2m_job_abort(void *priv);
+int venus_helper_queue_initial_bufs(struct venus_inst *inst, unsigned int type);
+int venus_helper_alloc_intbufs(struct venus_inst *inst);
 int venus_helper_get_bufreq(struct venus_inst *inst, u32 type,
 			    struct hfi_buffer_requirements *req);
 u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height);
@@ -62,4 +64,5 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 fmt, u32 *out_fmt,
 int venus_helper_free_dpb_bufs(struct venus_inst *inst);
 int venus_helper_power_enable(struct venus_core *core, u32 session_type,
 			      bool enable);
+int venus_helper_alloc_reconfig_bufs(struct venus_inst *inst);
 #endif
diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c
index 2420782..36a4784 100644
--- a/drivers/media/platform/qcom/venus/hfi.c
+++ b/drivers/media/platform/qcom/venus/hfi.c
@@ -308,6 +308,7 @@ int hfi_session_stop(struct venus_inst *inst)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(hfi_session_stop);
 
 int hfi_session_continue(struct venus_inst *inst)
 {
@@ -384,14 +385,14 @@ int hfi_session_unload_res(struct venus_inst *inst)
 	return 0;
 }
 
-int hfi_session_flush(struct venus_inst *inst)
+int hfi_session_flush(struct venus_inst *inst, u32 mode)
 {
 	const struct hfi_ops *ops = inst->core->ops;
 	int ret;
 
 	reinit_completion(&inst->done);
 
-	ret = ops->session_flush(inst, HFI_FLUSH_ALL);
+	ret = ops->session_flush(inst, mode);
 	if (ret)
 		return ret;
 
diff --git a/drivers/media/platform/qcom/venus/hfi.h b/drivers/media/platform/qcom/venus/hfi.h
index 6038d8e..5e883a1 100644
--- a/drivers/media/platform/qcom/venus/hfi.h
+++ b/drivers/media/platform/qcom/venus/hfi.h
@@ -170,7 +170,7 @@ struct hfi_ops {
 int hfi_session_abort(struct venus_inst *inst);
 int hfi_session_load_res(struct venus_inst *inst);
 int hfi_session_unload_res(struct venus_inst *inst);
-int hfi_session_flush(struct venus_inst *inst);
+int hfi_session_flush(struct venus_inst *inst, u32 mode);
 int hfi_session_set_buffers(struct venus_inst *inst,
 			    struct hfi_buffer_desc *bd);
 int hfi_session_unset_buffers(struct venus_inst *inst,
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index 991e158..98675db 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -207,7 +207,6 @@ static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
 
 		inst->out_width = inst->reconfig_width;
 		inst->out_height = inst->reconfig_height;
-		inst->reconfig = false;
 
 		format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 		format.fmt.pix_mp.pixelformat = inst->fmt_cap->pixfmt;
@@ -223,6 +222,9 @@ static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
 	pixmp->pixelformat = fmt->pixfmt;
 
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (!(inst->reconfig))
+			return -EINVAL;
+
 		pixmp->width = inst->width;
 		pixmp->height = inst->height;
 		pixmp->colorspace = inst->colorspace;
@@ -451,6 +453,8 @@ static int vdec_subscribe_event(struct v4l2_fh *fh,
 		if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
 			return -EINVAL;
 		break;
+	case V4L2_DEC_CMD_START:
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -465,6 +469,9 @@ static int vdec_subscribe_event(struct v4l2_fh *fh,
 	struct hfi_frame_data fdata = {0};
 	int ret;
 
+	if (cmd->cmd != V4L2_DEC_CMD_STOP)
+		return 0;
+
 	ret = vdec_try_decoder_cmd(file, fh, cmd);
 	if (ret)
 		return ret;
@@ -790,22 +797,60 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct venus_inst *inst = vb2_get_drv_priv(q);
 	int ret;
+	bool is_mplane_enabled;
 
 	mutex_lock(&inst->lock);
+	is_mplane_enabled = q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+				inst->streamon_cap;
+	is_mplane_enabled |= q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+				inst->streamon_out;
 
-	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-		inst->streamon_out = 1;
-	else
-		inst->streamon_cap = 1;
+	if (is_mplane_enabled) {
+		mutex_unlock(&inst->lock);
+		return 0;
+	}
 
-	if (!(inst->streamon_out & inst->streamon_cap)) {
+	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+	    !inst->streamon_out){
 		mutex_unlock(&inst->lock);
 		return 0;
 	}
 
+	if (inst->streamon_out && !inst->streamon_cap &&
+	    q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		ret = vdec_output_conf(inst);
+		if (ret)
+			goto deinit_sess;
+
+		ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs,
+						inst->num_output_bufs,
+						inst->num_output_bufs);
+
+		if (ret)
+			goto deinit_sess;
+
+		ret = vdec_verify_conf(inst);
+		if (ret)
+			goto deinit_sess;
+
+		if (inst->reconfig)
+			ret = venus_helper_alloc_reconfig_bufs(inst);
+
+		if (ret)
+			goto deinit_sess;
+
+		ret = venus_helper_alloc_dpb_bufs(inst);
+		if (ret)
+			goto deinit_sess;
+
+		if (inst->reconfig) {
+			hfi_session_continue(inst);
+			inst->reconfig = false;
+		}
+		goto enable_mplane;
+	}
 	venus_helper_init_instance(inst);
 
-	inst->reconfig = false;
 	inst->sequence_cap = 0;
 	inst->sequence_out = 0;
 
@@ -830,14 +875,17 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
 	if (ret)
 		goto deinit_sess;
 
-	ret = venus_helper_alloc_dpb_bufs(inst);
-	if (ret)
-		goto deinit_sess;
-
 	ret = venus_helper_vb2_start_streaming(inst);
 	if (ret)
 		goto deinit_sess;
 
+enable_mplane:
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		inst->streamon_out = 1;
+	else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		inst->streamon_cap = 1;
+
+	ret = venus_helper_queue_initial_bufs(inst, q->type);
 	mutex_unlock(&inst->lock);
 
 	return 0;
@@ -854,12 +902,42 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
 	return ret;
 }
 
+static void vdec_stop_streaming(struct vb2_queue *q)
+{
+	struct venus_inst *inst = vb2_get_drv_priv(q);
+	int ret;
+
+	mutex_lock(&inst->lock);
+
+	if (!inst->streamon_cap && !inst->streamon_out)
+		goto unlock;
+
+	if (inst->streamon_cap &&
+	    q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		ret = hfi_session_stop(inst);
+		inst->streamon_cap = 0;
+	}
+
+	if (inst->streamon_out && !inst->streamon_cap) {
+		inst->streamon_out = 0;
+		venus_helper_vb2_stop_streaming(q);
+	}
+
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		inst->streamon_out = 0;
+	else
+		inst->streamon_cap = 0;
+unlock:
+	venus_helper_buffers_done(inst, VB2_BUF_STATE_ERROR);
+	mutex_unlock(&inst->lock);
+}
+
 static const struct vb2_ops vdec_vb2_ops = {
 	.queue_setup = vdec_queue_setup,
 	.buf_init = venus_helper_vb2_buf_init,
 	.buf_prepare = venus_helper_vb2_buf_prepare,
 	.start_streaming = vdec_start_streaming,
-	.stop_streaming = venus_helper_vb2_stop_streaming,
+	.stop_streaming = vdec_stop_streaming,
 	.buf_queue = venus_helper_vb2_buf_queue,
 };
 
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index ce85962..3ce0f7a 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -1005,12 +1005,30 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count)
 	return ret;
 }
 
+void venc_stop_streaming(struct vb2_queue *q)
+{
+	struct venus_inst *inst = vb2_get_drv_priv(q);
+
+	mutex_lock(&inst->lock);
+
+	if (inst->streamon_out & inst->streamon_cap)
+		venus_helper_vb2_stop_streaming(q);
+
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		inst->streamon_out = 0;
+	else
+		inst->streamon_cap = 0;
+
+	mutex_unlock(&inst->lock);
+}
+EXPORT_SYMBOL_GPL(venc_stop_streaming);
+
 static const struct vb2_ops venc_vb2_ops = {
 	.queue_setup = venc_queue_setup,
 	.buf_init = venus_helper_vb2_buf_init,
 	.buf_prepare = venus_helper_vb2_buf_prepare,
 	.start_streaming = venc_start_streaming,
-	.stop_streaming = venus_helper_vb2_stop_streaming,
+	.stop_streaming = venc_stop_streaming,
 	.buf_queue = venus_helper_vb2_buf_queue,
 };
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux