/* * We always combine two pixels to prevent color bleed in the packed * yuv case.
*/
srcw /= 2;
dstw /= 2;
int_part = srcw / dstw;
fract_part = srcw % dstw; for (x = 0; x < dstw; x++, dst += twopixsize) {
memcpy(dst, src + src_x * twopixsize, twopixsize);
src_x += int_part;
error += fract_part; if (error >= dstw) {
error -= dstw;
src_x++;
}
}
}
/* * Precalculate the rectangles needed to perform video looping: * * The nominal pipeline is that the video output buffer is cropped by * crop_out, scaled to compose_out, overlaid with the output overlay, * cropped on the capture side by crop_cap and scaled again to the video * capture buffer using compose_cap. * * To keep things efficient we calculate the intersection of compose_out * and crop_cap (since that's the only part of the video that will * actually end up in the capture buffer), determine which part of the * video output buffer that is and which part of the video capture buffer * so we can scale the video straight from the output buffer to the capture * buffer without any intermediate steps. * * If we need to deal with an output overlay, then there is no choice and * that intermediate step still has to be taken. For the output overlay * support we calculate the intersection of the framebuffer and the overlay * window (which may be partially or wholly outside of the framebuffer * itself) and the intersection of that with loop_vid_copy (i.e. the part of * the actual looped video that will be overlaid). The result is calculated * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates * (loop_vid_overlay). Finally calculate the part of the capture buffer that * will receive that overlaid video.
*/ staticvoid vivid_precalc_copy_rects(struct vivid_dev *dev, struct vivid_dev *out_dev)
{ /* Framebuffer rectangle */ struct v4l2_rect r_fb = {
0, 0, dev->display_width, dev->display_height
}; /* Overlay window rectangle in framebuffer coordinates */ struct v4l2_rect r_overlay = {
out_dev->overlay_out_left, out_dev->overlay_out_top,
out_dev->compose_out.width, out_dev->compose_out.height
};
/* shift r_overlay to the same origin as compose_out */
r_overlay.left += out_dev->compose_out.left - out_dev->overlay_out_left;
r_overlay.top += out_dev->compose_out.top - out_dev->overlay_out_top;
/* shift dev->loop_fb_copy back again to the fb origin */
dev->loop_fb_copy.left -= out_dev->compose_out.left - out_dev->overlay_out_left;
dev->loop_fb_copy.top -= out_dev->compose_out.top - out_dev->overlay_out_top;
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 / vdiv; y++, vcapbuf += stride_cap)
memcpy(vcapbuf, tpg->black_line[p], img_width); return 0;
}
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 += 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;
/* * If this line of the capture buffer doesn't get any video, then * just fill with black.
*/ 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); continue;
}
/* fill the left border with black */ if (dev->loop_vid_cap.left)
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, tpg->black_line[p],
img_width - vid_cap_right);
if (quick && !osdline) {
memcpy(vcapbuf + vid_cap_left,
voutbuf + vid_out_y * stride_out,
tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); goto update_vid_out_y;
} if (dev->cur_scaled_line == vid_out_y) {
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,
tpg_hdiv(tpg, p, dev->loop_vid_out.width),
tpg_hdiv(tpg, p, dev->loop_vid_cap.width),
tpg_g_twopixelsize(tpg, p));
} else { /* * Offset in bytes within loop_vid_copy to the start of the * loop_vid_overlay rectangle.
*/ unsigned offset =
((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) *
twopixsize) / 2;
u8 *osd = vosdbuf + vid_overlay_y * stride_osd;
buf->vb.sequence = dev->vid_cap_seq_count;
v4l2_ctrl_s_ctrl(dev->ro_int32, buf->vb.sequence & 0xff); if (dev->field_cap == V4L2_FIELD_ALTERNATE) { /* * 60 Hz standards start with the bottom field, 50 Hz standards * with the top field. So if the 0-based seq_count is even, * then the field is TOP for 50 Hz and BOTTOM for 60 Hz * standards.
*/
buf->vb.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ?
V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; /* * The sequence counter counts frames, not fields. So divide * by two.
*/
buf->vb.sequence /= 2;
} else {
buf->vb.field = dev->field_cap;
}
tpg_s_field(tpg, buf->vb.field,
dev->field_cap == V4L2_FIELD_ALTERNATE);
tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.vb2_buf.index]);
if (vivid_vid_can_loop(dev) &&
((vivid_is_svid_cap(dev) &&
!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) ||
(vivid_is_hdmi_cap(dev) &&
!VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])))) {
out_dev = vivid_input_is_connected_to(dev); /* * If the vivid instance of the output device is different * from the vivid instance of this input device, then we * must take care to properly serialize the output device to * prevent that the buffer we are copying from is being freed. * * If the output device is part of the same instance, then the * lock is already taken and there is no need to take the mutex. * * The problem with taking the mutex is that you can get * deadlocked if instance A locks instance B and vice versa. * It is not really worth trying to be very smart about this, * so just try to take the lock, and if you can't, then just * set out_dev to NULL and you will end up with a single frame * of Noise (the default test pattern in this case).
*/ if (out_dev && dev != out_dev && !mutex_trylock(&out_dev->mutex))
out_dev = NULL;
}
if (out_dev)
vivid_precalc_copy_rects(dev, out_dev);
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 (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(tpg, basep, p, vbuf); if (!out_dev || vivid_copy_buffer(dev, out_dev, p, vbuf, buf))
tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev),
p, vbuf);
} if (out_dev && dev != out_dev)
mutex_unlock(&out_dev->mutex);
dev->must_blank[buf->vb.vb2_buf.index] = false;
/* Updates stream time, only update at the start of a new frame. */ if (dev->field_cap != V4L2_FIELD_ALTERNATE ||
(dev->vid_cap_seq_count & 1) == 0)
dev->ms_vid_cap =
jiffies_to_msecs(jiffies - dev->jiffies_vid_cap);
if (dev->field_cap == V4L2_FIELD_ALTERNATE)
denominator *= 2;
/* Calculate the number of jiffies since we started streaming */
jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap; /* Get the number of buffers streamed since the start */
buffers_since_start = (u64)jiffies_since_start * denominator +
(HZ * numerator) / 2;
do_div(buffers_since_start, HZ * numerator);
/* * After more than 0xf0000000 (rounded down to a multiple of * 'jiffies-per-day' to ease jiffies_to_msecs calculation) * jiffies have passed since we started streaming reset the * counters and keep track of the sequence offset.
*/ if (jiffies_since_start > JIFFIES_RESYNC) {
dev->jiffies_vid_cap = cur_jiffies;
dev->cap_seq_offset = buffers_since_start;
buffers_since_start = 0;
}
dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count;
dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset;
dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start;
dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start;
dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start;
vivid_thread_vid_cap_tick(dev, dropped_bufs);
/* * Calculate the number of 'numerators' streamed since we started, * including the current buffer.
*/
numerators_since_start = ++buffers_since_start * numerator;
/* And the number of jiffies since we started */
jiffies_since_start = jiffies - dev->jiffies_vid_cap;
mutex_unlock(&dev->mutex);
/* * Calculate when that next buffer is supposed to start * in jiffies since we started streaming.
*/
next_jiffies_since_start = numerators_since_start * HZ +
denominator / 2;
do_div(next_jiffies_since_start, denominator); /* If it is in the past, then just schedule asap */ if (next_jiffies_since_start < jiffies_since_start)
next_jiffies_since_start = jiffies_since_start;
wait_jiffies = next_jiffies_since_start - jiffies_since_start; if (!time_is_after_jiffies(cur_jiffies + wait_jiffies)) continue;
*pstreaming = false; if (pstreaming == &dev->vid_cap_streaming) { /* Release all active buffers */ while (!list_empty(&dev->vid_cap_active)) { struct vivid_buffer *buf;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.