Skip to content

Commit e8d31cb

Browse files
jc-kynesimpopcornmix
authored andcommitted
media: rpivid: Avoid returning EINVAL to a G_FMT ioctl
V4L2 spec says that G/S/TRY_FMT IOCTLs should never return errors for anything other than wrong buffer types. Improve the capture format function such that this is so and unsupported values get converted to supported ones properly. Signed-off-by: John Cox <[email protected]>
1 parent 9ed1fd3 commit e8d31cb

File tree

4 files changed

+54
-51
lines changed

4 files changed

+54
-51
lines changed

drivers/staging/media/rpivid/rpivid.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@ static int rpivid_open(struct file *file)
249249
/* The only bit of format info that we can guess now is H265 src
250250
* Everything else we need more info for
251251
*/
252-
ctx->src_fmt.pixelformat = RPIVID_SRC_PIXELFORMAT_DEFAULT;
253252
rpivid_prepare_src_format(&ctx->src_fmt);
254253

255254
v4l2_fh_add(&ctx->fh);

drivers/staging/media/rpivid/rpivid.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@
3535

3636
#define RPIVID_QUIRK_NO_DMA_OFFSET BIT(0)
3737

38-
#define RPIVID_SRC_PIXELFORMAT_DEFAULT V4L2_PIX_FMT_HEVC_SLICE
39-
4038
enum rpivid_irq_status {
4139
RPIVID_IRQ_NONE,
4240
RPIVID_IRQ_ERROR,

drivers/staging/media/rpivid/rpivid_video.c

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727

2828
#define RPIVID_MIN_WIDTH 16U
2929
#define RPIVID_MIN_HEIGHT 16U
30+
#define RPIVID_DEFAULT_WIDTH 1920U
31+
#define RPIVID_DEFAULT_HEIGHT 1088U
3032
#define RPIVID_MAX_WIDTH 4096U
3133
#define RPIVID_MAX_HEIGHT 4096U
3234

@@ -70,25 +72,22 @@ size_t rpivid_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_min
7072
return rpivid_round_up_size(bits_alloc);
7173
}
7274

73-
int rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt)
75+
void rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt)
7476
{
7577
size_t size;
7678
u32 w;
7779
u32 h;
7880

79-
if (pix_fmt->pixelformat != V4L2_PIX_FMT_HEVC_SLICE)
80-
return -EINVAL;
81-
8281
w = pix_fmt->width;
8382
h = pix_fmt->height;
8483
if (!w || !h) {
85-
w = 1920;
86-
h = 1080;
84+
w = RPIVID_DEFAULT_WIDTH;
85+
h = RPIVID_DEFAULT_HEIGHT;
8786
}
88-
if (w > 4096)
89-
w = 4096;
90-
if (h > 4096)
91-
h = 4096;
87+
if (w > RPIVID_MAX_WIDTH)
88+
w = RPIVID_MAX_WIDTH;
89+
if (h > RPIVID_MAX_HEIGHT)
90+
h = RPIVID_MAX_HEIGHT;
9291

9392
if (!pix_fmt->plane_fmt[0].sizeimage ||
9493
pix_fmt->plane_fmt[0].sizeimage > SZ_32M) {
@@ -98,29 +97,41 @@ int rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt)
9897
/* Set a minimum */
9998
size = max_t(u32, SZ_4K, pix_fmt->plane_fmt[0].sizeimage);
10099

100+
pix_fmt->pixelformat = V4L2_PIX_FMT_HEVC_SLICE;
101101
pix_fmt->width = w;
102102
pix_fmt->height = h;
103103
pix_fmt->num_planes = 1;
104104
pix_fmt->field = V4L2_FIELD_NONE;
105105
/* Zero bytes per line for encoded source. */
106106
pix_fmt->plane_fmt[0].bytesperline = 0;
107107
pix_fmt->plane_fmt[0].sizeimage = size;
108-
109-
return 0;
110108
}
111109

112-
int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt)
110+
/* Take any pix_format and make it valid */
111+
static void rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt)
113112
{
114113
unsigned int width = pix_fmt->width;
115114
unsigned int height = pix_fmt->height;
116115
unsigned int sizeimage = pix_fmt->plane_fmt[0].sizeimage;
117116
unsigned int bytesperline = pix_fmt->plane_fmt[0].bytesperline;
118117

119-
switch (pix_fmt->pixelformat) {
118+
if (!width)
119+
width = RPIVID_DEFAULT_WIDTH;
120+
if (width > RPIVID_MAX_WIDTH)
121+
width = RPIVID_MAX_WIDTH;
122+
if (!height)
123+
height = RPIVID_DEFAULT_HEIGHT;
124+
if (height > RPIVID_MAX_HEIGHT)
125+
height = RPIVID_MAX_HEIGHT;
126+
120127
/* For column formats set bytesperline to column height (stride2) */
128+
switch (pix_fmt->pixelformat) {
129+
default:
130+
pix_fmt->pixelformat = V4L2_PIX_FMT_NV12_COL128;
131+
fallthrough;
121132
case V4L2_PIX_FMT_NV12_COL128:
122133
/* Width rounds up to columns */
123-
width = ALIGN(min(width, RPIVID_MAX_WIDTH), 128);
134+
width = ALIGN(width, 128);
124135

125136
/* 16 aligned height - not sure we even need that */
126137
height = ALIGN(height, 16);
@@ -140,7 +151,7 @@ int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt)
140151
/* width in pixels (3 pels = 4 bytes) rounded to 128 byte
141152
* columns
142153
*/
143-
width = ALIGN(((min(width, RPIVID_MAX_WIDTH) + 2) / 3), 32) * 3;
154+
width = ALIGN(((width + 2) / 3), 32) * 3;
144155

145156
/* 16-aligned height. */
146157
height = ALIGN(height, 16);
@@ -157,9 +168,6 @@ int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt)
157168
sizeimage = constrain2x(sizeimage,
158169
bytesperline * width * 4 / 3);
159170
break;
160-
161-
default:
162-
return -EINVAL;
163171
}
164172

165173
pix_fmt->width = width;
@@ -169,7 +177,6 @@ int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt)
169177
pix_fmt->plane_fmt[0].bytesperline = bytesperline;
170178
pix_fmt->plane_fmt[0].sizeimage = sizeimage;
171179
pix_fmt->num_planes = 1;
172-
return 0;
173180
}
174181

175182
static int rpivid_querycap(struct file *file, void *priv,
@@ -260,14 +267,13 @@ static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps,
260267
{
261268
u32 pf = 0;
262269

263-
// Use width 0 as a signifier of unsetness
264-
if (!is_sps_set(sps)) {
270+
if (!is_sps_set(sps) || !rpivid_hevc_validate_sps(sps)) {
265271
/* Treat this as an error? For now return both */
266272
if (index == 0)
267273
pf = V4L2_PIX_FMT_NV12_COL128;
268274
else if (index == 1)
269275
pf = V4L2_PIX_FMT_NV12_10_COL128;
270-
} else if (index == 0 && rpivid_hevc_validate_sps(sps)) {
276+
} else if (index == 0) {
271277
if (sps->bit_depth_luma_minus8 == 0)
272278
pf = V4L2_PIX_FMT_NV12_COL128;
273279
else if (sps->bit_depth_luma_minus8 == 2)
@@ -282,11 +288,14 @@ rpivid_hevc_default_dst_fmt(struct rpivid_ctx * const ctx)
282288
{
283289
const struct v4l2_ctrl_hevc_sps * const sps =
284290
rpivid_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
285-
struct v4l2_pix_format_mplane pix_fmt = {
286-
.width = sps->pic_width_in_luma_samples,
287-
.height = sps->pic_height_in_luma_samples,
288-
.pixelformat = pixelformat_from_sps(sps, 0)
289-
};
291+
struct v4l2_pix_format_mplane pix_fmt;
292+
293+
memset(&pix_fmt, 0, sizeof(pix_fmt));
294+
if (is_sps_set(sps)) {
295+
pix_fmt.width = sps->pic_width_in_luma_samples;
296+
pix_fmt.height = sps->pic_height_in_luma_samples;
297+
pix_fmt.pixelformat = pixelformat_from_sps(sps, 0);
298+
}
290299

291300
rpivid_prepare_dst_format(&pix_fmt);
292301
return pix_fmt;
@@ -315,14 +324,23 @@ static int rpivid_enum_fmt_vid_cap(struct file *file, void *priv,
315324
return 0;
316325
}
317326

327+
/*
328+
* get dst format - sets it to default if otherwise unset
329+
* returns a pointer to the struct as a convienience
330+
*/
331+
static struct v4l2_pix_format_mplane *get_dst_fmt(struct rpivid_ctx *const ctx)
332+
{
333+
if (!ctx->dst_fmt_set)
334+
ctx->dst_fmt = rpivid_hevc_default_dst_fmt(ctx);
335+
return &ctx->dst_fmt;
336+
}
337+
318338
static int rpivid_g_fmt_vid_cap(struct file *file, void *priv,
319339
struct v4l2_format *f)
320340
{
321341
struct rpivid_ctx *ctx = rpivid_file2ctx(file);
322342

323-
if (!ctx->dst_fmt_set)
324-
ctx->dst_fmt = rpivid_hevc_default_dst_fmt(ctx);
325-
f->fmt.pix_mp = ctx->dst_fmt;
343+
f->fmt.pix_mp = *get_dst_fmt(ctx);
326344
return 0;
327345
}
328346

@@ -358,31 +376,20 @@ static int rpivid_try_fmt_vid_cap(struct file *file, void *priv,
358376
break;
359377
}
360378

361-
// If we can't use requested fmt then set to default
362-
if (pixelformat == 0) {
363-
pixelformat = pixelformat_from_sps(sps, 0);
364-
// If we don't have a default then give up
365-
if (pixelformat == 0)
366-
return -EINVAL;
367-
}
368-
369379
// We don't have any way of finding out colourspace so believe
370380
// anything we are told - take anything set in src as a default
371381
if (f->fmt.pix_mp.colorspace == V4L2_COLORSPACE_DEFAULT)
372382
copy_color(&f->fmt.pix_mp, &ctx->src_fmt);
373383

374384
f->fmt.pix_mp.pixelformat = pixelformat;
375-
return rpivid_prepare_dst_format(&f->fmt.pix_mp);
385+
rpivid_prepare_dst_format(&f->fmt.pix_mp);
386+
return 0;
376387
}
377388

378389
static int rpivid_try_fmt_vid_out(struct file *file, void *priv,
379390
struct v4l2_format *f)
380391
{
381-
if (rpivid_prepare_src_format(&f->fmt.pix_mp)) {
382-
// Set default src format
383-
f->fmt.pix_mp.pixelformat = RPIVID_SRC_PIXELFORMAT_DEFAULT;
384-
rpivid_prepare_src_format(&f->fmt.pix_mp);
385-
}
392+
rpivid_prepare_src_format(&f->fmt.pix_mp);
386393
return 0;
387394
}
388395

@@ -474,7 +481,7 @@ static int rpivid_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
474481
if (V4L2_TYPE_IS_OUTPUT(vq->type))
475482
pix_fmt = &ctx->src_fmt;
476483
else
477-
pix_fmt = &ctx->dst_fmt;
484+
pix_fmt = get_dst_fmt(ctx);
478485

479486
if (*nplanes) {
480487
if (sizes[0] < pix_fmt->plane_fmt[0].sizeimage)

drivers/staging/media/rpivid/rpivid_video.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ int rpivid_queue_init(void *priv, struct vb2_queue *src_vq,
2828
size_t rpivid_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8);
2929
size_t rpivid_round_up_size(const size_t x);
3030

31-
int rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt);
32-
int rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt);
31+
void rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt);
3332

3433
#endif

0 commit comments

Comments
 (0)