From 1aee6cdc25572d856ca414940689194f54fd9054 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Sun, 31 Jan 2016 13:12:34 +0100 Subject: [PATCH] kmssink: calculate display ratio Get the aspect ratio given the information provided by libdrm, and with it calculate the display ratio. https://bugzilla.gnome.org/show_bug.cgi?id=761059 --- sys/kms/gstkmssink.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++-- sys/kms/gstkmsutils.c | 53 +++++++++++++++++++++++++++++++++++++++ sys/kms/gstkmsutils.h | 6 +++++ 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/sys/kms/gstkmssink.c b/sys/kms/gstkmssink.c index 7256eb7..cd1401f6 100644 --- a/sys/kms/gstkmssink.c +++ b/sys/kms/gstkmssink.c @@ -381,6 +381,12 @@ gst_kms_sink_start (GstBaseSink * bsink) self->hdisplay = crtc->mode.hdisplay; self->vdisplay = crtc->mode.vdisplay; + self->mm_width = conn->mmWidth; + self->mm_height = conn->mmHeight; + + GST_INFO_OBJECT (self, "display size: pixels = %dx%d / millimeters = %dx%d", + self->hdisplay, self->vdisplay, self->mm_width, self->mm_height); + ret = TRUE; bail: @@ -535,6 +541,57 @@ config_failed: } static gboolean +gst_kms_sink_calculate_display_ratio (GstKMSSink * self, GstVideoInfo * vinfo) +{ + guint dar_n, dar_d; + guint video_width, video_height; + guint video_par_n, video_par_d; + guint dpy_par_n, dpy_par_d; + + video_width = GST_VIDEO_INFO_WIDTH (vinfo); + video_height = GST_VIDEO_INFO_HEIGHT (vinfo); + video_par_n = GST_VIDEO_INFO_PAR_N (vinfo); + video_par_d = GST_VIDEO_INFO_PAR_D (vinfo); + + gst_video_calculate_device_ratio (self->hdisplay, self->vdisplay, + self->mm_width, self->mm_height, &dpy_par_n, &dpy_par_d); + + if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, video_width, + video_height, video_par_n, video_par_d, dpy_par_n, dpy_par_d)) + return FALSE; + + GST_DEBUG_OBJECT (self, "video calculated display ratio: %d/%d", dar_n, + dar_d); + + /* now find a width x height that respects this display ratio. + * prefer those that have one of w/h the same as the incoming video + * using wd / hd = dar_n / dar_d */ + + /* start with same height, because of interlaced video */ + /* check hd / dar_d is an integer scale factor, and scale wd with the PAR */ + if (video_height % dar_d == 0) { + GST_DEBUG_OBJECT (self, "keeping video height"); + GST_VIDEO_SINK_WIDTH (self) = (guint) + gst_util_uint64_scale_int (video_height, dar_n, dar_d); + GST_VIDEO_SINK_HEIGHT (self) = video_height; + } else if (video_width % dar_n == 0) { + GST_DEBUG_OBJECT (self, "keeping video width"); + GST_VIDEO_SINK_WIDTH (self) = video_width; + GST_VIDEO_SINK_HEIGHT (self) = (guint) + gst_util_uint64_scale_int (video_width, dar_d, dar_n); + } else { + GST_DEBUG_OBJECT (self, "approximating while keeping video height"); + GST_VIDEO_SINK_WIDTH (self) = (guint) + gst_util_uint64_scale_int (video_height, dar_n, dar_d); + GST_VIDEO_SINK_HEIGHT (self) = video_height; + } + GST_DEBUG_OBJECT (self, "scaling to %dx%d", GST_VIDEO_SINK_WIDTH (self), + GST_VIDEO_SINK_HEIGHT (self)); + + return TRUE; +} + +static gboolean gst_kms_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) { GstKMSSink *self; @@ -546,8 +603,8 @@ gst_kms_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) if (!gst_video_info_from_caps (&vinfo, caps)) goto invalid_format; - GST_VIDEO_SINK_WIDTH (self) = GST_VIDEO_INFO_WIDTH (&vinfo); - GST_VIDEO_SINK_HEIGHT (self) = GST_VIDEO_INFO_HEIGHT (&vinfo); + if (!gst_kms_sink_calculate_display_ratio (self, &vinfo)) + goto no_disp_ratio; if (GST_VIDEO_SINK_WIDTH (self) <= 0 || GST_VIDEO_SINK_HEIGHT (self) <= 0) goto invalid_size; @@ -586,6 +643,13 @@ invalid_size: ("Invalid image size.")); return FALSE; } + +no_disp_ratio: + { + GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, (NULL), + ("Error calculating the output display ratio of the video.")); + return FALSE; + } no_pool: { /* Already warned in create_pool */ diff --git a/sys/kms/gstkmsutils.c b/sys/kms/gstkmsutils.c index b571a0b..77061b7 100644 --- a/sys/kms/gstkmsutils.c +++ b/sys/kms/gstkmsutils.c @@ -121,3 +121,56 @@ gst_kms_sink_caps_template_fill (void) } return gst_caps_simplify (caps); } + +static const gint device_par_map[][2] = { + {1, 1}, /* regular screen */ + {16, 15}, /* PAL TV */ + {11, 10}, /* 525 line Rec.601 video */ + {54, 59}, /* 625 line Rec.601 video */ + {64, 45}, /* 1280x1024 on 16:9 display */ + {5, 3}, /* 1280x1024 on 4:3 display */ + {4, 3} /* 800x600 on 16:9 display */ +}; + +#define DELTA(ratio, idx, w) \ + (ABS(ratio - ((gdouble)device_par_map[idx][w] / device_par_map[idx][!(w)]))) + +void +gst_video_calculate_device_ratio (guint dev_width, guint dev_height, + guint dev_width_mm, guint dev_height_mm, + guint * dpy_par_n, guint * dpy_par_d) +{ + gdouble ratio, delta, cur_delta; + gint i, j, index, windex; + + /* First, calculate the "real" ratio based on the X values; which is + * the "physical" w/h divided by the w/h in pixels of the display */ + if (dev_width == 0 || dev_height == 0 + || dev_width_mm == 0 || dev_height_mm == 0) + ratio = 1.0; + else + ratio = (gdouble) (dev_width_mm * dev_height) / (dev_height_mm * dev_width); + + /* Now, find the one from device_par_map[][2] with the lowest delta + * to the real one */ + delta = DELTA (ratio, 0, 0); + index = 0; + windex = 0; + + for (i = 1; i < G_N_ELEMENTS (device_par_map); i++) { + for (j = 0; j < 2; j++) { + cur_delta = DELTA (ratio, i, j); + if (cur_delta < delta) { + index = i; + windex = j; + delta = cur_delta; + } + } + } + + if (dpy_par_n) + *dpy_par_n = device_par_map[index][windex]; + + if (dpy_par_d) + *dpy_par_d = device_par_map[index][windex ^ 1]; +} diff --git a/sys/kms/gstkmsutils.h b/sys/kms/gstkmsutils.h index 3ffc1dc..75e9ba3 100644 --- a/sys/kms/gstkmsutils.h +++ b/sys/kms/gstkmsutils.h @@ -33,6 +33,12 @@ G_BEGIN_DECLS GstVideoFormat gst_video_format_from_drm (guint32 drmfmt); guint32 gst_drm_format_from_video (GstVideoFormat fmt); GstCaps * gst_kms_sink_caps_template_fill (void); +void gst_video_calculate_device_ratio (guint dev_width, + guint dev_height, + guint dev_width_mm, + guint dev_height_mm, + guint * dpy_par_n, + guint * dpy_par_d); G_END_DECLS -- 2.7.4