jpegdec: decode the correct number of lines for interlaced frames
authorMichael Olbrich <m.olbrich@pengutronix.de>
Mon, 31 Aug 2020 14:12:33 +0000 (16:12 +0200)
committerTim-Philipp Müller <tim@centricular.com>
Fri, 26 May 2023 00:04:02 +0000 (01:04 +0100)
For interlaced jpeg, gst_jpeg_dec_decode_direct() is called twice, once for each
field. In this case, stride[n] is plane_stride[n] * 2 to ensure that only every
other line is written. So the loop must stop at height / num_fields.

If the frame is really interlaced then continuing beyound this, is not harmful,
because jpeg_read_raw_data() will do nothing and return 0, so am info message is
printed.

However, if the frame is not actually interlaced, just misdetected as interlaced
then there is still data available from the second half of the frame. Now
line[0][j] is set to the scratch buffer. If the scratch buffer is not allocated
(because the height is a multiple of v_samp[0] * DCTSIZE) then the result is a
segfault due to a null-pointer dereference.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4717>

subprojects/gst-plugins-good/ext/jpeg/gstjpegdec.c

index dd1a039..c91844a 100644 (file)
@@ -880,7 +880,7 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame,
   gint lines, v_samp[3];
   guchar *base[3], *last[3];
   gint stride[3];
-  guint height, field_height;
+  guint field_height;
 
   line[0] = y;
   line[1] = u;
@@ -893,7 +893,7 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame,
   if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2))
     goto format_not_supported;
 
-  height = field_height = GST_VIDEO_FRAME_HEIGHT (frame);
+  field_height = GST_VIDEO_FRAME_HEIGHT (frame);
 
   /* XXX: division by 2 here might not be a good idea yes. But we are doing this
    * already in gst_jpeg_dec_handle_frame() for interlaced jpeg */
@@ -943,7 +943,7 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame,
   } else
 #endif
   {
-    for (i = 0; i < height; i += v_samp[0] * DCTSIZE) {
+    for (i = 0; i < field_height; i += v_samp[0] * DCTSIZE) {
       for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) {
         /* Y */
         line[0][j] = base[0] + (i + j) * stride[0];