From e1d9d9761be94fcf2dc529b861809bddd7f4e5c4 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Tue, 11 Apr 2017 09:33:04 +0200 Subject: [PATCH] kmscube: Add patches for better GStreamer support and for YUY2 support Change-Id: I17c77cbae9f23ba415a5d4bb433fcee28a04deab Signed-off-by: Carlos Rafael Giani Signed-off-by: Otavio Salvador Signed-off-by: Fabio Berton --- ...improved-information-about-EGL-and-O.patch | 51 ++++ ...add-kmscube-GStreamer-debug-category.patch | 56 ++++ ....c-add-support-for-YUY2-pixel-format.patch | 32 +++ ...ok-at-the-caps-event-instead-of-the-.patch | 59 ++++ ...e-element-factory-name-to-detect-V4L.patch | 48 ++++ .../0006-gst-decoder.c-add-bus-watch.patch | 150 ++++++++++ .../0007-gst-decoder.c-minor-cleanup.patch | 75 +++++ ...e-a-custom-appsink-subclass-to-make-.patch | 254 +++++++++++++++++ ...mprove-synchronicity-of-video-output.patch | 50 ++++ ...r.c-improve-buffer_to_image-function.patch | 259 ++++++++++++++++++ .../kmscube/use-dri-card1-by-default.patch | 18 ++ recipes-graphics/kmscube/kmscube_%.bbappend | 14 + 12 files changed, 1066 insertions(+) create mode 100644 recipes-graphics/kmscube/kmscube/0001-output-more-and-improved-information-about-EGL-and-O.patch create mode 100644 recipes-graphics/kmscube/kmscube/0002-add-kmscube-GStreamer-debug-category.patch create mode 100644 recipes-graphics/kmscube/kmscube/0003-gst-decoder.c-add-support-for-YUY2-pixel-format.patch create mode 100644 recipes-graphics/kmscube/kmscube/0004-gst-decoder.c-look-at-the-caps-event-instead-of-the-.patch create mode 100644 recipes-graphics/kmscube/kmscube/0005-gst-decoder.c-Use-element-factory-name-to-detect-V4L.patch create mode 100644 recipes-graphics/kmscube/kmscube/0006-gst-decoder.c-add-bus-watch.patch create mode 100644 recipes-graphics/kmscube/kmscube/0007-gst-decoder.c-minor-cleanup.patch create mode 100644 recipes-graphics/kmscube/kmscube/0008-gst-decoder.c-use-a-custom-appsink-subclass-to-make-.patch create mode 100644 recipes-graphics/kmscube/kmscube/0009-gst-decoder.c-Improve-synchronicity-of-video-output.patch create mode 100644 recipes-graphics/kmscube/kmscube/0010-gst-decoder.c-improve-buffer_to_image-function.patch create mode 100644 recipes-graphics/kmscube/kmscube/use-dri-card1-by-default.patch create mode 100644 recipes-graphics/kmscube/kmscube_%.bbappend diff --git a/recipes-graphics/kmscube/kmscube/0001-output-more-and-improved-information-about-EGL-and-O.patch b/recipes-graphics/kmscube/kmscube/0001-output-more-and-improved-information-about-EGL-and-O.patch new file mode 100644 index 00000000..677a0d3c --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0001-output-more-and-improved-information-about-EGL-and-O.patch @@ -0,0 +1,51 @@ +From fc0da8b8d4c2e15258ffc55710e495c967c69c11 Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 20:42:32 +0200 +Subject: [PATCH kmscube 01/10] output more and improved information about EGL + and OpenGL ES 2.x + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + common.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/common.c b/common.c +index 4bf3c5a..4d29eef 100644 +--- a/common.c ++++ b/common.c +@@ -97,9 +97,12 @@ int init_egl(struct egl *egl, const struct gbm *gbm) + printf("Using display %p with EGL version %d.%d\n", + egl->display, major, minor); + +- printf("EGL Version \"%s\"\n", eglQueryString(egl->display, EGL_VERSION)); +- printf("EGL Vendor \"%s\"\n", eglQueryString(egl->display, EGL_VENDOR)); +- printf("EGL Extensions \"%s\"\n", eglQueryString(egl->display, EGL_EXTENSIONS)); ++ printf("===================================\n"); ++ printf("EGL information:\n"); ++ printf(" version: \"%s\"\n", eglQueryString(egl->display, EGL_VERSION)); ++ printf(" vendor: \"%s\"\n", eglQueryString(egl->display, EGL_VENDOR)); ++ printf(" extensions: \"%s\"\n", eglQueryString(egl->display, EGL_EXTENSIONS)); ++ printf("===================================\n"); + + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + printf("failed to bind api EGL_OPENGL_ES_API\n"); +@@ -128,7 +131,13 @@ int init_egl(struct egl *egl, const struct gbm *gbm) + /* connect the context to the surface */ + eglMakeCurrent(egl->display, egl->surface, egl->surface, egl->context); + +- printf("GL Extensions: \"%s\"\n", glGetString(GL_EXTENSIONS)); ++ printf("OpenGL ES 2.x information:\n"); ++ printf(" version: \"%s\"\n", glGetString(GL_VERSION)); ++ printf(" shading language version: \"%s\"\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); ++ printf(" vendor: \"%s\"\n", glGetString(GL_VENDOR)); ++ printf(" renderer: \"%s\"\n", glGetString(GL_RENDERER)); ++ printf(" extensions: \"%s\"\n", glGetString(GL_EXTENSIONS)); ++ printf("===================================\n"); + + return 0; + } +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0002-add-kmscube-GStreamer-debug-category.patch b/recipes-graphics/kmscube/kmscube/0002-add-kmscube-GStreamer-debug-category.patch new file mode 100644 index 00000000..2ef2e65b --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0002-add-kmscube-GStreamer-debug-category.patch @@ -0,0 +1,56 @@ +From 6d6ff5895e2a86f2c4a7684da97085aa7c5b2b2a Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 23:05:22 +0200 +Subject: [PATCH kmscube 02/10] add "kmscube" GStreamer debug category + +Without this, the various GST_* log macros won't output anything. +To enable, add "kmscube:" to the GST_DEBUG environment variable. +Example: GST_DEBUG=kmscube:5 + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + gst-decoder.c | 3 +++ + kmscube.c | 4 +++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/gst-decoder.c b/gst-decoder.c +index 1140213..22dc068 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -39,6 +39,9 @@ + #include + #include + ++GST_DEBUG_CATEGORY_EXTERN(kmscube_debug); ++#define GST_CAT_DEFAULT kmscube_debug ++ + struct decoder { + GMainLoop *loop; + GstElement *pipeline; +diff --git a/kmscube.c b/kmscube.c +index 54f4328..8e2d008 100644 +--- a/kmscube.c ++++ b/kmscube.c +@@ -32,7 +32,8 @@ + #include "drm-common.h" + + #ifdef HAVE_GST +-# include ++#include ++GST_DEBUG_CATEGORY(kmscube_debug); + #endif + + #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +@@ -77,6 +78,7 @@ int main(int argc, char *argv[]) + + #ifdef HAVE_GST + gst_init(&argc, &argv); ++ GST_DEBUG_CATEGORY_INIT(kmscube_debug, "kmscube", 0, "kmscube video pipeline"); + #endif + + while ((opt = getopt_long_only(argc, argv, shortopts, longopts, NULL)) != -1) { +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0003-gst-decoder.c-add-support-for-YUY2-pixel-format.patch b/recipes-graphics/kmscube/kmscube/0003-gst-decoder.c-add-support-for-YUY2-pixel-format.patch new file mode 100644 index 00000000..bae0792b --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0003-gst-decoder.c-add-support-for-YUY2-pixel-format.patch @@ -0,0 +1,32 @@ +From 2cb0be7d7e52180a2403d9fa1f2d58b964878f9f Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 20:43:45 +0200 +Subject: [PATCH kmscube 03/10] gst-decoder.c: add support for YUY2 pixel + format + +This format is used for example by the i.MX6 CODA hardware video codec + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + gst-decoder.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/gst-decoder.c b/gst-decoder.c +index 22dc068..fd28201 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -91,6 +91,9 @@ pad_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) + case GST_VIDEO_FORMAT_NV12: + dec->format = DRM_FORMAT_NV12; + break; ++ case GST_VIDEO_FORMAT_YUY2: ++ dec->format = DRM_FORMAT_YUYV; ++ break; + default: + GST_ERROR("unknown format\n"); + return GST_PAD_PROBE_OK; +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0004-gst-decoder.c-look-at-the-caps-event-instead-of-the-.patch b/recipes-graphics/kmscube/kmscube/0004-gst-decoder.c-look-at-the-caps-event-instead-of-the-.patch new file mode 100644 index 00000000..754ba226 --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0004-gst-decoder.c-look-at-the-caps-event-instead-of-the-.patch @@ -0,0 +1,59 @@ +From 88a7a4427e34db3288a0b43b5e111f108caa3ce3 Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 21:44:25 +0200 +Subject: [PATCH kmscube 04/10] gst-decoder.c: look at the caps event instead + of the allocation query + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + gst-decoder.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/gst-decoder.c b/gst-decoder.c +index fd28201..51304a2 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -63,24 +63,23 @@ static GstPadProbeReturn + pad_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) + { + struct decoder *dec = user_data; +- GstQuery *query = GST_PAD_PROBE_INFO_QUERY(info); +- gboolean need_pool; ++ GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info); + GstCaps *caps; + + (void)pad; + +- if (GST_QUERY_TYPE(query) != GST_QUERY_ALLOCATION) ++ if (GST_EVENT_TYPE(event) != GST_EVENT_CAPS) + return GST_PAD_PROBE_OK; + +- gst_query_parse_allocation(query, &caps, &need_pool); ++ gst_event_parse_caps(event, &caps); + + if (!caps) { +- GST_ERROR("allocation query without caps"); ++ GST_ERROR("caps event without caps"); + return GST_PAD_PROBE_OK; + } + + if (!gst_video_info_from_caps(&dec->info, caps)) { +- GST_ERROR("allocation query with invalid caps"); ++ GST_ERROR("caps event with invalid video caps"); + return GST_PAD_PROBE_OK; + } + +@@ -156,7 +155,7 @@ video_init(const struct egl *egl, const struct gbm *gbm, const char *filename) + g_object_set(G_OBJECT(dec->sink), "max-buffers", 2, NULL); + + gst_pad_add_probe(gst_element_get_static_pad(dec->sink, "sink"), +- GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM, ++ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + pad_probe, dec, NULL); + + /* hack to make sure we get dmabuf's from v4l2video0dec.. */ +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0005-gst-decoder.c-Use-element-factory-name-to-detect-V4L.patch b/recipes-graphics/kmscube/kmscube/0005-gst-decoder.c-Use-element-factory-name-to-detect-V4L.patch new file mode 100644 index 00000000..59766ff2 --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0005-gst-decoder.c-Use-element-factory-name-to-detect-V4L.patch @@ -0,0 +1,48 @@ +From 0e42a19481dac6a0d971eb7ae7503c3db0f349e0 Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 21:45:27 +0200 +Subject: [PATCH kmscube 05/10] gst-decoder.c: Use element factory name to + detect V4L2 video decoder + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + gst-decoder.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/gst-decoder.c b/gst-decoder.c +index 51304a2..05d73b7 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -115,15 +115,24 @@ gst_thread_func(void *args) + static void + element_added_cb(GstBin *bin, GstElement *element, gpointer user_data) + { ++ GstElementFactory *elem_factory; ++ gchar const *factory_name; ++ + (void)user_data; + (void)bin; + +- printf("added: %s\n", GST_OBJECT_NAME(element)); ++ elem_factory = gst_element_get_factory(element); ++ factory_name = gst_plugin_feature_get_name(elem_factory); ++ ++ GST_DEBUG("added element %s (created with factory %s)", GST_OBJECT_NAME(element), factory_name); + +- // XXX is there a better way to do this, like match class name? +- if (strstr(GST_OBJECT_NAME(element), "v4l2video0dec") == GST_OBJECT_NAME(element)) { ++ /* v4l2 video decoder factories are generated by the GStreamer v4l probe. ++ * The format is v4l2videoNdec, where N is an integer. So, check if the ++ * element's factory name fits this pattern. */ ++ if (g_str_has_prefix(factory_name, "v4l2video") && g_str_has_suffix(factory_name, "dec")) { + /* yes, "capture" rather than "output" because v4l2 is bonkers */ + gst_util_set_object_arg(G_OBJECT(element), "capture-io-mode", "dmabuf"); ++ printf("found GStreamer V4L2 video decoder element with name \"%s\"\n", GST_OBJECT_NAME(element)); + } + } + +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0006-gst-decoder.c-add-bus-watch.patch b/recipes-graphics/kmscube/kmscube/0006-gst-decoder.c-add-bus-watch.patch new file mode 100644 index 00000000..de99110c --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0006-gst-decoder.c-add-bus-watch.patch @@ -0,0 +1,150 @@ +From 42e67ce706bf02fa6643fa5822610091c466dbfb Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 21:49:52 +0200 +Subject: [PATCH kmscube 06/10] gst-decoder.c: add bus watch + +The bus watch is useful for logging state changes, printing out +info/warning/error messages and handling common GStreamer activities like +latency redistribution and state change requests (that are sent by +elements since they are not allowed to directly change the state). + +State changes and error messages can also cause a dot graph of the +pipeline to be generated if the GST_DEBUG_DUMP_DOT_DIR environment +variable is set. See the GST_DEBUG_BIN_TO_DOT_FILE documentation for more. + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + gst-decoder.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 103 insertions(+) + +diff --git a/gst-decoder.c b/gst-decoder.c +index 05d73b7..d1cb18c 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -136,11 +136,108 @@ element_added_cb(GstBin *bin, GstElement *element, gpointer user_data) + } + } + ++static gboolean ++bus_watch_cb(GstBus *bus, GstMessage *msg, gpointer user_data) ++{ ++ struct decoder *dec = (struct decoder *)user_data; ++ ++ (void)bus; ++ ++ switch (GST_MESSAGE_TYPE(msg)) { ++ case GST_MESSAGE_STATE_CHANGED: { ++ gchar *dotfilename; ++ GstState old_gst_state, cur_gst_state, pending_gst_state; ++ ++ /* Only consider state change messages coming from ++ * the toplevel element. */ ++ if (GST_MESSAGE_SRC(msg) != GST_OBJECT(dec->pipeline)) ++ break; ++ ++ gst_message_parse_state_changed(msg, &old_gst_state, &cur_gst_state, &pending_gst_state); ++ ++ printf( ++ "GStreamer state change: old: %s current: %s pending: %s\n", ++ gst_element_state_get_name(old_gst_state), ++ gst_element_state_get_name(cur_gst_state), ++ gst_element_state_get_name(pending_gst_state) ++ ); ++ ++ dotfilename = g_strdup_printf( ++ "statechange__old-%s__cur-%s__pending-%s", ++ gst_element_state_get_name(old_gst_state), ++ gst_element_state_get_name(cur_gst_state), ++ gst_element_state_get_name(pending_gst_state) ++ ); ++ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(dec->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, dotfilename); ++ g_free(dotfilename); ++ ++ break; ++ } ++ case GST_MESSAGE_REQUEST_STATE: { ++ GstState requested_state; ++ gst_message_parse_request_state(msg, &requested_state); ++ printf( ++ "state change to %s was requested by %s\n", ++ gst_element_state_get_name(requested_state), ++ GST_MESSAGE_SRC_NAME(msg) ++ ); ++ gst_element_set_state(GST_ELEMENT(dec->pipeline), requested_state); ++ break; ++ } ++ case GST_MESSAGE_LATENCY: { ++ printf("redistributing latency\n"); ++ gst_bin_recalculate_latency(GST_BIN(dec->pipeline)); ++ break; ++ } ++ case GST_MESSAGE_INFO: ++ case GST_MESSAGE_WARNING: ++ case GST_MESSAGE_ERROR: { ++ GError *error = NULL; ++ gchar *debug_info = NULL; ++ gchar const *prefix; ++ ++ switch (GST_MESSAGE_TYPE(msg)) { ++ case GST_MESSAGE_INFO: ++ gst_message_parse_info(msg, &error, &debug_info); ++ prefix = "INFO"; ++ break; ++ case GST_MESSAGE_WARNING: ++ gst_message_parse_warning(msg, &error, &debug_info); ++ prefix = "WARNING"; ++ break; ++ case GST_MESSAGE_ERROR: ++ gst_message_parse_error(msg, &error, &debug_info); ++ prefix = "ERROR"; ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ printf("GStreamer %s: %s; debug info: %s", prefix, error->message, debug_info); ++ ++ g_clear_error(&error); ++ g_free(debug_info); ++ ++ if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) { ++ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(dec->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "error"); ++ } ++ ++ // TODO: stop mainloop in case of an error ++ ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return TRUE; ++} ++ + struct decoder * + video_init(const struct egl *egl, const struct gbm *gbm, const char *filename) + { + struct decoder *dec; + GstElement *src, *decodebin; ++ GstBus *bus; + + dec = calloc(1, sizeof(*dec)); + dec->loop = g_main_loop_new(NULL, FALSE); +@@ -171,6 +268,12 @@ video_init(const struct egl *egl, const struct gbm *gbm, const char *filename) + decodebin = gst_bin_get_by_name(GST_BIN(dec->pipeline), "decode"); + g_signal_connect(decodebin, "element-added", G_CALLBACK(element_added_cb), dec); + ++ /* add bus to be able to receive error message, handle latency ++ * requests, produce pipeline dumps, etc. */ ++ bus = gst_pipeline_get_bus(GST_PIPELINE(dec->pipeline)); ++ gst_bus_add_watch(bus, bus_watch_cb, dec); ++ gst_object_unref(GST_OBJECT(bus)); ++ + /* let 'er rip! */ + gst_element_set_state(dec->pipeline, GST_STATE_PLAYING); + +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0007-gst-decoder.c-minor-cleanup.patch b/recipes-graphics/kmscube/kmscube/0007-gst-decoder.c-minor-cleanup.patch new file mode 100644 index 00000000..959ed180 --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0007-gst-decoder.c-minor-cleanup.patch @@ -0,0 +1,75 @@ +From eebd58fde0a5142afe0a871a3aa4e255faac9c18 Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 23:09:29 +0200 +Subject: [PATCH kmscube 07/10] gst-decoder.c: minor cleanup + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + gst-decoder.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/gst-decoder.c b/gst-decoder.c +index d1cb18c..768aa1b 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -42,6 +42,8 @@ + GST_DEBUG_CATEGORY_EXTERN(kmscube_debug); + #define GST_CAT_DEFAULT kmscube_debug + ++#define MAX_NUM_PLANES 3 ++ + struct decoder { + GMainLoop *loop; + GstElement *pipeline; +@@ -83,7 +85,7 @@ pad_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) + return GST_PAD_PROBE_OK; + } + +- switch (dec->info.finfo->format) { ++ switch (GST_VIDEO_INFO_FORMAT(&(dec->info))) { + case GST_VIDEO_FORMAT_I420: + dec->format = DRM_FORMAT_YUV420; + break; +@@ -264,7 +266,7 @@ video_init(const struct egl *egl, const struct gbm *gbm, const char *filename) + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + pad_probe, dec, NULL); + +- /* hack to make sure we get dmabuf's from v4l2video0dec.. */ ++ /* callback needed to make sure we get dmabuf's from v4l2videoNdec.. */ + decodebin = gst_bin_get_by_name(GST_BIN(dec->pipeline), "decode"); + g_signal_connect(decodebin, "element-added", G_CALLBACK(element_added_cb), dec); + +@@ -322,7 +324,7 @@ buf_to_fd(const struct gbm *gbm, int size, void *ptr) + static EGLImage + buffer_to_image(struct decoder *dec, GstBuffer *buf) + { +- struct { int fd, offset, stride; } planes[3]; ++ struct { int fd, offset, stride; } planes[MAX_NUM_PLANES]; + GstVideoMeta *meta = gst_buffer_get_video_meta(buf); + EGLImage image; + unsigned nmems = gst_buffer_n_memory(buf); +@@ -412,6 +414,7 @@ buffer_to_image(struct decoder *dec, GstBuffer *buf) + EGL_LINUX_DMA_BUF_EXT, NULL, attr); + } + ++ /* Cleanup */ + for (unsigned i = 0; i < nmems; i++) + close(planes[i].fd); + +@@ -426,8 +429,10 @@ video_frame(struct decoder *dec) + EGLImage frame = NULL; + + samp = gst_app_sink_pull_sample(GST_APP_SINK(dec->sink)); +- if (!samp) ++ if (!samp) { ++ GST_DEBUG("got no appsink sample"); + return NULL; ++ } + + buf = gst_sample_get_buffer(samp); + +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0008-gst-decoder.c-use-a-custom-appsink-subclass-to-make-.patch b/recipes-graphics/kmscube/kmscube/0008-gst-decoder.c-use-a-custom-appsink-subclass-to-make-.patch new file mode 100644 index 00000000..d4769d8e --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0008-gst-decoder.c-use-a-custom-appsink-subclass-to-make-.patch @@ -0,0 +1,254 @@ +From a5b27790efb40775209d0e079d4bf021ef1c953c Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 22:55:58 +0200 +Subject: [PATCH kmscube 08/10] gst-decoder.c: use a custom appsink subclass to + make sure videometa exists + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + Makefile.am | 2 +- + gst-decoder.c | 20 ++++++++- + gst-video-appsink.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + gst-video-appsink.h | 31 +++++++++++++ + kmscube.c | 2 + + 5 files changed, 178 insertions(+), 3 deletions(-) + create mode 100644 gst-video-appsink.c + create mode 100644 gst-video-appsink.h + +diff --git a/Makefile.am b/Makefile.am +index a36087d..0407e89 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -57,5 +57,5 @@ kmscube_SOURCES = \ + if ENABLE_GST + kmscube_LDADD += $(GST_LIBS) + kmscube_CFLAGS += $(GST_CFLAGS) +-kmscube_SOURCES += cube-video.c gst-decoder.c ++kmscube_SOURCES += cube-video.c gst-decoder.c gst-video-appsink.c + endif +diff --git a/gst-decoder.c b/gst-decoder.c +index 768aa1b..188fe4b 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -246,9 +246,25 @@ video_init(const struct egl *egl, const struct gbm *gbm, const char *filename) + dec->gbm = gbm; + dec->egl = egl; + +- /* Setup pipeline: */ ++ /* Setup pipeline. Note that we use video_appsink here, not appsink. ++ * video_appsink is an appsink subclass that adds the videometa to ++ * the allocation query's list of metas supported by the sink. ++ * ++ * In some cases, sinks that do not declare videometa as supported ++ * can trigger unexpected behavior when used with video decoders. ++ * For example, with the v4l2videoNdec decoder, if the sink did not ++ * declare videometa as supported, and if the decoder detects that ++ * video frames have padding rows/columns (for example, a 1920x1088 ++ * frame whose last 8 rows are padding rows), then it will perform ++ * an internal CPU-based copy that does not have these padding pixels. ++ * ++ * To avoid such CPU-based copies, make sure the sink declares ++ * videometa as supported. This has the side benefit that the code ++ * inside buffer_to_image() can also make use of the videmeta ++ * information. ++ */ + static const char *pipeline = +- "filesrc name=\"src\" ! decodebin name=\"decode\" ! video/x-raw ! appsink sync=false name=\"sink\""; ++ "filesrc name=\"src\" ! decodebin name=\"decode\" ! video/x-raw ! video_appsink name=\"sink\""; + dec->pipeline = gst_parse_launch(pipeline, NULL); + + dec->sink = gst_bin_get_by_name(GST_BIN(dec->pipeline), "sink"); +diff --git a/gst-video-appsink.c b/gst-video-appsink.c +new file mode 100644 +index 0000000..2c5c15b +--- /dev/null ++++ b/gst-video-appsink.c +@@ -0,0 +1,126 @@ ++/* ++ * Copyright (c) 2017 Carlos Rafael Giani ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include "gst-video-appsink.h" ++ ++ ++typedef struct _GstVideoAppsink GstVideoAppsink; ++typedef struct _GstVideoAppsinkClass GstVideoAppsinkClass; ++ ++ ++#define GST_TYPE_VIDEO_APPSINK (gst_video_appsink_get_type()) ++#define GST_VIDEO_APPSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_VIDEO_APPSINK,GstVideoAppsink)) ++#define GST_VIDEO_APPSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_VIDEO_APPSINK, GstVideoAppsinkClass)) ++#define GST_IS_VIDEO_APPSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VIDEO_APPSINK)) ++#define GST_IS_VIDEO_APPSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VIDEO_APPSINK)) ++ ++ ++struct _GstVideoAppsink ++{ ++ GstAppSink parent; ++}; ++ ++ ++struct _GstVideoAppsinkClass ++{ ++ GstAppSinkClass parent_class; ++}; ++ ++ ++GType gst_video_appsink_get_type(void); ++ ++ ++static gboolean gst_video_appsink_sink_propose_allocation (GstBaseSink *bsink, GstQuery *query); ++ ++ ++G_DEFINE_TYPE(GstVideoAppsink, gst_video_appsink, GST_TYPE_APP_SINK); ++ ++ ++static void ++gst_video_appsink_class_init(GstVideoAppsinkClass *klass) ++{ ++ GstElementClass *element_class = GST_ELEMENT_CLASS(klass); ++ GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS(klass); ++ ++ base_sink_class->propose_allocation = ++ GST_DEBUG_FUNCPTR(gst_video_appsink_sink_propose_allocation); ++ ++ gst_element_class_set_static_metadata( ++ element_class, ++ "video appsink", ++ "Video/Sink", ++ "Appsink subclass for video streams (adds video meta)", ++ "Carlos Rafael Giani " ++ ); ++} ++ ++ ++static void ++gst_video_appsink_init(GstVideoAppsink *video_appsink) ++{ ++ /* QoS and max-lateness lines taken from gstvideosink.c */ ++ gst_base_sink_set_max_lateness(GST_BASE_SINK(video_appsink), 20 * GST_MSECOND); ++ gst_base_sink_set_qos_enabled(GST_BASE_SINK(video_appsink), TRUE); ++} ++ ++ ++static gboolean ++gst_video_appsink_sink_propose_allocation (GstBaseSink *bsink, GstQuery *query) ++{ ++ (void)bsink; ++ ++ gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL); ++ ++ return TRUE; ++} ++ ++ ++ ++ ++static gboolean ++init_internal_video_appsink_plugin(GstPlugin *plugin) ++{ ++ gst_element_register(plugin, "video_appsink", GST_RANK_NONE, gst_video_appsink_get_type()); ++ return TRUE; ++} ++ ++ ++void ++register_gst_video_appsink(void) ++{ ++ gst_plugin_register_static( ++ GST_VERSION_MAJOR, ++ GST_VERSION_MINOR, ++ "internal video appsink plugin", ++ "internal video appsink plugin", ++ init_internal_video_appsink_plugin, ++ "1.0", ++ "BSD", ++ "kmscube", ++ "kmscube", ++ "kmscube" ++ ); ++} +diff --git a/gst-video-appsink.h b/gst-video-appsink.h +new file mode 100644 +index 0000000..d47484a +--- /dev/null ++++ b/gst-video-appsink.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2017 Carlos Rafael Giani ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef _GST_VIDEO_APPSINK_H ++#define _GST_VIDEO_APPSINK_H ++ ++ ++void register_gst_video_appsink(void); ++ ++ ++#endif /* _GST_VIDEO_APPSINK_H */ +diff --git a/kmscube.c b/kmscube.c +index 8e2d008..61509ef 100644 +--- a/kmscube.c ++++ b/kmscube.c +@@ -33,6 +33,7 @@ + + #ifdef HAVE_GST + #include ++#include "gst-video-appsink.h" + GST_DEBUG_CATEGORY(kmscube_debug); + #endif + +@@ -79,6 +80,7 @@ int main(int argc, char *argv[]) + #ifdef HAVE_GST + gst_init(&argc, &argv); + GST_DEBUG_CATEGORY_INIT(kmscube_debug, "kmscube", 0, "kmscube video pipeline"); ++ register_gst_video_appsink(); + #endif + + while ((opt = getopt_long_only(argc, argv, shortopts, longopts, NULL)) != -1) { +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0009-gst-decoder.c-Improve-synchronicity-of-video-output.patch b/recipes-graphics/kmscube/kmscube/0009-gst-decoder.c-Improve-synchronicity-of-video-output.patch new file mode 100644 index 00000000..cd6fa886 --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0009-gst-decoder.c-Improve-synchronicity-of-video-output.patch @@ -0,0 +1,50 @@ +From 82b273fae95ef5c501eb9d81d62ce8d1db49eede Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 22:57:42 +0200 +Subject: [PATCH kmscube 09/10] gst-decoder.c: Improve synchronicity of video + output + +sync=false causes a sink to output data as fast as it can. This explains +why without max-buffers=2 the pipeline used to use up 100's of MB of +buffers. + +Instead, set sync to true, and enable frame dropping, to make sure the +video playback speed remains intact. + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + gst-decoder.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/gst-decoder.c b/gst-decoder.c +index 188fe4b..67efbfd 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -273,10 +273,19 @@ video_init(const struct egl *egl, const struct gbm *gbm, const char *filename) + g_object_set(G_OBJECT(src), "location", filename, NULL); + gst_object_unref(src); + +- /* if we don't limit max-buffers then we can let the decoder outrun +- * vsync and quickly chew up 100's of MB of buffers: ++ /* If frames cannot be displayed on time, drop them. This makes ++ * sure playback speed remains intact even if the EGL display ++ * intervals don't match the pipeline's decoding intervals. ++ * sync=TRUE makes sure the sink blocks the pipeline until the ++ * video frame is scheduled to be output (based on its PTS). ++ * This also avoids excessive CPU usage, since the blocking ++ * wait puts the streaming thread to sleep until the video ++ * frame is due. ++ * max-buffers=1 makes sure only one frame is queued (more are ++ * not necessary). + */ +- g_object_set(G_OBJECT(dec->sink), "max-buffers", 2, NULL); ++ g_object_set(G_OBJECT(dec->sink), "drop", (gboolean)TRUE, "max-buffers", 1, ++ "sync", (gboolean)TRUE, NULL); + + gst_pad_add_probe(gst_element_get_static_pad(dec->sink, "sink"), + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/0010-gst-decoder.c-improve-buffer_to_image-function.patch b/recipes-graphics/kmscube/kmscube/0010-gst-decoder.c-improve-buffer_to_image-function.patch new file mode 100644 index 00000000..7d006e3d --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/0010-gst-decoder.c-improve-buffer_to_image-function.patch @@ -0,0 +1,259 @@ +From f8c5cf72af8add2e0db6d3f73443f1adcff28e4a Mon Sep 17 00:00:00 2001 +From: Carlos Rafael Giani +Date: Fri, 7 Apr 2017 22:58:11 +0200 +Subject: [PATCH kmscube 10/10] gst-decoder.c: improve buffer_to_image() + function + +* Make EGL image attribute specification code more generic, and not + specific to certain pixel formats, implicitely gaining support for YUY2 +* Better handling of gstbuffers with multiple memory blocks +* Print out more information about the stream +* Use the GST_VIDEO_INFO_* macros instead of directly accessing the + GstVideoInfo fields; this is what the GStreamer documentation recommends + +Upstream-Status: Submitted [mesa-dev mailing list] + +Signed-off-by: Carlos Rafael Giani +--- + gst-decoder.c | 196 +++++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 119 insertions(+), 77 deletions(-) + +diff --git a/gst-decoder.c b/gst-decoder.c +index 67efbfd..cc5c3b2 100644 +--- a/gst-decoder.c ++++ b/gst-decoder.c +@@ -1,5 +1,6 @@ + /* + * Copyright (c) 2017 Rob Clark ++ * Copyright (c) 2017 Carlos Rafael Giani + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), +@@ -44,6 +45,12 @@ GST_DEBUG_CATEGORY_EXTERN(kmscube_debug); + + #define MAX_NUM_PLANES 3 + ++inline static const char * ++yesno(int yes) ++{ ++ return yes ? "yes" : "no"; ++} ++ + struct decoder { + GMainLoop *loop; + GstElement *pipeline; +@@ -100,9 +107,6 @@ pad_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) + return GST_PAD_PROBE_OK; + } + +- GST_DEBUG("got: %ux%u@%4.4s\n", dec->info.width, dec->info.height, +- (char *)&dec->format); +- + return GST_PAD_PROBE_OK; + } + +@@ -352,89 +356,127 @@ buffer_to_image(struct decoder *dec, GstBuffer *buf) + struct { int fd, offset, stride; } planes[MAX_NUM_PLANES]; + GstVideoMeta *meta = gst_buffer_get_video_meta(buf); + EGLImage image; +- unsigned nmems = gst_buffer_n_memory(buf); +- unsigned nplanes = (dec->format == DRM_FORMAT_YUV420) ? 3 : 2; +- unsigned i; +- +- if (nmems == nplanes) { +- // XXX TODO.. +- } else if (nmems == 1) { +- GstMemory *mem = gst_buffer_peek_memory(buf, 0); +- int fd; +- +- if (dec->frame == 0) { +- printf("%s zero-copy\n", gst_is_dmabuf_memory(mem) ? "using" : "not"); ++ guint nmems = gst_buffer_n_memory(buf); ++ guint nplanes = GST_VIDEO_INFO_N_PLANES(&(dec->info)); ++ guint i; ++ guint width, height; ++ gboolean is_dmabuf_mem; ++ GstMemory *mem; ++ int dmabuf_fd = -1; ++ ++ static const EGLint egl_dmabuf_plane_fd_attr[MAX_NUM_PLANES] = { ++ EGL_DMA_BUF_PLANE0_FD_EXT, ++ EGL_DMA_BUF_PLANE1_FD_EXT, ++ EGL_DMA_BUF_PLANE2_FD_EXT, ++ }; ++ static const EGLint egl_dmabuf_plane_offset_attr[MAX_NUM_PLANES] = { ++ EGL_DMA_BUF_PLANE0_OFFSET_EXT, ++ EGL_DMA_BUF_PLANE1_OFFSET_EXT, ++ EGL_DMA_BUF_PLANE2_OFFSET_EXT, ++ }; ++ static const EGLint egl_dmabuf_plane_pitch_attr[MAX_NUM_PLANES] = { ++ EGL_DMA_BUF_PLANE0_PITCH_EXT, ++ EGL_DMA_BUF_PLANE1_PITCH_EXT, ++ EGL_DMA_BUF_PLANE2_PITCH_EXT, ++ }; ++ ++ /* Query gst_is_dmabuf_memory() here, since the gstmemory ++ * block might get merged below by gst_buffer_map(), meaning ++ * that the mem pointer would become invalid */ ++ mem = gst_buffer_peek_memory(buf, 0); ++ is_dmabuf_mem = gst_is_dmabuf_memory(mem); ++ ++ if (nmems > 1) { ++ if (is_dmabuf_mem) { ++ /* this case currently is not defined */ ++ ++ GST_FIXME("gstbuffers with multiple memory blocks and DMABUF " ++ "memory currently are not supported"); ++ return EGL_NO_IMAGE_KHR; + } + +- if (gst_is_dmabuf_memory(mem)) { +- fd = dup(gst_dmabuf_memory_get_fd(mem)); +- } else { +- GstMapInfo info; +- gst_memory_map(mem, &info, GST_MAP_READ); +- fd = buf_to_fd(dec->gbm, info.size, info.data); +- gst_memory_unmap(mem, &info); +- } ++ /* if this is not DMABUF memory, then the gst_buffer_map() ++ * call below will automatically merge the memory blocks ++ */ ++ } + +- // XXX why don't we get meta?? +- if (meta) { +- for (i = 0; i < nplanes; i++) { +- planes[i].fd = fd; +- planes[i].offset = meta->offset[i]; +- planes[i].stride = meta->stride[i]; +- } +- } else { +- int offset = 0, stride = dec->info.width, height = dec->info.height; +- +- for (i = 0; i < nplanes; i++) { +- +- if (i == 1) { +- height /= 2; +- if (nplanes == 3) +- stride /= 2; +- } +- +- planes[i].fd = fd; +- planes[i].offset = offset; +- planes[i].stride = stride; +- +- offset += stride * height; +- } +- } ++ if (is_dmabuf_mem) { ++ dmabuf_fd = dup(gst_dmabuf_memory_get_fd(mem)); ++ } else { ++ GstMapInfo map_info; ++ gst_buffer_map(buf, &map_info, GST_MAP_READ); ++ dmabuf_fd = buf_to_fd(dec->gbm, map_info.size, map_info.data); ++ gst_buffer_unmap(buf, &map_info); + } + +- if (dec->format == DRM_FORMAT_NV12) { +- const EGLint attr[] = { +- EGL_WIDTH, dec->info.width, +- EGL_HEIGHT, dec->info.height, +- EGL_LINUX_DRM_FOURCC_EXT, dec->format, +- EGL_DMA_BUF_PLANE0_FD_EXT, planes[0].fd, +- EGL_DMA_BUF_PLANE0_OFFSET_EXT, planes[0].offset, +- EGL_DMA_BUF_PLANE0_PITCH_EXT, planes[0].stride, +- EGL_DMA_BUF_PLANE1_FD_EXT, planes[1].fd, +- EGL_DMA_BUF_PLANE1_OFFSET_EXT, planes[1].offset, +- EGL_DMA_BUF_PLANE1_PITCH_EXT, planes[1].stride, +- EGL_NONE +- }; ++ if (dmabuf_fd < 0) { ++ GST_ERROR("could not obtain DMABUF FD"); ++ return EGL_NO_IMAGE_KHR; ++ } + +- image = dec->egl->eglCreateImageKHR(dec->egl->display, EGL_NO_CONTEXT, +- EGL_LINUX_DMA_BUF_EXT, NULL, attr); ++ /* Usually, a videometa should be present, since by using the internal kmscube ++ * video_appsink element instead of the regular appsink, it is guaranteed that ++ * video meta support is declared in the video_appsink's allocation query. ++ * However, this assumes that upstream elements actually look at the allocation ++ * query's contents properly, or that they even send a query at all. If this ++ * is not the case, then upstream might decide to push frames without adding ++ * a meta. It can happen, and in this case, look at the video info data as ++ * a fallback (it is computed out of the input caps). ++ */ ++ if (meta) { ++ for (i = 0; i < nplanes; i++) { ++ planes[i].fd = dmabuf_fd; ++ planes[i].offset = meta->offset[i]; ++ planes[i].stride = meta->stride[i]; ++ } + } else { +- const EGLint attr[] = { +- EGL_WIDTH, dec->info.width, +- EGL_HEIGHT, dec->info.height, +- EGL_LINUX_DRM_FOURCC_EXT, dec->format, +- EGL_DMA_BUF_PLANE0_FD_EXT, planes[0].fd, +- EGL_DMA_BUF_PLANE0_OFFSET_EXT, planes[0].offset, +- EGL_DMA_BUF_PLANE0_PITCH_EXT, planes[0].stride, +- EGL_DMA_BUF_PLANE1_FD_EXT, planes[1].fd, +- EGL_DMA_BUF_PLANE1_OFFSET_EXT, planes[1].offset, +- EGL_DMA_BUF_PLANE1_PITCH_EXT, planes[1].stride, +- EGL_DMA_BUF_PLANE2_FD_EXT, planes[2].fd, +- EGL_DMA_BUF_PLANE2_OFFSET_EXT, planes[2].offset, +- EGL_DMA_BUF_PLANE2_PITCH_EXT, planes[2].stride, +- EGL_NONE ++ for (i = 0; i < nplanes; i++) { ++ planes[i].fd = dmabuf_fd; ++ planes[i].offset = GST_VIDEO_INFO_PLANE_OFFSET(&(dec->info), i); ++ planes[i].stride = GST_VIDEO_INFO_PLANE_STRIDE(&(dec->info), i); ++ } ++ } ++ ++ width = GST_VIDEO_INFO_WIDTH(&(dec->info)); ++ height = GST_VIDEO_INFO_HEIGHT(&(dec->info)); ++ ++ /* output some information at the beginning (= when the first frame is handled) */ ++ if (dec->frame == 0) { ++ GstVideoFormat pixfmt; ++ const char *pixfmt_str; ++ ++ pixfmt = GST_VIDEO_INFO_FORMAT(&(dec->info)); ++ pixfmt_str = gst_video_format_to_string(pixfmt); ++ ++ printf("===================================\n"); ++ printf("GStreamer video stream information:\n"); ++ printf(" size: %u x %u pixel\n", width, height); ++ printf(" pixel format: %s number of planes: %u\n", pixfmt_str, nplanes); ++ printf(" can use zero-copy: %s\n", yesno(is_dmabuf_mem)); ++ printf(" video meta found: %s\n", yesno(meta != NULL)); ++ printf("===================================\n"); ++ } ++ ++ { ++ /* Initialize the first 6 attributes with values that are ++ * plane invariant (width, height, format) */ ++ EGLint attr[6 + 6*(MAX_NUM_PLANES) + 1] = { ++ EGL_WIDTH, width, ++ EGL_HEIGHT, height, ++ EGL_LINUX_DRM_FOURCC_EXT, dec->format + }; + ++ for (i = 0; i < nplanes; i++) { ++ attr[6 + 6*i + 0] = egl_dmabuf_plane_fd_attr[i]; ++ attr[6 + 6*i + 1] = planes[i].fd; ++ attr[6 + 6*i + 2] = egl_dmabuf_plane_offset_attr[i]; ++ attr[6 + 6*i + 3] = planes[i].offset; ++ attr[6 + 6*i + 4] = egl_dmabuf_plane_pitch_attr[i]; ++ attr[6 + 6*i + 5] = planes[i].stride; ++ } ++ ++ attr[6 + 6*nplanes] = EGL_NONE; ++ + image = dec->egl->eglCreateImageKHR(dec->egl->display, EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, NULL, attr); + } +-- +2.7.4 + diff --git a/recipes-graphics/kmscube/kmscube/use-dri-card1-by-default.patch b/recipes-graphics/kmscube/kmscube/use-dri-card1-by-default.patch new file mode 100644 index 00000000..4844ff7f --- /dev/null +++ b/recipes-graphics/kmscube/kmscube/use-dri-card1-by-default.patch @@ -0,0 +1,18 @@ +On i.MX devices, etnaviv is located at /dev/dri/card1 . For convenience, make +this the default instead of card0. + +Upstream-Status: Inappropriate [i.MX specific] + +diff --git a/kmscube.c b/kmscube.c +index 61509ef..9cc05d7 100644 +--- a/kmscube.c ++++ b/kmscube.c +@@ -71,7 +71,7 @@ static void usage(const char *name) + + int main(int argc, char *argv[]) + { +- const char *device = "/dev/dri/card0"; ++ const char *device = "/dev/dri/card1"; + const char *video = NULL; + enum mode mode = SMOOTH; + int atomic = 0; diff --git a/recipes-graphics/kmscube/kmscube_%.bbappend b/recipes-graphics/kmscube/kmscube_%.bbappend new file mode 100644 index 00000000..21526906 --- /dev/null +++ b/recipes-graphics/kmscube/kmscube_%.bbappend @@ -0,0 +1,14 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI_append = " file://0001-output-more-and-improved-information-about-EGL-and-O.patch \ + file://0002-add-kmscube-GStreamer-debug-category.patch \ + file://0003-gst-decoder.c-add-support-for-YUY2-pixel-format.patch \ + file://0004-gst-decoder.c-look-at-the-caps-event-instead-of-the-.patch \ + file://0005-gst-decoder.c-Use-element-factory-name-to-detect-V4L.patch \ + file://0006-gst-decoder.c-add-bus-watch.patch \ + file://0007-gst-decoder.c-minor-cleanup.patch \ + file://0008-gst-decoder.c-use-a-custom-appsink-subclass-to-make-.patch \ + file://0009-gst-decoder.c-Improve-synchronicity-of-video-output.patch \ + file://0010-gst-decoder.c-improve-buffer_to_image-function.patch \ + file://use-dri-card1-by-default.patch \ +" -- 2.40.1