mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-22 15:18:21 +00:00
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
This commit is contained in:
parent
620e1d2fcd
commit
1aee6cdc25
3 changed files with 125 additions and 2 deletions
|
@ -381,6 +381,12 @@ gst_kms_sink_start (GstBaseSink * bsink)
|
||||||
self->hdisplay = crtc->mode.hdisplay;
|
self->hdisplay = crtc->mode.hdisplay;
|
||||||
self->vdisplay = crtc->mode.vdisplay;
|
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;
|
ret = TRUE;
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
|
@ -534,6 +540,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
|
static gboolean
|
||||||
gst_kms_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
gst_kms_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
{
|
{
|
||||||
|
@ -546,8 +603,8 @@ gst_kms_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
if (!gst_video_info_from_caps (&vinfo, caps))
|
if (!gst_video_info_from_caps (&vinfo, caps))
|
||||||
goto invalid_format;
|
goto invalid_format;
|
||||||
|
|
||||||
GST_VIDEO_SINK_WIDTH (self) = GST_VIDEO_INFO_WIDTH (&vinfo);
|
if (!gst_kms_sink_calculate_display_ratio (self, &vinfo))
|
||||||
GST_VIDEO_SINK_HEIGHT (self) = GST_VIDEO_INFO_HEIGHT (&vinfo);
|
goto no_disp_ratio;
|
||||||
|
|
||||||
if (GST_VIDEO_SINK_WIDTH (self) <= 0 || GST_VIDEO_SINK_HEIGHT (self) <= 0)
|
if (GST_VIDEO_SINK_WIDTH (self) <= 0 || GST_VIDEO_SINK_HEIGHT (self) <= 0)
|
||||||
goto invalid_size;
|
goto invalid_size;
|
||||||
|
@ -586,6 +643,13 @@ invalid_size:
|
||||||
("Invalid image size."));
|
("Invalid image size."));
|
||||||
return FALSE;
|
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:
|
no_pool:
|
||||||
{
|
{
|
||||||
/* Already warned in create_pool */
|
/* Already warned in create_pool */
|
||||||
|
|
|
@ -121,3 +121,56 @@ gst_kms_sink_caps_template_fill (void)
|
||||||
}
|
}
|
||||||
return gst_caps_simplify (caps);
|
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];
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,12 @@ G_BEGIN_DECLS
|
||||||
GstVideoFormat gst_video_format_from_drm (guint32 drmfmt);
|
GstVideoFormat gst_video_format_from_drm (guint32 drmfmt);
|
||||||
guint32 gst_drm_format_from_video (GstVideoFormat fmt);
|
guint32 gst_drm_format_from_video (GstVideoFormat fmt);
|
||||||
GstCaps * gst_kms_sink_caps_template_fill (void);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue