|
@@ -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);
|
|
|
}
|