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
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.
12 Signed-off-by: John Cox <jc@kynesim.co.uk>
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(-)
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
26 - ctx->src_fmt.pixelformat = RPIVID_SRC_PIXELFORMAT_DEFAULT;
27 rpivid_prepare_src_format(&ctx->src_fmt);
29 v4l2_fh_add(&ctx->fh);
30 --- a/drivers/staging/media/rpivid/rpivid.h
31 +++ b/drivers/staging/media/rpivid/rpivid.h
34 #define RPIVID_QUIRK_NO_DMA_OFFSET BIT(0)
36 -#define RPIVID_SRC_PIXELFORMAT_DEFAULT V4L2_PIX_FMT_HEVC_SLICE
38 enum rpivid_irq_status {
41 --- a/drivers/staging/media/rpivid/rpivid_video.c
42 +++ b/drivers/staging/media/rpivid/rpivid_video.c
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
52 @@ -70,25 +72,22 @@ size_t rpivid_bit_buf_size(unsigned int
53 return rpivid_round_up_size(bits_alloc);
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)
63 - if (pix_fmt->pixelformat != V4L2_PIX_FMT_HEVC_SLICE)
71 + w = RPIVID_DEFAULT_WIDTH;
72 + h = RPIVID_DEFAULT_HEIGHT;
78 + if (w > RPIVID_MAX_WIDTH)
79 + w = RPIVID_MAX_WIDTH;
80 + if (h > RPIVID_MAX_HEIGHT)
81 + h = RPIVID_MAX_HEIGHT;
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
87 size = max_t(u32, SZ_4K, pix_fmt->plane_fmt[0].sizeimage);
89 + pix_fmt->pixelformat = V4L2_PIX_FMT_HEVC_SLICE;
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;
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)
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;
110 - switch (pix_fmt->pixelformat) {
112 + width = RPIVID_DEFAULT_WIDTH;
113 + if (width > RPIVID_MAX_WIDTH)
114 + width = RPIVID_MAX_WIDTH;
116 + height = RPIVID_DEFAULT_HEIGHT;
117 + if (height > RPIVID_MAX_HEIGHT)
118 + height = RPIVID_MAX_HEIGHT;
120 /* For column formats set bytesperline to column height (stride2) */
121 + switch (pix_fmt->pixelformat) {
123 + pix_fmt->pixelformat = V4L2_PIX_FMT_NV12_COL128;
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);
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
136 - width = ALIGN(((min(width, RPIVID_MAX_WIDTH) + 2) / 3), 32) * 3;
137 + width = ALIGN(((width + 2) / 3), 32) * 3;
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);
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;
158 static int rpivid_querycap(struct file *file, void *priv,
159 @@ -260,14 +267,13 @@ static u32 pixelformat_from_sps(const st
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 */
168 pf = V4L2_PIX_FMT_NV12_COL128;
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
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)
185 + struct v4l2_pix_format_mplane pix_fmt;
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);
194 rpivid_prepare_dst_format(&pix_fmt);
196 @@ -315,14 +324,23 @@ static int rpivid_enum_fmt_vid_cap(struc
201 + * get dst format - sets it to default if otherwise unset
202 + * returns a pointer to the struct as a convienience
204 +static struct v4l2_pix_format_mplane *get_dst_fmt(struct rpivid_ctx *const ctx)
206 + if (!ctx->dst_fmt_set)
207 + ctx->dst_fmt = rpivid_hevc_default_dst_fmt(ctx);
208 + return &ctx->dst_fmt;
211 static int rpivid_g_fmt_vid_cap(struct file *file, void *priv,
212 struct v4l2_format *f)
214 struct rpivid_ctx *ctx = rpivid_file2ctx(file);
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);
223 @@ -358,31 +376,20 @@ static int rpivid_try_fmt_vid_cap(struct
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)
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);
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);
246 static int rpivid_try_fmt_vid_out(struct file *file, void *priv,
247 struct v4l2_format *f)
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);
254 + rpivid_prepare_src_format(&f->fmt.pix_mp);
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;
262 - pix_fmt = &ctx->dst_fmt;
263 + pix_fmt = get_dst_fmt(ctx);
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);
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);