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

[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
...@@ -1400,15 +1400,29 @@ void tpg_calc_text_basep(struct tpg_data *tpg, ...@@ -1400,15 +1400,29 @@ void tpg_calc_text_basep(struct tpg_data *tpg,
u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf) u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
{ {
unsigned stride = tpg->bytesperline[p]; unsigned stride = tpg->bytesperline[p];
unsigned h = tpg->buf_height;
tpg_recalc(tpg); tpg_recalc(tpg);
basep[p][0] = vbuf; basep[p][0] = vbuf;
basep[p][1] = vbuf; basep[p][1] = vbuf;
h /= tpg->vdownsampling[p];
if (tpg->field == V4L2_FIELD_SEQ_TB) 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) 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) 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 ...@@ -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 hmax = (tpg->compose.height * tpg->perc_fill) / 100;
int h; int h;
unsigned twopixsize = tpg->twopixelsize[p]; 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 line_offset;
unsigned left_pillar_width = 0; unsigned left_pillar_width = 0;
unsigned right_pillar_start = img_width; 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 ...@@ -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; vbuf += tpg->compose.left * twopixsize / 2;
line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width; 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) { if (tpg->crop.left < tpg->border.left) {
left_pillar_width = tpg->border.left - tpg->crop.left; left_pillar_width = tpg->border.left - tpg->crop.left;
if (left_pillar_width > tpg->crop.width) if (left_pillar_width > tpg->crop.width)
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 * 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) { 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->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 * 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) if (right_pillar_start > img_width)
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 ...@@ -1490,6 +1506,26 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
src_y++; 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 (h >= hmax) {
if (hmax == tpg->compose.height) if (hmax == tpg->compose.height)
continue; continue;
...@@ -1515,14 +1551,63 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 ...@@ -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] + linestart_newer = tpg->random_line[p] +
twopixsize * prandom_u32_max(tpg->src_width / 2); twopixsize * prandom_u32_max(tpg->src_width / 2);
} else { } else {
pat_line_old = tpg_get_pat_line(tpg, unsigned frame_line_old =
(frame_line + mv_vert_old) % tpg->src_height); (frame_line + mv_vert_old) % tpg->src_height;
pat_line_new = tpg_get_pat_line(tpg, unsigned frame_line_new =
(frame_line + mv_vert_new) % tpg->src_height); (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] + 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] + 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_older += line_offset;
linestart_newer += 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 ...@@ -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] + u8 *wss = tpg->random_line[p] +
twopixsize * prandom_u32_max(tpg->src_width / 2); 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 = orig_vbuf;
vbuf += tpg->compose.left * twopixsize / 2; vbuf += (tpg->compose.left / hdiv) * twopixsize / 2;
src_y = 0; src_y = 0;
error = 0; error = 0;
for (h = 0; h < tpg->compose.height; h++) { 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 ...@@ -1594,6 +1680,12 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
src_y++; src_y++;
} }
if (vdiv > 1) {
if (h & 1)
continue;
buf_line /= vdiv;
}
if (tpg->show_border && frame_line >= b->top && if (tpg->show_border && frame_line >= b->top &&
frame_line < b->top + b->height) { frame_line < b->top + b->height) {
unsigned bottom = b->top + b->height - 1; 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 ...@@ -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; width -= left + width - c->left - c->width;
left -= c->left; left -= c->left;
left = (left * tpg->scaled_width) / tpg->src_width; 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 * 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); memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
} }
if (tpg->insert_sav) { 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; u8 *p = vbuf + buf_line * stride + offset;
unsigned vact = 0, hact = 0; 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 ...@@ -1656,7 +1748,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8
(hact ^ vact ^ f); (hact ^ vact ^ f);
} }
if (tpg->insert_eav) { 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; u8 *p = vbuf + buf_line * stride + offset;
unsigned vact = 0, hact = 1; unsigned vact = 0, hact = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment