e375dcbeb35d8dcfd09fb4b22af6f4d591ae231f
[openwrt/staging/neocturne.git] /
1 From 6eded7dd8bcf00c6c4f354cd2edfaabc8e82e8b7 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Fri, 9 Oct 2020 10:40:27 +0100
4 Subject: [PATCH] staging: bcm2835-codec: Allow decode res changed
5 before STREAMON(CAPTURE)
6
7 The V4L2 stateful video decoder API requires that you can STREAMON
8 on only the OUTPUT queue, feed in buffers, and wait for the
9 SOURCE_CHANGE event.
10 This requires that we enable the MMAL output port at the same time
11 as the input port, because the output port is the one that creates
12 the SOURCE_CHANGED event.
13
14 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
15 ---
16 .../bcm2835-codec/bcm2835-v4l2-codec.c | 137 +++++++++++++++---
17 1 file changed, 117 insertions(+), 20 deletions(-)
18
19 --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
20 +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
21 @@ -1498,6 +1498,7 @@ static int vidioc_s_fmt(struct bcm2835_c
22 struct vb2_queue *vq;
23 struct vchiq_mmal_port *port;
24 bool update_capture_port = false;
25 + bool reenable_port = false;
26 int ret;
27
28 v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
29 @@ -1575,6 +1576,24 @@ static int vidioc_s_fmt(struct bcm2835_c
30 if (!port)
31 return 0;
32
33 + if (port->enabled) {
34 + /*
35 + * This should only ever happen with DECODE and the MMAL output
36 + * port that has been enabled for resolution changed events.
37 + * In this case no buffers have been allocated or sent to the
38 + * component, so warn on that.
39 + */
40 + WARN_ON(ctx->dev->role != DECODE ||
41 + f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
42 + atomic_read(&port->buffers_with_vpu));
43 +
44 + ret = vchiq_mmal_port_disable(ctx->dev->instance, port);
45 + if (ret)
46 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Error disabling port update buffer count, ret %d\n",
47 + __func__, ret);
48 + reenable_port = true;
49 + }
50 +
51 setup_mmal_port_format(ctx, q_data, port);
52 ret = vchiq_mmal_port_set_format(ctx->dev->instance, port);
53 if (ret) {
54 @@ -1589,6 +1608,14 @@ static int vidioc_s_fmt(struct bcm2835_c
55 port->minimum_buffer.size);
56 }
57
58 + if (reenable_port) {
59 + ret = vchiq_mmal_port_enable(ctx->dev->instance,
60 + port,
61 + op_buffer_cb);
62 + if (ret)
63 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
64 + __func__, ret);
65 + }
66 v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Set format for type %d, wxh: %dx%d, fmt: %08x, size %u\n",
67 f->type, q_data->crop_width, q_data->height,
68 q_data->fmt->fourcc, q_data->sizeimage);
69 @@ -2467,9 +2494,11 @@ static int bcm2835_codec_create_componen
70
71 setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC],
72 &ctx->component->input[0]);
73 + ctx->component->input[0].cb_ctx = ctx;
74
75 setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST],
76 &ctx->component->output[0]);
77 + ctx->component->output[0].cb_ctx = ctx;
78
79 ret = vchiq_mmal_port_set_format(dev->instance,
80 &ctx->component->input[0]);
81 @@ -2724,6 +2753,24 @@ static void bcm2835_codec_buffer_cleanup
82 bcm2835_codec_mmal_buf_cleanup(&buf->mmal);
83 }
84
85 +static void bcm2835_codec_flush_buffers(struct bcm2835_codec_ctx *ctx,
86 + struct vchiq_mmal_port *port)
87 +{
88 + int ret;
89 +
90 + while (atomic_read(&port->buffers_with_vpu)) {
91 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n",
92 + __func__, atomic_read(&port->buffers_with_vpu));
93 + ret = wait_for_completion_timeout(&ctx->frame_cmplt,
94 + COMPLETE_TIMEOUT);
95 + if (ret <= 0) {
96 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
97 + __func__,
98 + atomic_read(&port->buffers_with_vpu));
99 + break;
100 + }
101 + }
102 +}
103 static int bcm2835_codec_start_streaming(struct vb2_queue *q,
104 unsigned int count)
105 {
106 @@ -2731,7 +2778,7 @@ static int bcm2835_codec_start_streaming
107 struct bcm2835_codec_dev *dev = ctx->dev;
108 struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type);
109 struct vchiq_mmal_port *port = get_port_data(ctx, q->type);
110 - int ret;
111 + int ret = 0;
112
113 v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d count %d\n",
114 __func__, q->type, count);
115 @@ -2746,6 +2793,34 @@ static int bcm2835_codec_start_streaming
116 ctx->component_enabled = true;
117 }
118
119 + if (port->enabled) {
120 + unsigned int num_buffers;
121 +
122 + init_completion(&ctx->frame_cmplt);
123 +
124 + /*
125 + * This should only ever happen with DECODE and the MMAL output
126 + * port that has been enabled for resolution changed events.
127 + * In this case no buffers have been allocated or sent to the
128 + * component, so warn on that.
129 + */
130 + WARN_ON(ctx->dev->role != DECODE);
131 + WARN_ON(q->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
132 + WARN_ON(atomic_read(&port->buffers_with_vpu));
133 +
134 + /*
135 + * Disable will reread the port format, so retain buffer count.
136 + */
137 + num_buffers = port->current_buffer.num;
138 +
139 + ret = vchiq_mmal_port_disable(dev->instance, port);
140 + if (ret)
141 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Error disabling port update buffer count, ret %d\n",
142 + __func__, ret);
143 + bcm2835_codec_flush_buffers(ctx, port);
144 + port->current_buffer.num = num_buffers;
145 + }
146 +
147 if (count < port->minimum_buffer.num)
148 count = port->minimum_buffer.num;
149
150 @@ -2760,6 +2835,22 @@ static int bcm2835_codec_start_streaming
151 __func__, ret);
152 }
153
154 + if (dev->role == DECODE &&
155 + q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
156 + !ctx->component->output[0].enabled) {
157 + /*
158 + * Decode needs to enable the MMAL output/V4L2 CAPTURE
159 + * port at this point too so that we have everything
160 + * set up for dynamic resolution changes.
161 + */
162 + ret = vchiq_mmal_port_enable(dev->instance,
163 + &ctx->component->output[0],
164 + op_buffer_cb);
165 + if (ret)
166 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
167 + __func__, ret);
168 + }
169 +
170 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
171 /*
172 * Create the EOS buffer.
173 @@ -2771,7 +2862,6 @@ static int bcm2835_codec_start_streaming
174 &q_data->eos_buffer.mmal);
175 q_data->eos_buffer_in_use = false;
176
177 - port->cb_ctx = ctx;
178 ret = vchiq_mmal_port_enable(dev->instance,
179 port,
180 ip_buffer_cb);
181 @@ -2779,14 +2869,17 @@ static int bcm2835_codec_start_streaming
182 v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling i/p port, ret %d\n",
183 __func__, ret);
184 } else {
185 - port->cb_ctx = ctx;
186 - ret = vchiq_mmal_port_enable(dev->instance,
187 - port,
188 - op_buffer_cb);
189 - if (ret)
190 - v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
191 - __func__, ret);
192 + if (!port->enabled) {
193 + ret = vchiq_mmal_port_enable(dev->instance,
194 + port,
195 + op_buffer_cb);
196 + if (ret)
197 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
198 + __func__, ret);
199 + }
200 }
201 + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Done, ret %d\n",
202 + __func__, ret);
203 return ret;
204 }
205
206 @@ -2825,17 +2918,21 @@ static void bcm2835_codec_stop_streaming
207 __func__, V4L2_TYPE_IS_OUTPUT(q->type) ? "i/p" : "o/p",
208 ret);
209
210 - while (atomic_read(&port->buffers_with_vpu)) {
211 - v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n",
212 - __func__, atomic_read(&port->buffers_with_vpu));
213 - ret = wait_for_completion_timeout(&ctx->frame_cmplt,
214 - COMPLETE_TIMEOUT);
215 - if (ret <= 0) {
216 - v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
217 - __func__,
218 - atomic_read(&port->buffers_with_vpu));
219 - break;
220 - }
221 + bcm2835_codec_flush_buffers(ctx, port);
222 +
223 + if (dev->role == DECODE &&
224 + q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
225 + ctx->component->input[0].enabled) {
226 + /*
227 + * For decode we need to keep the MMAL output port enabled for
228 + * resolution changed events whenever the input is enabled.
229 + */
230 + ret = vchiq_mmal_port_enable(dev->instance,
231 + &ctx->component->output[0],
232 + op_buffer_cb);
233 + if (ret)
234 + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n",
235 + __func__, ret);
236 }
237
238 /* If both ports disabled, then disable the component */