344 lines
9.9 KiB
Diff
344 lines
9.9 KiB
Diff
From a1affa1293e31870d6fb9dda85e4c648cc4dd247 Mon Sep 17 00:00:00 2001
|
|
From: Haihua Hu <jared.hu@nxp.com>
|
|
Date: Tue, 20 Jun 2017 13:11:27 +0800
|
|
Subject: [PATCH 2/3] [MMFMWK-7567] kmssink: support videooverlay interface
|
|
|
|
Implement videooverlay interface in kmssink, divided into two cases:
|
|
when driver supports scale, then we do refresh in show_frame(); if
|
|
not, send a reconfigure event to upstream and re-negotiate, using the
|
|
new size.
|
|
|
|
Upstream-Status: Backport [1.13.1]
|
|
https://bugzilla.gnome.org/show_bug.cgi?id=784599
|
|
---
|
|
sys/kms/gstkmssink.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++---
|
|
sys/kms/gstkmssink.h | 12 ++++
|
|
2 files changed, 167 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/sys/kms/gstkmssink.c b/sys/kms/gstkmssink.c
|
|
index e91c211..6d9b765 100644
|
|
--- a/sys/kms/gstkmssink.c
|
|
+++ b/sys/kms/gstkmssink.c
|
|
@@ -43,6 +43,7 @@
|
|
#endif
|
|
|
|
#include <gst/video/video.h>
|
|
+#include <gst/video/videooverlay.h>
|
|
#include <gst/allocators/gstdmabuf.h>
|
|
|
|
#include <drm.h>
|
|
@@ -66,11 +67,17 @@ GST_DEBUG_CATEGORY_STATIC (gst_kms_sink_debug);
|
|
GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
|
|
#define GST_CAT_DEFAULT gst_kms_sink_debug
|
|
|
|
+static GstFlowReturn gst_kms_sink_show_frame (GstVideoSink * vsink,
|
|
+ GstBuffer * buf);
|
|
+static void gst_kms_sink_video_overlay_init (GstVideoOverlayInterface * iface);
|
|
+
|
|
#define parent_class gst_kms_sink_parent_class
|
|
G_DEFINE_TYPE_WITH_CODE (GstKMSSink, gst_kms_sink, GST_TYPE_VIDEO_SINK,
|
|
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_PLUGIN_NAME, 0,
|
|
GST_PLUGIN_DESC);
|
|
- GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE"));
|
|
+ GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
|
|
+ G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
|
|
+ gst_kms_sink_video_overlay_init));
|
|
|
|
enum
|
|
{
|
|
@@ -83,6 +90,79 @@ enum
|
|
|
|
static GParamSpec *g_properties[PROP_N] = { NULL, };
|
|
|
|
+static void
|
|
+gst_kms_sink_set_render_rectangle (GstVideoOverlay * overlay,
|
|
+ gint x, gint y, gint width, gint height)
|
|
+{
|
|
+ GstKMSSink *self = GST_KMS_SINK (overlay);
|
|
+
|
|
+ if (width <= 0 || height <= 0) {
|
|
+ if (width == -1 && height == -1) {
|
|
+ x = 0;
|
|
+ y = 0;
|
|
+ width = self->hdisplay;
|
|
+ height = self->vdisplay;
|
|
+ goto commit;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+
|
|
+commit:
|
|
+ GST_OBJECT_LOCK (self);
|
|
+ if (self->can_scale) {
|
|
+ self->preferred_rect.x = x;
|
|
+ self->preferred_rect.y = y;
|
|
+ self->preferred_rect.w = width;
|
|
+ self->preferred_rect.h = height;
|
|
+ } else {
|
|
+ GstVideoRectangle src = { 0, };
|
|
+ GstVideoRectangle dst = { 0, };
|
|
+ GstVideoRectangle result;
|
|
+
|
|
+ src.w = self->original_width;
|
|
+ src.h = self->original_heigth;
|
|
+
|
|
+ dst.w = width;
|
|
+ dst.h = height;
|
|
+
|
|
+ gst_video_sink_center_rect (src, dst, &result, TRUE);
|
|
+
|
|
+ self->pending_rect.x = x + result.x;
|
|
+ self->pending_rect.y = y + result.y;
|
|
+ self->pending_rect.w = result.w;
|
|
+ self->pending_rect.h = result.h;
|
|
+
|
|
+ GST_DEBUG_OBJECT (self, "pending resize to (%d,%d)-(%dx%d)",
|
|
+ self->pending_rect.x, self->pending_rect.y,
|
|
+ self->pending_rect.w, self->pending_rect.h);
|
|
+ }
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
+}
|
|
+
|
|
+static void
|
|
+gst_kms_sink_expose (GstVideoOverlay * overlay)
|
|
+{
|
|
+ GstKMSSink *self = GST_KMS_SINK (overlay);
|
|
+
|
|
+ if (self->can_scale) {
|
|
+ gst_kms_sink_show_frame (GST_VIDEO_SINK (self), NULL);
|
|
+ } else {
|
|
+ GST_OBJECT_LOCK (self);
|
|
+ self->reconfigure = TRUE;
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
+
|
|
+ gst_pad_push_event (GST_BASE_SINK (self)->sinkpad,
|
|
+ gst_event_new_reconfigure ());
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+gst_kms_sink_video_overlay_init (GstVideoOverlayInterface * iface)
|
|
+{
|
|
+ iface->expose = gst_kms_sink_expose;
|
|
+ iface->set_render_rectangle = gst_kms_sink_set_render_rectangle;
|
|
+}
|
|
+
|
|
static int
|
|
kms_open (gchar ** driver)
|
|
{
|
|
@@ -539,7 +619,7 @@ gst_kms_sink_start (GstBaseSink * bsink)
|
|
if (!get_drm_caps (self))
|
|
goto bail;
|
|
|
|
- self->can_scale = TRUE;
|
|
+ //self->can_scale = TRUE;
|
|
|
|
res = drmModeGetResources (self->fd);
|
|
if (!res)
|
|
@@ -588,8 +668,10 @@ retry_find_plane:
|
|
GST_INFO_OBJECT (self, "connector id = %d / crtc id = %d / plane id = %d",
|
|
self->conn_id, self->crtc_id, self->plane_id);
|
|
|
|
- self->hdisplay = crtc->mode.hdisplay;
|
|
- self->vdisplay = crtc->mode.vdisplay;
|
|
+ self->preferred_rect.x = 0;
|
|
+ self->preferred_rect.y = 0;
|
|
+ self->hdisplay = self->preferred_rect.w = crtc->mode.hdisplay;
|
|
+ self->vdisplay = self->preferred_rect.h = crtc->mode.vdisplay;
|
|
self->buffer_id = crtc->buffer_id;
|
|
|
|
self->mm_width = conn->mmWidth;
|
|
@@ -602,6 +684,9 @@ retry_find_plane:
|
|
gst_poll_add_fd (self->poll, &self->pollfd);
|
|
gst_poll_fd_ctl_read (self->poll, &self->pollfd, TRUE);
|
|
|
|
+ self->original_width = -1;
|
|
+ self->original_heigth = -1;
|
|
+
|
|
ret = TRUE;
|
|
|
|
bail:
|
|
@@ -731,17 +816,29 @@ static GstCaps *
|
|
gst_kms_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
|
|
{
|
|
GstKMSSink *self;
|
|
- GstCaps *caps, *out_caps;
|
|
+ GstCaps *caps, *out_caps, *tmp;
|
|
|
|
self = GST_KMS_SINK (bsink);
|
|
|
|
caps = gst_kms_sink_get_allowed_caps (self);
|
|
+
|
|
+ GST_OBJECT_LOCK (self);
|
|
+ if (caps && self->reconfigure) {
|
|
+ tmp = gst_caps_copy (caps);
|
|
+ gst_caps_set_simple (tmp, "width", G_TYPE_INT, self->pending_rect.w,
|
|
+ "height", G_TYPE_INT, self->pending_rect.h, NULL);
|
|
+ gst_caps_append (tmp, caps);
|
|
+ caps = tmp;
|
|
+ }
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
+
|
|
if (caps && filter) {
|
|
out_caps = gst_caps_intersect_full (caps, filter, GST_CAPS_INTERSECT_FIRST);
|
|
gst_caps_unref (caps);
|
|
} else {
|
|
out_caps = caps;
|
|
}
|
|
+ GST_DEBUG_OBJECT (self, "out caps %" GST_PTR_FORMAT, out_caps);
|
|
|
|
return out_caps;
|
|
}
|
|
@@ -880,6 +977,19 @@ gst_kms_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
|
|
|
self->vinfo = vinfo;
|
|
|
|
+ GST_OBJECT_LOCK (self);
|
|
+ if (self->reconfigure) {
|
|
+ self->reconfigure = FALSE;
|
|
+ self->preferred_rect = self->pending_rect;
|
|
+ }
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
+
|
|
+ /* initialize original video size */
|
|
+ if (self->original_width < 0) {
|
|
+ self->original_width = GST_VIDEO_INFO_WIDTH (&self->vinfo);
|
|
+ self->original_heigth = GST_VIDEO_INFO_HEIGHT (&self->vinfo);
|
|
+ }
|
|
+
|
|
GST_DEBUG_OBJECT (self, "negotiated caps = %" GST_PTR_FORMAT, caps);
|
|
|
|
return TRUE;
|
|
@@ -1258,7 +1368,13 @@ gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
|
|
|
res = GST_FLOW_ERROR;
|
|
|
|
- buffer = gst_kms_sink_get_input_buffer (self, buf);
|
|
+ buffer = NULL;
|
|
+
|
|
+ if (buf)
|
|
+ buffer = gst_kms_sink_get_input_buffer (self, buf);
|
|
+ else if (self->last_buffer)
|
|
+ buffer = gst_buffer_ref (self->last_buffer);
|
|
+
|
|
if (!buffer)
|
|
return GST_FLOW_ERROR;
|
|
fb_id = gst_kms_memory_get_fb_id (gst_buffer_peek_memory (buffer, 0));
|
|
@@ -1267,6 +1383,7 @@ gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
|
|
|
GST_TRACE_OBJECT (self, "displaying fb %d", fb_id);
|
|
|
|
+ GST_OBJECT_LOCK (self);
|
|
if (self->modesetting_enabled) {
|
|
self->buffer_id = fb_id;
|
|
goto sync_frame;
|
|
@@ -1287,12 +1404,15 @@ gst_kms_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
|
|
src.w = GST_VIDEO_SINK_WIDTH (self);
|
|
src.h = GST_VIDEO_SINK_HEIGHT (self);
|
|
|
|
- dst.w = self->hdisplay;
|
|
- dst.h = self->vdisplay;
|
|
+ dst.w = self->preferred_rect.w;
|
|
+ dst.h = self->preferred_rect.h;
|
|
|
|
retry_set_plane:
|
|
gst_video_sink_center_rect (src, dst, &result, self->can_scale);
|
|
|
|
+ result.x += self->preferred_rect.x;
|
|
+ result.y += self->preferred_rect.y;
|
|
+
|
|
if (crop) {
|
|
src.w = crop->width;
|
|
src.h = crop->height;
|
|
@@ -1301,6 +1421,27 @@ retry_set_plane:
|
|
src.h = GST_VIDEO_INFO_HEIGHT (&self->vinfo);
|
|
}
|
|
|
|
+ /* handle out of screen case */
|
|
+ if ((result.x + result.w) > self->hdisplay)
|
|
+ src.w = self->hdisplay - result.x;
|
|
+
|
|
+ if ((result.y + result.h) > self->vdisplay)
|
|
+ src.h = self->vdisplay - result.y;
|
|
+
|
|
+ if (src.w <= 0 || src.h <= 0) {
|
|
+ GST_WARNING_OBJECT (self, "video is out of display range");
|
|
+ goto sync_frame;
|
|
+ }
|
|
+ GST_TRACE_OBJECT (self,
|
|
+ "before drmModeSetPlane at (%i,%i) %ix%i sourcing at (%i,%i) %ix%i",
|
|
+ result.x, result.y, result.w, result.h, src.x, src.y, src.w, src.h);
|
|
+
|
|
+ /* to make sure it can be show when driver don't support scale */
|
|
+ if (!self->can_scale) {
|
|
+ result.w = src.w;
|
|
+ result.h = src.h;
|
|
+ }
|
|
+
|
|
GST_TRACE_OBJECT (self,
|
|
"drmModeSetPlane at (%i,%i) %ix%i sourcing at (%i,%i) %ix%i",
|
|
result.x, result.y, result.w, result.h, src.x, src.y, src.w, src.h);
|
|
@@ -1322,9 +1463,11 @@ sync_frame:
|
|
if (!gst_kms_sink_sync (self))
|
|
goto bail;
|
|
|
|
- gst_buffer_replace (&self->last_buffer, buffer);
|
|
+ if (buffer != self->last_buffer)
|
|
+ gst_buffer_replace (&self->last_buffer, buffer);
|
|
g_clear_pointer (&self->tmp_kmsmem, gst_memory_unref);
|
|
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
res = GST_FLOW_OK;
|
|
|
|
bail:
|
|
@@ -1339,6 +1482,7 @@ buffer_invalid:
|
|
}
|
|
set_plane_failed:
|
|
{
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
GST_DEBUG_OBJECT (self, "result = { %d, %d, %d, %d} / "
|
|
"src = { %d, %d, %d %d } / dst = { %d, %d, %d %d }", result.x, result.y,
|
|
result.w, result.h, src.x, src.y, src.w, src.h, dst.x, dst.y, dst.w,
|
|
@@ -1349,6 +1493,7 @@ set_plane_failed:
|
|
}
|
|
no_disp_ratio:
|
|
{
|
|
+ GST_OBJECT_UNLOCK (self);
|
|
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, (NULL),
|
|
("Error calculating the output display ratio of the video."));
|
|
goto bail;
|
|
@@ -1427,6 +1572,7 @@ gst_kms_sink_init (GstKMSSink * sink)
|
|
sink->fd = -1;
|
|
sink->conn_id = -1;
|
|
sink->plane_id = -1;
|
|
+ sink->can_scale = TRUE;
|
|
gst_poll_fd_init (&sink->pollfd);
|
|
sink->poll = gst_poll_new (TRUE);
|
|
gst_video_info_init (&sink->vinfo);
|
|
diff --git a/sys/kms/gstkmssink.h b/sys/kms/gstkmssink.h
|
|
index f2ab4d4..44476e1 100644
|
|
--- a/sys/kms/gstkmssink.h
|
|
+++ b/sys/kms/gstkmssink.h
|
|
@@ -79,6 +79,18 @@ struct _GstKMSSink {
|
|
|
|
GstPoll *poll;
|
|
GstPollFD pollfd;
|
|
+
|
|
+ /* preferred video rectangle */
|
|
+ GstVideoRectangle preferred_rect;
|
|
+
|
|
+ /* reconfigure info if driver doesn't scale */
|
|
+ GstVideoRectangle pending_rect;
|
|
+ gboolean reconfigure;
|
|
+
|
|
+ /* kept original video size */
|
|
+ gint original_width;
|
|
+ gint original_heigth;
|
|
+
|
|
};
|
|
|
|
struct _GstKMSSinkClass {
|
|
--
|
|
1.9.1
|
|
|