diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2015-03-07 14:50:41 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-02 20:41:49 -0300 |
commit | 280abe474ec3c4e14b9bf3bdbe19c12b08530408 (patch) | |
tree | bf8c2db1907f8d23b5cabe558229fbf35c21f1db /drivers/media | |
parent | 3e14e7a82c1efdd15253a67cf5dccb84b1e9b7f1 (diff) |
[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 <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/platform/vivid/vivid-tpg.c | 128 |
1 files changed, 110 insertions, 18 deletions
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; |