2 * Copyright (C) 2016 Renesas Electronics Corporation
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 #include <gst/video/video.h>
23 #include <gst/video/videooverlay.h>
25 #include <gst/wayland/wayland.h>
27 #include <glib-unix.h>
29 #include <wayland-client.h>
31 #include <linux/input.h>
33 #include <sys/types.h>
42 #define INFINITE_LOOP_PLAYBACK -1
47 #include "gst-wayland-demo.hpp"
51 #include <libwebsockets.h>
53 #include <sys/syscall.h>
66 #include <sys/socket.h>
67 #include <sys/ioctl.h>
70 #include <linux/can.h>
71 #include <linux/can/raw.h>
78 void websocket_init();
79 void lws_touch_handle_down(uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
80 void lws_touch_handle_up(uint32_t time, int32_t id);
81 void lws_touch_handle_motion(uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
94 struct wl_display *display;
95 struct wl_event_queue *queue;
96 struct wl_registry *registry;
97 struct wl_compositor *compositor;
98 struct wl_shell *shell;
100 struct wl_seat *seat;
101 struct wl_pointer *pointer;
102 struct wl_touch *touch;
104 GList *shell_surfaces;
107 struct wl_surface *focused_surface;
111 guint signal_watch_id;
115 void fatal(const char* format, ...)
118 va_start(va_args, format);
119 vfprintf(stderr, format, va_args);
125 void warn(const char* format, ...)
128 va_start(va_args, format);
129 vfprintf(stderr, format, va_args);
133 void debug(const char* format, ...)
136 va_start(va_args, format);
137 vfprintf(stderr, format, va_args);
141 static void event_loop_run(struct sd_event* loop){
143 sd_event_unref(loop);
150 static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
154 static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
158 static void _on_event_static(void* closure, const char* event, struct afb_wsj1_msg *msg)
160 static_cast<RunXDG*>(closure)->on_event(NULL,event,msg);
163 static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)
165 AGL_DEBUG("_on_reply_static msg: (%s)", afb_wsj1_msg_object_s(msg));
168 void RunXDG::notify_ivi_control_cb (ilmObjectType object, t_ilm_uint id,
171 if (object == ILM_SURFACE) {
172 struct ilmSurfaceProperties surf_props;
174 ilm_getPropertiesOfSurface(id, &surf_props);
175 pid_t surf_pid = surf_props.creatorPid;
177 fprintf(stderr, "ivi surface (id=%d, pid=%d) destroyed. \n", id, surf_pid);
181 fprintf(stderr, "ivi surface (id=%d, pid=%d) is created. \n", id, surf_pid);
182 if (surf_pid == m_pid)
189 fprintf(stderr, "ivi surface is not created. \n");
193 void RunXDG::notify_ivi_control_cb_static (ilmObjectType object, t_ilm_uint id,
194 t_ilm_bool created, void *user_data)
196 fprintf(stderr, "notify_ivi_control_cb_static called. \n");
197 RunXDG *runxdg = static_cast<RunXDG*>(user_data);
198 runxdg->notify_ivi_control_cb(object, id, created);
201 int RunXDG::init_wm (void)
203 m_wm = new LibWindowmanager();
204 if (m_wm->init(m_port, m_token.c_str())) {
205 AGL_DEBUG("cannot initialize windowmanager");
209 std::function< void(json_object*) > h_active = [this](json_object* object) {
210 AGL_DEBUG("Got Event_Active");
211 t_ilm_surface s_ids[1] = { this->m_ivi_id };
212 ilm_setInputFocus(s_ids, 1, ILM_INPUT_DEVICE_KEYBOARD, ILM_TRUE);
215 std::function< void(json_object*) > h_inactive = [this](json_object* object) {
216 AGL_DEBUG("Got Event_Inactive");
217 t_ilm_surface s_ids[1] = { this->m_ivi_id };
218 ilm_setInputFocus(s_ids, 1, ILM_INPUT_DEVICE_KEYBOARD, ILM_FALSE);
221 std::function< void(json_object*) > h_visible = [](json_object* object) {
222 AGL_DEBUG("Got Event_Visible");
225 std::function< void(json_object*) > h_invisible = [](json_object* object) {
226 AGL_DEBUG("Got Event_Invisible");
229 std::function< void(json_object*) > h_syncdraw =
230 [this](json_object* object) {
231 AGL_DEBUG("Got Event_SyncDraw");
232 this->m_wm->endDraw(this->m_role.c_str());
235 std::function< void(json_object*) > h_flushdraw= [](json_object* object) {
236 AGL_DEBUG("Got Event_FlushDraw");
239 m_wm->set_event_handler(LibWindowmanager::Event_Active, h_active);
240 m_wm->set_event_handler(LibWindowmanager::Event_Inactive, h_inactive);
241 m_wm->set_event_handler(LibWindowmanager::Event_Visible, h_visible);
242 m_wm->set_event_handler(LibWindowmanager::Event_Invisible, h_invisible);
243 m_wm->set_event_handler(LibWindowmanager::Event_SyncDraw, h_syncdraw);
244 m_wm->set_event_handler(LibWindowmanager::Event_FlushDraw, h_flushdraw);
249 int RunXDG::init_hs (void)
251 m_hs = new LibHomeScreen();
252 if (m_hs->init(m_port, m_token.c_str())) {
253 AGL_DEBUG("cannot initialize homescreen");
257 std::function< void(json_object*) > handler = [this] (json_object* object) {
258 AGL_DEBUG("Activesurface %s ", this->m_role.c_str());
259 this->m_wm->activateWindow(this->m_role.c_str(), "normal.full");
261 m_hs->set_event_handler(LibHomeScreen::Event_ShowWindow, handler);
263 std::function< void(json_object*) > h_default= [](json_object* object) {
264 const char *j_str = json_object_to_json_string(object);
265 AGL_DEBUG("Got event [%s]", j_str);
267 m_hs->set_event_handler(LibHomeScreen::Event_OnScreenMessage, h_default);
272 int RunXDG::init_carlaclient(void)
274 memset(&m_carla_info, 0, sizeof(struct Carla_Info));
275 int ret = sd_event_new(&mploop);
278 AGL_DEBUG("Failed to create event loop");
283 // enforce context to avoid initialization/goto error
284 std::thread th(event_loop_run, mploop);
288 /* Initialize interface from websocket */
289 minterface.on_hangup = _on_hangup_static;
290 minterface.on_call = _on_call_static;
291 minterface.on_event = _on_event_static;
292 muri += "ws://localhost:" + std::to_string(m_port) + "/api?token=" + m_token; /*To be modified*/
293 sp_websock = afb_ws_client_connect_wsj1(mploop, muri.c_str(), &minterface, this);
294 if(sp_websock == NULL) {
295 AGL_DEBUG("Failed to create websocket connection");
299 struct json_object* j_obj = json_object_new_object();
300 json_object_object_add(j_obj, "event", json_object_new_int(0));
302 ret = afb_wsj1_call_j(sp_websock, "carlaclient", "subscribe", j_obj, _on_reply_static, this);
304 AGL_DEBUG("Failed to call carlaclient subscribe verb");
307 struct json_object* speed_obj = json_object_new_object();
308 json_object_object_add(speed_obj, "event", json_object_new_string("vehicle.average.speed"));
310 ret = afb_wsj1_call_j(sp_websock, "low-can", "subscribe", speed_obj, _on_reply_static, this);
312 AGL_DEBUG("Failed to call low-can subscribe verb");
318 void RunXDG::on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
320 AGL_DEBUG("event: (%s) msg: (%s).", event, afb_wsj1_msg_object_s(msg));
321 struct json_object* ev_contents = afb_wsj1_msg_object_j(msg);
322 if(!strcasecmp(event, "carlaclient/positionUpdated")) {
323 struct json_object *json_data;
324 if(!json_object_object_get_ex(ev_contents, "data", &json_data)) {
325 AGL_DEBUG("got ev_contents error.");
329 struct json_object *longitude_obj, *latitude_obj, *yaw_obj;
330 if(json_object_object_get_ex(json_data, "longitude", &longitude_obj)
331 && json_object_object_get_ex(json_data, "latitude", &latitude_obj)
332 && json_object_object_get_ex(json_data, "yaw", &yaw_obj)) {
333 AGL_DEBUG("got yaw(%s) longitude(%s) latitude(%s).", json_object_get_string(yaw_obj), json_object_get_string(longitude_obj), json_object_get_string(latitude_obj));
334 m_carla_info.yaw = json_object_get_string(yaw_obj);
335 std::string::size_type sz;
336 m_carla_info.longitude = std::stod(json_object_get_string(longitude_obj), &sz);
337 m_carla_info.latitude = std::stod(json_object_get_string(latitude_obj), &sz);
338 // TBD: call sdl interface
341 else if(!strcasecmp(event, "low-can/messages.vehicle.average.speed")) {
342 // [5,"low-can/messages.vehicle.average.speed",{"event":"low-can\/messages.vehicle.average.speed","data":{"value":10},"jtype":"afb-event"}]
344 if(json_object_get_type(ev_contents) == json_type_array) {
345 int array_len = json_object_array_length(ev_contents);
346 struct json_object *event_obj = json_object_array_get_idx(ev_contents, 2);
347 struct json_object *data_obj, *val_obj;
348 if(json_object_object_get_ex(event_obj, "data", &data_obj)
349 &&json_object_object_get_ex(data_obj, "value", &val_obj)) {
350 m_carla_info.speed = json_object_get_int(val_obj);
356 RunXDG::RunXDG (int port, const char* token, const char* id)
358 m_id = std::string(id);
360 m_token = std::string(token);
361 m_role = "gstwayland";
364 // Setup HomeScreen/WindowManager API
366 AGL_FATAL("cannot setup wm API");
369 AGL_FATAL("cannot setup hs API");
371 if (init_carlaclient())
372 AGL_FATAL("cannot setup carlaclient API");
374 // Setup ilmController API
375 m_ic = new ILMControl(notify_ivi_control_cb_static, this);
377 fprintf(stderr, "RunXDG created. \n");
380 void RunXDG::setup_ivi_surface (void)
382 std::string sid = std::to_string(m_ivi_id);
384 // This surface is mine, register pair app_name and ivi id.
385 AGL_DEBUG("requestSurfaceXDG(%s,%d)", m_role.c_str(), m_ivi_id);
386 m_wm->requestSurfaceXDG(this->m_role.c_str(), (unsigned int)m_ivi_id);
388 if (m_pending_create) {
389 // Recovering 1st time tap_shortcut is dropped because
390 // the application has not been run yet (1st time launch)
391 m_pending_create = false;
392 // m_wm->activateWindow(this->m_role.c_str(), "normal.full");
393 m_hs->publishSubscription();
397 void RunXDG::start (void)
399 // take care 1st time launch
400 AGL_DEBUG("waiting for notification: surafce created");
401 m_pending_create = true;
408 pointer_handle_enter (void *data, struct wl_pointer *pointer,
409 uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy)
411 fprintf(stderr, "%s called. \n", __func__);
412 // GstWlDemo *priv = data;
414 // priv->focused_surface = surface;
418 pointer_handle_leave (void *data, struct wl_pointer *pointer,
419 uint32_t serial, struct wl_surface *surface)
421 fprintf(stderr, "%s called. \n", __func__);
422 // GstWlDemo *priv = data;
424 // priv->focused_surface = NULL;
428 pointer_handle_motion (void *data, struct wl_pointer *pointer,
429 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
431 fprintf(stderr, "%s called. \n", __func__);
435 pointer_handle_button (void *data, struct wl_pointer *wl_pointer,
436 uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
438 fprintf(stderr, "%s called. \n", __func__);
439 // GstWlDemo *priv = data;
440 // struct wl_shell_surface *shell_surface;
442 // if (!priv->focused_surface)
445 // shell_surface = wl_surface_get_user_data (priv->focused_surface);
447 // if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
448 // wl_shell_surface_move (shell_surface, priv->seat, serial);
452 pointer_handle_axis (void *data, struct wl_pointer *wl_pointer,
453 uint32_t time, uint32_t axis, wl_fixed_t value)
455 fprintf(stderr, "%s called. \n", __func__);
458 static const struct wl_pointer_listener pointer_listener = {
459 pointer_handle_enter,
460 pointer_handle_leave,
461 pointer_handle_motion,
462 pointer_handle_button,
467 touch_handle_down (void *data, struct wl_touch *wl_touch,
468 uint32_t serial, uint32_t time, struct wl_surface *surface,
469 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
471 fprintf(stderr, "%s called. \n", __func__);
473 double cx = wl_fixed_to_double(x_w);
474 double cy = wl_fixed_to_double(y_w);
475 fprintf(stderr, "log: %s: cx=%f cy=%f", __func__, cx, cy);
477 // GstWlDemo *priv = data;
478 // struct wl_shell_surface *shell_surface;
480 // shell_surface = wl_surface_get_user_data (surface);
482 // wl_shell_surface_move (shell_surface, priv->seat, serial);
483 lws_touch_handle_down(time, id, x_w, y_w);
487 touch_handle_up (void *data, struct wl_touch *wl_touch,
488 uint32_t serial, uint32_t time, int32_t id)
490 fprintf(stderr, "%s called. \n", __func__);
491 lws_touch_handle_up(time, id);
495 touch_handle_motion (void *data, struct wl_touch *wl_touch,
496 uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
498 fprintf(stderr, "%s called. \n", __func__);
499 lws_touch_handle_motion(time, id, x_w, y_w);
503 touch_handle_frame (void *data, struct wl_touch *wl_touch)
505 fprintf(stderr, "%s called. \n", __func__);
509 touch_handle_cancel (void *data, struct wl_touch *wl_touch)
511 fprintf(stderr, "%s called. \n", __func__);
514 static const struct wl_touch_listener touch_listener = {
523 seat_handle_capabilities (void *data, struct wl_seat *seat,
524 enum wl_seat_capability caps)
526 GstWlDemo *priv = data;
528 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !priv->pointer) {
529 priv->pointer = wl_seat_get_pointer (seat);
530 wl_proxy_set_queue ((struct wl_proxy *) priv->pointer, priv->queue);
531 wl_pointer_add_listener (priv->pointer, &pointer_listener, priv);
532 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && priv->pointer) {
533 wl_pointer_destroy (priv->pointer);
534 priv->pointer = NULL;
537 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !priv->touch) {
538 priv->touch = wl_seat_get_touch (seat);
539 wl_touch_set_user_data (priv->touch, priv);
540 wl_proxy_set_queue ((struct wl_proxy *) priv->touch, priv->queue);
541 wl_touch_add_listener (priv->touch, &touch_listener, priv);
542 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && priv->touch) {
543 wl_touch_destroy (priv->touch);
548 static const struct wl_seat_listener seat_listener = {
549 seat_handle_capabilities,
553 handle_ping (void *data, struct wl_shell_surface *shell_surface,
556 wl_shell_surface_pong (shell_surface, serial);
560 handle_configure (void *data, struct wl_shell_surface *shell_surface,
561 uint32_t edges, int32_t width, int32_t height)
566 handle_popup_done (void *data, struct wl_shell_surface *shell_surface)
570 static const struct wl_shell_surface_listener shell_surface_listener = {
577 shm_format (void *data, struct wl_shm *wl_shm, uint32_t format)
579 GST_DEBUG ("supported format=%08x", format);
582 static const struct wl_shm_listener shm_listener = {
587 display_handle_geometry (void *data, struct wl_output *wl_output, int x, int y,
588 int physical_width, int physical_height, int subpixel, const char *make,
589 const char *model, int transform)
594 display_handle_mode (void *data, struct wl_output *wl_output, uint32_t flags,
595 int width, int height, int refresh)
597 GstWlDemo *priv = data;
599 if (flags & WL_OUTPUT_MODE_CURRENT && priv->min_refresh > refresh)
600 priv->min_refresh = refresh;
604 display_handle_done (void *data, struct wl_output *wl_output)
609 display_handle_scale (void *data, struct wl_output *wl_output, int32_t scale)
613 static const struct wl_output_listener output_listener = {
614 display_handle_geometry,
621 registry_handle_global (void *data, struct wl_registry *registry,
622 uint32_t id, const char *interface, uint32_t version)
624 GstWlDemo *priv = data;
625 struct wl_output *output;
627 if (g_strcmp0 (interface, "wl_compositor") == 0) {
628 priv->compositor = wl_registry_bind (registry, id, &wl_compositor_interface,
630 } else if (g_strcmp0 (interface, "wl_shell") == 0) {
631 priv->shell = wl_registry_bind (registry, id, &wl_shell_interface, 1);
632 } else if (g_strcmp0 (interface, "wl_shm") == 0) {
633 priv->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1);
634 } else if (g_strcmp0 (interface, "wl_seat") == 0) {
635 priv->seat = wl_registry_bind (registry, id, &wl_seat_interface, 1);
636 wl_proxy_set_queue ((struct wl_proxy *) priv->seat, priv->queue);
637 wl_seat_add_listener (priv->seat, &seat_listener, priv);
638 } else if (g_strcmp0 (interface, "wl_output") == 0) {
639 output = wl_registry_bind (registry, id, &wl_output_interface, 1);
640 wl_proxy_set_queue ((struct wl_proxy *) output, priv->queue);
641 wl_output_add_listener (output, &output_listener, priv);
642 priv->outputs = g_list_append (priv->outputs, output);
646 static const struct wl_registry_listener registry_listener = {
647 registry_handle_global
651 setup_surface (GstWlDemo * priv, struct wl_surface *surface,
652 struct wl_shell_surface *shell_surface, gint width, gint height)
659 struct wl_shm_pool *shm_pool;
660 struct wl_buffer *wlbuffer;
663 * waylandsink creates a wl_subsurface from an external wl_surface passed by
664 * the application and attaches buffers from the upstream to
665 * the wl_subsurface. A wl_subsurface becomes visible by mapping
666 * its parent wl_surface, so we have to draw the wl_surface that will be passed
669 /* Transparently draw the area of the same size as the video resolution
670 by using a shm buffer. */
671 gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_BGRA, width, height);
673 snprintf (filename, 1024, "%s/%s-demo-%d-%s", g_get_user_runtime_dir (),
674 "wayland-shm", cnt++, "XXXXXX");
676 fd = mkstemp (filename);
678 g_printerr ("temp file %s creation failed: %s\n", filename,
683 if (ftruncate (fd, vinfo.size) < 0) {
684 g_printerr ("ftruncate failed: %s\n", strerror (errno));
689 data = mmap (NULL, vinfo.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
690 if (data == MAP_FAILED) {
691 g_printerr ("mmap failed: %s\n", strerror (errno));
696 memset (data, 0, vinfo.size);
698 munmap (data, vinfo.size);
700 shm_pool = wl_shm_create_pool (priv->shm, fd, vinfo.size);
702 wl_shm_pool_create_buffer (shm_pool, 0, GST_VIDEO_INFO_WIDTH (&vinfo),
703 GST_VIDEO_INFO_HEIGHT (&vinfo),
704 GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, 0), WL_SHM_FORMAT_ARGB8888);
705 wl_shm_pool_destroy (shm_pool);
709 wl_proxy_set_queue ((struct wl_proxy *) shell_surface, priv->queue);
711 wl_shell_surface_add_listener (shell_surface, &shell_surface_listener, priv);
712 wl_shell_surface_set_toplevel (shell_surface);
714 wl_surface_set_user_data (surface, shell_surface);
716 if (priv->fullscreen != -1) {
717 struct wl_event_queue *queue;
718 struct wl_region *region;
719 struct wl_output *output;
721 region = wl_compositor_create_region (priv->compositor);
722 wl_region_add (region, 0, 0, width, height);
723 wl_surface_set_opaque_region (surface, region);
724 wl_region_destroy (region);
726 output = g_list_nth_data (priv->outputs, priv->fullscreen);
729 ("failed to get wl_output object, so could not set fullscreen\n");
733 queue = wl_display_create_queue (priv->display);
735 wl_shell_surface_set_fullscreen (shell_surface,
736 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, output);
737 wl_display_roundtrip_queue (priv->display, queue);
739 wl_event_queue_destroy (queue);
742 wl_surface_attach (surface, wlbuffer, 0, 0);
743 wl_surface_damage (surface, 0, 0, GST_VIDEO_INFO_WIDTH (&vinfo),
744 GST_VIDEO_INFO_HEIGHT (&vinfo));
745 wl_surface_commit (surface);
746 wl_display_flush (priv->display);
751 static GstBusSyncReply
752 bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data)
754 GstWlDemo *priv = user_data;
756 if (gst_is_wayland_display_handle_need_context_message (message)) {
759 context = gst_wayland_display_handle_context_new (priv->display);
760 gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (message)), context);
763 } else if (gst_is_video_overlay_prepare_window_handle_message (message)) {
766 GstStructure *structure;
767 struct wl_surface *surface;
768 struct wl_shell_surface *shell_surface;
771 if (!g_str_has_prefix (GST_MESSAGE_SRC_NAME (message), "waylandsink"))
774 pad = gst_element_get_static_pad ((GstElement *) GST_MESSAGE_SRC (message),
776 caps = gst_pad_get_current_caps (pad);
777 structure = gst_caps_get_structure (caps, 0);
778 gst_structure_get_int (structure, "width", &width);
779 gst_structure_get_int (structure, "height", &height);
780 gst_caps_unref (caps);
781 gst_object_unref (pad);
783 surface = wl_compositor_create_surface (priv->compositor);
784 shell_surface = wl_shell_get_shell_surface (priv->shell, surface);
786 if (!setup_surface (priv, surface, shell_surface, width, height)) {
787 wl_shell_surface_destroy (shell_surface);
788 wl_surface_destroy (surface);
792 priv->surfaces = g_list_append (priv->surfaces, surface);
793 priv->shell_surfaces = g_list_append (priv->shell_surfaces, shell_surface);
795 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC
796 (message)), (guintptr) surface);
797 gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC
798 (message)), 0, 0, width, height);
806 gst_message_unref (message);
811 bus_async_handler (GstBus * bus, GstMessage * message, gpointer user_data)
813 GstWlDemo *priv = user_data;
815 switch (GST_MESSAGE_TYPE (message)) {
816 case GST_MESSAGE_ERROR:{
820 gst_message_parse_error (message, &err, &debug);
821 g_print ("Error: %s\n", err->message);
827 case GST_MESSAGE_APPLICATION:
829 const GstStructure *s;
831 s = gst_message_get_structure (message);
833 if (gst_structure_has_name (s, "GstWaylandDemoInterrupt"))
837 case GST_MESSAGE_EOS:
838 if (priv->nloop > 1 || priv->nloop == INFINITE_LOOP_PLAYBACK) {
839 if (!gst_element_seek (priv->pipeline,
840 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
841 GST_SEEK_TYPE_SET, 0,
842 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
843 g_printerr ("seek event sending failed\n");
847 if (priv->nloop != INFINITE_LOOP_PLAYBACK)
860 g_main_loop_quit (priv->loop);
861 g_source_destroy (priv->source);
866 typedef struct _GstWaylandEventSource
870 struct wl_display *display;
871 struct wl_event_queue *queue;
873 } GstWaylandEventSource;
876 event_source_prepare (GSource * source, gint * timeout)
878 GstWaylandEventSource *wl_source = (GstWaylandEventSource *) source;
882 if (wl_source->reading)
885 while (wl_display_prepare_read_queue (wl_source->display,
886 wl_source->queue) != 0) {
887 wl_display_dispatch_queue_pending (wl_source->display, wl_source->queue);
889 wl_display_flush (wl_source->display);
891 wl_source->reading = TRUE;
897 event_source_check (GSource * source)
899 GstWaylandEventSource *wl_source = (GstWaylandEventSource *) source;
901 return ! !(wl_source->pfd.revents & G_IO_IN);
905 event_source_dispatch (GSource * source, GSourceFunc callback,
908 GstWaylandEventSource *wl_source = (GstWaylandEventSource *) source;
910 wl_display_read_events (wl_source->display);
911 wl_display_dispatch_queue_pending (wl_source->display, wl_source->queue);
913 wl_source->reading = FALSE;
919 event_source_finalize (GSource * source)
921 GstWaylandEventSource *wl_source = (GstWaylandEventSource *) source;
923 if (wl_source->reading) {
924 wl_display_cancel_read (wl_source->display);
925 wl_source->reading = FALSE;
929 static GSourceFuncs GstWaylandEventSourceFuncs = {
930 event_source_prepare,
932 event_source_dispatch,
933 event_source_finalize
937 setup_framerate_adjustment (const GValue * item, gpointer user_data)
939 GstWlDemo *priv = user_data;
941 GstElement *peer_elem;
946 elem = g_value_get_object (item);
948 if (g_str_has_prefix (GST_ELEMENT_NAME (elem), "videorate")) {
949 /* Get the element immediately after this videorate */
950 pad = gst_element_get_static_pad (elem, "src");
951 peer_pad = gst_pad_get_peer (pad);
952 peer_elem = gst_pad_get_parent_element (peer_pad);
953 gst_object_unref (pad);
954 gst_object_unref (peer_pad);
956 caps = gst_caps_new_simple ("video/x-raw", "framerate",
957 GST_TYPE_FRACTION, priv->min_refresh / 1000, 1, NULL);
959 gst_element_unlink (elem, peer_elem);
960 gst_element_link_filtered (elem, peer_elem, caps);
961 gst_object_unref (peer_elem);
965 static GstPadProbeReturn
966 cb_have_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
968 GstWlDemo *priv = user_data;
973 static gint64 prev_time = 0;
974 static gint64 prev_cnt = 0;
978 if (prev_time == 0) {
979 prev_time = g_get_monotonic_time ();
980 return GST_PAD_PROBE_OK;
983 cur_time = g_get_monotonic_time ();
985 if (cur_time - prev_time >= 1000000) {
986 framesinsec = priv->frame_cnt - prev_cnt;
990 g_print ("FPS: %3ld TIME %02d:%02d:%02d\n", framesinsec, tm->tm_hour,
991 tm->tm_min, tm->tm_sec);
993 prev_cnt = priv->frame_cnt;
994 prev_time = cur_time;
997 return GST_PAD_PROBE_OK;
1001 sigint_handler (gpointer user_data)
1003 GstWlDemo *priv = user_data;
1005 gst_element_post_message (GST_ELEMENT (priv->pipeline),
1006 gst_message_new_application (GST_OBJECT (priv->pipeline),
1007 gst_structure_new ("GstWaylandDemoInterrupt", "message",
1008 G_TYPE_STRING, "Pipeline interrupted", NULL)));
1010 priv->signal_watch_id = 0;
1016 shell_surface_destroy (struct wl_shell_surface *shell_surface)
1018 wl_shell_surface_destroy (shell_surface);
1022 surface_destroy (struct wl_surface *surface)
1024 wl_surface_destroy (surface);
1028 output_destroy (struct wl_output *output)
1030 wl_output_destroy (output);
1034 main (int argc, char **argv)
1036 GstWaylandEventSource *wl_source;
1038 GOptionContext *context;
1043 GstStateChangeReturn state_ret;
1044 GTimer *timer = NULL;
1045 GError *error = NULL;
1047 gint fullscreen = -1;
1049 gchar *measuring_pad = NULL;
1055 int ret = EXIT_FAILURE;
1056 GOptionEntry options[] = {
1057 {"fullscreen", 'f', 0, G_OPTION_ARG_INT, &fullscreen,
1058 "Display in fullscreen mode on dest_num output [-f dest_num]", NULL},
1059 {"loop", 'l', 0, G_OPTION_ARG_INT, &nloop,
1060 "Loop Playback for loop_count [-l loop_count]", NULL},
1061 {"fps", 'p', 0, G_OPTION_ARG_STRING, &measuring_pad,
1062 "Framerate display (specify a measuring point as regular format [-p element:pad])",
1069 //char *static_options[] = { argv[0], "filesrc", "location=/home/0/3.mp4", "!", "decodebin", "!", "videoconvert", "!", "waylandsink", "sync=false", NULL };
1070 //char **static_argv = static_options;
1071 //int static_argc = 10;
1072 char **static_argv = NULL;
1073 int static_argc = 0;
1080 const char *afm_id = getenv("AFM_ID");
1081 if (afm_id == NULL || !afm_id[0]) {
1085 // Get pipeline information
1086 auto path = std::string(getenv("AFM_APP_INSTALL_DIR"));
1087 path = path + "/pipeline.ini";
1093 // Read pipeline from file
1094 pFile = fopen ( path.c_str() , "rb" );
1096 fprintf(stderr, "failed to open file\n");
1101 fseek (pFile , 0 , SEEK_END);
1102 lSize = ftell (pFile);
1105 // allocate memory to contain the whole file
1106 pipe = (char*) malloc (sizeof(char)*lSize);
1108 fprintf(stderr,"Cannot allocate memory\n");
1112 // copy the file into the buffer
1113 res = fread (pipe,1,lSize,pFile);
1115 fprintf(stderr,"File read error\n");
1118 //fprintf(stderr,pipe);
1125 static_argv = charlist;
1128 memlen = strlen(argv[0])+1;
1129 charlist[0] = (char*) malloc (memlen);
1130 memset(charlist[0],0,memlen);
1131 strcpy(charlist[0],argv[0]);
1135 char *substr= strtok(pipe,seg);
1136 while (substr != NULL) {
1137 memlen = strlen(substr)+1;
1138 charlist[cnt] = (char*) malloc (memlen);
1139 memset(charlist[cnt],0,memlen);
1140 strcpy(charlist[cnt],substr);
1142 substr = strtok(NULL,seg);
1148 port = std::stol(argv[1]);
1151 fprintf(stderr, "port: { %d }, token: { %s}, id: { %s } \n", port, token, afm_id);
1154 gst_init (&static_argc, &static_argv);
1156 RunXDG runxdg(port, token, afm_id);
1160 GST_ERROR("[%s] [%s] end", "WebSocket_Debug", __func__);
1164 gst_init (&argc, &argv);
1167 context = g_option_context_new ("PIPELINE-DESCRIPTION");
1168 g_option_context_add_main_entries (context, options, NULL);
1169 g_option_context_add_group (context, gst_init_get_option_group ());
1171 if (!g_option_context_parse (context, &static_argc, &static_argv, &error)) {
1173 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1175 g_printerr ("option parsing failed: %s\n",
1176 (error) ? error->message : "Unknown error");
1177 return EXIT_FAILURE;
1179 g_option_context_free (context);
1181 priv = g_slice_new0 (GstWlDemo);
1183 priv->fullscreen = fullscreen;
1184 priv->nloop = nloop;
1185 priv->min_refresh = G_MAXINT;
1187 priv->loop = g_main_loop_new (NULL, FALSE);
1189 /* Construct a pipeline from the result of parsing argv
1190 similarly to gst-launch. */
1192 argvn = g_new0 (char *, static_argc);
1193 memcpy (argvn, static_argv + 1, sizeof (char *) * (static_argc - 1));
1195 argvn = g_new0 (char *, argc);
1196 memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));
1199 priv->pipeline = gst_parse_launchv ((const gchar **) argvn, &error);
1202 if (!priv->pipeline) {
1203 g_printerr ("pipeline could not be constructed: %s\n",
1204 (error) ? error->message : "Unknown error");
1205 return EXIT_FAILURE;
1208 priv->signal_watch_id =
1209 g_unix_signal_add (SIGINT, (GSourceFunc) sigint_handler, priv);
1211 bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
1212 gst_bus_set_sync_handler (bus, bus_sync_handler, priv, NULL);
1213 bus_watch_id = gst_bus_add_watch (bus, bus_async_handler, priv);
1214 gst_object_unref (bus);
1216 priv->display = wl_display_connect (NULL);
1217 if (!priv->display) {
1218 g_printerr ("display connection failed\n");
1222 priv->queue = wl_display_create_queue (priv->display);
1224 priv->registry = wl_display_get_registry (priv->display);
1225 wl_proxy_set_queue ((struct wl_proxy *) priv->registry, priv->queue);
1226 wl_registry_add_listener (priv->registry, ®istry_listener, priv);
1228 /* Need 2 roundtrips to do all the global objects processing. */
1229 for (i = 0; i < 2; i++)
1230 wl_display_roundtrip_queue (priv->display, priv->queue);
1232 priv->source = g_source_new (&GstWaylandEventSourceFuncs,
1233 sizeof (GstWaylandEventSource));
1234 wl_source = (GstWaylandEventSource *) priv->source;
1236 wl_source->pfd.fd = wl_display_get_fd (priv->display);
1237 wl_source->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP;
1238 g_source_add_poll (priv->source, &wl_source->pfd);
1240 wl_source->display = priv->display;
1241 wl_source->queue = priv->queue;
1242 wl_source->reading = FALSE;
1243 g_source_attach (priv->source, NULL);
1244 g_source_unref (priv->source);
1246 /* Setup the framerate adjustment by videorate. */
1247 it = gst_bin_iterate_elements (GST_BIN (priv->pipeline));
1248 gst_iterator_foreach (it, setup_framerate_adjustment, priv);
1249 gst_iterator_free (it);
1251 if (measuring_pad) {
1252 elem_name = strtok (measuring_pad, ":");
1253 pad_name = strtok (NULL, ":");
1254 if (!elem_name || !pad_name) {
1255 g_printerr ("tokens extraction failed\n");
1259 elem = gst_bin_get_by_name (GST_BIN (priv->pipeline), elem_name);
1261 g_printerr ("failed to get the element by name\n");
1265 pad = gst_element_get_static_pad (elem, pad_name);
1267 g_printerr ("failed to get the static pad by name\n");
1268 gst_object_unref (elem);
1272 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
1273 (GstPadProbeCallback) cb_have_data, priv, NULL);
1275 gst_object_unref (pad);
1276 gst_object_unref (elem);
1278 /* To calculate the average framerate throughout the playback. */
1279 timer = g_timer_new ();
1282 state_ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1283 while (state_ret == GST_STATE_CHANGE_ASYNC) {
1284 state_ret = gst_element_get_state (priv->pipeline, NULL, NULL,
1285 GST_CLOCK_TIME_NONE);
1289 g_timer_start (timer);
1291 gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1293 g_main_loop_run (priv->loop);
1296 g_timer_stop (timer);
1297 elapsed = g_timer_elapsed (timer, NULL);
1298 g_timer_destroy (timer);
1299 g_print ("Avg. FPS: %.2lf\n", priv->frame_cnt / elapsed);
1302 gst_element_set_state (priv->pipeline, GST_STATE_NULL);
1307 GST_ERROR ("log: gst_wl_display_finalize");
1310 g_source_destroy (priv->source);
1312 gst_object_unref (priv->pipeline);
1314 if (priv->shell_surfaces) {
1315 g_list_foreach (priv->shell_surfaces, (GFunc) shell_surface_destroy, NULL);
1316 g_list_free (priv->shell_surfaces);
1319 if (priv->surfaces) {
1320 g_list_foreach (priv->surfaces, (GFunc) surface_destroy, NULL);
1321 g_list_free (priv->surfaces);
1324 if (priv->outputs) {
1325 g_list_foreach (priv->outputs, (GFunc) output_destroy, NULL);
1326 g_list_free (priv->outputs);
1330 wl_shm_destroy (priv->shm);
1332 wl_shell_destroy (priv->shell);
1334 wl_registry_destroy (priv->registry);
1335 if (priv->compositor)
1336 wl_compositor_destroy (priv->compositor);
1338 wl_event_queue_destroy (priv->queue);
1340 wl_display_disconnect (priv->display);
1342 g_source_remove (bus_watch_id);
1343 if (priv->signal_watch_id > 0)
1344 g_source_remove (priv->signal_watch_id);
1345 g_main_loop_unref (priv->loop);
1346 g_slice_free (GstWlDemo, priv);
1349 g_free (measuring_pad);
1352 for(int i=0;i<cnt;i++)
1354 if(charlist[i]!=NULL)