aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0503-staging-bcm2835-codec-Allow-decode-res-changed-befor.patch
blob: e375dcbeb35d8dcfd09fb4b22af6f4d591ae231f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
From 6eded7dd8bcf00c6c4f354cd2edfaabc8e82e8b7 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Fri, 9 Oct 2020 10:40:27 +0100
Subject: [PATCH] staging: bcm2835-codec: Allow decode res changed
 before STREAMON(CAPTURE)

The V4L2 stateful video decoder API requires that you can STREAMON
on only the OUTPUT queue, feed in buffers, and wait for the
SOURCE_CHANGE event.
This requires that we enable the MMAL output port at the same time
as the input port, because the output port is the one that creates
the SOURCE_CHANGED event.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 .../bcm2835-codec/bcm2835-v4l2-codec.c        | 137 +++++++++++++++---
 1 file changed, 117 insertions(+), 20 deletions(-)

--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -1498,6 +1498,7 @@ static int vidioc_s_fmt(struct bcm2835_c
 	struct vb2_queue *vq;
 	struct vchiq_mmal_port *port;
 	bool update_capture_port = false;
+	bool reenable_port = false;
 	int ret;
 
 	v4l2_dbg(1, debug, &ctx->dev->v4l2_dev,	"Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
@@ -1575,6 +1576,24 @@ static int vidioc_s_fmt(struct bcm2835_c
 	if (!port)
 		return 0;
 
+	if (port->enabled) {
+		/*
+		 * This should only ever happen with DECODE and the MMAL output
+		 * port that has been enabled for resolution changed events.
+		 * In this case no buffers have been allocated or sent to the
+		 * component, so warn on that.
+		 */
+		WARN_ON(ctx->dev->role != DECODE ||
+			f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
+			atomic_read(&port->buffers_with_vpu));
+
+		ret = vchiq_mmal_port_disable(ctx->dev->instance, port);
+		if (ret)
+			v4l2_err(&ctx->dev->v4l2_dev, "%s: Error disabling port update buffer count, ret %d\n",
+				 __func__, ret);
+		reenable_port = true;
+	}
+
 	setup_mmal_port_format(ctx, q_data, port);
 	ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
 	if (ret) {
@@ -1589,6 +1608,14 @@ static int vidioc_s_fmt(struct bcm2835_c
 			 port->minimum_buffer.size);
 	}
 
+	if (reenable_port) {
+		ret = vchiq_mmal_port_enable(ctx->dev->instance,
+					     port,
+					     op_buffer_cb);
+		if (ret)
+			v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
+				 __func__, ret);
+	}
 	v4l2_dbg(1, debug, &ctx->dev->v4l2_dev,	"Set format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
 		 f->type, q_data->crop_width, q_data->height,
 		 q_data->fmt->fourcc, q_data->sizeimage);
@@ -2467,9 +2494,11 @@ static int bcm2835_codec_create_componen
 
 	setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC],
 			       &ctx->component->input[0]);
+	ctx->component->input[0].cb_ctx = ctx;
 
 	setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST],
 			       &ctx->component->output[0]);
+	ctx->component->output[0].cb_ctx = ctx;
 
 	ret = vchiq_mmal_port_set_format(dev->instance,
 					 &ctx->component->input[0]);
@@ -2724,6 +2753,24 @@ static void bcm2835_codec_buffer_cleanup
 	bcm2835_codec_mmal_buf_cleanup(&buf->mmal);
 }
 
+static void bcm2835_codec_flush_buffers(struct bcm2835_codec_ctx *ctx,
+					struct vchiq_mmal_port *port)
+{
+	int ret;
+
+	while (atomic_read(&port->buffers_with_vpu)) {
+		v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n",
+			 __func__, atomic_read(&port->buffers_with_vpu));
+		ret = wait_for_completion_timeout(&ctx->frame_cmplt,
+						  COMPLETE_TIMEOUT);
+		if (ret <= 0) {
+			v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
+				 __func__,
+				 atomic_read(&port->buffers_with_vpu));
+			break;
+		}
+	}
+}
 static int bcm2835_codec_start_streaming(struct vb2_queue *q,
 					 unsigned int count)
 {
@@ -2731,7 +2778,7 @@ static int bcm2835_codec_start_streaming
 	struct bcm2835_codec_dev *dev = ctx->dev;
 	struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type);
 	struct vchiq_mmal_port *port = get_port_data(ctx, q->type);
-	int ret;
+	int ret = 0;
 
 	v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d count %d\n",
 		 __func__, q->type, count);
@@ -2746,6 +2793,34 @@ static int bcm2835_codec_start_streaming
 		ctx->component_enabled = true;
 	}
 
+	if (port->enabled) {
+		unsigned int num_buffers;
+
+		init_completion(&ctx->frame_cmplt);
+
+		/*
+		 * This should only ever happen with DECODE and the MMAL output
+		 * port that has been enabled for resolution changed events.
+		 * In this case no buffers have been allocated or sent to the
+		 * component, so warn on that.
+		 */
+		WARN_ON(ctx->dev->role != DECODE);
+		WARN_ON(q->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+		WARN_ON(atomic_read(&port->buffers_with_vpu));
+
+		/*
+		 * Disable will reread the port format, so retain buffer count.
+		 */
+		num_buffers = port->current_buffer.num;
+
+		ret = vchiq_mmal_port_disable(dev->instance, port);
+		if (ret)
+			v4l2_err(&ctx->dev->v4l2_dev, "%s: Error disabling port update buffer count, ret %d\n",
+				 __func__, ret);
+		bcm2835_codec_flush_buffers(ctx, port);
+		port->current_buffer.num = num_buffers;
+	}
+
 	if (count < port->minimum_buffer.num)
 		count = port->minimum_buffer.num;
 
@@ -2760,6 +2835,22 @@ static int bcm2835_codec_start_streaming
 				 __func__, ret);
 	}
 
+	if (dev->role == DECODE &&
+	    q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+	    !ctx->component->output[0].enabled) {
+		/*
+		 * Decode needs to enable the MMAL output/V4L2 CAPTURE
+		 * port at this point too so that we have everything
+		 * set up for dynamic resolution changes.
+		 */
+		ret = vchiq_mmal_port_enable(dev->instance,
+					     &ctx->component->output[0],
+					     op_buffer_cb);
+		if (ret)
+			v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
+				 __func__, ret);
+	}
+
 	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		/*
 		 * Create the EOS buffer.
@@ -2771,7 +2862,6 @@ static int bcm2835_codec_start_streaming
 				      &q_data->eos_buffer.mmal);
 		q_data->eos_buffer_in_use = false;
 
-		port->cb_ctx = ctx;
 		ret = vchiq_mmal_port_enable(dev->instance,
 					     port,
 					     ip_buffer_cb);
@@ -2779,14 +2869,17 @@ static int bcm2835_codec_start_streaming
 			v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling i/p port, ret %d\n",
 				 __func__, ret);
 	} else {
-		port->cb_ctx = ctx;
-		ret = vchiq_mmal_port_enable(dev->instance,
-					     port,
-					     op_buffer_cb);
-		if (ret)
-			v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
-				 __func__, ret);
+		if (!port->enabled) {
+			ret = vchiq_mmal_port_enable(dev->instance,
+						     port,
+						     op_buffer_cb);
+			if (ret)
+				v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
+					 __func__, ret);
+		}
 	}
+	v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Done, ret %d\n",
+		 __func__, ret);
 	return ret;
 }
 
@@ -2825,17 +2918,21 @@ static void bcm2835_codec_stop_streaming
 			 __func__, V4L2_TYPE_IS_OUTPUT(q->type) ? "i/p" : "o/p",
 			 ret);
 
-	while (atomic_read(&port->buffers_with_vpu)) {
-		v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n",
-			 __func__, atomic_read(&port->buffers_with_vpu));
-		ret = wait_for_completion_timeout(&ctx->frame_cmplt,
-						  COMPLETE_TIMEOUT);
-		if (ret <= 0) {
-			v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
-				 __func__,
-				 atomic_read(&port->buffers_with_vpu));
-			break;
-		}
+	bcm2835_codec_flush_buffers(ctx, port);
+
+	if (dev->role == DECODE &&
+	    q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+	    ctx->component->input[0].enabled) {
+		/*
+		 * For decode we need to keep the MMAL output port enabled for
+		 * resolution changed events whenever the input is enabled.
+		 */
+		ret = vchiq_mmal_port_enable(dev->instance,
+					     &ctx->component->output[0],
+					     op_buffer_cb);
+		if (ret)
+			v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
+				 __func__, ret);
 	}
 
 	/* If both ports disabled, then disable the component */