From 4e30a37345e6f723553d457becc423efa4bf2703 Mon Sep 17 00:00:00 2001 From: Prashant Laddha Date: Wed, 4 Feb 2015 06:07:31 -0300 Subject: [media] vivid sdr: Use LUT based implementation for sin/cos() The common implementation for sin/cos in include/linux/fixp-arith.h has been improved recently to provide higher precision. Replacing native implementation of sin/cos in vivid sdr with common implementation. This serves two purposes: 1. Improved accuracy: the native implementation based on the Taylor series is more prone to rounding errors. 2. Reuse of common function: this is better compared to maintaining native versions for each driver. Suggested by: Mauro Carvalho Chehab Cc: Antti Palosaari Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-sdr-cap.c | 66 ++++++++++++---------------- 1 file changed, 27 insertions(+), 39 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 4af55f18829f..5e089cb58a38 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "vivid-core.h" #include "vivid-ctrls.h" @@ -423,40 +424,19 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) return 0; } -#define FIXP_FRAC (1 << 15) -#define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589)) - -/* cos() from cx88 driver: cx88-dsp.c */ -static s32 fixp_cos(unsigned int x) -{ - u32 t2, t4, t6, t8; - u16 period = x / FIXP_PI; - - if (period % 2) - return -fixp_cos(x - FIXP_PI); - x = x % FIXP_PI; - if (x > FIXP_PI/2) - return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2))); - /* Now x is between 0 and FIXP_PI/2. - * To calculate cos(x) we use it's Taylor polinom. */ - t2 = x*x/FIXP_FRAC/2; - t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4; - t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6; - t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8; - return FIXP_FRAC-t2+t4-t6+t8; -} - -static inline s32 fixp_sin(unsigned int x) -{ - return -fixp_cos(x + (FIXP_PI / 2)); -} +#define FIXP_N (15) +#define FIXP_FRAC (1 << FIXP_N) +#define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC)) void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) { u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); unsigned long i; unsigned long plane_size = vb2_plane_size(&buf->vb, 0); - int fixp_src_phase_step, fixp_i, fixp_q; + s32 src_phase_step; + s32 mod_phase_step; + s32 fixp_i; + s32 fixp_q; /* * TODO: Generated beep tone goes very crackly when sample rate is @@ -466,28 +446,36 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) /* calculate phase step */ #define BEEP_FREQ 1000 /* 1kHz beep */ - fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ, + src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ, dev->sdr_adc_freq); for (i = 0; i < plane_size; i += 2) { - dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase); - dev->sdr_fixp_src_phase += fixp_src_phase_step; + mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase, + FIXP_2PI) >> (31 - FIXP_N); + + dev->sdr_fixp_src_phase += src_phase_step; + dev->sdr_fixp_mod_phase += mod_phase_step; /* * Transfer phases to [0 / 2xPI] in order to avoid variable * overflow and make it suitable for cosine implementation * used, which does not support negative angles. */ - while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI)) - dev->sdr_fixp_mod_phase += (2 * FIXP_PI); - while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI)) - dev->sdr_fixp_mod_phase -= (2 * FIXP_PI); + while (dev->sdr_fixp_mod_phase < FIXP_2PI) + dev->sdr_fixp_mod_phase += FIXP_2PI; + while (dev->sdr_fixp_mod_phase > FIXP_2PI) + dev->sdr_fixp_mod_phase -= FIXP_2PI; + + while (dev->sdr_fixp_src_phase > FIXP_2PI) + dev->sdr_fixp_src_phase -= FIXP_2PI; - while (dev->sdr_fixp_src_phase > (2 * FIXP_PI)) - dev->sdr_fixp_src_phase -= (2 * FIXP_PI); + fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); + fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); - fixp_i = fixp_cos(dev->sdr_fixp_mod_phase); - fixp_q = fixp_sin(dev->sdr_fixp_mod_phase); + /* Normalize fraction values represented with 32 bit precision + * to fixed point representation with FIXP_N bits */ + fixp_i >>= (31 - FIXP_N); + fixp_q >>= (31 - FIXP_N); /* convert 'fixp float' to u8 */ /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ -- cgit v1.2.3 From d585c1e14a84f08a4a714553d9fc459ee697ff95 Mon Sep 17 00:00:00 2001 From: Prashant Laddha Date: Wed, 4 Feb 2015 06:07:32 -0300 Subject: [media] vivid sdr: fix broken sine tone generated for sdr FM FM (frequency modulated) signal for SDR is generated by varying the phase, where phase variation is proportional to input signal. It is seen that, the larger phase increments leads to discontinuities in the signal recovered after demodulation. Reducing the extent of phase variation with respect to input signal, equivalent to reducing the modulation index. Tested using FM receiver flow graph in gnuradio-companion. Cc: Antti Palosaari Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-sdr-cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 5e089cb58a38..caf131666e37 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -454,7 +454,7 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) FIXP_2PI) >> (31 - FIXP_N); dev->sdr_fixp_src_phase += src_phase_step; - dev->sdr_fixp_mod_phase += mod_phase_step; + dev->sdr_fixp_mod_phase += mod_phase_step / 4; /* * Transfer phases to [0 / 2xPI] in order to avoid variable -- cgit v1.2.3 From 4eaa3a6cc4c577103d678492ec50979b3aa360a4 Mon Sep 17 00:00:00 2001 From: Tapasweni Pathak Date: Thu, 5 Mar 2015 23:39:40 -0300 Subject: [media] drivers: media: platform: vivid: Fix possible null derefrence Check for dev_fmt being null before derefrencing it, to assign it to planes. Found using Coccinelle. Signed-off-by: Tapasweni Pathak Acked-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-out.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 39ff79f6aa67..8f081bbb7f2c 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -114,7 +114,7 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb) { struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); unsigned long size; - unsigned planes = dev->fmt_out->planes; + unsigned planes; unsigned p; dprintk(dev, 1, "%s\n", __func__); @@ -122,6 +122,8 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb) if (WARN_ON(NULL == dev->fmt_out)) return -EINVAL; + planes = dev->fmt_out->planes; + if (dev->buf_prepare_error) { /* * Error injection: test what happens if buf_prepare() returns -- cgit v1.2.3 From c0b50d951283eddec292811440f1d38eb2a3f455 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 8 Mar 2015 04:53:33 -0300 Subject: [media] vivid: BT.2020 R'G'B' is limited range According to the standard the R'G'B' BT.2020 colorspace is limited range, not full range. Fix this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 34493f435d5a..acb73b67b16a 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1265,6 +1265,10 @@ static void tpg_recalc(struct tpg_data *tpg) V4L2_QUANTIZATION_LIM_RANGE; break; } + } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) { + /* R'G'B' BT.2020 is limited range */ + tpg->real_quantization = + V4L2_QUANTIZATION_LIM_RANGE; } } tpg_precalculate_colors(tpg); -- cgit v1.2.3 From 9832e0e013c5cbbf688c1c2421a0b05e01fe409b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 12:34:32 -0300 Subject: [media] vivid: the overlay API wasn't disabled completely for multiplanar If the vivid driver is loaded in multiplanar mode, then the capture overlay functionality should be disabled. This wasn't fully done, which led to v4l2-compliance errors. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-cap.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 867a29a6d18f..550945a432c9 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1012,8 +1012,12 @@ int vivid_vid_cap_cropcap(struct file *file, void *priv, int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { + struct vivid_dev *dev = video_drvdata(file); const struct vivid_fmt *fmt; + if (dev->multiplanar) + return -ENOTTY; + if (f->index >= ARRAY_SIZE(formats_ovl)) return -EINVAL; @@ -1032,6 +1036,9 @@ int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_window *win = &f->fmt.win; unsigned clipcount = win->clipcount; + if (dev->multiplanar) + return -ENOTTY; + win->w.top = dev->overlay_cap_top; win->w.left = dev->overlay_cap_left; win->w.width = compose->width; @@ -1063,6 +1070,9 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_window *win = &f->fmt.win; int i, j; + if (dev->multiplanar) + return -ENOTTY; + win->w.left = clamp_t(int, win->w.left, -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); win->w.top = clamp_t(int, win->w.top, @@ -1150,6 +1160,9 @@ int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i) { struct vivid_dev *dev = video_drvdata(file); + if (dev->multiplanar) + return -ENOTTY; + if (i && dev->fb_vbase_cap == NULL) return -EINVAL; @@ -1169,6 +1182,9 @@ int vivid_vid_cap_g_fbuf(struct file *file, void *fh, { struct vivid_dev *dev = video_drvdata(file); + if (dev->multiplanar) + return -ENOTTY; + *a = dev->fb_cap; a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING | V4L2_FBUF_CAP_LIST_CLIPPING; @@ -1185,6 +1201,9 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh, struct vivid_dev *dev = video_drvdata(file); const struct vivid_fmt *fmt; + if (dev->multiplanar) + return -ENOTTY; + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; -- cgit v1.2.3 From 360565fcf72637258ebe6d3984c669bc9d86f7cd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 12:19:36 -0300 Subject: [media] vivid: fix typo in plane size checks The plane size check was hardcoded to plane 0 instead of using the plane index. This failed when using the NV61M format which has a larger plane size for the second plane compared to the first plane. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-cap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 550945a432c9..49f79a0aa2f6 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -188,9 +188,9 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb) size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height + dev->fmt_cap->data_offset[p]; - if (vb2_plane_size(vb, 0) < size) { + if (vb2_plane_size(vb, p) < size) { dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n", - __func__, p, vb2_plane_size(vb, 0), size); + __func__, p, vb2_plane_size(vb, p), size); return -EINVAL; } -- cgit v1.2.3 From a94e7d6e825ac20f17436477120fb3fd8a755ebf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 6 Mar 2015 11:24:04 -0300 Subject: [media] vivid: wrong top/bottom order for FIELD_ALTERNATE The condition to decide whether the current field is top or bottom was inverted. Fix this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-kthread-cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 39a67cfae120..9898072e9a40 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -427,7 +427,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) * standards. */ buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; + V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; /* * The sequence counter counts frames, not fields. So divide * by two. -- cgit v1.2.3 From c501abcfbfd75da44f35992d0da39af92860fb01 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 12:30:43 -0300 Subject: [media] vivid: use TPG_MAX_PLANES instead of hardcoding plane-arrays Two arrays of size 'max number of planes' have a hardcoded size instead of using TPG_MAX_PLANES. Fix that, since TPG_MAX_PLANES will be increased later on. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 4b497df4b6a4..191d9b506e18 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -84,7 +84,7 @@ struct vivid_fmt { bool can_do_overlay; u32 alpha_mask; u8 planes; - u32 data_offset[2]; + u32 data_offset[TPG_MAX_PLANES]; }; extern struct vivid_fmt vivid_formats[]; @@ -332,7 +332,7 @@ struct vivid_dev { u32 ycbcr_enc_out; u32 quantization_out; u32 service_set_out; - u32 bytesperline_out[2]; + u32 bytesperline_out[TPG_MAX_PLANES]; unsigned tv_field_out; unsigned tv_audio_output; bool vbi_out_have_wss; -- cgit v1.2.3 From 43047f6b7467c2c9e3ef0b8113469c40b0b78cc3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 12:38:42 -0300 Subject: [media] vivid: fix test pattern movement for V4L2_FIELD_ALTERNATE The successive TOP/BOTTOM fields did not move as they should: only every other field actually changed position. The cause was that the tpg needs to know if it is dealing with a FIELD_ALTERNATE case since that requires slightly different handling. So tell the TPG whether or not the field setting is for the ALTERNATE case or not. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-kthread-cap.c | 3 ++- drivers/media/platform/vivid/vivid-tpg.c | 4 +++- drivers/media/platform/vivid/vivid-tpg.h | 4 +++- drivers/media/platform/vivid/vivid-vid-cap.c | 5 ++++- 4 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 9898072e9a40..9976d4523366 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -436,7 +436,8 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) } else { buf->vb.v4l2_buf.field = dev->field_cap; } - tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field); + tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field, + dev->field_cap == V4L2_FIELD_ALTERNATE); tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]); vivid_precalc_copy_rects(dev); diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index acb73b67b16a..f4e9108bfd06 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1413,7 +1413,9 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) linestart_older += line_offset; linestart_newer += line_offset; } - if (is_60hz) { + if (tpg->field_alternate) { + linestart_top = linestart_bottom = linestart_older; + } else if (is_60hz) { linestart_top = linestart_newer; linestart_bottom = linestart_older; } else { diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index bd8b1c760b3f..810042579584 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -98,6 +98,7 @@ struct tpg_data { /* Scaled output frame size */ unsigned scaled_width; u32 field; + bool field_alternate; /* crop coordinates are frame-based */ struct v4l2_rect crop; /* compose coordinates are format-based */ @@ -348,9 +349,10 @@ static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) tpg->buf_height = h; } -static inline void tpg_s_field(struct tpg_data *tpg, unsigned field) +static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate) { tpg->field = field; + tpg->field_alternate = alternate; } static inline void tpg_s_perc_fill(struct tpg_data *tpg, diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 49f79a0aa2f6..d41ac4475317 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -733,7 +733,10 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, if (tpg_g_planes(&dev->tpg) > 1) tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline); dev->field_cap = mp->field; - tpg_s_field(&dev->tpg, dev->field_cap); + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true); + else + tpg_s_field(&dev->tpg, dev->field_cap, false); tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); if (vivid_is_sdtv_cap(dev)) -- cgit v1.2.3 From 1a05d3133f826c9578986d9ec6ffab64ced62a03 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 12:49:57 -0300 Subject: [media] vivid: add new checkboard patterns Add a 2x2 checker patterns and 1x1 and 2x2 red/blue checker patterns. Useful for testing 4:2:2 and 4:2:0 formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 26 +++++++++++++++++++++++--- drivers/media/platform/vivid/vivid-tpg.h | 3 +++ 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index f4e9108bfd06..8f455681f606 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -35,7 +35,10 @@ const char * const tpg_pattern_strings[] = { "100% Green", "100% Blue", "16x16 Checkers", + "2x2 Checkers", "1x1 Checkers", + "2x2 Red/Green Checkers", + "1x1 Red/Green Checkers", "Alternating Hor Lines", "Alternating Vert Lines", "One Pixel Wide Cross", @@ -744,11 +747,14 @@ static void gen_twopix(struct tpg_data *tpg, } /* Return how many pattern lines are used by the current pattern. */ -static unsigned tpg_get_pat_lines(struct tpg_data *tpg) +static unsigned tpg_get_pat_lines(const struct tpg_data *tpg) { switch (tpg->pattern) { case TPG_PAT_CHECKERS_16X16: + case TPG_PAT_CHECKERS_2X2: case TPG_PAT_CHECKERS_1X1: + case TPG_PAT_COLOR_CHECKERS_2X2: + case TPG_PAT_COLOR_CHECKERS_1X1: case TPG_PAT_ALTERNATING_HLINES: case TPG_PAT_CROSS_1_PIXEL: case TPG_PAT_CROSS_2_PIXELS: @@ -763,14 +769,18 @@ static unsigned tpg_get_pat_lines(struct tpg_data *tpg) } /* Which pattern line should be used for the given frame line. */ -static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line) +static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line) { switch (tpg->pattern) { case TPG_PAT_CHECKERS_16X16: return (line >> 4) & 1; case TPG_PAT_CHECKERS_1X1: + case TPG_PAT_COLOR_CHECKERS_1X1: case TPG_PAT_ALTERNATING_HLINES: return line & 1; + case TPG_PAT_CHECKERS_2X2: + case TPG_PAT_COLOR_CHECKERS_2X2: + return (line & 2) >> 1; case TPG_PAT_100_COLORSQUARES: case TPG_PAT_100_HCOLORBAR: return (line * 8) / tpg->src_height; @@ -789,7 +799,8 @@ static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line) * Which color should be used for the given pattern line and X coordinate. * Note: x is in the range 0 to 2 * tpg->src_width. */ -static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x) +static enum tpg_color tpg_get_color(const struct tpg_data *tpg, + unsigned pat_line, unsigned x) { /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code should be modified */ @@ -836,6 +847,15 @@ static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, uns case TPG_PAT_CHECKERS_1X1: return ((x & 1) ^ (pat_line & 1)) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; + case TPG_PAT_COLOR_CHECKERS_1X1: + return ((x & 1) ^ (pat_line & 1)) ? + TPG_COLOR_100_RED : TPG_COLOR_100_BLUE; + case TPG_PAT_CHECKERS_2X2: + return (((x >> 1) & 1) ^ (pat_line & 1)) ? + TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; + case TPG_PAT_COLOR_CHECKERS_2X2: + return (((x >> 1) & 1) ^ (pat_line & 1)) ? + TPG_COLOR_100_RED : TPG_COLOR_100_BLUE; case TPG_PAT_ALTERNATING_HLINES: return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; case TPG_PAT_ALTERNATING_VLINES: diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index 810042579584..e796a54e6c9f 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -41,7 +41,10 @@ enum tpg_pattern { TPG_PAT_GREEN, TPG_PAT_BLUE, TPG_PAT_CHECKERS_16X16, + TPG_PAT_CHECKERS_2X2, TPG_PAT_CHECKERS_1X1, + TPG_PAT_COLOR_CHECKERS_2X2, + TPG_PAT_COLOR_CHECKERS_1X1, TPG_PAT_ALTERNATING_HLINES, TPG_PAT_ALTERNATING_VLINES, TPG_PAT_CROSS_1_PIXEL, -- cgit v1.2.3 From 9c35bd48d54345b2c89426dd2efdb33adaa0aac3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 12:53:39 -0300 Subject: [media] vivid-tpg: don't add offset when switching to monochrome The grayscale values are still full range sRGB, so don't add the limited range offset. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 8f455681f606..145b6ff2f816 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -530,7 +530,7 @@ static void precalculate_color(struct tpg_data *tpg, int k) if (tpg->qual == TPG_QUAL_GRAY) { /* Rec. 709 Luma function */ /* (0.2126, 0.7152, 0.0722) * (255 * 256) */ - r = g = b = ((13879 * r + 46688 * g + 4713 * b) >> 16) + (16 << 4); + r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16; } /* -- cgit v1.2.3 From ba24b442033b7f50e24798685f4b24b8e4c3aaa2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 10:06:55 -0300 Subject: [media] vivid: do not allow video loopback for SEQ_TB/BT Sequential top-bottom/bottom-top fields are not supported as video loopback. This is too much work to implement for field settings that are rarely used. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/vivid.txt | 5 +++++ drivers/media/platform/vivid/vivid-vid-common.c | 7 +++++++ 2 files changed, 12 insertions(+) (limited to 'drivers/media/platform/vivid') diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt index 6cfc8541a362..cd4b5a1ac529 100644 --- a/Documentation/video4linux/vivid.txt +++ b/Documentation/video4linux/vivid.txt @@ -912,6 +912,11 @@ looped to the video input provided that: sequence and field counting in struct v4l2_buffer on the capture side may not be 100% accurate. +- field settings V4L2_FIELD_SEQ_TB/BT are not supported. While it is possible to + implement this, it would mean a lot of work to get this right. Since these + field values are rarely used the decision was made not to implement this for + now. + - on the input side the "Standard Signal Mode" for the S-Video input or the "DV Timings Signal Mode" for the HDMI input should be configured so that a valid signal is passed to the video input. diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 6bef1e6d6788..49c9bc68c14f 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -210,6 +210,13 @@ bool vivid_vid_can_loop(struct vivid_dev *dev) return false; if (dev->field_cap != dev->field_out) return false; + /* + * While this can be supported, it is just too much work + * to actually implement. + */ + if (dev->field_cap == V4L2_FIELD_SEQ_TB || + dev->field_cap == V4L2_FIELD_SEQ_BT) + return false; if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { if (!(dev->std_cap & V4L2_STD_525_60) != !(dev->std_out & V4L2_STD_525_60)) -- cgit v1.2.3 From 06d1f0c2eaaebe04fa3ea780ca37dcd6e05ade16 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 13:01:53 -0300 Subject: [media] vivid-tpg: separate planes and buffers Add a new field that contains the number of buffers. This may be less than the number of planes in case multiple planes are combined into one buffer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 3 +++ drivers/media/platform/vivid/vivid-tpg.h | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 145b6ff2f816..d7f55d437f91 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -170,7 +170,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) { tpg->fourcc = fourcc; tpg->planes = 1; + tpg->buffers = 1; tpg->recalc_colors = true; + switch (fourcc) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: @@ -190,6 +192,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) break; case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: + tpg->buffers = 2; tpg->planes = 2; /* fall-through */ case V4L2_PIX_FMT_YUYV: diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index e796a54e6c9f..9ce2d015a322 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -138,6 +138,7 @@ struct tpg_data { enum tpg_pixel_aspect pix_aspect; unsigned rgb_range; unsigned real_rgb_range; + unsigned buffers; unsigned planes; /* Used to store the colors in native format, either RGB or YUV */ u8 colors[TPG_COLOR_MAX][3]; @@ -327,6 +328,11 @@ static inline u32 tpg_g_quantization(const struct tpg_data *tpg) return tpg->quantization; } +static inline unsigned tpg_g_buffers(const struct tpg_data *tpg) +{ + return tpg->buffers; +} + static inline unsigned tpg_g_planes(const struct tpg_data *tpg) { return tpg->planes; -- cgit v1.2.3 From 4db22041892946348f98672a5524bdf2f18f66f5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 13:39:01 -0300 Subject: [media] vivid-tpg: add helper functions for single buffer planar formats Add helpers functions to determine the line widths and image sizes for planar formats that are stores in a single buffer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 18 ++++++++++- drivers/media/platform/vivid/vivid-tpg.h | 53 +++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index d7f55d437f91..66df19d02b34 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1321,7 +1321,7 @@ void tpg_calc_text_basep(struct tpg_data *tpg, basep[p][0] += tpg->buf_height * stride / 2; } -void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) +void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) { bool is_tv = std; bool is_60hz = is_tv && (std & V4L2_STD_525_60); @@ -1581,3 +1581,19 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) } } } + +void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) +{ + unsigned offset = 0; + unsigned i; + + if (tpg->buffers > 1) { + tpg_fill_plane_buffer(tpg, std, p, vbuf); + return; + } + + for (i = 0; i < tpg->planes; i++) { + tpg_fill_plane_buffer(tpg, std, i, vbuf + offset); + offset += tpg_calc_plane_size(tpg, i); + } +} diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index 9ce2d015a322..b90ce7d4a384 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -189,6 +189,7 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); void tpg_calc_text_basep(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); +void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf); void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf); bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, @@ -350,7 +351,57 @@ static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned p static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl) { - tpg->bytesperline[plane] = bpl; + unsigned p; + + if (tpg->buffers > 1) { + tpg->bytesperline[plane] = bpl; + return; + } + + for (p = 0; p < tpg->planes; p++) { + unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; + + tpg->bytesperline[p] = plane_w; + } +} + +static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane) +{ + unsigned w = 0; + unsigned p; + + if (tpg->buffers > 1) + return tpg_g_bytesperline(tpg, plane); + for (p = 0; p < tpg->planes; p++) { + unsigned plane_w = tpg_g_bytesperline(tpg, p); + + w += plane_w; + } + return w; +} + +static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, + unsigned plane, unsigned bpl) +{ + unsigned w = 0; + unsigned p; + + if (tpg->buffers > 1) + return bpl; + for (p = 0; p < tpg->planes; p++) { + unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; + + w += plane_w; + } + return w; +} + +static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane) +{ + if (plane >= tpg->planes) + return 0; + + return tpg_g_bytesperline(tpg, plane) * tpg->buf_height; } static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) -- cgit v1.2.3 From ba01f673e031ade4f60583ab1ac4f06dd260a972 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 13:57:27 -0300 Subject: [media] vivid-tpg: add hor/vert downsampling fields This is step one of supporting horizontal and vertical downsampling. This just adds support for the h/vdownsampling fields and it increases the maximum number of planes to 3. Currently none of the planar formats need horizontal or vertical downsampling, so this change has no effect at the moment. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 7 ++++++- drivers/media/platform/vivid/vivid-tpg.h | 15 ++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 66df19d02b34..fa50a1f8a6c1 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -172,6 +172,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->planes = 1; tpg->buffers = 1; tpg->recalc_colors = true; + tpg->vdownsampling[0] = 1; + tpg->hdownsampling[0] = 1; switch (fourcc) { case V4L2_PIX_FMT_RGB565: @@ -192,6 +194,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) break; case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: + tpg->vdownsampling[1] = 1; + tpg->hdownsampling[1] = 1; tpg->buffers = 2; tpg->planes = 2; /* fall-through */ @@ -273,7 +277,8 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, tpg->compose.width = width; tpg->compose.height = tpg->buf_height; for (p = 0; p < tpg->planes; p++) - tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2; + tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) / + (2 * tpg->hdownsampling[p]); tpg->recalc_square_border = true; } diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index b90ce7d4a384..cec5bb4f3632 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -90,7 +90,7 @@ enum tpg_move_mode { extern const char * const tpg_aspect_strings[]; -#define TPG_MAX_PLANES 2 +#define TPG_MAX_PLANES 3 #define TPG_MAX_PAT_LINES 8 struct tpg_data { @@ -140,6 +140,8 @@ struct tpg_data { unsigned real_rgb_range; unsigned buffers; unsigned planes; + u8 vdownsampling[TPG_MAX_PLANES]; + u8 hdownsampling[TPG_MAX_PLANES]; /* Used to store the colors in native format, either RGB or YUV */ u8 colors[TPG_COLOR_MAX][3]; u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; @@ -361,10 +363,11 @@ static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsi for (p = 0; p < tpg->planes; p++) { unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; - tpg->bytesperline[p] = plane_w; + tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p]; } } + static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane) { unsigned w = 0; @@ -375,7 +378,7 @@ static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned pla for (p = 0; p < tpg->planes; p++) { unsigned plane_w = tpg_g_bytesperline(tpg, p); - w += plane_w; + w += plane_w / tpg->vdownsampling[p]; } return w; } @@ -391,7 +394,8 @@ static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, for (p = 0; p < tpg->planes; p++) { unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; - w += plane_w; + plane_w /= tpg->hdownsampling[p]; + w += plane_w / tpg->vdownsampling[p]; } return w; } @@ -401,7 +405,8 @@ static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned if (plane >= tpg->planes) return 0; - return tpg_g_bytesperline(tpg, plane) * tpg->buf_height; + return tpg_g_bytesperline(tpg, plane) * tpg->buf_height / + tpg->vdownsampling[plane]; } static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) -- cgit v1.2.3 From 5d7c539e194af598a8f8d8f616ce97581f3d079a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 14:06:43 -0300 Subject: [media] vivid-tpg: precalculate downsampled lines When dealing with vertical downsampling two successive lines have to be averaged. In the case of the test pattern generator that only happens if the two lines are using different patterns. So precalculate the average between two pattern lines: one of pattern P and one of pattern P + 1. That way there is no need to do any on-the-fly downsampling: it's all done in the precalculate phase. This patch also implements horizontal downsampling in the precalculate phase. The only thing that needs to be done is to half the width since the actual downsampling happens when two pixels at a time are generated. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 40 ++++++++++++++++++++++++++++++-- drivers/media/platform/vivid/vivid-tpg.h | 1 + 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index fa50a1f8a6c1..f99756dff3f2 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -128,6 +128,11 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); if (!tpg->lines[pat][plane]) return -ENOMEM; + if (plane == 0) + continue; + tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); + if (!tpg->downsampled_lines[pat][plane]) + return -ENOMEM; } } for (plane = 0; plane < TPG_MAX_PLANES; plane++) { @@ -155,6 +160,10 @@ void tpg_free(struct tpg_data *tpg) for (plane = 0; plane < TPG_MAX_PLANES; plane++) { vfree(tpg->lines[pat][plane]); tpg->lines[pat][plane] = NULL; + if (plane == 0) + continue; + vfree(tpg->downsampled_lines[pat][plane]); + tpg->downsampled_lines[pat][plane] = NULL; } for (plane = 0; plane < TPG_MAX_PLANES; plane++) { vfree(tpg->contrast_line[plane]); @@ -1029,12 +1038,39 @@ static void tpg_precalculate_line(struct tpg_data *tpg) gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1); for (p = 0; p < tpg->planes; p++) { unsigned twopixsize = tpg->twopixelsize[p]; - u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2; + unsigned hdiv = tpg->hdownsampling[p]; + u8 *pos = tpg->lines[pat][p] + + (x / hdiv) * twopixsize / 2; + + memcpy(pos, pix[p], twopixsize / hdiv); + } + } + } + + if (tpg->vdownsampling[tpg->planes - 1] > 1) { + unsigned pat_lines = tpg_get_pat_lines(tpg); + + for (pat = 0; pat < pat_lines; pat++) { + unsigned next_pat = (pat + 1) % pat_lines; + + for (p = 1; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + unsigned hdiv = tpg->hdownsampling[p]; - memcpy(pos, pix[p], twopixsize); + for (x = 0; x < tpg->scaled_width * 2; x += 2) { + unsigned offset = (x / hdiv) * twopixsize / 2; + u8 *pos1 = tpg->lines[pat][p] + offset; + u8 *pos2 = tpg->lines[next_pat][p] + offset; + u8 *dest = tpg->downsampled_lines[pat][p] + offset; + unsigned i; + + for (i = 0; i < twopixsize / hdiv; i++, dest++, pos1++, pos2++) + *dest = ((u16)*pos1 + (u16)*pos2) / 2; + } } } } + for (x = 0; x < tpg->scaled_width; x += 2) { u8 pix[TPG_MAX_PLANES][8]; diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index cec5bb4f3632..5a53eb99b6de 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -175,6 +175,7 @@ struct tpg_data { /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */ unsigned max_line_width; u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; + u8 *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; u8 *random_line[TPG_MAX_PLANES]; u8 *contrast_line[TPG_MAX_PLANES]; u8 *black_line[TPG_MAX_PLANES]; -- cgit v1.2.3 From 1f088dc162ff191b95d4737d9a3664d8b6a4fca8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 14:15:25 -0300 Subject: [media] vivid-tpg: correctly average the two pixels in gen_twopix() gen_twopix() is always called twice: once for the first and once for the second pixel. Improve the code to properly average the two if the format requires horizontal downsampling. This is necessary for patterns like 1x1 red/blue checkers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 48 ++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index f99756dff3f2..5b3930c9dcac 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -687,28 +687,64 @@ static void gen_twopix(struct tpg_data *tpg, switch (tpg->fourcc) { case V4L2_PIX_FMT_NV16M: buf[0][offset] = r_y; - buf[1][offset] = odd ? b_v : g_u; + if (odd) { + buf[1][0] = (buf[1][0] + g_u) / 2; + buf[1][1] = (buf[1][1] + b_v) / 2; + break; + } + buf[1][0] = g_u; + buf[1][1] = b_v; break; case V4L2_PIX_FMT_NV61M: buf[0][offset] = r_y; - buf[1][offset] = odd ? g_u : b_v; + if (odd) { + buf[1][0] = (buf[1][0] + b_v) / 2; + buf[1][1] = (buf[1][1] + g_u) / 2; + break; + } + buf[1][0] = b_v; + buf[1][1] = g_u; break; case V4L2_PIX_FMT_YUYV: buf[0][offset] = r_y; - buf[0][offset + 1] = odd ? b_v : g_u; + if (odd) { + buf[0][1] = (buf[0][1] + g_u) / 2; + buf[0][3] = (buf[0][3] + b_v) / 2; + break; + } + buf[0][1] = g_u; + buf[0][3] = b_v; break; case V4L2_PIX_FMT_UYVY: - buf[0][offset] = odd ? b_v : g_u; buf[0][offset + 1] = r_y; + if (odd) { + buf[0][0] = (buf[0][0] + g_u) / 2; + buf[0][2] = (buf[0][2] + b_v) / 2; + break; + } + buf[0][0] = g_u; + buf[0][2] = b_v; break; case V4L2_PIX_FMT_YVYU: buf[0][offset] = r_y; - buf[0][offset + 1] = odd ? g_u : b_v; + if (odd) { + buf[0][1] = (buf[0][1] + b_v) / 2; + buf[0][3] = (buf[0][3] + g_u) / 2; + break; + } + buf[0][1] = b_v; + buf[0][3] = g_u; break; case V4L2_PIX_FMT_VYUY: - buf[0][offset] = odd ? g_u : b_v; buf[0][offset + 1] = r_y; + if (odd) { + buf[0][0] = (buf[0][0] + b_v) / 2; + buf[0][2] = (buf[0][2] + g_u) / 2; + break; + } + buf[0][0] = b_v; + buf[0][2] = g_u; break; case V4L2_PIX_FMT_RGB565: buf[0][offset] = (g_u << 5) | b_v; -- cgit v1.2.3 From 3e14e7a82c1efdd15253a67cf5dccb84b1e9b7f1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 14:23:16 -0300 Subject: [media] vivid-tpg: add hor/vert downsampling support to tpg_gen_text This will just skip lines/pixels since color fidelity is not quite as important here as it is with the test patterns themselves. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 5b3930c9dcac..f4f0b746d778 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1183,24 +1183,37 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], div = 2; for (p = 0; p < tpg->planes; p++) { - /* Print stream time */ + unsigned vdiv = tpg->vdownsampling[p]; + unsigned hdiv = tpg->hdownsampling[p]; + + /* Print text */ #define PRINTSTR(PIXTYPE) do { \ PIXTYPE fg; \ PIXTYPE bg; \ memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \ memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \ \ - for (line = first; line < 16; line += step) { \ + for (line = first; line < 16; line += vdiv * step) { \ int l = tpg->vflip ? 15 - line : line; \ - PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \ - ((y * step + l) / div) * tpg->bytesperline[p] + \ - x * sizeof(PIXTYPE)); \ + PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \ + ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \ + (x / hdiv) * sizeof(PIXTYPE)); \ unsigned s; \ \ for (s = 0; s < len; s++) { \ u8 chr = font8x16[text[s] * 16 + line]; \ \ - if (tpg->hflip) { \ + if (hdiv == 2 && tpg->hflip) { \ + pos[3] = (chr & (0x01 << 6) ? fg : bg); \ + pos[2] = (chr & (0x01 << 4) ? fg : bg); \ + pos[1] = (chr & (0x01 << 2) ? fg : bg); \ + pos[0] = (chr & (0x01 << 0) ? fg : bg); \ + } else if (hdiv == 2) { \ + pos[0] = (chr & (0x01 << 7) ? fg : bg); \ + pos[1] = (chr & (0x01 << 5) ? fg : bg); \ + pos[2] = (chr & (0x01 << 3) ? fg : bg); \ + pos[3] = (chr & (0x01 << 1) ? fg : bg); \ + } else if (tpg->hflip) { \ pos[7] = (chr & (0x01 << 7) ? fg : bg); \ pos[6] = (chr & (0x01 << 6) ? fg : bg); \ pos[5] = (chr & (0x01 << 5) ? fg : bg); \ @@ -1220,7 +1233,7 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], pos[7] = (chr & (0x01 << 0) ? fg : bg); \ } \ \ - pos += tpg->hflip ? -8 : 8; \ + pos += (tpg->hflip ? -8 : 8) / hdiv; \ } \ } \ } while (0) -- cgit v1.2.3 From 280abe474ec3c4e14b9bf3bdbe19c12b08530408 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 14:50:41 -0300 Subject: [media] vivid-tpg: finish hor/vert downsampling support Implement horizontal and vertical downsampling when filling in the plane. The TPG is now ready to support such formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 128 ++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 18 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index f4f0b746d778..838625bd2b96 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1400,15 +1400,29 @@ void tpg_calc_text_basep(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf) { unsigned stride = tpg->bytesperline[p]; + unsigned h = tpg->buf_height; tpg_recalc(tpg); basep[p][0] = vbuf; basep[p][1] = vbuf; + h /= tpg->vdownsampling[p]; if (tpg->field == V4L2_FIELD_SEQ_TB) - basep[p][1] += tpg->buf_height * stride / 2; + basep[p][1] += h * stride / 2; else if (tpg->field == V4L2_FIELD_SEQ_BT) - basep[p][0] += tpg->buf_height * stride / 2; + basep[p][0] += h * stride / 2; +} + +static int tpg_pattern_avg(const struct tpg_data *tpg, + unsigned pat1, unsigned pat2) +{ + unsigned pat_lines = tpg_get_pat_lines(tpg); + + if (pat1 == (pat2 + 1) % pat_lines) + return pat2; + if (pat2 == (pat1 + 1) % pat_lines) + return pat1; + return -1; } void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) @@ -1424,7 +1438,9 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 int hmax = (tpg->compose.height * tpg->perc_fill) / 100; int h; unsigned twopixsize = tpg->twopixelsize[p]; - unsigned img_width = tpg->compose.width * twopixsize / 2; + unsigned hdiv = tpg->hdownsampling[p]; + unsigned vdiv = tpg->vdownsampling[p]; + unsigned img_width = (tpg->compose.width / hdiv) * twopixsize / 2; unsigned line_offset; unsigned left_pillar_width = 0; unsigned right_pillar_start = img_width; @@ -1450,18 +1466,18 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 vbuf += tpg->compose.left * twopixsize / 2; line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width; - line_offset = (line_offset & ~1) * twopixsize / 2; + line_offset = ((line_offset & ~1) / hdiv) * twopixsize / 2; if (tpg->crop.left < tpg->border.left) { left_pillar_width = tpg->border.left - tpg->crop.left; if (left_pillar_width > tpg->crop.width) left_pillar_width = tpg->crop.width; left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width; - left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2; + left_pillar_width = ((left_pillar_width & ~1) / hdiv) * twopixsize / 2; } if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) { right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left; right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width; - right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2; + right_pillar_start = ((right_pillar_start & ~1) / hdiv) * twopixsize / 2; if (right_pillar_start > img_width) right_pillar_start = img_width; } @@ -1490,6 +1506,26 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 src_y++; } + if (vdiv > 1) { + /* + * When doing vertical downsampling the field setting + * matters: for SEQ_BT/TB we downsample each field + * separately (i.e. lines 0+2 are combined, as are + * lines 1+3), for the other field settings we combine + * odd and even lines. Doing that for SEQ_BT/TB would + * be really weird. + */ + if (tpg->field == V4L2_FIELD_SEQ_BT || + tpg->field == V4L2_FIELD_SEQ_TB) { + if ((h & 3) >= 2) + continue; + } else if (h & 1) { + continue; + } + + buf_line /= vdiv; + } + if (h >= hmax) { if (hmax == tpg->compose.height) continue; @@ -1515,14 +1551,63 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 linestart_newer = tpg->random_line[p] + twopixsize * prandom_u32_max(tpg->src_width / 2); } else { - pat_line_old = tpg_get_pat_line(tpg, - (frame_line + mv_vert_old) % tpg->src_height); - pat_line_new = tpg_get_pat_line(tpg, - (frame_line + mv_vert_new) % tpg->src_height); + unsigned frame_line_old = + (frame_line + mv_vert_old) % tpg->src_height; + unsigned frame_line_new = + (frame_line + mv_vert_new) % tpg->src_height; + unsigned pat_line_next_old; + unsigned pat_line_next_new; + + pat_line_old = tpg_get_pat_line(tpg, frame_line_old); + pat_line_new = tpg_get_pat_line(tpg, frame_line_new); linestart_older = tpg->lines[pat_line_old][p] + - mv_hor_old * twopixsize / 2; + (mv_hor_old / hdiv) * twopixsize / 2; linestart_newer = tpg->lines[pat_line_new][p] + - mv_hor_new * twopixsize / 2; + (mv_hor_new / hdiv) * twopixsize / 2; + + if (vdiv > 1) { + unsigned frame_line_next; + int avg_pat; + + /* + * Now decide whether we need to use downsampled_lines[]. + * That's necessary if the two lines use different patterns. + */ + frame_line_next = tpg_calc_frameline(tpg, src_y, tpg->field); + if (tpg->vflip) + frame_line_next = tpg->src_height - frame_line_next - 1; + pat_line_next_old = tpg_get_pat_line(tpg, + (frame_line_next + mv_vert_old) % tpg->src_height); + pat_line_next_new = tpg_get_pat_line(tpg, + (frame_line_next + mv_vert_new) % tpg->src_height); + + switch (tpg->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_INTERLACED_TB: + avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new); + if (avg_pat < 0) + break; + linestart_older = tpg->downsampled_lines[avg_pat][p] + + (mv_hor_old / hdiv) * twopixsize / 2; + linestart_newer = linestart_older; + break; + case V4L2_FIELD_NONE: + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_SEQ_TB: + avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old); + if (avg_pat >= 0) + linestart_older = tpg->downsampled_lines[avg_pat][p] + + (mv_hor_old / hdiv) * twopixsize / 2; + avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new); + if (avg_pat >= 0) + linestart_newer = tpg->downsampled_lines[avg_pat][p] + + (mv_hor_new / hdiv) * twopixsize / 2; + break; + } + } linestart_older += line_offset; linestart_newer += line_offset; } @@ -1572,12 +1657,13 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 u8 *wss = tpg->random_line[p] + twopixsize * prandom_u32_max(tpg->src_width / 2); - memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2); + memcpy(vbuf + buf_line * stride, wss, + (wss_width / hdiv) * twopixsize / 2); } } vbuf = orig_vbuf; - vbuf += tpg->compose.left * twopixsize / 2; + vbuf += (tpg->compose.left / hdiv) * twopixsize / 2; src_y = 0; error = 0; for (h = 0; h < tpg->compose.height; h++) { @@ -1594,6 +1680,12 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 src_y++; } + if (vdiv > 1) { + if (h & 1) + continue; + buf_line /= vdiv; + } + if (tpg->show_border && frame_line >= b->top && frame_line < b->top + b->height) { unsigned bottom = b->top + b->height - 1; @@ -1636,13 +1728,13 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 width -= left + width - c->left - c->width; left -= c->left; left = (left * tpg->scaled_width) / tpg->src_width; - left = (left & ~1) * twopixsize / 2; + left = ((left & ~1) / hdiv) * twopixsize / 2; width = (width * tpg->scaled_width) / tpg->src_width; - width = (width & ~1) * twopixsize / 2; + width = ((width & ~1) / hdiv) * twopixsize / 2; memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width); } if (tpg->insert_sav) { - unsigned offset = (tpg->compose.width / 6) * twopixsize; + unsigned offset = (tpg->compose.width / (6 * hdiv)) * twopixsize; u8 *p = vbuf + buf_line * stride + offset; unsigned vact = 0, hact = 0; @@ -1656,7 +1748,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 (hact ^ vact ^ f); } if (tpg->insert_eav) { - unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize; + unsigned offset = (tpg->compose.width / (6 * hdiv)) * 2 * twopixsize; u8 *p = vbuf + buf_line * stride + offset; unsigned vact = 0, hact = 1; -- cgit v1.2.3 From 68c90d64964de8a0c8c19825f373943096e3f673 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 14:55:09 -0300 Subject: [media] vivid-tpg: add support for more planar formats Now that the support for hor/vert downsampled planar formats is in place we can add support for such formats to the TPG. This patch adds support for: V4L2_PIX_FMT_YUV420M V4L2_PIX_FMT_YVU420M V4L2_PIX_FMT_YUV420 V4L2_PIX_FMT_YVU420 V4L2_PIX_FMT_YUV422P V4L2_PIX_FMT_NV16 V4L2_PIX_FMT_NV61 V4L2_PIX_FMT_NV12 V4L2_PIX_FMT_NV21 V4L2_PIX_FMT_NV12P V4L2_PIX_FMT_NV21P Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 90 +++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 838625bd2b96..79dc3101eb86 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -201,13 +201,49 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_ABGR32: tpg->is_yuv = false; break; + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YVU420M: + tpg->buffers = 3; + /* fall through */ + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + tpg->vdownsampling[1] = 2; + tpg->vdownsampling[2] = 2; + tpg->hdownsampling[1] = 2; + tpg->hdownsampling[2] = 2; + tpg->planes = 3; + tpg->is_yuv = true; + break; + case V4L2_PIX_FMT_YUV422P: + tpg->vdownsampling[1] = 1; + tpg->vdownsampling[2] = 1; + tpg->hdownsampling[1] = 2; + tpg->hdownsampling[2] = 2; + tpg->planes = 3; + tpg->is_yuv = true; + break; case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: + tpg->buffers = 2; + /* fall through */ + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: tpg->vdownsampling[1] = 1; tpg->hdownsampling[1] = 1; + tpg->planes = 2; + tpg->is_yuv = true; + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: tpg->buffers = 2; + /* fall through */ + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + tpg->vdownsampling[1] = 2; + tpg->hdownsampling[1] = 1; tpg->planes = 2; - /* fall-through */ + tpg->is_yuv = true; + break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: @@ -243,11 +279,29 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_ABGR32: tpg->twopixelsize[0] = 2 * 4; break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + tpg->twopixelsize[0] = 2; + tpg->twopixelsize[1] = 2; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: tpg->twopixelsize[0] = 2; tpg->twopixelsize[1] = 2; break; + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YVU420M: + tpg->twopixelsize[0] = 2; + tpg->twopixelsize[1] = 2; + tpg->twopixelsize[2] = 2; + break; } return true; } @@ -685,6 +739,37 @@ static void gen_twopix(struct tpg_data *tpg, b_v = tpg->colors[color][2]; /* B or precalculated V */ switch (tpg->fourcc) { + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YUV420M: + buf[0][offset] = r_y; + if (odd) { + buf[1][0] = (buf[1][0] + g_u) / 2; + buf[2][0] = (buf[2][0] + b_v) / 2; + buf[1][1] = buf[1][0]; + buf[2][1] = buf[2][0]; + break; + } + buf[1][0] = g_u; + buf[2][0] = b_v; + break; + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YVU420M: + buf[0][offset] = r_y; + if (odd) { + buf[1][0] = (buf[1][0] + b_v) / 2; + buf[2][0] = (buf[2][0] + g_u) / 2; + buf[1][1] = buf[1][0]; + buf[2][1] = buf[2][0]; + break; + } + buf[1][0] = b_v; + buf[2][0] = g_u; + break; + + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV16M: buf[0][offset] = r_y; if (odd) { @@ -695,6 +780,9 @@ static void gen_twopix(struct tpg_data *tpg, buf[1][0] = g_u; buf[1][1] = b_v; break; + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV61M: buf[0][offset] = r_y; if (odd) { -- cgit v1.2.3 From 51f309683510ced24b1b3886f0935a0ab32d1e0b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 14:57:50 -0300 Subject: [media] vivid-tpg: add support for V4L2_PIX_FMT_GREY Add monochrome support to the TPG. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 79dc3101eb86..ccb4a6be26c1 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -199,6 +199,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_GREY: tpg->is_yuv = false; break; case V4L2_PIX_FMT_YUV420M: @@ -279,6 +280,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_ABGR32: tpg->twopixelsize[0] = 2 * 4; break; + case V4L2_PIX_FMT_GREY: + tpg->twopixelsize[0] = 2; + break; case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV12M: @@ -598,7 +602,7 @@ static void precalculate_color(struct tpg_data *tpg, int k) g <<= 4; b <<= 4; } - if (tpg->qual == TPG_QUAL_GRAY) { + if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) { /* Rec. 709 Luma function */ /* (0.2126, 0.7152, 0.0722) * (255 * 256) */ r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16; @@ -739,6 +743,9 @@ static void gen_twopix(struct tpg_data *tpg, b_v = tpg->colors[color][2]; /* B or precalculated V */ switch (tpg->fourcc) { + case V4L2_PIX_FMT_GREY: + buf[0][offset] = r_y; + break; case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV420M: -- cgit v1.2.3 From 9991deff1ac9361abbe0c5938b27f903f16d1ca0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 8 Mar 2015 05:53:10 -0300 Subject: [media] vivid-tpg: add helper functions to simplify common calculations Add helper functions to handle horizontal downscaling and horizontal scaling. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 130 ++++++++++++++----------------- drivers/media/platform/vivid/vivid-tpg.h | 23 ++++++ 2 files changed, 80 insertions(+), 73 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index ccb4a6be26c1..048b1f128a19 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -183,6 +183,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->recalc_colors = true; tpg->vdownsampling[0] = 1; tpg->hdownsampling[0] = 1; + tpg->hmask[0] = ~0; + tpg->hmask[1] = ~0; + tpg->hmask[2] = ~0; switch (fourcc) { case V4L2_PIX_FMT_RGB565: @@ -231,6 +234,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_NV61: tpg->vdownsampling[1] = 1; tpg->hdownsampling[1] = 1; + tpg->hmask[1] = ~1; tpg->planes = 2; tpg->is_yuv = true; break; @@ -242,6 +246,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_NV21: tpg->vdownsampling[1] = 2; tpg->hdownsampling[1] = 1; + tpg->hmask[1] = ~1; tpg->planes = 2; tpg->is_yuv = true; break; @@ -249,6 +254,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: + tpg->hmask[0] = ~1; tpg->is_yuv = true; break; default: @@ -1116,6 +1122,7 @@ static void tpg_calculate_square_border(struct tpg_data *tpg) static void tpg_precalculate_line(struct tpg_data *tpg) { enum tpg_color contrast; + u8 pix[TPG_MAX_PLANES][8]; unsigned pat; unsigned p; unsigned x; @@ -1142,7 +1149,6 @@ static void tpg_precalculate_line(struct tpg_data *tpg) for (x = 0; x < tpg->scaled_width * 2; x += 2) { unsigned real_x = src_x; enum tpg_color color1, color2; - u8 pix[TPG_MAX_PLANES][8]; real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x; color1 = tpg_get_color(tpg, pat, real_x); @@ -1170,8 +1176,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg) for (p = 0; p < tpg->planes; p++) { unsigned twopixsize = tpg->twopixelsize[p]; unsigned hdiv = tpg->hdownsampling[p]; - u8 *pos = tpg->lines[pat][p] + - (x / hdiv) * twopixsize / 2; + u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x); memcpy(pos, pix[p], twopixsize / hdiv); } @@ -1185,50 +1190,38 @@ static void tpg_precalculate_line(struct tpg_data *tpg) unsigned next_pat = (pat + 1) % pat_lines; for (p = 1; p < tpg->planes; p++) { - unsigned twopixsize = tpg->twopixelsize[p]; - unsigned hdiv = tpg->hdownsampling[p]; - - for (x = 0; x < tpg->scaled_width * 2; x += 2) { - unsigned offset = (x / hdiv) * twopixsize / 2; - u8 *pos1 = tpg->lines[pat][p] + offset; - u8 *pos2 = tpg->lines[next_pat][p] + offset; - u8 *dest = tpg->downsampled_lines[pat][p] + offset; - unsigned i; + unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2); + u8 *pos1 = tpg->lines[pat][p]; + u8 *pos2 = tpg->lines[next_pat][p]; + u8 *dest = tpg->downsampled_lines[pat][p]; - for (i = 0; i < twopixsize / hdiv; i++, dest++, pos1++, pos2++) - *dest = ((u16)*pos1 + (u16)*pos2) / 2; - } + for (x = 0; x < w; x++, pos1++, pos2++, dest++) + *dest = ((u16)*pos1 + (u16)*pos2) / 2; } } } - for (x = 0; x < tpg->scaled_width; x += 2) { - u8 pix[TPG_MAX_PLANES][8]; - - gen_twopix(tpg, pix, contrast, 0); - gen_twopix(tpg, pix, contrast, 1); - for (p = 0; p < tpg->planes; p++) { - unsigned twopixsize = tpg->twopixelsize[p]; - u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2; + gen_twopix(tpg, pix, contrast, 0); + gen_twopix(tpg, pix, contrast, 1); + for (p = 0; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + u8 *pos = tpg->contrast_line[p]; + for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize) memcpy(pos, pix[p], twopixsize); - } } - for (x = 0; x < tpg->scaled_width; x += 2) { - u8 pix[TPG_MAX_PLANES][8]; - gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0); - gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1); - for (p = 0; p < tpg->planes; p++) { - unsigned twopixsize = tpg->twopixelsize[p]; - u8 *pos = tpg->black_line[p] + x * twopixsize / 2; + gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0); + gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1); + for (p = 0; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + u8 *pos = tpg->black_line[p]; + for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize) memcpy(pos, pix[p], twopixsize); - } } - for (x = 0; x < tpg->scaled_width * 2; x += 2) { - u8 pix[TPG_MAX_PLANES][8]; + for (x = 0; x < tpg->scaled_width * 2; x += 2) { gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0); gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1); for (p = 0; p < tpg->planes; p++) { @@ -1238,6 +1231,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg) memcpy(pos, pix[p], twopixsize); } } + gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0); gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1); gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0); @@ -1533,9 +1527,8 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 int hmax = (tpg->compose.height * tpg->perc_fill) / 100; int h; unsigned twopixsize = tpg->twopixelsize[p]; - unsigned hdiv = tpg->hdownsampling[p]; unsigned vdiv = tpg->vdownsampling[p]; - unsigned img_width = (tpg->compose.width / hdiv) * twopixsize / 2; + unsigned img_width = tpg_hdiv(tpg, p, tpg->compose.width); unsigned line_offset; unsigned left_pillar_width = 0; unsigned right_pillar_start = img_width; @@ -1551,28 +1544,25 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 tpg_recalc(tpg); - mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1; - mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1; + mv_hor_old = tpg_hscale_div(tpg, p, mv_hor_old); + mv_hor_new = tpg_hscale_div(tpg, p, mv_hor_new); wss_width = tpg->crop.left < tpg->src_width / 2 ? tpg->src_width / 2 - tpg->crop.left : 0; if (wss_width > tpg->crop.width) wss_width = tpg->crop.width; - wss_width = wss_width * tpg->scaled_width / tpg->src_width; + wss_width = tpg_hscale_div(tpg, p, wss_width); - vbuf += tpg->compose.left * twopixsize / 2; - line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width; - line_offset = ((line_offset & ~1) / hdiv) * twopixsize / 2; + vbuf += tpg_hdiv(tpg, p, tpg->compose.left); + line_offset = tpg_hscale_div(tpg, p, tpg->crop.left); if (tpg->crop.left < tpg->border.left) { left_pillar_width = tpg->border.left - tpg->crop.left; if (left_pillar_width > tpg->crop.width) left_pillar_width = tpg->crop.width; - left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width; - left_pillar_width = ((left_pillar_width & ~1) / hdiv) * twopixsize / 2; + left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width); } if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) { right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left; - right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width; - right_pillar_start = ((right_pillar_start & ~1) / hdiv) * twopixsize / 2; + right_pillar_start = tpg_hscale_div(tpg, p, right_pillar_start); if (right_pillar_start > img_width) right_pillar_start = img_width; } @@ -1655,10 +1645,8 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 pat_line_old = tpg_get_pat_line(tpg, frame_line_old); pat_line_new = tpg_get_pat_line(tpg, frame_line_new); - linestart_older = tpg->lines[pat_line_old][p] + - (mv_hor_old / hdiv) * twopixsize / 2; - linestart_newer = tpg->lines[pat_line_new][p] + - (mv_hor_new / hdiv) * twopixsize / 2; + linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old; + linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new; if (vdiv > 1) { unsigned frame_line_next; @@ -1683,8 +1671,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new); if (avg_pat < 0) break; - linestart_older = tpg->downsampled_lines[avg_pat][p] + - (mv_hor_old / hdiv) * twopixsize / 2; + linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old; linestart_newer = linestart_older; break; case V4L2_FIELD_NONE: @@ -1695,11 +1682,11 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old); if (avg_pat >= 0) linestart_older = tpg->downsampled_lines[avg_pat][p] + - (mv_hor_old / hdiv) * twopixsize / 2; + mv_hor_old; avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new); if (avg_pat >= 0) linestart_newer = tpg->downsampled_lines[avg_pat][p] + - (mv_hor_new / hdiv) * twopixsize / 2; + mv_hor_new; break; } } @@ -1743,22 +1730,10 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 memcpy(vbuf + buf_line * stride, linestart_older, img_width); break; } - - if (is_tv && !is_60hz && frame_line == 0 && wss_width) { - /* - * Replace the first half of the top line of a 50 Hz frame - * with random data to simulate a WSS signal. - */ - u8 *wss = tpg->random_line[p] + - twopixsize * prandom_u32_max(tpg->src_width / 2); - - memcpy(vbuf + buf_line * stride, wss, - (wss_width / hdiv) * twopixsize / 2); - } } vbuf = orig_vbuf; - vbuf += (tpg->compose.left / hdiv) * twopixsize / 2; + vbuf += tpg_hdiv(tpg, p, tpg->compose.left); src_y = 0; error = 0; for (h = 0; h < tpg->compose.height; h++) { @@ -1781,6 +1756,17 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 buf_line /= vdiv; } + if (is_tv && !is_60hz && frame_line == 0 && wss_width) { + /* + * Replace the first half of the top line of a 50 Hz frame + * with random data to simulate a WSS signal. + */ + u8 *wss = tpg->random_line[p] + + twopixsize * prandom_u32_max(tpg->src_width / 2); + + memcpy(vbuf + buf_line * stride, wss, wss_width); + } + if (tpg->show_border && frame_line >= b->top && frame_line < b->top + b->height) { unsigned bottom = b->top + b->height - 1; @@ -1822,14 +1808,12 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 if (c->left + c->width < left + width) width -= left + width - c->left - c->width; left -= c->left; - left = (left * tpg->scaled_width) / tpg->src_width; - left = ((left & ~1) / hdiv) * twopixsize / 2; - width = (width * tpg->scaled_width) / tpg->src_width; - width = ((width & ~1) / hdiv) * twopixsize / 2; + left = tpg_hscale_div(tpg, p, left); + width = tpg_hscale_div(tpg, p, width); memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width); } if (tpg->insert_sav) { - unsigned offset = (tpg->compose.width / (6 * hdiv)) * twopixsize; + unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3); u8 *p = vbuf + buf_line * stride + offset; unsigned vact = 0, hact = 0; @@ -1843,7 +1827,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 (hact ^ vact ^ f); } if (tpg->insert_eav) { - unsigned offset = (tpg->compose.width / (6 * hdiv)) * 2 * twopixsize; + unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3); u8 *p = vbuf + buf_line * stride + offset; unsigned vact = 0, hact = 1; diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index 5a53eb99b6de..b62f392bb10d 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -142,6 +142,11 @@ struct tpg_data { unsigned planes; u8 vdownsampling[TPG_MAX_PLANES]; u8 hdownsampling[TPG_MAX_PLANES]; + /* + * horizontal positions must be ANDed with this value to enforce + * correct boundaries for packed YUYV values. + */ + unsigned hmask[TPG_MAX_PLANES]; /* Used to store the colors in native format, either RGB or YUV */ u8 colors[TPG_COLOR_MAX][3]; u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; @@ -347,6 +352,24 @@ static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned p return tpg->twopixelsize[plane]; } +static inline unsigned tpg_hdiv(const struct tpg_data *tpg, + unsigned plane, unsigned x) +{ + return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) * + tpg->twopixelsize[plane] / 2; +} + +static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x) +{ + return (x * tpg->scaled_width) / tpg->src_width; +} + +static inline unsigned tpg_hscale_div(const struct tpg_data *tpg, + unsigned plane, unsigned x) +{ + return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x)); +} + static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) { return tpg->bytesperline[plane]; -- cgit v1.2.3 From dfff048953eb1e38e1f1ee718ff1295f219f1a89 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 11:04:02 -0300 Subject: [media] vivid-tpg: add const where appropriate Added 'const' to several functions where that is possible to do. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 8 ++++---- drivers/media/platform/vivid/vivid-tpg.h | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 048b1f128a19..2b7362d4b618 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1241,8 +1241,8 @@ static void tpg_precalculate_line(struct tpg_data *tpg) /* need this to do rgb24 rendering */ typedef struct { u16 __; u8 _; } __packed x24; -void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], - int y, int x, char *text) +void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], + int y, int x, char *text) { int line; unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; @@ -1389,7 +1389,7 @@ void tpg_update_mv_step(struct tpg_data *tpg) } /* Map the line number relative to the crop rectangle to a frame line number */ -static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y, +static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y, unsigned field) { switch (field) { @@ -1406,7 +1406,7 @@ static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y, * Map the line number relative to the compose rectangle to a destination * buffer line number. */ -static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y, +static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y, unsigned field) { y += tpg->compose.top; diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index b62f392bb10d..82ce9bfa8604 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -193,12 +193,14 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, u32 field); void tpg_set_font(const u8 *f); -void tpg_gen_text(struct tpg_data *tpg, +void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); void tpg_calc_text_basep(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); -void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf); -void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf); +void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, + unsigned p, u8 *vbuf); +void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, + unsigned p, u8 *vbuf); bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, const struct v4l2_rect *compose); -- cgit v1.2.3 From e76036d8507ca8568661e5c4f5010219d7097497 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 11:07:23 -0300 Subject: [media] vivid-tpg: add a new tpg_draw_params structure This is needed to refactor the drawing function which is much too big. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 2b7362d4b618..c04c45868793 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1514,6 +1514,35 @@ static int tpg_pattern_avg(const struct tpg_data *tpg, return -1; } +/* + * This struct contains common parameters used by both the drawing of the + * test pattern and the drawing of the extras (borders, square, etc.) + */ +struct tpg_draw_params { + /* common data */ + bool is_tv; + bool is_60hz; + unsigned twopixsize; + unsigned img_width; + unsigned stride; + unsigned hmax; + unsigned frame_line; + unsigned frame_line_next; + + /* test pattern */ + unsigned mv_hor_old; + unsigned mv_hor_new; + unsigned mv_vert_old; + unsigned mv_vert_new; + + /* extras */ + unsigned wss_width; + unsigned wss_random_offset; + unsigned sav_eav_f; + unsigned left_pillar_width; + unsigned right_pillar_start; +}; + void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) { bool is_tv = std; -- cgit v1.2.3 From 5e72939322862770f5dea9634c3cd2700dff9ca2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 11:26:43 -0300 Subject: [media] vivid-tpg: move common parameters to tpg_draw_params Replace local variables by fields in the tpg_draw_params struct. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 34 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index c04c45868793..cd40d4d7fdd6 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1545,23 +1545,21 @@ struct tpg_draw_params { void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) { - bool is_tv = std; - bool is_60hz = is_tv && (std & V4L2_STD_525_60); + struct tpg_draw_params params; unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width; unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width; unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height; unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; unsigned wss_width; unsigned f; - int hmax = (tpg->compose.height * tpg->perc_fill) / 100; int h; - unsigned twopixsize = tpg->twopixelsize[p]; + unsigned twopixsize; unsigned vdiv = tpg->vdownsampling[p]; - unsigned img_width = tpg_hdiv(tpg, p, tpg->compose.width); + unsigned img_width; unsigned line_offset; unsigned left_pillar_width = 0; - unsigned right_pillar_start = img_width; - unsigned stride = tpg->bytesperline[p]; + unsigned right_pillar_start; + unsigned stride; unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; u8 *orig_vbuf = vbuf; @@ -1573,6 +1571,17 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 tpg_recalc(tpg); + params.is_tv = std; + params.is_60hz = std & V4L2_STD_525_60; + params.twopixsize = tpg->twopixelsize[p]; + params.img_width = tpg_hdiv(tpg, p, tpg->compose.width); + params.stride = tpg->bytesperline[p]; + params.hmax = (tpg->compose.height * tpg->perc_fill) / 100; + + twopixsize = params.twopixsize; + img_width = params.img_width; + stride = params.stride; + mv_hor_old = tpg_hscale_div(tpg, p, mv_hor_old); mv_hor_new = tpg_hscale_div(tpg, p, mv_hor_new); wss_width = tpg->crop.left < tpg->src_width / 2 ? @@ -1589,6 +1598,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 left_pillar_width = tpg->crop.width; left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width); } + right_pillar_start = img_width; if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) { right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left; right_pillar_start = tpg_hscale_div(tpg, p, right_pillar_start); @@ -1596,7 +1606,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 right_pillar_start = img_width; } - f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); + f = tpg->field == (params.is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); for (h = 0; h < tpg->compose.height; h++) { bool even; @@ -1640,8 +1650,8 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 buf_line /= vdiv; } - if (h >= hmax) { - if (hmax == tpg->compose.height) + if (h >= params.hmax) { + if (params.hmax == tpg->compose.height) continue; if (!tpg->perc_fill_blank) continue; @@ -1724,7 +1734,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 } if (tpg->field_alternate) { linestart_top = linestart_bottom = linestart_older; - } else if (is_60hz) { + } else if (params.is_60hz) { linestart_top = linestart_newer; linestart_bottom = linestart_older; } else { @@ -1785,7 +1795,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 buf_line /= vdiv; } - if (is_tv && !is_60hz && frame_line == 0 && wss_width) { + if (params.is_tv && !params.is_60hz && frame_line == 0 && wss_width) { /* * Replace the first half of the top line of a 50 Hz frame * with random data to simulate a WSS signal. -- cgit v1.2.3 From f0ce4fd6e03afcc22c6b2cd59e155832cea644a9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 11:30:05 -0300 Subject: [media] vivid-tpg: move pattern-related fields to struct tpg_draw_params Add a new function that fills in pattern-related fields in struct tpg_draw_params. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index cd40d4d7fdd6..b2730bbc96b3 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1543,13 +1543,26 @@ struct tpg_draw_params { unsigned right_pillar_start; }; +static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p, + struct tpg_draw_params *params) +{ + params->mv_hor_old = + tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width); + params->mv_hor_new = + tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) % + tpg->src_width); + params->mv_vert_old = tpg->mv_vert_count % tpg->src_height; + params->mv_vert_new = + (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; +} + void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) { struct tpg_draw_params params; - unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width; - unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width; - unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height; - unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; + unsigned mv_hor_old; + unsigned mv_hor_new; + unsigned mv_vert_old; + unsigned mv_vert_new; unsigned wss_width; unsigned f; int h; @@ -1578,12 +1591,17 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 params.stride = tpg->bytesperline[p]; params.hmax = (tpg->compose.height * tpg->perc_fill) / 100; + tpg_fill_params_pattern(tpg, p, ¶ms); + + mv_hor_old = params.mv_hor_old; + mv_hor_new = params.mv_hor_new; + mv_vert_old = params.mv_vert_old; + mv_vert_new = params.mv_vert_new; + twopixsize = params.twopixsize; img_width = params.img_width; stride = params.stride; - mv_hor_old = tpg_hscale_div(tpg, p, mv_hor_old); - mv_hor_new = tpg_hscale_div(tpg, p, mv_hor_new); wss_width = tpg->crop.left < tpg->src_width / 2 ? tpg->src_width / 2 - tpg->crop.left : 0; if (wss_width > tpg->crop.width) -- cgit v1.2.3 From 07386b9ab1d2adcf83543dfee0e835db56ccb3d5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 11:39:19 -0300 Subject: [media] vivid-tpg: move 'extras' parameters to tpg_draw_params Any parameters related to drawing 'extras' like the border, the square, etc. are moved to struct tpg_draw_params. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 100 ++++++++++++++++++------------- 1 file changed, 58 insertions(+), 42 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index b2730bbc96b3..f76ef3e2f498 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1556,6 +1556,44 @@ static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p, (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; } +static void tpg_fill_params_extras(const struct tpg_data *tpg, + unsigned p, + struct tpg_draw_params *params) +{ + unsigned left_pillar_width = 0; + unsigned right_pillar_start = params->img_width; + + params->wss_width = tpg->crop.left < tpg->src_width / 2 ? + tpg->src_width / 2 - tpg->crop.left : 0; + if (params->wss_width > tpg->crop.width) + params->wss_width = tpg->crop.width; + params->wss_width = tpg_hscale_div(tpg, p, params->wss_width); + params->wss_random_offset = + params->twopixsize * prandom_u32_max(tpg->src_width / 2); + + if (tpg->crop.left < tpg->border.left) { + left_pillar_width = tpg->border.left - tpg->crop.left; + if (left_pillar_width > tpg->crop.width) + left_pillar_width = tpg->crop.width; + left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width); + } + params->left_pillar_width = left_pillar_width; + + if (tpg->crop.left + tpg->crop.width > + tpg->border.left + tpg->border.width) { + right_pillar_start = + tpg->border.left + tpg->border.width - tpg->crop.left; + right_pillar_start = + tpg_hscale_div(tpg, p, right_pillar_start); + if (right_pillar_start > params->img_width) + right_pillar_start = params->img_width; + } + params->right_pillar_start = right_pillar_start; + + params->sav_eav_f = tpg->field == + (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); +} + void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) { struct tpg_draw_params params; @@ -1563,15 +1601,11 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 unsigned mv_hor_new; unsigned mv_vert_old; unsigned mv_vert_new; - unsigned wss_width; - unsigned f; int h; unsigned twopixsize; unsigned vdiv = tpg->vdownsampling[p]; unsigned img_width; unsigned line_offset; - unsigned left_pillar_width = 0; - unsigned right_pillar_start; unsigned stride; unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; u8 *orig_vbuf = vbuf; @@ -1598,33 +1632,14 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 mv_vert_old = params.mv_vert_old; mv_vert_new = params.mv_vert_new; + tpg_fill_params_extras(tpg, p, ¶ms); + twopixsize = params.twopixsize; img_width = params.img_width; stride = params.stride; - wss_width = tpg->crop.left < tpg->src_width / 2 ? - tpg->src_width / 2 - tpg->crop.left : 0; - if (wss_width > tpg->crop.width) - wss_width = tpg->crop.width; - wss_width = tpg_hscale_div(tpg, p, wss_width); - vbuf += tpg_hdiv(tpg, p, tpg->compose.left); line_offset = tpg_hscale_div(tpg, p, tpg->crop.left); - if (tpg->crop.left < tpg->border.left) { - left_pillar_width = tpg->border.left - tpg->crop.left; - if (left_pillar_width > tpg->crop.width) - left_pillar_width = tpg->crop.width; - left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width); - } - right_pillar_start = img_width; - if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) { - right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left; - right_pillar_start = tpg_hscale_div(tpg, p, right_pillar_start); - if (right_pillar_start > img_width) - right_pillar_start = img_width; - } - - f = tpg->field == (params.is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); for (h = 0; h < tpg->compose.height; h++) { bool even; @@ -1813,22 +1828,21 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 buf_line /= vdiv; } - if (params.is_tv && !params.is_60hz && frame_line == 0 && wss_width) { + if (params.is_tv && !params.is_60hz && frame_line == 0 && params.wss_width) { /* * Replace the first half of the top line of a 50 Hz frame * with random data to simulate a WSS signal. */ - u8 *wss = tpg->random_line[p] + - twopixsize * prandom_u32_max(tpg->src_width / 2); + u8 *wss = tpg->random_line[p] + params.wss_random_offset; - memcpy(vbuf + buf_line * stride, wss, wss_width); + memcpy(vbuf + buf_line * stride, wss, params.wss_width); } if (tpg->show_border && frame_line >= b->top && frame_line < b->top + b->height) { unsigned bottom = b->top + b->height - 1; - unsigned left = left_pillar_width; - unsigned right = right_pillar_start; + unsigned left = params.left_pillar_width; + unsigned right = params.right_pillar_start; if (frame_line == b->top || frame_line == b->top + 1 || frame_line == bottom || frame_line == bottom - 1) { @@ -1847,9 +1861,9 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 } if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top && frame_line < b->top + b->height) { - memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width); - memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p], - img_width - right_pillar_start); + memcpy(vbuf + buf_line * stride, tpg->black_line[p], params.left_pillar_width); + memcpy(vbuf + buf_line * stride + params.right_pillar_start, tpg->black_line[p], + img_width - params.right_pillar_start); } if (tpg->show_square && frame_line >= sq->top && frame_line < sq->top + sq->height && @@ -1877,11 +1891,12 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 p[0] = 0xff; p[1] = 0; p[2] = 0; - p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) | + p[3] = 0x80 | (params.sav_eav_f << 6) | + (vact << 5) | (hact << 4) | ((hact ^ vact) << 3) | - ((hact ^ f) << 2) | - ((f ^ vact) << 1) | - (hact ^ vact ^ f); + ((hact ^ params.sav_eav_f) << 2) | + ((params.sav_eav_f ^ vact) << 1) | + (hact ^ vact ^ params.sav_eav_f); } if (tpg->insert_eav) { unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3); @@ -1891,11 +1906,12 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 p[0] = 0xff; p[1] = 0; p[2] = 0; - p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) | + p[3] = 0x80 | (params.sav_eav_f << 6) | + (vact << 5) | (hact << 4) | ((hact ^ vact) << 3) | - ((hact ^ f) << 2) | - ((f ^ vact) << 1) | - (hact ^ vact ^ f); + ((hact ^ params.sav_eav_f) << 2) | + ((params.sav_eav_f ^ vact) << 1) | + (hact ^ vact ^ params.sav_eav_f); } } } -- cgit v1.2.3 From c6ff1c1b5ba0cff72f899e3b3ba0343b5a0e0024 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 11:47:48 -0300 Subject: [media] vivid-tpg: move the 'extras' drawing to a separate function This moves the drawing code for the extras (border, square, etc) to a function of its own instead of having this in the main for loop. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 216 +++++++++++++++---------------- 1 file changed, 104 insertions(+), 112 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index f76ef3e2f498..21c2f4b3242e 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1594,6 +1594,105 @@ static void tpg_fill_params_extras(const struct tpg_data *tpg, (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); } +static void tpg_fill_plane_extras(const struct tpg_data *tpg, + const struct tpg_draw_params *params, + unsigned p, unsigned h, u8 *vbuf) +{ + unsigned twopixsize = params->twopixsize; + unsigned img_width = params->img_width; + unsigned frame_line = params->frame_line; + const struct v4l2_rect *sq = &tpg->square; + const struct v4l2_rect *b = &tpg->border; + const struct v4l2_rect *c = &tpg->crop; + + if (params->is_tv && !params->is_60hz && + frame_line == 0 && params->wss_width) { + /* + * Replace the first half of the top line of a 50 Hz frame + * with random data to simulate a WSS signal. + */ + u8 *wss = tpg->random_line[p] + params->wss_random_offset; + + memcpy(vbuf, wss, params->wss_width); + } + + if (tpg->show_border && frame_line >= b->top && + frame_line < b->top + b->height) { + unsigned bottom = b->top + b->height - 1; + unsigned left = params->left_pillar_width; + unsigned right = params->right_pillar_start; + + if (frame_line == b->top || frame_line == b->top + 1 || + frame_line == bottom || frame_line == bottom - 1) { + memcpy(vbuf + left, tpg->contrast_line[p], + right - left); + } else { + if (b->left >= c->left && + b->left < c->left + c->width) + memcpy(vbuf + left, + tpg->contrast_line[p], twopixsize); + if (b->left + b->width > c->left && + b->left + b->width <= c->left + c->width) + memcpy(vbuf + right - twopixsize, + tpg->contrast_line[p], twopixsize); + } + } + if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top && + frame_line < b->top + b->height) { + memcpy(vbuf, tpg->black_line[p], params->left_pillar_width); + memcpy(vbuf + params->right_pillar_start, tpg->black_line[p], + img_width - params->right_pillar_start); + } + if (tpg->show_square && frame_line >= sq->top && + frame_line < sq->top + sq->height && + sq->left < c->left + c->width && + sq->left + sq->width >= c->left) { + unsigned left = sq->left; + unsigned width = sq->width; + + if (c->left > left) { + width -= c->left - left; + left = c->left; + } + if (c->left + c->width < left + width) + width -= left + width - c->left - c->width; + left -= c->left; + left = tpg_hscale_div(tpg, p, left); + width = tpg_hscale_div(tpg, p, width); + memcpy(vbuf + left, tpg->contrast_line[p], width); + } + if (tpg->insert_sav) { + unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3); + u8 *p = vbuf + offset; + unsigned vact = 0, hact = 0; + + p[0] = 0xff; + p[1] = 0; + p[2] = 0; + p[3] = 0x80 | (params->sav_eav_f << 6) | + (vact << 5) | (hact << 4) | + ((hact ^ vact) << 3) | + ((hact ^ params->sav_eav_f) << 2) | + ((params->sav_eav_f ^ vact) << 1) | + (hact ^ vact ^ params->sav_eav_f); + } + if (tpg->insert_eav) { + unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3); + u8 *p = vbuf + offset; + unsigned vact = 0, hact = 1; + + p[0] = 0xff; + p[1] = 0; + p[2] = 0; + p[3] = 0x80 | (params->sav_eav_f << 6) | + (vact << 5) | (hact << 4) | + ((hact ^ vact) << 3) | + ((hact ^ params->sav_eav_f) << 2) | + ((params->sav_eav_f ^ vact) << 1) | + (hact ^ vact ^ params->sav_eav_f); + } +} + void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) { struct tpg_draw_params params; @@ -1608,7 +1707,6 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 unsigned line_offset; unsigned stride; unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; - u8 *orig_vbuf = vbuf; /* Coarse scaling with Bresenham */ unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height; @@ -1653,7 +1751,9 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 u8 *linestart_top; u8 *linestart_bottom; - frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); + params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); + params.frame_line_next = params.frame_line; + frame_line = params.frame_line; even = !(frame_line & 1); buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); src_y += int_part; @@ -1802,117 +1902,9 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 memcpy(vbuf + buf_line * stride, linestart_older, img_width); break; } - } - vbuf = orig_vbuf; - vbuf += tpg_hdiv(tpg, p, tpg->compose.left); - src_y = 0; - error = 0; - for (h = 0; h < tpg->compose.height; h++) { - unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); - unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); - const struct v4l2_rect *sq = &tpg->square; - const struct v4l2_rect *b = &tpg->border; - const struct v4l2_rect *c = &tpg->crop; - - src_y += int_part; - error += fract_part; - if (error >= tpg->compose.height) { - error -= tpg->compose.height; - src_y++; - } - - if (vdiv > 1) { - if (h & 1) - continue; - buf_line /= vdiv; - } - - if (params.is_tv && !params.is_60hz && frame_line == 0 && params.wss_width) { - /* - * Replace the first half of the top line of a 50 Hz frame - * with random data to simulate a WSS signal. - */ - u8 *wss = tpg->random_line[p] + params.wss_random_offset; - - memcpy(vbuf + buf_line * stride, wss, params.wss_width); - } - - if (tpg->show_border && frame_line >= b->top && - frame_line < b->top + b->height) { - unsigned bottom = b->top + b->height - 1; - unsigned left = params.left_pillar_width; - unsigned right = params.right_pillar_start; - - if (frame_line == b->top || frame_line == b->top + 1 || - frame_line == bottom || frame_line == bottom - 1) { - memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], - right - left); - } else { - if (b->left >= c->left && - b->left < c->left + c->width) - memcpy(vbuf + buf_line * stride + left, - tpg->contrast_line[p], twopixsize); - if (b->left + b->width > c->left && - b->left + b->width <= c->left + c->width) - memcpy(vbuf + buf_line * stride + right - twopixsize, - tpg->contrast_line[p], twopixsize); - } - } - if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top && - frame_line < b->top + b->height) { - memcpy(vbuf + buf_line * stride, tpg->black_line[p], params.left_pillar_width); - memcpy(vbuf + buf_line * stride + params.right_pillar_start, tpg->black_line[p], - img_width - params.right_pillar_start); - } - if (tpg->show_square && frame_line >= sq->top && - frame_line < sq->top + sq->height && - sq->left < c->left + c->width && - sq->left + sq->width >= c->left) { - unsigned left = sq->left; - unsigned width = sq->width; - - if (c->left > left) { - width -= c->left - left; - left = c->left; - } - if (c->left + c->width < left + width) - width -= left + width - c->left - c->width; - left -= c->left; - left = tpg_hscale_div(tpg, p, left); - width = tpg_hscale_div(tpg, p, width); - memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width); - } - if (tpg->insert_sav) { - unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3); - u8 *p = vbuf + buf_line * stride + offset; - unsigned vact = 0, hact = 0; - - p[0] = 0xff; - p[1] = 0; - p[2] = 0; - p[3] = 0x80 | (params.sav_eav_f << 6) | - (vact << 5) | (hact << 4) | - ((hact ^ vact) << 3) | - ((hact ^ params.sav_eav_f) << 2) | - ((params.sav_eav_f ^ vact) << 1) | - (hact ^ vact ^ params.sav_eav_f); - } - if (tpg->insert_eav) { - unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3); - u8 *p = vbuf + buf_line * stride + offset; - unsigned vact = 0, hact = 1; - - p[0] = 0xff; - p[1] = 0; - p[2] = 0; - p[3] = 0x80 | (params.sav_eav_f << 6) | - (vact << 5) | (hact << 4) | - ((hact ^ vact) << 3) | - ((hact ^ params.sav_eav_f) << 2) | - ((params.sav_eav_f ^ vact) << 1) | - (hact ^ vact ^ params.sav_eav_f); - } + tpg_fill_plane_extras(tpg, ¶ms, p, h, + vbuf + buf_line * params.stride); } } -- cgit v1.2.3 From ecb9e91b2dfa3ef69c17c03b2e73ce935254fa65 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 11:52:43 -0300 Subject: [media] vivid-tpg: split off the pattern drawing code The last part of the vivid-tpg refactoring: split off the pattern drawing code into a function of its own. This greatly improves the readability and maintainability of this code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 320 ++++++++++++++++--------------- 1 file changed, 162 insertions(+), 158 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 21c2f4b3242e..3f0ec9ab7030 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -1693,19 +1693,153 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg, } } -void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) +static void tpg_fill_plane_pattern(const struct tpg_data *tpg, + const struct tpg_draw_params *params, + unsigned p, unsigned h, u8 *vbuf) +{ + unsigned twopixsize = params->twopixsize; + unsigned img_width = params->img_width; + unsigned mv_hor_old = params->mv_hor_old; + unsigned mv_hor_new = params->mv_hor_new; + unsigned mv_vert_old = params->mv_vert_old; + unsigned mv_vert_new = params->mv_vert_new; + unsigned frame_line = params->frame_line; + unsigned frame_line_next = params->frame_line_next; + unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left); + bool even; + bool fill_blank = false; + unsigned pat_line_old; + unsigned pat_line_new; + u8 *linestart_older; + u8 *linestart_newer; + u8 *linestart_top; + u8 *linestart_bottom; + + even = !(frame_line & 1); + + if (h >= params->hmax) { + if (params->hmax == tpg->compose.height) + return; + if (!tpg->perc_fill_blank) + return; + fill_blank = true; + } + + if (tpg->vflip) { + frame_line = tpg->src_height - frame_line - 1; + frame_line_next = tpg->src_height - frame_line_next - 1; + } + + if (fill_blank) { + linestart_older = tpg->contrast_line[p]; + linestart_newer = tpg->contrast_line[p]; + } else if (tpg->qual != TPG_QUAL_NOISE && + (frame_line < tpg->border.top || + frame_line >= tpg->border.top + tpg->border.height)) { + linestart_older = tpg->black_line[p]; + linestart_newer = tpg->black_line[p]; + } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) { + linestart_older = tpg->random_line[p] + + twopixsize * prandom_u32_max(tpg->src_width / 2); + linestart_newer = tpg->random_line[p] + + twopixsize * prandom_u32_max(tpg->src_width / 2); + } else { + unsigned frame_line_old = + (frame_line + mv_vert_old) % tpg->src_height; + unsigned frame_line_new = + (frame_line + mv_vert_new) % tpg->src_height; + unsigned pat_line_next_old; + unsigned pat_line_next_new; + + pat_line_old = tpg_get_pat_line(tpg, frame_line_old); + pat_line_new = tpg_get_pat_line(tpg, frame_line_new); + linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old; + linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new; + + if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) { + int avg_pat; + + /* + * Now decide whether we need to use downsampled_lines[]. + * That's necessary if the two lines use different patterns. + */ + pat_line_next_old = tpg_get_pat_line(tpg, + (frame_line_next + mv_vert_old) % tpg->src_height); + pat_line_next_new = tpg_get_pat_line(tpg, + (frame_line_next + mv_vert_new) % tpg->src_height); + + switch (tpg->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_INTERLACED_TB: + avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new); + if (avg_pat < 0) + break; + linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old; + linestart_newer = linestart_older; + break; + case V4L2_FIELD_NONE: + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_SEQ_TB: + avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old); + if (avg_pat >= 0) + linestart_older = tpg->downsampled_lines[avg_pat][p] + + mv_hor_old; + avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new); + if (avg_pat >= 0) + linestart_newer = tpg->downsampled_lines[avg_pat][p] + + mv_hor_new; + break; + } + } + linestart_older += line_offset; + linestart_newer += line_offset; + } + if (tpg->field_alternate) { + linestart_top = linestart_bottom = linestart_older; + } else if (params->is_60hz) { + linestart_top = linestart_newer; + linestart_bottom = linestart_older; + } else { + linestart_top = linestart_older; + linestart_bottom = linestart_newer; + } + + switch (tpg->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + if (even) + memcpy(vbuf, linestart_top, img_width); + else + memcpy(vbuf, linestart_bottom, img_width); + break; + case V4L2_FIELD_INTERLACED_BT: + if (even) + memcpy(vbuf, linestart_bottom, img_width); + else + memcpy(vbuf, linestart_top, img_width); + break; + case V4L2_FIELD_TOP: + memcpy(vbuf, linestart_top, img_width); + break; + case V4L2_FIELD_BOTTOM: + memcpy(vbuf, linestart_bottom, img_width); + break; + case V4L2_FIELD_NONE: + default: + memcpy(vbuf, linestart_older, img_width); + break; + } +} + +void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, + unsigned p, u8 *vbuf) { struct tpg_draw_params params; - unsigned mv_hor_old; - unsigned mv_hor_new; - unsigned mv_vert_old; - unsigned mv_vert_new; - int h; - unsigned twopixsize; - unsigned vdiv = tpg->vdownsampling[p]; - unsigned img_width; - unsigned line_offset; - unsigned stride; unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; /* Coarse scaling with Bresenham */ @@ -1713,6 +1847,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height; unsigned src_y = 0; unsigned error = 0; + unsigned h; tpg_recalc(tpg); @@ -1724,37 +1859,15 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 params.hmax = (tpg->compose.height * tpg->perc_fill) / 100; tpg_fill_params_pattern(tpg, p, ¶ms); - - mv_hor_old = params.mv_hor_old; - mv_hor_new = params.mv_hor_new; - mv_vert_old = params.mv_vert_old; - mv_vert_new = params.mv_vert_new; - tpg_fill_params_extras(tpg, p, ¶ms); - twopixsize = params.twopixsize; - img_width = params.img_width; - stride = params.stride; - vbuf += tpg_hdiv(tpg, p, tpg->compose.left); - line_offset = tpg_hscale_div(tpg, p, tpg->crop.left); for (h = 0; h < tpg->compose.height; h++) { - bool even; - bool fill_blank = false; - unsigned frame_line; unsigned buf_line; - unsigned pat_line_old; - unsigned pat_line_new; - u8 *linestart_older; - u8 *linestart_newer; - u8 *linestart_top; - u8 *linestart_bottom; params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); params.frame_line_next = params.frame_line; - frame_line = params.frame_line; - even = !(frame_line & 1); buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); src_y += int_part; error += fract_part; @@ -1763,7 +1876,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 src_y++; } - if (vdiv > 1) { + if (tpg->vdownsampling[p] > 1) { /* * When doing vertical downsampling the field setting * matters: for SEQ_BT/TB we downsample each field @@ -1774,135 +1887,26 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 */ if (tpg->field == V4L2_FIELD_SEQ_BT || tpg->field == V4L2_FIELD_SEQ_TB) { + unsigned next_src_y = src_y; + if ((h & 3) >= 2) continue; - } else if (h & 1) { - continue; - } - - buf_line /= vdiv; - } - - if (h >= params.hmax) { - if (params.hmax == tpg->compose.height) - continue; - if (!tpg->perc_fill_blank) - continue; - fill_blank = true; - } - - if (tpg->vflip) - frame_line = tpg->src_height - frame_line - 1; - - if (fill_blank) { - linestart_older = tpg->contrast_line[p]; - linestart_newer = tpg->contrast_line[p]; - } else if (tpg->qual != TPG_QUAL_NOISE && - (frame_line < tpg->border.top || - frame_line >= tpg->border.top + tpg->border.height)) { - linestart_older = tpg->black_line[p]; - linestart_newer = tpg->black_line[p]; - } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) { - linestart_older = tpg->random_line[p] + - twopixsize * prandom_u32_max(tpg->src_width / 2); - linestart_newer = tpg->random_line[p] + - twopixsize * prandom_u32_max(tpg->src_width / 2); - } else { - unsigned frame_line_old = - (frame_line + mv_vert_old) % tpg->src_height; - unsigned frame_line_new = - (frame_line + mv_vert_new) % tpg->src_height; - unsigned pat_line_next_old; - unsigned pat_line_next_new; - - pat_line_old = tpg_get_pat_line(tpg, frame_line_old); - pat_line_new = tpg_get_pat_line(tpg, frame_line_new); - linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old; - linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new; - - if (vdiv > 1) { - unsigned frame_line_next; - int avg_pat; - - /* - * Now decide whether we need to use downsampled_lines[]. - * That's necessary if the two lines use different patterns. - */ - frame_line_next = tpg_calc_frameline(tpg, src_y, tpg->field); - if (tpg->vflip) - frame_line_next = tpg->src_height - frame_line_next - 1; - pat_line_next_old = tpg_get_pat_line(tpg, - (frame_line_next + mv_vert_old) % tpg->src_height); - pat_line_next_new = tpg_get_pat_line(tpg, - (frame_line_next + mv_vert_new) % tpg->src_height); - - switch (tpg->field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_INTERLACED_BT: - case V4L2_FIELD_INTERLACED_TB: - avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new); - if (avg_pat < 0) - break; - linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old; - linestart_newer = linestart_older; - break; - case V4L2_FIELD_NONE: - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_SEQ_BT: - case V4L2_FIELD_SEQ_TB: - avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old); - if (avg_pat >= 0) - linestart_older = tpg->downsampled_lines[avg_pat][p] + - mv_hor_old; - avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new); - if (avg_pat >= 0) - linestart_newer = tpg->downsampled_lines[avg_pat][p] + - mv_hor_new; - break; - } + next_src_y += int_part; + if (error + fract_part >= tpg->compose.height) + next_src_y++; + params.frame_line_next = + tpg_calc_frameline(tpg, next_src_y, tpg->field); + } else { + if (h & 1) + continue; + params.frame_line_next = + tpg_calc_frameline(tpg, src_y, tpg->field); } - linestart_older += line_offset; - linestart_newer += line_offset; - } - if (tpg->field_alternate) { - linestart_top = linestart_bottom = linestart_older; - } else if (params.is_60hz) { - linestart_top = linestart_newer; - linestart_bottom = linestart_older; - } else { - linestart_top = linestart_older; - linestart_bottom = linestart_newer; - } - switch (tpg->field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_SEQ_TB: - case V4L2_FIELD_SEQ_BT: - if (even) - memcpy(vbuf + buf_line * stride, linestart_top, img_width); - else - memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); - break; - case V4L2_FIELD_INTERLACED_BT: - if (even) - memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); - else - memcpy(vbuf + buf_line * stride, linestart_top, img_width); - break; - case V4L2_FIELD_TOP: - memcpy(vbuf + buf_line * stride, linestart_top, img_width); - break; - case V4L2_FIELD_BOTTOM: - memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); - break; - case V4L2_FIELD_NONE: - default: - memcpy(vbuf + buf_line * stride, linestart_older, img_width); - break; + buf_line /= tpg->vdownsampling[p]; } - + tpg_fill_plane_pattern(tpg, ¶ms, p, h, + vbuf + buf_line * params.stride); tpg_fill_plane_extras(tpg, ¶ms, p, h, vbuf + buf_line * params.stride); } -- cgit v1.2.3 From 96c76efae3211c7b798553602d3165b4ea34aa95 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 7 Mar 2015 15:04:49 -0300 Subject: [media] vivid: add new format fields These fields are necessary to handle the new planar formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.h | 4 +- drivers/media/platform/vivid/vivid-vid-cap.c | 18 ++++-- drivers/media/platform/vivid/vivid-vid-common.c | 84 ++++++++++++++++++------- drivers/media/platform/vivid/vivid-vid-out.c | 8 +-- 4 files changed, 81 insertions(+), 33 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 191d9b506e18..bcefd19f25ca 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -79,12 +79,14 @@ extern unsigned vivid_debug; struct vivid_fmt { const char *name; u32 fourcc; /* v4l2 format id */ - u8 depth; bool is_yuv; bool can_do_overlay; + u8 vdownsampling[TPG_MAX_PLANES]; u32 alpha_mask; u8 planes; + u8 buffers; u32 data_offset[TPG_MAX_PLANES]; + u32 bit_depth[TPG_MAX_PLANES]; }; extern struct vivid_fmt vivid_formats[]; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index d41ac4475317..4d50961f35c2 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -42,20 +42,26 @@ static const struct vivid_fmt formats_ovl[] = { { .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, }, { .name = "XRGB555 (LE)", .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, }, { .name = "ARGB555 (LE)", .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, }, }; @@ -597,9 +603,9 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, /* This driver supports custom bytesperline values */ /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->depth) >> 3; + bytesperline = (mp->width * fmt->bit_depth[0]) >> 3; /* Calculate the maximum supported bytesperline value */ - max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3; + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3; mp->num_planes = fmt->planes; for (p = 0; p < mp->num_planes; p++) { if (pfmt[p].bytesperline > max_bpl) @@ -1224,7 +1230,7 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh, fmt = vivid_get_format(dev, a->fmt.pixelformat); if (!fmt || !fmt->can_do_overlay) return -EINVAL; - if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8) + if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8) return -EINVAL; if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage) return -EINVAL; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 49c9bc68c14f..7a02aef0bdaa 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -46,139 +46,179 @@ struct vivid_fmt vivid_formats[] = { { .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .is_yuv = true, .planes = 1, + .buffers = 1, .data_offset = { PLANE0_DATA_OFFSET, 0 }, }, { .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .is_yuv = true, .planes = 1, + .buffers = 1, }, { .name = "4:2:2, packed, YVYU", .fourcc = V4L2_PIX_FMT_YVYU, - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .is_yuv = true, .planes = 1, + .buffers = 1, }, { .name = "4:2:2, packed, VYUY", .fourcc = V4L2_PIX_FMT_VYUY, - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .is_yuv = true, .planes = 1, + .buffers = 1, }, { .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { .name = "RGB565 (BE)", .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { .name = "RGB555 (LE)", .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { .name = "XRGB555 (LE)", .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { .name = "ARGB555 (LE)", .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, .alpha_mask = 0x8000, }, { .name = "RGB555 (BE)", .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { .name = "RGB24 (LE)", .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ - .depth = 24, + .vdownsampling = { 1 }, + .bit_depth = { 24 }, .planes = 1, + .buffers = 1, }, { .name = "RGB24 (BE)", .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ - .depth = 24, + .vdownsampling = { 1 }, + .bit_depth = { 24 }, .planes = 1, + .buffers = 1, }, { .name = "RGB32 (LE)", .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ - .depth = 32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, }, { .name = "RGB32 (BE)", .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */ - .depth = 32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, }, { .name = "XRGB32 (LE)", .fourcc = V4L2_PIX_FMT_XRGB32, /* argb */ - .depth = 32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, }, { .name = "XRGB32 (BE)", .fourcc = V4L2_PIX_FMT_XBGR32, /* bgra */ - .depth = 32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, }, { .name = "ARGB32 (LE)", .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ - .depth = 32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, .alpha_mask = 0x000000ff, }, { .name = "ARGB32 (BE)", .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ - .depth = 32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, .alpha_mask = 0xff000000, }, { - .name = "4:2:2, planar, YUV", + .name = "4:2:2, biplanar, YUV", .fourcc = V4L2_PIX_FMT_NV16M, - .depth = 8, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, .is_yuv = true, .planes = 2, + .buffers = 2, .data_offset = { PLANE0_DATA_OFFSET, 0 }, }, { - .name = "4:2:2, planar, YVU", + .name = "4:2:2, biplanar, YVU", .fourcc = V4L2_PIX_FMT_NV61M, - .depth = 8, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, .is_yuv = true, .planes = 2, + .buffers = 2, .data_offset = { 0, PLANE0_DATA_OFFSET }, }, }; diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 8f081bbb7f2c..9cf036cfd3fb 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -269,9 +269,9 @@ void vivid_update_format_out(struct vivid_dev *dev) if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) dev->crop_out.height /= 2; dev->fmt_out_rect = dev->crop_out; - dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8; + dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->bit_depth[0]) / 8; if (dev->fmt_out->planes == 2) - dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8; + dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->bit_depth[0]) / 8; } /* Map the field to something that is valid for the current output */ @@ -388,9 +388,9 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, /* This driver supports custom bytesperline values */ /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->depth) >> 3; + bytesperline = (mp->width * fmt->bit_depth[0]) >> 3; /* Calculate the maximum supported bytesperline value */ - max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3; + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3; mp->num_planes = fmt->planes; for (p = 0; p < mp->num_planes; p++) { if (pfmt[p].bytesperline > max_bpl) -- cgit v1.2.3 From ddcaee9dd4c00174db8ddf913c87ddf3773c446e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 12:03:52 -0300 Subject: [media] vivid: add support for single buffer planar formats Make vivid aware of the difference of planes and buffers. Note that this does not yet add support for hor/vert downsampled formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.h | 2 +- drivers/media/platform/vivid/vivid-kthread-cap.c | 54 ++++++++++++------- drivers/media/platform/vivid/vivid-vid-cap.c | 58 ++++++++++---------- drivers/media/platform/vivid/vivid-vid-common.c | 2 +- drivers/media/platform/vivid/vivid-vid-out.c | 68 ++++++++++++++---------- 5 files changed, 105 insertions(+), 79 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index bcefd19f25ca..9e15aee9a52e 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -334,7 +334,7 @@ struct vivid_dev { u32 ycbcr_enc_out; u32 quantization_out; u32 service_set_out; - u32 bytesperline_out[TPG_MAX_PLANES]; + unsigned bytesperline_out[TPG_MAX_PLANES]; unsigned tv_field_out; unsigned tv_audio_output; bool vbi_out_have_wss; diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 9976d4523366..22e17847e67f 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -229,6 +229,20 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev) dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); } +static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf, + unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h) +{ + unsigned i; + void *vbuf; + + if (p == 0 || tpg_g_buffers(tpg) > 1) + return vb2_plane_vaddr(&buf->vb, p); + vbuf = vb2_plane_vaddr(&buf->vb, 0); + for (i = 0; i < p; i++) + vbuf += bpl[i] * h / tpg->vdownsampling[i]; + return vbuf; +} + static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, struct vivid_buffer *vid_cap_buf) { @@ -269,8 +283,10 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field; - voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) + - vid_out_buf->vb.v4l2_planes[p].data_offset; + voutbuf = plane_vaddr(tpg, vid_out_buf, p, + dev->bytesperline_out, dev->fmt_out_rect.height); + if (p < dev->fmt_out->buffers) + voutbuf += vid_out_buf->vb.v4l2_planes[p].data_offset; voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out; vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap; @@ -395,6 +411,7 @@ update_vid_out_y: static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) { + struct tpg_data *tpg = &dev->tpg; unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; unsigned line_height = 16 / factor; bool is_tv = vivid_is_sdtv_cap(dev); @@ -436,28 +453,29 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) } else { buf->vb.v4l2_buf.field = dev->field_cap; } - tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field, + tpg_s_field(tpg, buf->vb.v4l2_buf.field, dev->field_cap == V4L2_FIELD_ALTERNATE); - tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]); + tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.v4l2_buf.index]); vivid_precalc_copy_rects(dev); - for (p = 0; p < tpg_g_planes(&dev->tpg); p++) { - void *vbuf = vb2_plane_vaddr(&buf->vb, p); + for (p = 0; p < tpg_g_planes(tpg); p++) { + void *vbuf = plane_vaddr(tpg, buf, p, + tpg->bytesperline, tpg->buf_height); /* * The first plane of a multiplanar format has a non-zero * data_offset. This helps testing whether the application * correctly supports non-zero data offsets. */ - if (dev->fmt_cap->data_offset[p]) { + if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) { memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff, dev->fmt_cap->data_offset[p]); vbuf += dev->fmt_cap->data_offset[p]; } - tpg_calc_text_basep(&dev->tpg, basep, p, vbuf); + tpg_calc_text_basep(tpg, basep, p, vbuf); if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf)) - tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf); + tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev), p, vbuf); } dev->must_blank[buf->vb.v4l2_buf.index] = false; @@ -476,12 +494,12 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) (dev->field_cap == V4L2_FIELD_ALTERNATE) ? (buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ? " top" : " bottom") : ""); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); } if (dev->osd_mode == 0) { snprintf(str, sizeof(str), " %dx%d, input %d ", dev->src_rect.width, dev->src_rect.height, dev->input); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); gain = v4l2_ctrl_g_ctrl(dev->gain); mutex_lock(dev->ctrl_hdl_user_vid.lock); @@ -491,38 +509,38 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) dev->contrast->cur.val, dev->saturation->cur.val, dev->hue->cur.val); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), " autogain %d, gain %3d, alpha 0x%02x ", dev->autogain->cur.val, gain, dev->alpha->cur.val); mutex_unlock(dev->ctrl_hdl_user_vid.lock); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); mutex_lock(dev->ctrl_hdl_user_aud.lock); snprintf(str, sizeof(str), " volume %3d, mute %d ", dev->volume->cur.val, dev->mute->cur.val); mutex_unlock(dev->ctrl_hdl_user_aud.lock); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); mutex_lock(dev->ctrl_hdl_user_gen.lock); snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", dev->int32->cur.val, *dev->int64->p_cur.p_s64, dev->bitmask->cur.val); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", dev->boolean->cur.val, dev->menu->qmenu[dev->menu->cur.val], dev->string->p_cur.p_char); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), " integer_menu %lld, value %d ", dev->int_menu->qmenu_int[dev->int_menu->cur.val], dev->int_menu->cur.val); mutex_unlock(dev->ctrl_hdl_user_gen.lock); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); if (dev->button_pressed) { dev->button_pressed--; snprintf(str, sizeof(str), " button pressed!"); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); } } diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 4d50961f35c2..1d9ea2d9d61a 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -100,7 +100,7 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f unsigned sizes[], void *alloc_ctxs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned planes = tpg_g_planes(&dev->tpg); + unsigned buffers = tpg_g_buffers(&dev->tpg); unsigned h = dev->fmt_cap_rect.height; unsigned p; @@ -133,39 +133,36 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f mp = &fmt->fmt.pix_mp; /* * Check if the number of planes in the specified format match - * the number of planes in the current format. You can't mix that. + * the number of buffers in the current format. You can't mix that. */ - if (mp->num_planes != planes) + if (mp->num_planes != buffers) return -EINVAL; vfmt = vivid_get_format(dev, mp->pixelformat); - for (p = 0; p < planes; p++) { + for (p = 0; p < buffers; p++) { sizes[p] = mp->plane_fmt[p].sizeimage; - if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h + + if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h + vfmt->data_offset[p]) return -EINVAL; } } else { - for (p = 0; p < planes; p++) - sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h + + for (p = 0; p < buffers; p++) + sizes[p] = tpg_g_line_width(&dev->tpg, p) * h + dev->fmt_cap->data_offset[p]; } if (vq->num_buffers + *nbuffers < 2) *nbuffers = 2 - vq->num_buffers; - *nplanes = planes; + *nplanes = buffers; /* * videobuf2-vmalloc allocator is context-less so no need to set * alloc_ctxs array. */ - if (planes == 2) - dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__, - *nbuffers, sizes[0], sizes[1]); - else - dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__, - *nbuffers, sizes[0]); + dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); + for (p = 0; p < buffers; p++) + dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); return 0; } @@ -174,7 +171,7 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb) { struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); unsigned long size; - unsigned planes = tpg_g_planes(&dev->tpg); + unsigned buffers = tpg_g_buffers(&dev->tpg); unsigned p; dprintk(dev, 1, "%s\n", __func__); @@ -190,8 +187,8 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb) dev->buf_prepare_error = false; return -EINVAL; } - for (p = 0; p < planes; p++) { - size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height + + for (p = 0; p < buffers; p++) { + size = tpg_g_line_width(&dev->tpg, p) * dev->fmt_cap_rect.height + dev->fmt_cap->data_offset[p]; if (vb2_plane_size(vb, p) < size) { @@ -532,11 +529,11 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv, mp->colorspace = vivid_colorspace_cap(dev); mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); mp->quantization = vivid_quantization_cap(dev); - mp->num_planes = dev->fmt_cap->planes; + mp->num_planes = dev->fmt_cap->buffers; for (p = 0; p < mp->num_planes; p++) { mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); mp->plane_fmt[p].sizeimage = - mp->plane_fmt[p].bytesperline * mp->height + + tpg_g_line_width(&dev->tpg, p) * mp->height + dev->fmt_cap->data_offset[p]; } return 0; @@ -602,18 +599,19 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, /* This driver supports custom bytesperline values */ - /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->bit_depth[0]) >> 3; - /* Calculate the maximum supported bytesperline value */ - max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3; - mp->num_planes = fmt->planes; + mp->num_planes = fmt->buffers; for (p = 0; p < mp->num_planes; p++) { + /* Calculate the minimum supported bytesperline value */ + bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; + /* Calculate the maximum supported bytesperline value */ + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; + if (pfmt[p].bytesperline > max_bpl) pfmt[p].bytesperline = max_bpl; if (pfmt[p].bytesperline < bytesperline) pfmt[p].bytesperline = bytesperline; - pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height + - fmt->data_offset[p]; + pfmt[p].sizeimage = tpg_calc_line_width(&dev->tpg, p, pfmt[p].bytesperline) * + mp->height + fmt->data_offset[p]; memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } mp->colorspace = vivid_colorspace_cap(dev); @@ -633,6 +631,7 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct vb2_queue *q = &dev->vb_vid_cap_q; int ret = vivid_try_fmt_vid_cap(file, priv, f); unsigned factor = 1; + unsigned p; unsigned i; if (ret < 0) @@ -735,16 +734,15 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, dev->fmt_cap_rect.width = mp->width; dev->fmt_cap_rect.height = mp->height; tpg_s_buf_height(&dev->tpg, mp->height); - tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline); - if (tpg_g_planes(&dev->tpg) > 1) - tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline); + tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); + for (p = 0; p < tpg_g_buffers(&dev->tpg); p++) + tpg_s_bytesperline(&dev->tpg, p, mp->plane_fmt[p].bytesperline); dev->field_cap = mp->field; if (dev->field_cap == V4L2_FIELD_ALTERNATE) tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true); else tpg_s_field(&dev->tpg, dev->field_cap, false); tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); - tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); if (vivid_is_sdtv_cap(dev)) dev->tv_field_cap = mp->field; tpg_update_mv_step(&dev->tpg); diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 7a02aef0bdaa..0f93fea5d56d 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -234,7 +234,7 @@ const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) { fmt = &vivid_formats[k]; if (fmt->fourcc == pixelformat) - if (fmt->planes == 1 || dev->multiplanar) + if (fmt->buffers == 1 || dev->multiplanar) return fmt; } diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 9cf036cfd3fb..eeafb6c93c64 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -36,9 +36,14 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f unsigned sizes[], void *alloc_ctxs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned planes = dev->fmt_out->planes; + const struct vivid_fmt *vfmt = dev->fmt_out; + unsigned planes = vfmt->buffers; unsigned h = dev->fmt_out_rect.height; unsigned size = dev->bytesperline_out[0] * h; + unsigned p; + + for (p = vfmt->buffers; p < vfmt->planes; p++) + size += dev->bytesperline_out[p] * h; if (dev->field_out == V4L2_FIELD_ALTERNATE) { /* @@ -74,21 +79,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f if (mp->num_planes != planes) return -EINVAL; sizes[0] = mp->plane_fmt[0].sizeimage; - if (planes == 2) { - sizes[1] = mp->plane_fmt[1].sizeimage; - if (sizes[0] < dev->bytesperline_out[0] * h || - sizes[1] < dev->bytesperline_out[1] * h) - return -EINVAL; - } else if (sizes[0] < size) { + if (sizes[0] < size) return -EINVAL; + for (p = 1; p < planes; p++) { + sizes[p] = mp->plane_fmt[p].sizeimage; + if (sizes[p] < dev->bytesperline_out[p] * h) + return -EINVAL; } } else { - if (planes == 2) { - sizes[0] = dev->bytesperline_out[0] * h; - sizes[1] = dev->bytesperline_out[1] * h; - } else { - sizes[0] = size; - } + for (p = 0; p < planes; p++) + sizes[p] = p ? dev->bytesperline_out[p] * h : size; } if (vq->num_buffers + *nbuffers < 2) @@ -101,12 +101,9 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f * alloc_ctxs array. */ - if (planes == 2) - dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__, - *nbuffers, sizes[0], sizes[1]); - else - dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__, - *nbuffers, sizes[0]); + dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); + for (p = 0; p < planes; p++) + dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); return 0; } @@ -222,7 +219,7 @@ const struct vb2_ops vivid_vid_out_qops = { void vivid_update_format_out(struct vivid_dev *dev) { struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; - unsigned size; + unsigned size, p; switch (dev->output_type[dev->output]) { case SVID: @@ -269,9 +266,9 @@ void vivid_update_format_out(struct vivid_dev *dev) if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) dev->crop_out.height /= 2; dev->fmt_out_rect = dev->crop_out; - dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->bit_depth[0]) / 8; - if (dev->fmt_out->planes == 2) - dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->bit_depth[0]) / 8; + for (p = 0; p < dev->fmt_out->planes; p++) + dev->bytesperline_out[p] = + (dev->sink_rect.width * dev->fmt_out->bit_depth[p]) / 8; } /* Map the field to something that is valid for the current output */ @@ -315,21 +312,27 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv, { struct vivid_dev *dev = video_drvdata(file); struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + const struct vivid_fmt *fmt = dev->fmt_out; unsigned p; mp->width = dev->fmt_out_rect.width; mp->height = dev->fmt_out_rect.height; mp->field = dev->field_out; - mp->pixelformat = dev->fmt_out->fourcc; + mp->pixelformat = fmt->fourcc; mp->colorspace = dev->colorspace_out; mp->ycbcr_enc = dev->ycbcr_enc_out; mp->quantization = dev->quantization_out; - mp->num_planes = dev->fmt_out->planes; + mp->num_planes = fmt->buffers; for (p = 0; p < mp->num_planes; p++) { mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; mp->plane_fmt[p].sizeimage = mp->plane_fmt[p].bytesperline * mp->height; } + for (p = fmt->buffers; p < fmt->planes; p++) { + unsigned stride = dev->bytesperline_out[p]; + + mp->plane_fmt[0].sizeimage += stride * mp->height; + } return 0; } @@ -391,7 +394,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, bytesperline = (mp->width * fmt->bit_depth[0]) >> 3; /* Calculate the maximum supported bytesperline value */ max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3; - mp->num_planes = fmt->planes; + mp->num_planes = fmt->buffers; for (p = 0; p < mp->num_planes; p++) { if (pfmt[p].bytesperline > max_bpl) pfmt[p].bytesperline = max_bpl; @@ -400,6 +403,9 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height; memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } + for (p = fmt->buffers; p < fmt->planes; p++) + pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) / + fmt->bit_depth[0]; mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; mp->quantization = V4L2_QUANTIZATION_DEFAULT; if (vivid_is_svid_out(dev)) { @@ -431,6 +437,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, struct vb2_queue *q = &dev->vb_vid_out_q; int ret = vivid_try_fmt_vid_out(file, priv, f); unsigned factor = 1; + unsigned p; if (ret < 0) return ret; @@ -526,9 +533,12 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, dev->fmt_out_rect.width = mp->width; dev->fmt_out_rect.height = mp->height; - dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline; - if (mp->num_planes > 1) - dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline; + for (p = 0; p < mp->num_planes; p++) + dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline; + for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++) + dev->bytesperline_out[p] = + (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) / + dev->fmt_out->bit_depth[0]; dev->field_out = mp->field; if (vivid_is_svid_out(dev)) dev->tv_field_out = mp->field; -- cgit v1.2.3 From 1f9f23f62fb46d6cef93febe57bf41fb21fd01fa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 12:06:27 -0300 Subject: [media] vivid: add downsampling support Add support in vivid for downsampling. Most of the changes are in vivid_copy_buffer which needs to know about the right line widths. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-kthread-cap.c | 68 ++++++++++++++---------- drivers/media/platform/vivid/vivid-vid-out.c | 7 +-- 2 files changed, 43 insertions(+), 32 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 22e17847e67f..1727f5453f0b 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -249,8 +249,9 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index]; struct tpg_data *tpg = &dev->tpg; struct vivid_buffer *vid_out_buf = NULL; - unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2; - unsigned img_width = dev->compose_cap.width; + unsigned vdiv = dev->fmt_out->vdownsampling[p]; + unsigned twopixsize = tpg_g_twopixelsize(tpg, p); + unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width); unsigned img_height = dev->compose_cap.height; unsigned stride_cap = tpg->bytesperline[p]; unsigned stride_out = dev->bytesperline_out[p]; @@ -269,6 +270,7 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, unsigned vid_overlay_fract_part = 0; unsigned vid_overlay_y = 0; unsigned vid_overlay_error = 0; + unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left); unsigned vid_cap_right; bool quick; @@ -287,23 +289,25 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, dev->bytesperline_out, dev->fmt_out_rect.height); if (p < dev->fmt_out->buffers) voutbuf += vid_out_buf->vb.v4l2_planes[p].data_offset; - voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out; - vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap; + voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) + + (dev->loop_vid_out.top / vdiv) * stride_out; + vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) + + (dev->compose_cap.top / vdiv) * stride_cap; if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) { /* * If there is nothing to copy, then just fill the capture window * with black. */ - for (y = 0; y < hmax; y++, vcapbuf += stride_cap) - memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize); + for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap) + memcpy(vcapbuf, tpg->black_line[p], img_width); return 0; } if (dev->overlay_out_enabled && dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) { vosdbuf = dev->video_vbase; - vosdbuf += dev->loop_fb_copy.left * pixsize + + vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 + dev->loop_fb_copy.top * stride_osd; vid_overlay_int_part = dev->loop_vid_overlay.height / dev->loop_vid_overlay_cap.height; @@ -311,12 +315,12 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, dev->loop_vid_overlay_cap.height; } - vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width; + vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width); /* quick is true if no video scaling is needed */ quick = dev->loop_vid_out.width == dev->loop_vid_cap.width; dev->cur_scaled_line = dev->loop_vid_out.height; - for (y = 0; y < hmax; y++, vcapbuf += stride_cap) { + for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) { /* osdline is true if this line requires overlay blending */ bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top && y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height; @@ -327,34 +331,34 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, */ if (y < dev->loop_vid_cap.top || y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) { - memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize); + memcpy(vcapbuf, tpg->black_line[p], img_width); continue; } /* fill the left border with black */ if (dev->loop_vid_cap.left) - memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize); + memcpy(vcapbuf, tpg->black_line[p], vid_cap_left); /* fill the right border with black */ if (vid_cap_right < img_width) - memcpy(vcapbuf + vid_cap_right * pixsize, - tpg->black_line[p], (img_width - vid_cap_right) * pixsize); + memcpy(vcapbuf + vid_cap_right, tpg->black_line[p], + img_width - vid_cap_right); if (quick && !osdline) { - memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, + memcpy(vcapbuf + vid_cap_left, voutbuf + vid_out_y * stride_out, - dev->loop_vid_cap.width * pixsize); + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); goto update_vid_out_y; } if (dev->cur_scaled_line == vid_out_y) { - memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, - dev->scaled_line, - dev->loop_vid_cap.width * pixsize); + memcpy(vcapbuf + vid_cap_left, dev->scaled_line, + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); goto update_vid_out_y; } if (!osdline) { scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line, - dev->loop_vid_out.width, dev->loop_vid_cap.width, + tpg_hdiv(tpg, p, dev->loop_vid_out.width), + tpg_hdiv(tpg, p, dev->loop_vid_cap.width), tpg_g_twopixelsize(tpg, p)); } else { /* @@ -362,7 +366,8 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, * loop_vid_overlay rectangle. */ unsigned offset = - (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize; + ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * + twopixsize) / 2; u8 *osd = vosdbuf + vid_overlay_y * stride_osd; scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line, @@ -372,18 +377,17 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top, dev->loop_vid_overlay.left, dev->blended_line + offset, osd, - dev->loop_vid_overlay.width, pixsize); + dev->loop_vid_overlay.width, twopixsize / 2); else memcpy(dev->blended_line + offset, - osd, dev->loop_vid_overlay.width * pixsize); + osd, (dev->loop_vid_overlay.width * twopixsize) / 2); scale_line(dev->blended_line, dev->scaled_line, dev->loop_vid_copy.width, dev->loop_vid_cap.width, tpg_g_twopixelsize(tpg, p)); } dev->cur_scaled_line = vid_out_y; - memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, - dev->scaled_line, - dev->loop_vid_cap.width * pixsize); + memcpy(vcapbuf + vid_cap_left, dev->scaled_line, + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); update_vid_out_y: if (osdline) { @@ -396,16 +400,16 @@ update_vid_out_y: } vid_out_y += vid_out_int_part; vid_out_error += vid_out_fract_part; - if (vid_out_error >= dev->loop_vid_cap.height) { - vid_out_error -= dev->loop_vid_cap.height; + if (vid_out_error >= dev->loop_vid_cap.height / vdiv) { + vid_out_error -= dev->loop_vid_cap.height / vdiv; vid_out_y++; } } if (!blank) return 0; - for (; y < img_height; y++, vcapbuf += stride_cap) - memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize); + for (; y < img_height; y += vdiv, vcapbuf += stride_cap) + memcpy(vcapbuf, tpg->contrast_line[p], img_width); return 0; } @@ -604,6 +608,12 @@ static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf) bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0; int x, y, w, out_x = 0; + /* + * Overlay support is only supported for formats that have a twopixelsize + * that's >= 2. Warn and bail out if that's not the case. + */ + if (WARN_ON(pixsize == 0)) + return; if ((dev->overlay_cap_field == V4L2_FIELD_TOP || dev->overlay_cap_field == V4L2_FIELD_BOTTOM) && dev->overlay_cap_field != buf->vb.v4l2_buf.field) diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index eeafb6c93c64..6c6deef3521c 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -43,7 +43,7 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f unsigned p; for (p = vfmt->buffers; p < vfmt->planes; p++) - size += dev->bytesperline_out[p] * h; + size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; if (dev->field_out == V4L2_FIELD_ALTERNATE) { /* @@ -331,7 +331,8 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv, for (p = fmt->buffers; p < fmt->planes; p++) { unsigned stride = dev->bytesperline_out[p]; - mp->plane_fmt[0].sizeimage += stride * mp->height; + mp->plane_fmt[0].sizeimage += + (stride * mp->height) / fmt->vdownsampling[p]; } return 0; } @@ -405,7 +406,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, } for (p = fmt->buffers; p < fmt->planes; p++) pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) / - fmt->bit_depth[0]; + (fmt->bit_depth[0] * fmt->vdownsampling[p]); mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; mp->quantization = V4L2_QUANTIZATION_DEFAULT; if (vivid_is_svid_out(dev)) { -- cgit v1.2.3 From b521c375519f7d2a2d703f004f122a0831d8f22e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 10:37:52 -0300 Subject: [media] vivid: add the new planar and monochrome formats Everything is in place to support these formats, so add them to the list. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-common.c | 114 +++++++++++++++++++++++- 1 file changed, 111 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 0f93fea5d56d..7cb4aa0ac036 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -51,7 +51,7 @@ struct vivid_fmt vivid_formats[] = { .is_yuv = true, .planes = 1, .buffers = 1, - .data_offset = { PLANE0_DATA_OFFSET, 0 }, + .data_offset = { PLANE0_DATA_OFFSET }, }, { .name = "4:2:2, packed, UYVY", @@ -80,6 +80,78 @@ struct vivid_fmt vivid_formats[] = { .planes = 1, .buffers = 1, }, + { + .name = "YUV 4:2:2 triplanar", + .fourcc = V4L2_PIX_FMT_YUV422P, + .vdownsampling = { 1, 1, 1 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 1, + }, + { + .name = "YUV 4:2:0 triplanar", + .fourcc = V4L2_PIX_FMT_YUV420, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 1, + }, + { + .name = "YVU 4:2:0 triplanar", + .fourcc = V4L2_PIX_FMT_YVU420, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 1, + }, + { + .name = "YUV 4:2:0 biplanar", + .fourcc = V4L2_PIX_FMT_NV12, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YVU 4:2:0 biplanar", + .fourcc = V4L2_PIX_FMT_NV21, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YUV 4:2:2 biplanar", + .fourcc = V4L2_PIX_FMT_NV16, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YVU 4:2:2 biplanar", + .fourcc = V4L2_PIX_FMT_NV61, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "Monochrome", + .fourcc = V4L2_PIX_FMT_GREY, + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .is_yuv = true, + .planes = 1, + .buffers = 1, + }, { .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ @@ -221,10 +293,46 @@ struct vivid_fmt vivid_formats[] = { .buffers = 2, .data_offset = { 0, PLANE0_DATA_OFFSET }, }, + { + .name = "4:2:0, triplanar, YUV", + .fourcc = V4L2_PIX_FMT_YUV420M, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 3, + }, + { + .name = "4:2:0, triplanar, YVU", + .fourcc = V4L2_PIX_FMT_YVU420M, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 3, + }, + { + .name = "4:2:0, biplanar, YUV", + .fourcc = V4L2_PIX_FMT_NV12M, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 2, + }, + { + .name = "4:2:0, biplanar, YVU", + .fourcc = V4L2_PIX_FMT_NV21M, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 2, + }, }; -/* There are 2 multiplanar formats in the list */ -#define VIVID_MPLANAR_FORMATS 2 +/* There are 6 multiplanar formats in the list */ +#define VIVID_MPLANAR_FORMATS 6 const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) { -- cgit v1.2.3 From 8aca230b6d2769a0441782bcba242d0d007f0cea Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 11 Mar 2015 08:14:34 -0300 Subject: [media] vivid: add RGB444 support Add support for (A/X)RGB444 formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 21 +++++++++++++++++++++ drivers/media/platform/vivid/vivid-vid-common.c | 25 +++++++++++++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 3f0ec9ab7030..fe546e976b7f 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -190,6 +190,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) switch (fourcc) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: + case V4L2_PIX_FMT_ARGB444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: @@ -264,6 +267,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) switch (fourcc) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: + case V4L2_PIX_FMT_ARGB444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: @@ -701,6 +707,13 @@ static void precalculate_color(struct tpg_data *tpg, int k) g >>= 6; b >>= 7; break; + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: + case V4L2_PIX_FMT_ARGB444: + r >>= 8; + g >>= 8; + b >>= 8; + break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: @@ -855,6 +868,14 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset] = (r_y << 3) | (g_u >> 3); buf[0][offset + 1] = (g_u << 5) | b_v; break; + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ARGB444: + buf[0][offset] = (g_u << 4) | b_v; + buf[0][offset + 1] = (alpha & 0xf0) | r_y; + break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: alpha = 0; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 7cb4aa0ac036..cb73c1ba82b9 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -170,6 +170,31 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, .can_do_overlay = true, }, + { + .name = "RGB444", + .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "XRGB444", + .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "ARGB444", + .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, { .name = "RGB555 (LE)", .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ -- cgit v1.2.3 From 9e1b73cfed2e28061810221467aa3bdd5284cc83 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 11 Mar 2015 08:16:03 -0300 Subject: [media] vivid: fix format comments Clarify which formats have an alpha channel and which do not by using 'x' instead of 'a' if there is no alpha channel. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-common.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index cb73c1ba82b9..453a5ad326f6 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -197,7 +197,7 @@ struct vivid_fmt vivid_formats[] = { }, { .name = "RGB555 (LE)", - .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, .planes = 1, @@ -206,7 +206,7 @@ struct vivid_fmt vivid_formats[] = { }, { .name = "XRGB555 (LE)", - .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ + .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */ .vdownsampling = { 1 }, .bit_depth = { 16 }, .planes = 1, @@ -225,7 +225,7 @@ struct vivid_fmt vivid_formats[] = { }, { .name = "RGB555 (BE)", - .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ + .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */ .vdownsampling = { 1 }, .bit_depth = { 16 }, .planes = 1, @@ -250,7 +250,7 @@ struct vivid_fmt vivid_formats[] = { }, { .name = "RGB32 (LE)", - .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ + .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */ .vdownsampling = { 1 }, .bit_depth = { 32 }, .planes = 1, @@ -258,7 +258,7 @@ struct vivid_fmt vivid_formats[] = { }, { .name = "RGB32 (BE)", - .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */ + .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */ .vdownsampling = { 1 }, .bit_depth = { 32 }, .planes = 1, @@ -266,7 +266,7 @@ struct vivid_fmt vivid_formats[] = { }, { .name = "XRGB32 (LE)", - .fourcc = V4L2_PIX_FMT_XRGB32, /* argb */ + .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */ .vdownsampling = { 1 }, .bit_depth = { 32 }, .planes = 1, @@ -274,7 +274,7 @@ struct vivid_fmt vivid_formats[] = { }, { .name = "XRGB32 (BE)", - .fourcc = V4L2_PIX_FMT_XBGR32, /* bgra */ + .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */ .vdownsampling = { 1 }, .bit_depth = { 32 }, .planes = 1, -- cgit v1.2.3 From 8f1ff5435d314d607504964f13593a074e8efac9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 12 Mar 2015 05:08:01 -0300 Subject: [media] vivid: add support for [A|X]RGB555X Only RGB555X was supported, add support for the other two variants. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 10 ++++++++++ drivers/media/platform/vivid/vivid-vid-common.c | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index fe546e976b7f..a906cc5a0331 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -197,6 +197,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_XRGB555X: + case V4L2_PIX_FMT_ARGB555X: case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: case V4L2_PIX_FMT_RGB32: @@ -274,6 +276,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_XRGB555X: + case V4L2_PIX_FMT_ARGB555X: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: @@ -718,6 +722,8 @@ static void precalculate_color(struct tpg_data *tpg, int k) case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_XRGB555X: + case V4L2_PIX_FMT_ARGB555X: r >>= 7; g >>= 7; b >>= 7; @@ -885,6 +891,10 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); break; case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_XRGB555X: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ARGB555X: buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); buf[0][offset + 1] = (g_u << 5) | b_v; break; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 453a5ad326f6..81e6c827357e 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -230,7 +230,23 @@ struct vivid_fmt vivid_formats[] = { .bit_depth = { 16 }, .planes = 1, .buffers = 1, - .can_do_overlay = true, + }, + { + .name = "XRGB555 (BE)", + .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "ARGB555 (BE)", + .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x0080, }, { .name = "RGB24 (LE)", -- cgit v1.2.3 From dde72bd773dfce36fd0fb193d8ac5096f31e041c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Mar 2015 05:51:21 -0300 Subject: [media] vivid: add support for NV24 and NV42 Add support for the YUV 4:4:4 formats NV24 and NV42. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 28 +++++++++++++++++++++++-- drivers/media/platform/vivid/vivid-vid-common.c | 18 ++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index a906cc5a0331..0d31532f7f42 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -123,7 +123,7 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) tpg->max_line_width = max_w; for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) { for (plane = 0; plane < TPG_MAX_PLANES; plane++) { - unsigned pixelsz = plane ? 1 : 4; + unsigned pixelsz = plane ? 2 : 4; tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); if (!tpg->lines[pat][plane]) @@ -136,7 +136,7 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) } } for (plane = 0; plane < TPG_MAX_PLANES; plane++) { - unsigned pixelsz = plane ? 1 : 4; + unsigned pixelsz = plane ? 2 : 4; tpg->contrast_line[plane] = vzalloc(max_w * pixelsz); if (!tpg->contrast_line[plane]) @@ -255,6 +255,13 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->planes = 2; tpg->is_yuv = true; break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + tpg->vdownsampling[1] = 1; + tpg->hdownsampling[1] = 1; + tpg->planes = 2; + tpg->is_yuv = true; + break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: @@ -322,6 +329,11 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->twopixelsize[1] = 2; tpg->twopixelsize[2] = 2; break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + tpg->twopixelsize[0] = 2; + tpg->twopixelsize[1] = 4; + break; } return true; } @@ -826,6 +838,18 @@ static void gen_twopix(struct tpg_data *tpg, buf[1][1] = g_u; break; + case V4L2_PIX_FMT_NV24: + buf[0][offset] = r_y; + buf[1][2 * offset] = g_u; + buf[1][2 * offset + 1] = b_v; + break; + + case V4L2_PIX_FMT_NV42: + buf[0][offset] = r_y; + buf[1][2 * offset] = b_v; + buf[1][2 * offset + 1] = g_u; + break; + case V4L2_PIX_FMT_YUYV: buf[0][offset] = r_y; if (odd) { diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 81e6c827357e..aa8985054405 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -143,6 +143,24 @@ struct vivid_fmt vivid_formats[] = { .planes = 2, .buffers = 1, }, + { + .name = "YUV 4:4:4 biplanar", + .fourcc = V4L2_PIX_FMT_NV24, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 16 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YVU 4:4:4 biplanar", + .fourcc = V4L2_PIX_FMT_NV42, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 16 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, { .name = "Monochrome", .fourcc = V4L2_PIX_FMT_GREY, -- cgit v1.2.3 From 71491063b85c04e6b68803db52cca7a9f14a945e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 12 Mar 2015 15:40:36 -0300 Subject: [media] vivid: add support for PIX_FMT_RGB332 Add support for the one-byte-per-pixel RGB332 format. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 12 ++++++++++++ drivers/media/platform/vivid/vivid-vid-common.c | 8 ++++++++ 2 files changed, 20 insertions(+) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 0d31532f7f42..fd28c6a5f8e9 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -188,6 +188,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->hmask[2] = ~0; switch (fourcc) { + case V4L2_PIX_FMT_RGB332: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_RGB444: @@ -274,6 +275,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) } switch (fourcc) { + case V4L2_PIX_FMT_RGB332: + tpg->twopixelsize[0] = 2; + break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_RGB444: @@ -717,6 +721,11 @@ static void precalculate_color(struct tpg_data *tpg, int k) b = (b * 219) / 255 + (16 << 4); } switch (tpg->fourcc) { + case V4L2_PIX_FMT_RGB332: + r >>= 9; + g >>= 9; + b >>= 10; + break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: r >>= 7; @@ -890,6 +899,9 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][0] = b_v; buf[0][2] = g_u; break; + case V4L2_PIX_FMT_RGB332: + buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v; + break; case V4L2_PIX_FMT_RGB565: buf[0][offset] = (g_u << 5) | b_v; buf[0][offset + 1] = (r_y << 3) | (g_u >> 3); diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index aa8985054405..9e8c06a102e9 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -170,6 +170,14 @@ struct vivid_fmt vivid_formats[] = { .planes = 1, .buffers = 1, }, + { + .name = "RGB332", + .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, { .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ -- cgit v1.2.3 From 68cd4e9f21d9d3b868f78eb3a85165229cb4f024 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Mar 2015 05:36:08 -0300 Subject: [media] vivid: add support for BGR666 Add support for the four byte BGR666 format. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 13 +++++++++++++ drivers/media/platform/vivid/vivid-vid-common.c | 8 ++++++++ 2 files changed, 21 insertions(+) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index fd28c6a5f8e9..0e2b8d4b8864 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -200,6 +200,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: case V4L2_PIX_FMT_ARGB555X: + case V4L2_PIX_FMT_BGR666: case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: case V4L2_PIX_FMT_RGB32: @@ -299,6 +300,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_BGR24: tpg->twopixelsize[0] = 2 * 3; break; + case V4L2_PIX_FMT_BGR666: case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XRGB32: @@ -749,6 +751,11 @@ static void precalculate_color(struct tpg_data *tpg, int k) g >>= 7; b >>= 7; break; + case V4L2_PIX_FMT_BGR666: + r >>= 6; + g >>= 6; + b >>= 6; + break; default: r >>= 4; g >>= 4; @@ -944,6 +951,12 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 1] = g_u; buf[0][offset + 2] = r_y; break; + case V4L2_PIX_FMT_BGR666: + buf[0][offset] = (b_v << 2) | (g_u >> 4); + buf[0][offset + 1] = (g_u << 4) | (r_y >> 2); + buf[0][offset + 2] = r_y << 6; + buf[0][offset + 3] = 0; + break; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_XRGB32: alpha = 0; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 9e8c06a102e9..58b42d267342 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -290,6 +290,14 @@ struct vivid_fmt vivid_formats[] = { .planes = 1, .buffers = 1, }, + { + .name = "BGR666", + .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, { .name = "RGB32 (LE)", .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */ -- cgit v1.2.3 From 628821c84e9047bffab8357668a6b1ef6c0038a5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Mar 2015 06:35:40 -0300 Subject: [media] vivid: add support for packed YUV formats Add support for the packed YUV formats YUV444, YUV555, YUV565 and YUV32. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 40 +++++++++++++++++++++++-- drivers/media/platform/vivid/vivid-vid-common.c | 35 ++++++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 0e2b8d4b8864..7079460deb61 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -212,6 +212,12 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_GREY: tpg->is_yuv = false; break; + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_YUV555: + case V4L2_PIX_FMT_YUV565: + case V4L2_PIX_FMT_YUV32: + tpg->is_yuv = true; + break; case V4L2_PIX_FMT_YUV420M: case V4L2_PIX_FMT_YVU420M: tpg->buffers = 3; @@ -294,6 +300,9 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_YUV555: + case V4L2_PIX_FMT_YUV565: tpg->twopixelsize[0] = 2 * 2; break; case V4L2_PIX_FMT_RGB24: @@ -307,6 +316,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_YUV32: tpg->twopixelsize[0] = 2 * 4; break; case V4L2_PIX_FMT_GREY: @@ -713,9 +723,29 @@ static void precalculate_color(struct tpg_data *tpg, int k) cb = clamp(cb, 16 << 4, 240 << 4); cr = clamp(cr, 16 << 4, 240 << 4); } - tpg->colors[k][0] = clamp(y >> 4, 1, 254); - tpg->colors[k][1] = clamp(cb >> 4, 1, 254); - tpg->colors[k][2] = clamp(cr >> 4, 1, 254); + y = clamp(y >> 4, 1, 254); + cb = clamp(cb >> 4, 1, 254); + cr = clamp(cr >> 4, 1, 254); + switch (tpg->fourcc) { + case V4L2_PIX_FMT_YUV444: + y >>= 4; + cb >>= 4; + cr >>= 4; + break; + case V4L2_PIX_FMT_YUV555: + y >>= 3; + cb >>= 3; + cr >>= 3; + break; + case V4L2_PIX_FMT_YUV565: + y >>= 3; + cb >>= 2; + cr >>= 3; + break; + } + tpg->colors[k][0] = y; + tpg->colors[k][1] = cb; + tpg->colors[k][2] = cr; } else { if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { r = (r * 219) / 255 + (16 << 4); @@ -909,6 +939,7 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_RGB332: buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v; break; + case V4L2_PIX_FMT_YUV565: case V4L2_PIX_FMT_RGB565: buf[0][offset] = (g_u << 5) | b_v; buf[0][offset + 1] = (r_y << 3) | (g_u >> 3); @@ -921,6 +952,7 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_XRGB444: alpha = 0; /* fall through */ + case V4L2_PIX_FMT_YUV444: case V4L2_PIX_FMT_ARGB444: buf[0][offset] = (g_u << 4) | b_v; buf[0][offset + 1] = (alpha & 0xf0) | r_y; @@ -929,6 +961,7 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_XRGB555: alpha = 0; /* fall through */ + case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_ARGB555: buf[0][offset] = (g_u << 5) | b_v; buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); @@ -961,6 +994,7 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_XRGB32: alpha = 0; /* fall through */ + case V4L2_PIX_FMT_YUV32: case V4L2_PIX_FMT_ARGB32: buf[0][offset] = alpha; buf[0][offset + 1] = r_y; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 58b42d267342..8f0910da2bc4 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -161,6 +161,41 @@ struct vivid_fmt vivid_formats[] = { .planes = 2, .buffers = 1, }, + { + .name = "YUV555 (LE)", + .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x8000, + }, + { + .name = "YUV565 (LE)", + .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "YUV444", + .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xf000, + }, + { + .name = "YUV32 (LE)", + .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x000000ff, + }, { .name = "Monochrome", .fourcc = V4L2_PIX_FMT_GREY, -- cgit v1.2.3 From f46d740fb0258982f00ffdbddc6486e674edafb5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Mar 2015 05:40:37 -0300 Subject: [media] vivid: turn this into a platform_device This turns this driver into a platform device. This ensures that it appears in /sys/bus/platform_device since it now has a proper parent device. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 50 +++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index a7e033a5d291..d2558db27751 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -618,7 +619,7 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { Initialization and module stuff ------------------------------------------------------------------*/ -static int __init vivid_create_instance(int inst) +static int vivid_create_instance(struct platform_device *pdev, int inst) { static const struct v4l2_dv_timings def_dv_timings = V4L2_DV_BT_CEA_1280X720P60; @@ -646,7 +647,7 @@ static int __init vivid_create_instance(int inst) /* register v4l2_device */ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s-%03d", VIVID_MODULE_NAME, inst); - ret = v4l2_device_register(NULL, &dev->v4l2_dev); + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) goto free_dev; @@ -1274,7 +1275,7 @@ free_dev: will succeed. This is limited to the maximum number of devices that videodev supports, which is equal to VIDEO_NUM_DEVICES. */ -static int __init vivid_init(void) +static int vivid_probe(struct platform_device *pdev) { const struct font_desc *font = find_font("VGA8x16"); int ret = 0, i; @@ -1289,7 +1290,7 @@ static int __init vivid_init(void) n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS); for (i = 0; i < n_devs; i++) { - ret = vivid_create_instance(i); + ret = vivid_create_instance(pdev, i); if (ret) { /* If some instantiations succeeded, keep driver */ if (i) @@ -1309,7 +1310,7 @@ static int __init vivid_init(void) return ret; } -static void __exit vivid_exit(void) +static int vivid_remove(struct platform_device *pdev) { struct vivid_dev *dev; unsigned i; @@ -1370,6 +1371,45 @@ static void __exit vivid_exit(void) kfree(dev); vivid_devs[i] = NULL; } + return 0; +} + +static void vivid_pdev_release(struct device *dev) +{ +} + +static struct platform_device vivid_pdev = { + .name = "vivid", + .dev.release = vivid_pdev_release, +}; + +static struct platform_driver vivid_pdrv = { + .probe = vivid_probe, + .remove = vivid_remove, + .driver = { + .name = "vivid", + }, +}; + +static int __init vivid_init(void) +{ + int ret; + + ret = platform_device_register(&vivid_pdev); + if (ret) + return ret; + + ret = platform_driver_register(&vivid_pdrv); + if (ret) + platform_device_unregister(&vivid_pdev); + + return ret; +} + +static void __exit vivid_exit(void) +{ + platform_driver_unregister(&vivid_pdrv); + platform_device_unregister(&vivid_pdev); } module_init(vivid_init); -- cgit v1.2.3 From 87c674e24362cf0f8d5b70d2e20f6160045fd753 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Mar 2015 07:41:05 -0300 Subject: [media] vivid: use v4l2_device.release to clean up the driver Use the release callback of the v4l2_device to clean up the memory. This prevents vivid from breaking if someone tries to unbind the driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 43 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index d2558db27751..d33f16495dbc 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -619,6 +619,22 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { Initialization and module stuff ------------------------------------------------------------------*/ +static void vivid_dev_release(struct v4l2_device *v4l2_dev) +{ + struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev); + + vivid_free_controls(dev); + v4l2_device_unregister(&dev->v4l2_dev); + vfree(dev->scaled_line); + vfree(dev->blended_line); + vfree(dev->edid); + vfree(dev->bitmap_cap); + vfree(dev->bitmap_out); + tpg_free(&dev->tpg); + kfree(dev->query_dv_timings_qmenu); + kfree(dev); +} + static int vivid_create_instance(struct platform_device *pdev, int inst) { static const struct v4l2_dv_timings def_dv_timings = @@ -648,8 +664,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s-%03d", VIVID_MODULE_NAME, inst); ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) - goto free_dev; + if (ret) { + kfree(dev); + return ret; + } + dev->v4l2_dev.release = vivid_dev_release; /* start detecting feature set */ @@ -1257,15 +1276,8 @@ unreg_dev: video_unregister_device(&dev->vbi_cap_dev); video_unregister_device(&dev->vid_out_dev); video_unregister_device(&dev->vid_cap_dev); - vivid_free_controls(dev); - v4l2_device_unregister(&dev->v4l2_dev); free_dev: - vfree(dev->scaled_line); - vfree(dev->blended_line); - vfree(dev->edid); - tpg_free(&dev->tpg); - kfree(dev->query_dv_timings_qmenu); - kfree(dev); + v4l2_device_put(&dev->v4l2_dev); return ret; } @@ -1359,16 +1371,7 @@ static int vivid_remove(struct platform_device *pdev) unregister_framebuffer(&dev->fb_info); vivid_fb_release_buffers(dev); } - v4l2_device_unregister(&dev->v4l2_dev); - vivid_free_controls(dev); - vfree(dev->scaled_line); - vfree(dev->blended_line); - vfree(dev->edid); - vfree(dev->bitmap_cap); - vfree(dev->bitmap_out); - tpg_free(&dev->tpg); - kfree(dev->query_dv_timings_qmenu); - kfree(dev); + v4l2_device_put(&dev->v4l2_dev); vivid_devs[i] = NULL; } return 0; -- cgit v1.2.3 From 02aa769d9fa12d51213e7b1db34bb9b200a967a3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 14 Mar 2015 08:01:50 -0300 Subject: [media] vivid: add support for 8-bit Bayer formats Add support for: PIX_FMT_SBGGR8, SGBRG8, SGRBG8 and SRGGB8. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 57 +++++++++++++++++++++++-- drivers/media/platform/vivid/vivid-tpg.h | 17 +++++--- drivers/media/platform/vivid/vivid-vid-common.c | 32 ++++++++++++++ 3 files changed, 97 insertions(+), 9 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 7079460deb61..9656e4dbd5e7 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -181,6 +181,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->planes = 1; tpg->buffers = 1; tpg->recalc_colors = true; + tpg->interleaved = false; tpg->vdownsampling[0] = 1; tpg->hdownsampling[0] = 1; tpg->hmask[0] = ~0; @@ -188,6 +189,15 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->hmask[2] = ~0; switch (fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + tpg->interleaved = true; + tpg->vdownsampling[1] = 1; + tpg->hdownsampling[1] = 1; + tpg->planes = 2; + /* fall through */ case V4L2_PIX_FMT_RGB332: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: @@ -326,13 +336,14 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV12M: case V4L2_PIX_FMT_NV21M: - tpg->twopixelsize[0] = 2; - tpg->twopixelsize[1] = 2; - break; case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: tpg->twopixelsize[0] = 2; tpg->twopixelsize[1] = 2; break; @@ -1011,6 +1022,35 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 2] = r_y; buf[0][offset + 3] = alpha; break; + case V4L2_PIX_FMT_SBGGR8: + buf[0][offset] = odd ? g_u : b_v; + buf[1][offset] = odd ? r_y : g_u; + break; + case V4L2_PIX_FMT_SGBRG8: + buf[0][offset] = odd ? b_v : g_u; + buf[1][offset] = odd ? g_u : r_y; + break; + case V4L2_PIX_FMT_SGRBG8: + buf[0][offset] = odd ? r_y : g_u; + buf[1][offset] = odd ? g_u : b_v; + break; + case V4L2_PIX_FMT_SRGGB8: + buf[0][offset] = odd ? g_u : r_y; + buf[1][offset] = odd ? b_v : g_u; + break; + } +} + +unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line) +{ + switch (tpg->fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return buf_line & 1; + default: + return 0; } } @@ -1614,6 +1654,8 @@ void tpg_calc_text_basep(struct tpg_data *tpg, basep[p][1] += h * stride / 2; else if (tpg->field == V4L2_FIELD_SEQ_BT) basep[p][0] += h * stride / 2; + if (p == 0 && tpg->interleaved) + tpg_calc_text_basep(tpg, basep, 1, vbuf); } static int tpg_pattern_avg(const struct tpg_data *tpg, @@ -1990,6 +2032,13 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, src_y++; } + /* + * For line-interleaved formats determine the 'plane' + * based on the buffer line. + */ + if (tpg_g_interleaved(tpg)) + p = tpg_g_interleaved_plane(tpg, buf_line); + if (tpg->vdownsampling[p] > 1) { /* * When doing vertical downsampling the field setting @@ -2036,7 +2085,7 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) return; } - for (i = 0; i < tpg->planes; i++) { + for (i = 0; i < tpg_g_planes(tpg); i++) { tpg_fill_plane_buffer(tpg, std, i, vbuf + offset); offset += tpg_calc_plane_size(tpg, i); } diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index 82ce9bfa8604..a50cd2e2535b 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -140,6 +140,7 @@ struct tpg_data { unsigned real_rgb_range; unsigned buffers; unsigned planes; + bool interleaved; u8 vdownsampling[TPG_MAX_PLANES]; u8 hdownsampling[TPG_MAX_PLANES]; /* @@ -197,6 +198,7 @@ void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); void tpg_calc_text_basep(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); +unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line); void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf); void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, @@ -346,7 +348,12 @@ static inline unsigned tpg_g_buffers(const struct tpg_data *tpg) static inline unsigned tpg_g_planes(const struct tpg_data *tpg) { - return tpg->planes; + return tpg->interleaved ? 1 : tpg->planes; +} + +static inline bool tpg_g_interleaved(const struct tpg_data *tpg) +{ + return tpg->interleaved; } static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane) @@ -386,7 +393,7 @@ static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsi return; } - for (p = 0; p < tpg->planes; p++) { + for (p = 0; p < tpg_g_planes(tpg); p++) { unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p]; @@ -401,7 +408,7 @@ static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned pla if (tpg->buffers > 1) return tpg_g_bytesperline(tpg, plane); - for (p = 0; p < tpg->planes; p++) { + for (p = 0; p < tpg_g_planes(tpg); p++) { unsigned plane_w = tpg_g_bytesperline(tpg, p); w += plane_w / tpg->vdownsampling[p]; @@ -417,7 +424,7 @@ static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, if (tpg->buffers > 1) return bpl; - for (p = 0; p < tpg->planes; p++) { + for (p = 0; p < tpg_g_planes(tpg); p++) { unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; plane_w /= tpg->hdownsampling[p]; @@ -428,7 +435,7 @@ static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane) { - if (plane >= tpg->planes) + if (plane >= tpg_g_planes(tpg)) return 0; return tpg_g_bytesperline(tpg, plane) * tpg->buf_height / diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 8f0910da2bc4..283b2e861b79 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -383,6 +383,38 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, .alpha_mask = 0xff000000, }, + { + .name = "Bayer BG/GR", + .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "Bayer GB/RG", + .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "Bayer GR/BG", + .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "Bayer RG/GB", + .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, { .name = "4:2:2, biplanar, YUV", .fourcc = V4L2_PIX_FMT_NV16M, -- cgit v1.2.3 From 1bd0835a27a8651c0a2a06415a64fdab161cbeba Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 14 Mar 2015 09:35:23 -0300 Subject: [media] vivid: allow s_dv_timings if it is the same as the current Allow setting the same timings as the current timings (i.e., do nothing in that case). The code was actually there, but the vb2_is_busy() call was done before the timings check instead of afterwards. Found by v4l2-compliance. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-cap.c | 4 ++-- drivers/media/platform/vivid/vivid-vid-out.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 1d9ea2d9d61a..c942bf7ac95a 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1585,13 +1585,13 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, if (!vivid_is_hdmi_cap(dev)) return -ENODATA; - if (vb2_is_busy(&dev->vb_vid_cap_q)) - return -EBUSY; if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, 0, NULL, NULL)) return -EINVAL; if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0)) return 0; + if (vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; dev->dv_timings_cap = *timings; vivid_update_format_cap(dev, false); return 0; diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 6c6deef3521c..19eadddb5776 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -1127,13 +1127,13 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, if (!vivid_is_hdmi_out(dev)) return -ENODATA; - if (vb2_is_busy(&dev->vb_vid_out_q)) - return -EBUSY; if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, 0, NULL, NULL)) return -EINVAL; if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0)) return 0; + if (vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; dev->dv_timings_out = *timings; vivid_update_format_out(dev); return 0; -- cgit v1.2.3 From 29813a6f34042da13d201694964d9dea3d4658ef Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Mar 2015 13:22:07 -0300 Subject: [media] vivid: report only one frameinterval The vivid driver reports a range of frame intervals for non-webcams, when in fact the frame interval is fixed for those inputs as it depends on the DV timings or standard. Just report the single discrete frame interval instead. Caught by v4l2-compliance. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-cap.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index c942bf7ac95a..1cc2c61e271d 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1689,18 +1689,14 @@ int vidioc_enum_frameintervals(struct file *file, void *priv, return -EINVAL; if (!vivid_is_webcam(dev)) { - static const struct v4l2_fract step = { 1, 1 }; - if (fival->index) return -EINVAL; if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM) return -EINVAL; if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM) return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; - fival->stepwise.min = tpf_min; - fival->stepwise.max = tpf_max; - fival->stepwise.step = step; + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = dev->timeperframe_vid_cap; return 0; } -- cgit v1.2.3 From 82bdb26abcae2988c74be29203caf23dabbe4be3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 15 Mar 2015 13:40:04 -0300 Subject: [media] vivid: sanitize selection rectangle Handle values like ~0 as width, height, left or top fields. Just strip off the top 16 bits will ensure that the calculations remain OK. Found with v4l2-compliance. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-common.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 283b2e861b79..53f0c1da940c 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -694,6 +694,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) unsigned w = r->width; unsigned h = r->height; + /* sanitize w and h in case someone passes ~0 as the value */ + w &= 0xffff; + h &= 0xffff; if (!(flags & V4L2_SEL_FLAG_LE)) { w++; h++; @@ -718,8 +721,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) r->top = 0; if (r->left < 0) r->left = 0; - r->left &= ~1; - r->top &= ~1; + /* sanitize left and top in case someone passes ~0 as the value */ + r->left &= 0xfffe; + r->top &= 0xfffe; if (r->left + w > MAX_WIDTH) r->left = MAX_WIDTH - w; if (r->top + h > MAX_HEIGHT) -- cgit v1.2.3 From e202e515b7278e4b418df3ceafae3fdd2bd31128 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Mar 2015 13:23:06 -0300 Subject: [media] vivid-tpg.c: fix wrong Bt.2020 coefficients Mistyping 0.2627 as 0.2726 I can understand, but -0.4598 as -0.4629? No idea how I managed that. Anyway, these coefficients are now correct again. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-tpg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 9656e4dbd5e7..cb766eb154e7 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -480,9 +480,9 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) }, }; static const int bt2020[3][3] = { - { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) }, + { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) }, { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) }, - { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) }, + { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) }, }; bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; unsigned y_offset = full ? 0 : 16; -- cgit v1.2.3 From 29103668e9be0aa28e3c893b398cb69978b920ad Mon Sep 17 00:00:00 2001 From: Prashant Laddha Date: Fri, 20 Mar 2015 03:41:45 -0300 Subject: [media] vivid: add CVT,GTF standards to vivid dv timings caps Currently vivid supports V4L2_DV_BT_STD_DMT and V4L2_DV_BT_STD_CEA861 discrete video standards. Extending the capability set to allow for setting CVT and GTF standards. This change, along with adding the support for calculating CVT, GTF timings in v4l2-ctl would extend the number of resolutions supported by vivid to almost any custom resolution. Also extending the limits on min and max pixel clock to accommodate pixel clock range provided by cvt/gtf for resolutions ranging from 640x360p50 to 4kx2Kp60. Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 53f0c1da940c..aa446271ad34 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -33,8 +33,9 @@ const struct v4l2_dv_timings_cap vivid_dv_timings_cap = { .type = V4L2_DV_BT_656_1120, /* keep this initialization for compatibility with GCC < 4.4.6 */ .reserved = { 0 }, - V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000, - V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT, + V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 14000000, 775000000, + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED) }; -- cgit v1.2.3 From 5190931d1d992fadc6ad9cc53b630783cf8e39c5 Mon Sep 17 00:00:00 2001 From: Prashant Laddha Date: Sat, 21 Mar 2015 09:29:14 -0300 Subject: [media] vivid: add support to set CVT, GTF timings In addition to v4l2_find_dv_timings_cap(), where timings are searched against the list of preset timings, the incoming timing from v4l2-ctl is checked against CVT and GTF standards. If it confirms to be CVT or GTF, it is treated as valid timing and vivid format is updated with new timings. Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-cap.c | 64 +++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 1cc2c61e271d..6492ea170831 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1578,6 +1578,65 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) return 0; } +static void find_aspect_ratio(u32 width, u32 height, + u32 *num, u32 *denom) +{ + if (!(height % 3) && ((height * 4 / 3) == width)) { + *num = 4; + *denom = 3; + } else if (!(height % 9) && ((height * 16 / 9) == width)) { + *num = 16; + *denom = 9; + } else if (!(height % 10) && ((height * 16 / 10) == width)) { + *num = 16; + *denom = 10; + } else if (!(height % 4) && ((height * 5 / 4) == width)) { + *num = 5; + *denom = 4; + } else if (!(height % 9) && ((height * 15 / 9) == width)) { + *num = 15; + *denom = 9; + } else { /* default to 16:9 */ + *num = 16; + *denom = 9; + } +} + +static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) +{ + struct v4l2_bt_timings *bt = &timings->bt; + u32 total_h_pixel; + u32 total_v_lines; + u32 h_freq; + + if (!v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap, + NULL, NULL)) + return false; + + total_h_pixel = V4L2_DV_BT_FRAME_WIDTH(bt); + total_v_lines = V4L2_DV_BT_FRAME_HEIGHT(bt); + + h_freq = (u32)bt->pixelclock / total_h_pixel; + + if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { + if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, + bt->polarities, timings)) + return true; + } + + if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) { + struct v4l2_fract aspect_ratio; + + find_aspect_ratio(bt->width, bt->height, + &aspect_ratio.numerator, + &aspect_ratio.denominator); + if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync, + bt->polarities, aspect_ratio, timings)) + return true; + } + return false; +} + int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { @@ -1586,12 +1645,15 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, if (!vivid_is_hdmi_cap(dev)) return -ENODATA; if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, - 0, NULL, NULL)) + 0, NULL, NULL) && + !valid_cvt_gtf_timings(timings)) return -EINVAL; + if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0)) return 0; if (vb2_is_busy(&dev->vb_vid_cap_q)) return -EBUSY; + dev->dv_timings_cap = *timings; vivid_update_format_cap(dev, false); return 0; -- cgit v1.2.3 From 4a203349593a636bff46c49be3f955e0a0c0b0d2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Mar 2015 14:05:06 -0300 Subject: [media] vivid: use V4L2_DV_FL_IS_CE_VIDEO instead of V4L2_DV_BT_STD_CEA861 Don't rely on V4L2_DV_BT_STD_CEA861 since that include the 640x480p format, which is an IT format, not CE. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-ctrls.c | 2 +- drivers/media/platform/vivid/vivid-vid-cap.c | 4 ++-- drivers/media/platform/vivid/vivid-vid-out.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media/platform/vivid') diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 32a798f2d953..2b9070098b08 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -818,7 +818,7 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D; if (!vivid_is_hdmi_out(dev)) break; - if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) { + if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { if (bt->width == 720 && bt->height <= 576) dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; else diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 6492ea170831..dab5990f45a0 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -444,7 +444,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) */ if (keep_controls || !dev->colorspace) break; - if (bt->standards & V4L2_DV_BT_STD_CEA861) { + if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { if (bt->width == 720 && bt->height <= 576) v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); else @@ -1358,7 +1358,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); break; case HDMI: - if (bt->standards & V4L2_DV_BT_STD_CEA861) { + if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { if (dev->src_rect.width == 720 && dev->src_rect.height <= 576) v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); else diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 19eadddb5776..0af43dc7715c 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -248,7 +248,7 @@ void vivid_update_format_out(struct vivid_dev *dev) dev->field_out = V4L2_FIELD_ALTERNATE; else dev->field_out = V4L2_FIELD_NONE; - if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) { + if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { if (bt->width == 720 && bt->height <= 576) dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; else @@ -411,7 +411,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, mp->quantization = V4L2_QUANTIZATION_DEFAULT; if (vivid_is_svid_out(dev)) { mp->colorspace = V4L2_COLORSPACE_SMPTE170M; - } else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861)) { + } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { mp->colorspace = V4L2_COLORSPACE_SRGB; if (dev->dvi_d_out) mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; -- cgit v1.2.3