• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 LG Electronics
3  *   @author Wonchul Lee <w.lee@lge.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include <gst/gst.h>
22 
23 #include <gst/video/videooverlay.h>
24 #include <gst/wayland/wayland.h>
25 
26 static gint retry = 100;
27 
28 typedef struct
29 {
30   struct wl_display *display;
31   struct wl_display *display_wrapper;
32   struct wl_registry *registry;
33   struct wl_compositor *compositor;
34   struct wl_event_queue *queue;
35 
36   GThread *thread;
37 
38   GstElement *pipeline1;
39   GstElement *pipeline2;
40   GstVideoOverlay *overlay;
41   GMainLoop *loop;
42 } App;
43 
44 static gboolean
message_cb(GstBus * bus,GstMessage * message,gpointer user_data)45 message_cb (GstBus * bus, GstMessage * message, gpointer user_data)
46 {
47   App *app = user_data;
48   switch (GST_MESSAGE_TYPE (message)) {
49     case GST_MESSAGE_ERROR:{
50       GError *err = NULL;
51       gchar *debug = NULL;
52 
53       gst_message_parse_error (message, &err, &debug);
54       gst_printerrln ("Error message received: %s", err->message);
55       gst_printerrln ("Debug info: %s", debug);
56       g_error_free (err);
57       g_free (debug);
58     }
59     case GST_MESSAGE_EOS:
60       if (retry <= 0)
61         g_main_loop_quit (app->loop);
62       gst_element_set_state (GST_ELEMENT (GST_MESSAGE_SRC (message)),
63           GST_STATE_NULL);
64       gst_element_set_state (GST_ELEMENT (GST_MESSAGE_SRC (message)),
65           GST_STATE_PLAYING);
66       retry--;
67       break;
68     default:
69       break;
70   }
71   return TRUE;
72 }
73 
74 static GstBusSyncReply
bus_sync_handler(GstBus * bus,GstMessage * message,gpointer user_data)75 bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data)
76 {
77   App *app = user_data;
78 
79   if (gst_is_wayland_display_handle_need_context_message (message)) {
80     GstContext *context;
81     context = gst_wayland_display_handle_context_new (app->display);
82     gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (message)), context);
83     gst_context_unref (context);
84 
85     goto drop;
86   }
87   return GST_BUS_PASS;
88 
89 drop:
90   gst_message_unref (message);
91   return GST_BUS_DROP;
92 }
93 
94 static void
registry_handle(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)95 registry_handle (void *data, struct wl_registry *registry,
96     uint32_t id, const char *interface, uint32_t version)
97 {
98   App *app = data;
99 
100   if (g_strcmp0 (interface, "wl_compositor") == 0) {
101     app->compositor =
102         wl_registry_bind (app->registry, id, &wl_compositor_interface,
103         MIN (version, 3));
104   }
105 }
106 
107 static const struct wl_registry_listener registry_listener = {
108   registry_handle
109 };
110 
111 static gpointer
wl_main_thread_run(gpointer data)112 wl_main_thread_run (gpointer data)
113 {
114   App *app = data;
115   while (wl_display_dispatch_queue (app->display, app->queue) != -1)
116     return NULL;
117 
118   return NULL;
119 }
120 
121 static GstElement *
build_pipeline(App * app,gint num_buffers)122 build_pipeline (App * app, gint num_buffers)
123 {
124   GstElement *pipeline;
125   GstBus *bus;
126   gchar *str;
127 
128   str =
129       g_strdup_printf ("videotestsrc num-buffers=%d ! waylandsink",
130       num_buffers);
131 
132   pipeline = gst_parse_launch (str, NULL);
133   g_free (str);
134   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
135   gst_bus_add_signal_watch (bus);
136   g_signal_connect (bus, "message", G_CALLBACK (message_cb), app);
137   gst_bus_set_sync_handler (bus, bus_sync_handler, app, NULL);
138   gst_object_unref (bus);
139 
140   return pipeline;
141 }
142 
143 int
main(int argc,char ** argv)144 main (int argc, char **argv)
145 {
146   App *app;
147   GError *error = NULL;
148 
149   gst_init (&argc, &argv);
150 
151   app = g_slice_new0 (App);
152 
153   app->loop = g_main_loop_new (NULL, FALSE);
154 
155   app->display = wl_display_connect (NULL);
156   if (!app->display)
157     goto done;
158   app->display_wrapper = wl_proxy_create_wrapper (app->display);
159   app->queue = wl_display_create_queue (app->display);
160   wl_proxy_set_queue ((struct wl_proxy *) app->display_wrapper, app->queue);
161   app->registry = wl_display_get_registry (app->display_wrapper);
162   wl_registry_add_listener (app->registry, &registry_listener, app);
163 
164   wl_display_roundtrip_queue (app->display, app->queue);
165   wl_display_roundtrip_queue (app->display, app->queue);
166 
167   if (!app->compositor) {
168     g_set_error (&error, g_quark_from_static_string ("waylandMultiThreads"), 0,
169         "Could not bind to wl_compositor interface");
170     goto done;
171   }
172 
173   app->thread =
174       g_thread_try_new ("WlMainThread", wl_main_thread_run, app, &error);
175   if (error) {
176     gst_printerrln ("error: %s", error->message);
177     g_error_free (error);
178     goto done;
179   }
180 
181   app->pipeline1 = build_pipeline (app, 30);
182   app->pipeline2 = build_pipeline (app, 40);
183 
184   gst_element_set_state (app->pipeline1, GST_STATE_PLAYING);
185   gst_element_set_state (app->pipeline2, GST_STATE_PLAYING);
186 
187   g_main_loop_run (app->loop);
188 
189   gst_element_set_state (app->pipeline1, GST_STATE_NULL);
190   gst_element_set_state (app->pipeline2, GST_STATE_NULL);
191 
192   gst_object_unref (app->pipeline1);
193   gst_object_unref (app->pipeline2);
194 
195 done:
196   if (app->thread)
197     g_thread_join (app->thread);
198 
199   if (app->compositor)
200     wl_compositor_destroy (app->compositor);
201   if (app->registry)
202     wl_registry_destroy (app->registry);
203   if (app->queue)
204     wl_event_queue_destroy (app->queue);
205   if (app->display_wrapper)
206     wl_proxy_wrapper_destroy (app->display_wrapper);
207   if (app->display) {
208     wl_display_flush (app->display);
209     wl_display_disconnect (app->display);
210   }
211   g_slice_free (App, app);
212   return 0;
213 }
214