Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 280abe47 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 3e14e7a8
Loading
Loading
Loading
Loading
+110 −18
Original line number Diff line number Diff line
@@ -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;