diff --git a/gst/videoscale/gstvideoscale.c b/gst/videoscale/gstvideoscale.c index 252d8ae1d0..10136a737d 100644 --- a/gst/videoscale/gstvideoscale.c +++ b/gst/videoscale/gstvideoscale.c @@ -494,7 +494,8 @@ unknown_format: } static gboolean -parse_caps (GstCaps * caps, gint * format, gint * width, gint * height) +parse_caps (GstCaps * caps, gint * format, gint * width, gint * height, + gboolean * interlaced) { gboolean ret; GstStructure *structure; @@ -506,6 +507,11 @@ parse_caps (GstCaps * caps, gint * format, gint * width, gint * height) if (format) *format = gst_video_scale_get_format (caps); + if (interlaced) { + *interlaced = FALSE; + gst_structure_get_boolean (structure, "interlaced", interlaced); + } + return ret; } @@ -518,8 +524,10 @@ gst_video_scale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) videoscale = GST_VIDEO_SCALE (trans); ret = parse_caps (in, &videoscale->format, &videoscale->from_width, - &videoscale->from_height); - ret &= parse_caps (out, NULL, &videoscale->to_width, &videoscale->to_height); + &videoscale->from_height, &videoscale->interlaced); + ret &= + parse_caps (out, NULL, &videoscale->to_width, &videoscale->to_height, + NULL); if (!ret) goto done; @@ -561,7 +569,7 @@ gst_video_scale_get_unit_size (GstBaseTransform * trans, GstCaps * caps, videoscale = GST_VIDEO_SCALE (trans); - if (!parse_caps (caps, &format, &width, &height)) + if (!parse_caps (caps, &format, &width, &height, NULL)) return FALSE; if (!gst_video_scale_prepare_size (videoscale, format, &img, width, height, @@ -696,7 +704,8 @@ gst_video_scale_fixate_caps (GstBaseTransform * base, GstPadDirection direction, static gboolean gst_video_scale_prepare_image (gint format, GstBuffer * buf, - VSImage * img, VSImage * img_u, VSImage * img_v) + VSImage * img, VSImage * img_u, VSImage * img_v, gint step, + gboolean interlaced) { gboolean res = TRUE; @@ -707,10 +716,19 @@ gst_video_scale_prepare_image (gint format, GstBuffer * buf, case GST_VIDEO_SCALE_YV12: img_u->pixels = img->pixels + GST_ROUND_UP_2 (img->height) * img->stride; img_u->height = GST_ROUND_UP_2 (img->height) / 2; + if (interlaced) { + img_u->height = (img_u->height / 2) + ((step == 0 + && img_u->height % 2 == 1) ? 1 : 0); + img_u->stride *= 2; + } img_u->width = GST_ROUND_UP_2 (img->width) / 2; img_u->stride = GST_ROUND_UP_4 (img_u->width); memcpy (img_v, img_u, sizeof (*img_v)); img_v->pixels = img_u->pixels + img_u->height * img_u->stride; + if (interlaced && step == 1) { + img_v->pixels += (img_v->stride / 2); + img_u->pixels += (img_u->stride / 2); + } break; default: break; @@ -722,182 +740,205 @@ static GstFlowReturn gst_video_scale_transform (GstBaseTransform * trans, GstBuffer * in, GstBuffer * out) { - GstVideoScale *videoscale; + GstVideoScale *videoscale = GST_VIDEO_SCALE (trans); GstFlowReturn ret = GST_FLOW_OK; - VSImage *dest; - VSImage *src; - VSImage dest_u; - VSImage dest_v; - VSImage src_u; - VSImage src_v; + VSImage dest = videoscale->dest; + VSImage src = videoscale->src; + VSImage dest_u = { NULL, }; + VSImage dest_v = { NULL, }; + VSImage src_u = { NULL, }; + VSImage src_v = { NULL, }; gint method; - - videoscale = GST_VIDEO_SCALE (trans); + gint step; + gboolean interlaced = videoscale->interlaced; GST_OBJECT_LOCK (videoscale); method = videoscale->method; GST_OBJECT_UNLOCK (videoscale); - src = &videoscale->src; - dest = &videoscale->dest; - - gst_video_scale_prepare_image (videoscale->format, in, src, &src_u, &src_v); - gst_video_scale_prepare_image (videoscale->format, out, dest, &dest_u, - &dest_v); - - if (src->height < 4 && method == GST_VIDEO_SCALE_4TAP) + if (src.height < 4 && method == GST_VIDEO_SCALE_4TAP) method = GST_VIDEO_SCALE_BILINEAR; - switch (method) { - case GST_VIDEO_SCALE_NEAREST: - GST_LOG_OBJECT (videoscale, "doing nearest scaling"); - switch (videoscale->format) { - case GST_VIDEO_SCALE_RGBx: - case GST_VIDEO_SCALE_xRGB: - case GST_VIDEO_SCALE_BGRx: - case GST_VIDEO_SCALE_xBGR: - case GST_VIDEO_SCALE_RGBA: - case GST_VIDEO_SCALE_ARGB: - case GST_VIDEO_SCALE_BGRA: - case GST_VIDEO_SCALE_ABGR: - case GST_VIDEO_SCALE_AYUV: - vs_image_scale_nearest_RGBA (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB: - case GST_VIDEO_SCALE_BGR: - case GST_VIDEO_SCALE_v308: - vs_image_scale_nearest_RGB (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_YUY2: - case GST_VIDEO_SCALE_YVYU: - vs_image_scale_nearest_YUYV (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_UYVY: - vs_image_scale_nearest_UYVY (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_Y: - case GST_VIDEO_SCALE_GRAY8: - vs_image_scale_nearest_Y (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_GRAY16: - vs_image_scale_nearest_Y16 (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_I420: - case GST_VIDEO_SCALE_YV12: - vs_image_scale_nearest_Y (dest, src, videoscale->tmp_buf); - vs_image_scale_nearest_Y (&dest_u, &src_u, videoscale->tmp_buf); - vs_image_scale_nearest_Y (&dest_v, &src_v, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB565: - vs_image_scale_nearest_RGB565 (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB555: - vs_image_scale_nearest_RGB555 (dest, src, videoscale->tmp_buf); - break; - default: - goto unsupported; + /* For interlaced content we have to run two times with half height + * and doubled stride */ + if (videoscale->interlaced) { + dest.height /= 2; + src.height /= 2; + dest.stride *= 2; + src.stride *= 2; + } + + for (step = 0; step < (interlaced ? 2 : 1); step++) { + gst_video_scale_prepare_image (videoscale->format, in, &src, &src_u, &src_v, + step, interlaced); + gst_video_scale_prepare_image (videoscale->format, out, &dest, &dest_u, + &dest_v, step, interlaced); + + if (step == 0 && interlaced) { + if (videoscale->from_height % 2 == 1) { + src.height += 1; } - break; - case GST_VIDEO_SCALE_BILINEAR: - GST_LOG_OBJECT (videoscale, "doing bilinear scaling"); - switch (videoscale->format) { - case GST_VIDEO_SCALE_RGBx: - case GST_VIDEO_SCALE_xRGB: - case GST_VIDEO_SCALE_BGRx: - case GST_VIDEO_SCALE_xBGR: - case GST_VIDEO_SCALE_RGBA: - case GST_VIDEO_SCALE_ARGB: - case GST_VIDEO_SCALE_BGRA: - case GST_VIDEO_SCALE_ABGR: - case GST_VIDEO_SCALE_AYUV: - vs_image_scale_linear_RGBA (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB: - case GST_VIDEO_SCALE_BGR: - case GST_VIDEO_SCALE_v308: - vs_image_scale_linear_RGB (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_YUY2: - case GST_VIDEO_SCALE_YVYU: - vs_image_scale_linear_YUYV (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_UYVY: - vs_image_scale_linear_UYVY (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_Y: - case GST_VIDEO_SCALE_GRAY8: - vs_image_scale_linear_Y (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_GRAY16: - vs_image_scale_linear_Y16 (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_I420: - case GST_VIDEO_SCALE_YV12: - vs_image_scale_linear_Y (dest, src, videoscale->tmp_buf); - vs_image_scale_linear_Y (&dest_u, &src_u, videoscale->tmp_buf); - vs_image_scale_linear_Y (&dest_v, &src_v, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB565: - vs_image_scale_linear_RGB565 (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB555: - vs_image_scale_linear_RGB555 (dest, src, videoscale->tmp_buf); - break; - default: - goto unsupported; + + if (videoscale->to_height % 2 == 1) { + dest.height += 1; } - break; - case GST_VIDEO_SCALE_4TAP: - GST_LOG_OBJECT (videoscale, "doing 4tap scaling"); - switch (videoscale->format) { - case GST_VIDEO_SCALE_RGBx: - case GST_VIDEO_SCALE_xRGB: - case GST_VIDEO_SCALE_BGRx: - case GST_VIDEO_SCALE_xBGR: - case GST_VIDEO_SCALE_RGBA: - case GST_VIDEO_SCALE_ARGB: - case GST_VIDEO_SCALE_BGRA: - case GST_VIDEO_SCALE_ABGR: - case GST_VIDEO_SCALE_AYUV: - vs_image_scale_4tap_RGBA (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB: - case GST_VIDEO_SCALE_BGR: - case GST_VIDEO_SCALE_v308: - vs_image_scale_4tap_RGB (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_YUY2: - case GST_VIDEO_SCALE_YVYU: - vs_image_scale_4tap_YUYV (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_UYVY: - vs_image_scale_4tap_UYVY (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_Y: - case GST_VIDEO_SCALE_GRAY8: - vs_image_scale_4tap_Y (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_GRAY16: - vs_image_scale_4tap_Y16 (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_I420: - case GST_VIDEO_SCALE_YV12: - vs_image_scale_4tap_Y (dest, src, videoscale->tmp_buf); - vs_image_scale_4tap_Y (&dest_u, &src_u, videoscale->tmp_buf); - vs_image_scale_4tap_Y (&dest_v, &src_v, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB565: - vs_image_scale_4tap_RGB565 (dest, src, videoscale->tmp_buf); - break; - case GST_VIDEO_SCALE_RGB555: - vs_image_scale_4tap_RGB555 (dest, src, videoscale->tmp_buf); - break; - default: - goto unsupported; - } - break; - default: - goto unknown_mode; + } else if (step == 1 && interlaced) { + src.pixels += (src.stride / 2); + dest.pixels += (dest.stride / 2); + } + + switch (method) { + case GST_VIDEO_SCALE_NEAREST: + GST_LOG_OBJECT (videoscale, "doing nearest scaling"); + switch (videoscale->format) { + case GST_VIDEO_SCALE_RGBx: + case GST_VIDEO_SCALE_xRGB: + case GST_VIDEO_SCALE_BGRx: + case GST_VIDEO_SCALE_xBGR: + case GST_VIDEO_SCALE_RGBA: + case GST_VIDEO_SCALE_ARGB: + case GST_VIDEO_SCALE_BGRA: + case GST_VIDEO_SCALE_ABGR: + case GST_VIDEO_SCALE_AYUV: + vs_image_scale_nearest_RGBA (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB: + case GST_VIDEO_SCALE_BGR: + case GST_VIDEO_SCALE_v308: + vs_image_scale_nearest_RGB (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_YUY2: + case GST_VIDEO_SCALE_YVYU: + vs_image_scale_nearest_YUYV (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_UYVY: + vs_image_scale_nearest_UYVY (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_Y: + case GST_VIDEO_SCALE_GRAY8: + vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_GRAY16: + vs_image_scale_nearest_Y16 (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_I420: + case GST_VIDEO_SCALE_YV12: + vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf); + vs_image_scale_nearest_Y (&dest_u, &src_u, videoscale->tmp_buf); + vs_image_scale_nearest_Y (&dest_v, &src_v, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB565: + vs_image_scale_nearest_RGB565 (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB555: + vs_image_scale_nearest_RGB555 (&dest, &src, videoscale->tmp_buf); + break; + default: + goto unsupported; + } + break; + case GST_VIDEO_SCALE_BILINEAR: + GST_LOG_OBJECT (videoscale, "doing bilinear scaling"); + switch (videoscale->format) { + case GST_VIDEO_SCALE_RGBx: + case GST_VIDEO_SCALE_xRGB: + case GST_VIDEO_SCALE_BGRx: + case GST_VIDEO_SCALE_xBGR: + case GST_VIDEO_SCALE_RGBA: + case GST_VIDEO_SCALE_ARGB: + case GST_VIDEO_SCALE_BGRA: + case GST_VIDEO_SCALE_ABGR: + case GST_VIDEO_SCALE_AYUV: + vs_image_scale_linear_RGBA (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB: + case GST_VIDEO_SCALE_BGR: + case GST_VIDEO_SCALE_v308: + vs_image_scale_linear_RGB (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_YUY2: + case GST_VIDEO_SCALE_YVYU: + vs_image_scale_linear_YUYV (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_UYVY: + vs_image_scale_linear_UYVY (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_Y: + case GST_VIDEO_SCALE_GRAY8: + vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_GRAY16: + vs_image_scale_linear_Y16 (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_I420: + case GST_VIDEO_SCALE_YV12: + vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf); + vs_image_scale_linear_Y (&dest_u, &src_u, videoscale->tmp_buf); + vs_image_scale_linear_Y (&dest_v, &src_v, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB565: + vs_image_scale_linear_RGB565 (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB555: + vs_image_scale_linear_RGB555 (&dest, &src, videoscale->tmp_buf); + break; + default: + goto unsupported; + } + break; + case GST_VIDEO_SCALE_4TAP: + GST_LOG_OBJECT (videoscale, "doing 4tap scaling"); + switch (videoscale->format) { + case GST_VIDEO_SCALE_RGBx: + case GST_VIDEO_SCALE_xRGB: + case GST_VIDEO_SCALE_BGRx: + case GST_VIDEO_SCALE_xBGR: + case GST_VIDEO_SCALE_RGBA: + case GST_VIDEO_SCALE_ARGB: + case GST_VIDEO_SCALE_BGRA: + case GST_VIDEO_SCALE_ABGR: + case GST_VIDEO_SCALE_AYUV: + vs_image_scale_4tap_RGBA (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB: + case GST_VIDEO_SCALE_BGR: + case GST_VIDEO_SCALE_v308: + vs_image_scale_4tap_RGB (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_YUY2: + case GST_VIDEO_SCALE_YVYU: + vs_image_scale_4tap_YUYV (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_UYVY: + vs_image_scale_4tap_UYVY (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_Y: + case GST_VIDEO_SCALE_GRAY8: + vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_GRAY16: + vs_image_scale_4tap_Y16 (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_I420: + case GST_VIDEO_SCALE_YV12: + vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf); + vs_image_scale_4tap_Y (&dest_u, &src_u, videoscale->tmp_buf); + vs_image_scale_4tap_Y (&dest_v, &src_v, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB565: + vs_image_scale_4tap_RGB565 (&dest, &src, videoscale->tmp_buf); + break; + case GST_VIDEO_SCALE_RGB555: + vs_image_scale_4tap_RGB555 (&dest, &src, videoscale->tmp_buf); + break; + default: + goto unsupported; + } + break; + default: + goto unknown_mode; + } + } GST_LOG_OBJECT (videoscale, "pushing buffer of %d bytes", diff --git a/gst/videoscale/gstvideoscale.h b/gst/videoscale/gstvideoscale.h index 2024270f46..9ccb575d01 100644 --- a/gst/videoscale/gstvideoscale.h +++ b/gst/videoscale/gstvideoscale.h @@ -78,6 +78,7 @@ struct _GstVideoScale { gint to_height; gint from_width; gint from_height; + gboolean interlaced; /*< private >*/ guint8 *tmp_buf;