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, ®istry_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