mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
simplevideomark: fix display of videomark partially or fully outside video
In case of the videomark being partially or fully outside, an error was being thrown saying the mark width is more than video width. And when the width, offset properties are set to maximum it resulted in crash. Instead of throwing an error, add logic to detect the mark in case of partial visibility or don't show the mark when it is outside. https://bugzilla.gnome.org/show_bug.cgi?id=743908
This commit is contained in:
parent
633b4db556
commit
0905746c0c
1 changed files with 70 additions and 18 deletions
|
@ -331,14 +331,26 @@ gst_video_mark_draw_box (GstSimpleVideoMark * simplevideomark, guint8 * data,
|
|||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
calculate_pw (gint pw, gint x, gint width)
|
||||
{
|
||||
if (x < 0)
|
||||
pw += x;
|
||||
else if ((x + pw) > width)
|
||||
pw = width - x;
|
||||
|
||||
return pw;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_video_mark_yuv (GstSimpleVideoMark * simplevideomark, GstVideoFrame * frame)
|
||||
{
|
||||
gint i, pw, ph, row_stride, pixel_stride;
|
||||
gint width, height, req_width, req_height;
|
||||
gint width, height, offset_calc, x, y;
|
||||
guint8 *d;
|
||||
guint64 pattern_shift;
|
||||
guint8 color;
|
||||
gint total_pattern;
|
||||
|
||||
width = frame->info.width;
|
||||
height = frame->info.height;
|
||||
|
@ -348,36 +360,63 @@ gst_video_mark_yuv (GstSimpleVideoMark * simplevideomark, GstVideoFrame * frame)
|
|||
row_stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
|
||||
pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
|
||||
|
||||
req_width =
|
||||
(simplevideomark->pattern_count +
|
||||
simplevideomark->pattern_data_count) * pw + simplevideomark->left_offset;
|
||||
req_height = simplevideomark->bottom_offset + ph;
|
||||
if (req_width > width || req_height > height) {
|
||||
GST_ELEMENT_ERROR (simplevideomark, STREAM, WRONG_TYPE, (NULL),
|
||||
("simplevideomark pattern doesn't fit video, need at least %ix%i (stream has %ix%i)",
|
||||
req_width, req_height, width, height));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
d = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
|
||||
/* move to start of bottom left */
|
||||
d += row_stride * (height - ph - simplevideomark->bottom_offset) +
|
||||
offset_calc =
|
||||
row_stride * (height - ph - simplevideomark->bottom_offset) +
|
||||
pixel_stride * simplevideomark->left_offset;
|
||||
x = simplevideomark->left_offset;
|
||||
y = height - ph - simplevideomark->bottom_offset;
|
||||
|
||||
total_pattern =
|
||||
simplevideomark->pattern_count + simplevideomark->pattern_data_count;
|
||||
/* If x and y offset values are outside the video, no need to draw */
|
||||
if ((x + (pw * total_pattern)) < 0 || x > width || (y + height) < 0
|
||||
|| y > height)
|
||||
return GST_FLOW_OK;
|
||||
|
||||
/* Offset calculation less than 0, then reset to 0 */
|
||||
if (offset_calc < 0)
|
||||
offset_calc = 0;
|
||||
/* Y position of mark is negative or pattern exceeds the video height,
|
||||
then recalculate pattern height for partial display */
|
||||
if (y < 0)
|
||||
ph += y;
|
||||
else if ((y + ph) > height)
|
||||
ph = height - y;
|
||||
/* If pattern height is less than 0, need not draw anything */
|
||||
if (ph < 0)
|
||||
return GST_FLOW_OK;
|
||||
|
||||
/* move to start of bottom left */
|
||||
d += offset_calc;
|
||||
|
||||
/* draw the bottom left pixels */
|
||||
for (i = 0; i < simplevideomark->pattern_count; i++) {
|
||||
gint draw_pw;
|
||||
|
||||
if (i & 1)
|
||||
/* odd pixels must be white */
|
||||
color = 255;
|
||||
else
|
||||
color = 0;
|
||||
|
||||
/* X position of mark is negative or pattern exceeds the video width,
|
||||
then recalculate pattern width for partial display */
|
||||
draw_pw = calculate_pw (pw, x, width);
|
||||
/* If pattern width is less than 0, continue with the next pattern */
|
||||
if (draw_pw < 0)
|
||||
continue;
|
||||
|
||||
/* draw box of width * height */
|
||||
gst_video_mark_draw_box (simplevideomark, d, pw, ph, row_stride,
|
||||
gst_video_mark_draw_box (simplevideomark, d, draw_pw, ph, row_stride,
|
||||
pixel_stride, color);
|
||||
|
||||
/* move to i-th pattern */
|
||||
d += pixel_stride * pw;
|
||||
d += pixel_stride * draw_pw;
|
||||
x += draw_pw;
|
||||
|
||||
if ((x + (pw * (total_pattern - i - 1))) < 0 || x >= width)
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
pattern_shift =
|
||||
|
@ -385,18 +424,31 @@ gst_video_mark_yuv (GstSimpleVideoMark * simplevideomark, GstVideoFrame * frame)
|
|||
|
||||
/* get the data of the pattern */
|
||||
for (i = 0; i < simplevideomark->pattern_data_count; i++) {
|
||||
gint draw_pw;
|
||||
if (simplevideomark->pattern_data & pattern_shift)
|
||||
color = 255;
|
||||
else
|
||||
color = 0;
|
||||
|
||||
gst_video_mark_draw_box (simplevideomark, d, pw, ph, row_stride,
|
||||
/* X position of mark is negative or pattern exceeds the video width,
|
||||
then recalculate pattern width for partial display */
|
||||
draw_pw = calculate_pw (pw, x, width);
|
||||
/* If pattern width is less than 0, continue with the next pattern */
|
||||
if (draw_pw < 0)
|
||||
continue;
|
||||
|
||||
gst_video_mark_draw_box (simplevideomark, d, draw_pw, ph, row_stride,
|
||||
pixel_stride, color);
|
||||
|
||||
pattern_shift >>= 1;
|
||||
|
||||
/* move to i-th pattern data */
|
||||
d += pixel_stride * pw;
|
||||
d += pixel_stride * draw_pw;
|
||||
x += draw_pw;
|
||||
|
||||
if ((x + (pw * (simplevideomark->pattern_data_count - i - 1))) < 0
|
||||
|| x >= width)
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
|
|
Loading…
Reference in a new issue