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
84 goto drop;
85 }
86 return GST_BUS_PASS;
87
88 drop:
89 gst_message_unref (message);
90 return GST_BUS_DROP;
91 }
92
93 static void
registry_handle(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)94 registry_handle (void *data, struct wl_registry *registry,
95 uint32_t id, const char *interface, uint32_t version)
96 {
97 App *app = data;
98
99 if (g_strcmp0 (interface, "wl_compositor") == 0) {
100 app->compositor =
101 wl_registry_bind (app->registry, id, &wl_compositor_interface,
102 MIN (version, 3));
103 }
104 }
105
106 static const struct wl_registry_listener registry_listener = {
107 registry_handle
108 };
109
110 static gpointer
wl_main_thread_run(gpointer data)111 wl_main_thread_run (gpointer data)
112 {
113 App *app = data;
114 while (wl_display_dispatch_queue (app->display, app->queue) != -1)
115 return NULL;
116
117 return NULL;
118 }
119
120 static GstElement *
build_pipeline(App * app,gint num_buffers)121 build_pipeline (App * app, gint num_buffers)
122 {
123 GstElement *pipeline;
124 GstBus *bus;
125 gchar *str;
126
127 str =
128 g_strdup_printf ("videotestsrc num-buffers=%d ! waylandsink",
129 num_buffers);
130
131 pipeline = gst_parse_launch (str, NULL);
132 g_free (str);
133 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
134 gst_bus_add_signal_watch (bus);
135 g_signal_connect (bus, "message", G_CALLBACK (message_cb), app);
136 gst_bus_set_sync_handler (bus, bus_sync_handler, app, NULL);
137 gst_object_unref (bus);
138
139 return pipeline;
140 }
141
142 int
main(int argc,char ** argv)143 main (int argc, char **argv)
144 {
145 App *app;
146 GError *error = NULL;
147
148 gst_init (&argc, &argv);
149
150 app = g_slice_new0 (App);
151
152 app->loop = g_main_loop_new (NULL, FALSE);
153
154 app->display = wl_display_connect (NULL);
155 if (!app->display)
156 goto done;
157 app->display_wrapper = wl_proxy_create_wrapper (app->display);
158 app->queue = wl_display_create_queue (app->display);
159 wl_proxy_set_queue ((struct wl_proxy *) app->display_wrapper, app->queue);
160 app->registry = wl_display_get_registry (app->display_wrapper);
161 wl_registry_add_listener (app->registry, ®istry_listener, app);
162
163 wl_display_roundtrip_queue (app->display, app->queue);
164 wl_display_roundtrip_queue (app->display, app->queue);
165
166 if (!app->compositor) {
167 g_set_error (&error, g_quark_from_static_string ("waylandMultiThreads"), 0,
168 "Could not bind to wl_compositor interface");
169 goto done;
170 }
171
172 app->thread =
173 g_thread_try_new ("WlMainThread", wl_main_thread_run, app, &error);
174 if (error) {
175 gst_printerrln ("error: %s", error->message);
176 g_error_free (error);
177 goto done;
178 }
179
180 app->pipeline1 = build_pipeline (app, 30);
181 app->pipeline2 = build_pipeline (app, 40);
182
183 gst_element_set_state (app->pipeline1, GST_STATE_PLAYING);
184 gst_element_set_state (app->pipeline2, GST_STATE_PLAYING);
185
186 g_main_loop_run (app->loop);
187
188 gst_element_set_state (app->pipeline1, GST_STATE_NULL);
189 gst_element_set_state (app->pipeline2, GST_STATE_NULL);
190
191 gst_object_unref (app->pipeline1);
192 gst_object_unref (app->pipeline2);
193
194 done:
195 if (app->thread)
196 g_thread_join (app->thread);
197
198 if (app->compositor)
199 wl_compositor_destroy (app->compositor);
200 if (app->registry)
201 wl_registry_destroy (app->registry);
202 if (app->queue)
203 wl_event_queue_destroy (app->queue);
204 if (app->display_wrapper)
205 wl_proxy_wrapper_destroy (app->display_wrapper);
206 if (app->display) {
207 wl_display_flush (app->display);
208 wl_display_disconnect (app->display);
209 }
210 g_slice_free (App, app);
211 return 0;
212 }
213