Skip to content

Commit

Permalink
video-converter: Fix crashes in fast-paths when converting interlaced…
Browse files Browse the repository at this point in the history
… formats with different vertical subsampling

E.g. the following pipelines fail because chroma values after the last
line are read (note: 486 % 4 == 2):

gst-launch-1.0 videotestsrc ! "video/x-raw,interlace-mode=interleaved,width=720,height=486,format=UYVY" ! videoconvert ! "video/x-raw,format=I420" ! fakesink
gst-launch-1.0 videotestsrc ! "video/x-raw,interlace-mode=interleaved,width=720,height=486,format=I420" ! videoconvert ! "video/x-raw,format=UYVY" ! fakesink
gst-launch-1.0 videotestsrc ! "video/x-raw,interlace-mode=interleaved,width=720,height=486,format=I420" ! videoconvert ! "video/x-raw,format=AYUV" ! fakesink
  • Loading branch information
sdroege committed Jan 16, 2017
1 parent a927a72 commit a8e9796
Showing 1 changed file with 87 additions and 27 deletions.
114 changes: 87 additions & 27 deletions gst-libs/gst/video/video-converter.c
Expand Up @@ -2882,8 +2882,18 @@ convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
gint height = convert->in_height;
gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
gint l1, l2;
gint h2;

/* I420 has half as many chroma lines, as such we have to
* always merge two into one. For non-interlaced these are
* the two next to each other, for interlaced one is skipped
* in between. */
if (interlaced)
h2 = GST_ROUND_DOWN_4 (height);
else
h2 = GST_ROUND_DOWN_2 (height);

for (i = 0; i < GST_ROUND_DOWN_2 (height); i += 2) {
for (i = 0; i < h2; i += 2) {
GET_LINE_OFFSETS (interlaced, i, l1, l2);

video_orc_convert_I420_YUY2 (FRAME_GET_LINE (dest, l1),
Expand All @@ -2894,10 +2904,12 @@ convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
FRAME_GET_V_LINE (src, i >> 1), (width + 1) / 2);
}

/* now handle last line */
if (height & 1) {
UNPACK_FRAME (src, convert->tmpline, height - 1, convert->in_x, width);
PACK_FRAME (dest, convert->tmpline, height - 1, width);
/* now handle last lines. For interlaced these are up to 3 */
if (h2 != height) {
for (i = h2; i < height; i++) {
UNPACK_FRAME (src, convert->tmpline, i, convert->in_x, width);
PACK_FRAME (dest, convert->tmpline, i, width);
}
}
}

Expand All @@ -2910,8 +2922,18 @@ convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
gint height = convert->in_height;
gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
gint l1, l2;
gint h2;

/* I420 has half as many chroma lines, as such we have to
* always merge two into one. For non-interlaced these are
* the two next to each other, for interlaced one is skipped
* in between. */
if (interlaced)
h2 = GST_ROUND_DOWN_4 (height);
else
h2 = GST_ROUND_DOWN_2 (height);

for (i = 0; i < GST_ROUND_DOWN_2 (height); i += 2) {
for (i = 0; i < h2; i += 2) {
GET_LINE_OFFSETS (interlaced, i, l1, l2);

video_orc_convert_I420_UYVY (FRAME_GET_LINE (dest, l1),
Expand All @@ -2922,10 +2944,12 @@ convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
FRAME_GET_V_LINE (src, i >> 1), (width + 1) / 2);
}

/* now handle last line */
if (height & 1) {
UNPACK_FRAME (src, convert->tmpline, height - 1, convert->in_x, width);
PACK_FRAME (dest, convert->tmpline, height - 1, width);
/* now handle last lines. For interlaced these are up to 3 */
if (h2 != height) {
for (i = h2; i < height; i++) {
UNPACK_FRAME (src, convert->tmpline, i, convert->in_x, width);
PACK_FRAME (dest, convert->tmpline, i, width);
}
}
}

Expand All @@ -2939,8 +2963,18 @@ convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
guint8 alpha = MIN (convert->alpha_value, 255);
gint l1, l2;
gint h2;

/* I420 has half as many chroma lines, as such we have to
* always merge two into one. For non-interlaced these are
* the two next to each other, for interlaced one is skipped
* in between. */
if (interlaced)
h2 = GST_ROUND_DOWN_4 (height);
else
h2 = GST_ROUND_DOWN_2 (height);

for (i = 0; i < GST_ROUND_DOWN_2 (height); i += 2) {
for (i = 0; i < h2; i += 2) {
GET_LINE_OFFSETS (interlaced, i, l1, l2);

video_orc_convert_I420_AYUV (FRAME_GET_LINE (dest, l1),
Expand All @@ -2951,12 +2985,14 @@ convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
alpha, width);
}

/* now handle last line */
if (height & 1) {
UNPACK_FRAME (src, convert->tmpline, height - 1, convert->in_x, width);
if (alpha != 0xff)
convert_set_alpha_u8 (convert, convert->tmpline, width);
PACK_FRAME (dest, convert->tmpline, height - 1, width);
/* now handle last lines. For interlaced these are up to 3 */
if (h2 != height) {
for (i = h2; i < height; i++) {
UNPACK_FRAME (src, convert->tmpline, i, convert->in_x, width);
if (alpha != 0xff)
convert_set_alpha_u8 (convert, convert->tmpline, width);
PACK_FRAME (dest, convert->tmpline, i, width);
}
}
}

Expand All @@ -2969,8 +3005,18 @@ convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
gint height = convert->in_height;
gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
gint l1, l2;
gint h2;

/* I420 has half as many chroma lines, as such we have to
* always merge two into one. For non-interlaced these are
* the two next to each other, for interlaced one is skipped
* in between. */
if (interlaced)
h2 = GST_ROUND_DOWN_4 (height);
else
h2 = GST_ROUND_DOWN_2 (height);

for (i = 0; i < GST_ROUND_DOWN_2 (height); i += 2) {
for (i = 0; i < h2; i += 2) {
GET_LINE_OFFSETS (interlaced, i, l1, l2);

video_orc_convert_YUY2_I420 (FRAME_GET_Y_LINE (dest, l1),
Expand All @@ -2980,10 +3026,12 @@ convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
FRAME_GET_LINE (src, l1), FRAME_GET_LINE (src, l2), (width + 1) / 2);
}

/* now handle last line */
if (height & 1) {
UNPACK_FRAME (src, convert->tmpline, height - 1, convert->in_x, width);
PACK_FRAME (dest, convert->tmpline, height - 1, width);
/* now handle last lines. For interlaced these are up to 3 */
if (h2 != height) {
for (i = h2; i < height; i++) {
UNPACK_FRAME (src, convert->tmpline, i, convert->in_x, width);
PACK_FRAME (dest, convert->tmpline, i, width);
}
}
}

Expand Down Expand Up @@ -3069,8 +3117,18 @@ convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
gint height = convert->in_height;
gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
gint l1, l2;
gint h2;

/* I420 has half as many chroma lines, as such we have to
* always merge two into one. For non-interlaced these are
* the two next to each other, for interlaced one is skipped
* in between. */
if (interlaced)
h2 = GST_ROUND_DOWN_4 (height);
else
h2 = GST_ROUND_DOWN_2 (height);

for (i = 0; i < GST_ROUND_DOWN_2 (height); i += 2) {
for (i = 0; i < h2; i += 2) {
GET_LINE_OFFSETS (interlaced, i, l1, l2);

video_orc_convert_UYVY_I420 (FRAME_GET_COMP_LINE (dest, 0, l1),
Expand All @@ -3080,10 +3138,12 @@ convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
FRAME_GET_LINE (src, l1), FRAME_GET_LINE (src, l2), (width + 1) / 2);
}

/* now handle last line */
if (height & 1) {
UNPACK_FRAME (src, convert->tmpline, height - 1, convert->in_x, width);
PACK_FRAME (dest, convert->tmpline, height - 1, width);
/* now handle last lines. For interlaced these are up to 3 */
if (h2 != height) {
for (i = h2; i < height; i++) {
UNPACK_FRAME (src, convert->tmpline, i, convert->in_x, width);
PACK_FRAME (dest, convert->tmpline, i, width);
}
}
}

Expand Down

0 comments on commit a8e9796

Please sign in to comment.