acfc07732698f245a6466e03564c292579918ec9
[openwrt/staging/linusw.git] /
1 From 7580dc7daa2ac363c20674545be200802e4f6dce Mon Sep 17 00:00:00 2001
2 From: John Cox <jc@kynesim.co.uk>
3 Date: Wed, 1 Sep 2021 16:34:50 +0100
4 Subject: [PATCH] media: rpivid: Avoid returning EINVAL to a G_FMT
5 ioctl
6
7 V4L2 spec says that G/S/TRY_FMT IOCTLs should never return errors for
8 anything other than wrong buffer types. Improve the capture format
9 function such that this is so and unsupported values get converted
10 to supported ones properly.
11
12 Signed-off-by: John Cox <jc@kynesim.co.uk>
13 ---
14 drivers/staging/media/rpivid/rpivid.c | 1 -
15 drivers/staging/media/rpivid/rpivid.h | 2 -
16 drivers/staging/media/rpivid/rpivid_video.c | 99 +++++++++++----------
17 drivers/staging/media/rpivid/rpivid_video.h | 3 +-
18 4 files changed, 54 insertions(+), 51 deletions(-)
19
20 --- a/drivers/staging/media/rpivid/rpivid.c
21 +++ b/drivers/staging/media/rpivid/rpivid.c
22 @@ -249,7 +249,6 @@ static int rpivid_open(struct file *file
23 /* The only bit of format info that we can guess now is H265 src
24 * Everything else we need more info for
25 */
26 - ctx->src_fmt.pixelformat = RPIVID_SRC_PIXELFORMAT_DEFAULT;
27 rpivid_prepare_src_format(&ctx->src_fmt);
28
29 v4l2_fh_add(&ctx->fh);
30 --- a/drivers/staging/media/rpivid/rpivid.h
31 +++ b/drivers/staging/media/rpivid/rpivid.h
32 @@ -35,8 +35,6 @@
33
34 #define RPIVID_QUIRK_NO_DMA_OFFSET BIT(0)
35
36 -#define RPIVID_SRC_PIXELFORMAT_DEFAULT V4L2_PIX_FMT_HEVC_SLICE
37 -
38 enum rpivid_irq_status {
39 RPIVID_IRQ_NONE,
40 RPIVID_IRQ_ERROR,
41 --- a/drivers/staging/media/rpivid/rpivid_video.c
42 +++ b/drivers/staging/media/rpivid/rpivid_video.c
43 @@ -27,6 +27,8 @@
44
45 #define RPIVID_MIN_WIDTH 16U
46 #define RPIVID_MIN_HEIGHT 16U
47 +#define RPIVID_DEFAULT_WIDTH 1920U
48 +#define RPIVID_DEFAULT_HEIGHT 1088U
49 #define RPIVID_MAX_WIDTH 4096U
50 #define RPIVID_MAX_HEIGHT 4096U
51
52 @@ -70,25 +72,22 @@ size_t rpivid_bit_buf_size(unsigned int
53 return rpivid_round_up_size(bits_alloc);
54 }
55
56 -int rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt)
57 +void rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt)
58 {
59 size_t size;
60 u32 w;
61 u32 h;
62
63 - if (pix_fmt->pixelformat != V4L2_PIX_FMT_HEVC_SLICE)
64 - return -EINVAL;
65 -
66 w = pix_fmt->width;
67 h = pix_fmt->height;
68 if (!w || !h) {
69 - w = 1920;
70 - h = 1080;
71 + w = RPIVID_DEFAULT_WIDTH;
72 + h = RPIVID_DEFAULT_HEIGHT;
73 }
74 - if (w > 4096)
75 - w = 4096;
76 - if (h > 4096)
77 - h = 4096;
78 + if (w > RPIVID_MAX_WIDTH)
79 + w = RPIVID_MAX_WIDTH;
80 + if (h > RPIVID_MAX_HEIGHT)
81 + h = RPIVID_MAX_HEIGHT;
82
83 if (!pix_fmt->plane_fmt[0].sizeimage ||
84 pix_fmt->plane_fmt[0].sizeimage > SZ_32M) {
85 @@ -98,6 +97,7 @@ int rpivid_prepare_src_format(struct v4l
86 /* Set a minimum */
87 size = max_t(u32, SZ_4K, pix_fmt->plane_fmt[0].sizeimage);
88
89 + pix_fmt->pixelformat = V4L2_PIX_FMT_HEVC_SLICE;
90 pix_fmt->width = w;
91 pix_fmt->height = h;
92 pix_fmt->num_planes = 1;
93 @@ -105,22 +105,33 @@ int rpivid_prepare_src_format(struct v4l
94 /* Zero bytes per line for encoded source. */
95 pix_fmt->plane_fmt[0].bytesperline = 0;
96 pix_fmt->plane_fmt[0].sizeimage = size;
97 -
98 - return 0;
99 }
100
101 -int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt)
102 +/* Take any pix_format and make it valid */
103 +static void rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt)
104 {
105 unsigned int width = pix_fmt->width;
106 unsigned int height = pix_fmt->height;
107 unsigned int sizeimage = pix_fmt->plane_fmt[0].sizeimage;
108 unsigned int bytesperline = pix_fmt->plane_fmt[0].bytesperline;
109
110 - switch (pix_fmt->pixelformat) {
111 + if (!width)
112 + width = RPIVID_DEFAULT_WIDTH;
113 + if (width > RPIVID_MAX_WIDTH)
114 + width = RPIVID_MAX_WIDTH;
115 + if (!height)
116 + height = RPIVID_DEFAULT_HEIGHT;
117 + if (height > RPIVID_MAX_HEIGHT)
118 + height = RPIVID_MAX_HEIGHT;
119 +
120 /* For column formats set bytesperline to column height (stride2) */
121 + switch (pix_fmt->pixelformat) {
122 + default:
123 + pix_fmt->pixelformat = V4L2_PIX_FMT_NV12_COL128;
124 + fallthrough;
125 case V4L2_PIX_FMT_NV12_COL128:
126 /* Width rounds up to columns */
127 - width = ALIGN(min(width, RPIVID_MAX_WIDTH), 128);
128 + width = ALIGN(width, 128);
129
130 /* 16 aligned height - not sure we even need that */
131 height = ALIGN(height, 16);
132 @@ -140,7 +151,7 @@ int rpivid_prepare_dst_format(struct v4l
133 /* width in pixels (3 pels = 4 bytes) rounded to 128 byte
134 * columns
135 */
136 - width = ALIGN(((min(width, RPIVID_MAX_WIDTH) + 2) / 3), 32) * 3;
137 + width = ALIGN(((width + 2) / 3), 32) * 3;
138
139 /* 16-aligned height. */
140 height = ALIGN(height, 16);
141 @@ -157,9 +168,6 @@ int rpivid_prepare_dst_format(struct v4l
142 sizeimage = constrain2x(sizeimage,
143 bytesperline * width * 4 / 3);
144 break;
145 -
146 - default:
147 - return -EINVAL;
148 }
149
150 pix_fmt->width = width;
151 @@ -169,7 +177,6 @@ int rpivid_prepare_dst_format(struct v4l
152 pix_fmt->plane_fmt[0].bytesperline = bytesperline;
153 pix_fmt->plane_fmt[0].sizeimage = sizeimage;
154 pix_fmt->num_planes = 1;
155 - return 0;
156 }
157
158 static int rpivid_querycap(struct file *file, void *priv,
159 @@ -260,14 +267,13 @@ static u32 pixelformat_from_sps(const st
160 {
161 u32 pf = 0;
162
163 - // Use width 0 as a signifier of unsetness
164 - if (!is_sps_set(sps)) {
165 + if (!is_sps_set(sps) || !rpivid_hevc_validate_sps(sps)) {
166 /* Treat this as an error? For now return both */
167 if (index == 0)
168 pf = V4L2_PIX_FMT_NV12_COL128;
169 else if (index == 1)
170 pf = V4L2_PIX_FMT_NV12_10_COL128;
171 - } else if (index == 0 && rpivid_hevc_validate_sps(sps)) {
172 + } else if (index == 0) {
173 if (sps->bit_depth_luma_minus8 == 0)
174 pf = V4L2_PIX_FMT_NV12_COL128;
175 else if (sps->bit_depth_luma_minus8 == 2)
176 @@ -282,11 +288,14 @@ rpivid_hevc_default_dst_fmt(struct rpivi
177 {
178 const struct v4l2_ctrl_hevc_sps * const sps =
179 rpivid_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
180 - struct v4l2_pix_format_mplane pix_fmt = {
181 - .width = sps->pic_width_in_luma_samples,
182 - .height = sps->pic_height_in_luma_samples,
183 - .pixelformat = pixelformat_from_sps(sps, 0)
184 - };
185 + struct v4l2_pix_format_mplane pix_fmt;
186 +
187 + memset(&pix_fmt, 0, sizeof(pix_fmt));
188 + if (is_sps_set(sps)) {
189 + pix_fmt.width = sps->pic_width_in_luma_samples;
190 + pix_fmt.height = sps->pic_height_in_luma_samples;
191 + pix_fmt.pixelformat = pixelformat_from_sps(sps, 0);
192 + }
193
194 rpivid_prepare_dst_format(&pix_fmt);
195 return pix_fmt;
196 @@ -315,14 +324,23 @@ static int rpivid_enum_fmt_vid_cap(struc
197 return 0;
198 }
199
200 +/*
201 + * get dst format - sets it to default if otherwise unset
202 + * returns a pointer to the struct as a convienience
203 + */
204 +static struct v4l2_pix_format_mplane *get_dst_fmt(struct rpivid_ctx *const ctx)
205 +{
206 + if (!ctx->dst_fmt_set)
207 + ctx->dst_fmt = rpivid_hevc_default_dst_fmt(ctx);
208 + return &ctx->dst_fmt;
209 +}
210 +
211 static int rpivid_g_fmt_vid_cap(struct file *file, void *priv,
212 struct v4l2_format *f)
213 {
214 struct rpivid_ctx *ctx = rpivid_file2ctx(file);
215
216 - if (!ctx->dst_fmt_set)
217 - ctx->dst_fmt = rpivid_hevc_default_dst_fmt(ctx);
218 - f->fmt.pix_mp = ctx->dst_fmt;
219 + f->fmt.pix_mp = *get_dst_fmt(ctx);
220 return 0;
221 }
222
223 @@ -358,31 +376,20 @@ static int rpivid_try_fmt_vid_cap(struct
224 break;
225 }
226
227 - // If we can't use requested fmt then set to default
228 - if (pixelformat == 0) {
229 - pixelformat = pixelformat_from_sps(sps, 0);
230 - // If we don't have a default then give up
231 - if (pixelformat == 0)
232 - return -EINVAL;
233 - }
234 -
235 // We don't have any way of finding out colourspace so believe
236 // anything we are told - take anything set in src as a default
237 if (f->fmt.pix_mp.colorspace == V4L2_COLORSPACE_DEFAULT)
238 copy_color(&f->fmt.pix_mp, &ctx->src_fmt);
239
240 f->fmt.pix_mp.pixelformat = pixelformat;
241 - return rpivid_prepare_dst_format(&f->fmt.pix_mp);
242 + rpivid_prepare_dst_format(&f->fmt.pix_mp);
243 + return 0;
244 }
245
246 static int rpivid_try_fmt_vid_out(struct file *file, void *priv,
247 struct v4l2_format *f)
248 {
249 - if (rpivid_prepare_src_format(&f->fmt.pix_mp)) {
250 - // Set default src format
251 - f->fmt.pix_mp.pixelformat = RPIVID_SRC_PIXELFORMAT_DEFAULT;
252 - rpivid_prepare_src_format(&f->fmt.pix_mp);
253 - }
254 + rpivid_prepare_src_format(&f->fmt.pix_mp);
255 return 0;
256 }
257
258 @@ -474,7 +481,7 @@ static int rpivid_queue_setup(struct vb2
259 if (V4L2_TYPE_IS_OUTPUT(vq->type))
260 pix_fmt = &ctx->src_fmt;
261 else
262 - pix_fmt = &ctx->dst_fmt;
263 + pix_fmt = get_dst_fmt(ctx);
264
265 if (*nplanes) {
266 if (sizes[0] < pix_fmt->plane_fmt[0].sizeimage)
267 --- a/drivers/staging/media/rpivid/rpivid_video.h
268 +++ b/drivers/staging/media/rpivid/rpivid_video.h
269 @@ -28,7 +28,6 @@ int rpivid_queue_init(void *priv, struct
270 size_t rpivid_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8);
271 size_t rpivid_round_up_size(const size_t x);
272
273 -int rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt);
274 -int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt);
275 +void rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt);
276
277 #endif