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.
21 #include <gst/video/video.h>
22 #include <gst/video/videooverlay.h>
24 #include <gst/wayland/wayland.h>
26 #include <glib-unix.h>
28 #include <wayland-client.h>
30 #include <linux/input.h>
32 #include <sys/types.h>
41 #define INFINITE_LOOP_PLAYBACK -1
46 #include "gst-wayland-demo.hpp"
50 #include <libwebsockets.h>
52 #include <sys/syscall.h>
65 #include <sys/socket.h>
66 #include <sys/ioctl.h>
69 #include <linux/can.h>
70 #include <linux/can/raw.h>
77 void websocket_init();
78 void lws_touch_handle_down(uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
79 void lws_touch_handle_up(uint32_t time, int32_t id);
80 void lws_touch_handle_motion(uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w);
93 struct wl_display *display;
94 struct wl_event_queue *queue;
95 struct wl_registry *registry;
96 struct wl_compositor *compositor;
97 struct wl_shell *shell;
100 struct wl_pointer *pointer;
101 struct wl_touch *touch;
103 GList *shell_surfaces;
106 struct wl_surface *focused_surface;
110 guint signal_watch_id;
114 void fatal(const char* format, ...)
117 va_start(va_args, format);
118 vfprintf(stderr, format, va_args);
124 void warn(const char* format, ...)
127 va_start(va_args, format);
128 vfprintf(stderr, format, va_args);
132 void debug(const char* format, ...)
135 va_start(va_args, format);
136 vfprintf(stderr, format, va_args);
140 static void event_loop_run(struct sd_event* loop){
142 sd_event_unref(loop);
149 static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
153 static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
157 static void _on_event_static(void* closure, const char* event, struct afb_wsj1_msg *msg)
159 static_cast<RunXDG*>(closure)->on_event(NULL,event,msg);
162 static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)
164 AGL_DEBUG("_on_reply_static msg: (%s)", afb_wsj1_msg_object_s(msg));
167 void RunXDG::notify_ivi_control_cb (ilmObjectType object, t_ilm_uint id,
170 if (object == ILM_SURFACE) {
171 struct ilmSurfaceProperties surf_props;
173 ilm_getPropertiesOfSurface(id, &surf_props);
174 pid_t surf_pid = surf_props.creatorPid;
176 fprintf(stderr, "ivi surface (id=%d, pid=%d) destroyed. \n", id, surf_pid);
180 fprintf(stderr, "ivi surface (id=%d, pid=%d) is created. \n", id, surf_pid);
181 if (surf_pid == m_pid)
188 fprintf(stderr, "ivi surface is not created. \n");
192 void RunXDG::notify_ivi_control_cb_static (ilmObjectType object, t_ilm_uint id,
193 t_ilm_bool created, void *user_data)
195 fprintf(stderr, "notify_ivi_control_cb_static called. \n");
196 RunXDG *runxdg = static_cast<RunXDG*>(user_data);
197 runxdg->notify_ivi_control_cb(object, id, created);
200 int RunXDG::init_wm (void)
202 m_wm = new LibWindowmanager();
203 if (m_wm->init(m_port, m_token.c_str())) {
204 AGL_DEBUG("cannot initialize windowmanager");
208 std::function< void(json_object*) > h_active = [this](json_object* object) {
209 AGL_DEBUG("Got Event_Active");
210 t_ilm_surface s_ids[1] = { this->m_ivi_id };
211 ilm_setInputFocus(s_ids, 1, ILM_INPUT_DEVICE_KEYBOARD, ILM_TRUE);
214 std::function< void(json_object*) > h_inactive = [this](json_object* object) {
215 AGL_DEBUG("Got Event_Inactive");
216 t_ilm_surface s_ids[1] = { this->m_ivi_id };
217 ilm_setInputFocus(s_ids, 1, ILM_INPUT_DEVICE_KEYBOARD, ILM_FALSE);
220 std::function< void(json_object*) > h_visible = [](json_object* object) {
221 AGL_DEBUG("Got Event_Visible");
224 std::function< void(json_object*) > h_invisible = [](json_object* object) {
225 AGL_DEBUG("Got Event_Invisible");
228 std::function< void(json_object*) > h_syncdraw =
229 [this](json_object* object) {
230 AGL_DEBUG("Got Event_SyncDraw");
231 this->m_wm->endDraw(this->m_role.c_str());
234 std::function< void(json_object*) > h_flushdraw= [](json_object* object) {
235 AGL_DEBUG("Got Event_FlushDraw");
238 m_wm->set_event_handler(LibWindowmanager::Event_Active, h_active);
239 m_wm->set_event_handler(LibWindowmanager::Event_Inactive, h_inactive);
240 m_wm->set_event_handler(LibWindowmanager::Event_Visible, h_visible);
241 m_wm->set_event_handler(LibWindowmanager::Event_Invisible, h_invisible);
242 m_wm->set_event_handler(LibWindowmanager::Event_SyncDraw, h_syncdraw);
243 m_wm->set_event_handler(LibWindowmanager::Event_FlushDraw, h_flushdraw);
248 int RunXDG::init_hs (void)
250 m_hs = new LibHomeScreen();
251 if (m_hs->init(m_port, m_token.c_str())) {
252 AGL_DEBUG("cannot initialize homescreen");
256 std::function< void(json_object*) > handler = [this] (json_object* object) {
257 AGL_DEBUG("Activesurface %s ", this->m_role.c_str());
258 this->m_wm->activateWindow(this->m_role.c_str(), "normal.full");
260 m_hs->set_event_handler(LibHomeScreen::Event_ShowWindow, handler);
262 std::function< void(json_object*) > h_default= [](json_object* object) {
263 const char *j_str = json_object_to_json_string(object);
264 AGL_DEBUG("Got event [%s]", j_str);
266 m_hs->set_event_handler(LibHomeScreen::Event_OnScreenMessage, h_default);
271 int RunXDG::init_carlaclient(void)
273 memset(&m_carla_info, 0, sizeof(struct Carla_Info));
274 int ret = sd_event_new(&mploop);
277 AGL_DEBUG("Failed to create event loop");
282 // enforce context to avoid initialization/goto error
283 std::thread th(event_loop_run, mploop);
287 /* Initialize interface from websocket */
288 minterface.on_hangup = _on_hangup_static;
289 minterface.on_call = _on_call_static;
290 minterface.on_event = _on_event_static;
291 muri += "ws://localhost:" + std::to_string(m_port) + "/api?token=" + m_token; /*To be modified*/
292 sp_websock = afb_ws_client_connect_wsj1(mploop, muri.c_str(), &minterface, this);
293 if(sp_websock == NULL) {
294 AGL_DEBUG("Failed to create websocket connection");
298 struct json_object* j_obj = json_object_new_object();
299 json_object_object_add(j_obj, "event", json_object_new_int(0));
301 ret = afb_wsj1_call_j(sp_websock, "carlaclient", "subscribe", j_obj, _on_reply_static, this);
303 AGL_DEBUG("Failed to call carlaclient subscribe verb");
306 struct json_object* speed_obj = json_object_new_object();
307 json_object_object_add(speed_obj, "event", json_object_new_string("vehicle.average.speed"));
309 ret = afb_wsj1_call_j(sp_websock, "low-can", "subscribe", speed_obj, _on_reply_static, this);
311 AGL_DEBUG("Failed to call low-can subscribe verb");
317 void RunXDG::on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
319 AGL_DEBUG("event: (%s) msg: (%s).", event, afb_wsj1_msg_object_s(msg));
320 struct json_object* ev_contents = afb_wsj1_msg_object_j(msg);
321 if(!strcasecmp(event, "carlaclient/positionUpdated")) {
322 struct json_object *json_data;
323 if(!json_object_object_get_ex(ev_contents, "data", &json_data)) {
324 AGL_DEBUG("got ev_contents error.");
328 struct json_object *longitude_obj, *latitude_obj, *yaw_obj;
329 if(json_object_object_get_ex(json_data, "longitude", &longitude_obj)
330 && json_object_object_get_ex(json_data, "latitude", &latitude_obj)
331 && json_object_object_get_ex(json_data, "yaw", &yaw_obj)) {
332 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));
333 m_carla_info.yaw = json_object_get_string(yaw_obj);
334 std::string::size_type sz;
335 m_carla_info.longitude = std::stod(json_object_get_string(longitude_obj), &sz);
336 m_carla_info.latitude = std::stod(json_object_get_string(latitude_obj), &sz);
337 // TBD: call sdl interface
340 else if(!strcasecmp(event, "low-can/messages.vehicle.average.speed")) {
341 // [5,"low-can/messages.vehicle.average.speed",{"event":"low-can\/messages.vehicle.average.speed","data":{"value":10},"jtype":"afb-event"}]
343 if(json_object_get_type(ev_contents) == json_type_array) {
344 int array_len = json_object_array_length(ev_contents);
345 struct json_object *event_obj = json_object_array_get_idx(ev_contents, 2);
346 struct json_object *data_obj, *val_obj;
347 if(json_object_object_get_ex(event_obj, "data", &data_obj)
348 &&json_object_object_get_ex(data_obj, "value", &val_obj)) {
349 m_carla_info.speed = json_object_get_int(val_obj);
355 RunXDG::RunXDG (int port, const char* token, const char* id)
357 m_id = std::string(id);
359 m_token = std::string(token);
360 m_role = "gstwayland";
363 // Setup HomeScreen/WindowManager API
365 AGL_FATAL("cannot setup wm API");
368 AGL_FATAL("cannot setup hs API");
370 if (init_carlaclient())
371 AGL_FATAL("cannot setup carlaclient API");
373 // Setup ilmController API
374 m_ic = new ILMControl(notify_ivi_control_cb_static, this);
376 fprintf(stderr, "RunXDG created. \n");
379 void RunXDG::setup_ivi_surface (void)
381 std::string sid = std::to_string(m_ivi_id);
383 // This surface is mine, register pair app_name and ivi id.
384 AGL_DEBUG("requestSurfaceXDG(%s,%d)", m_role.c_str(), m_ivi_id);
385 m_wm->requestSurfaceXDG(this->m_role.c_str(), (unsigned int)m_ivi_id);
387 if (m_pending_create) {
388 // Recovering 1st time tap_shortcut is dropped because
389 // the application has not been run yet (1st time launch)
390 m_pending_create = false;
391 // m_wm->activateWindow(this->m_role.c_str(), "normal.full");
392 m_hs->publishSubscription();
396 void RunXDG::start (void)
398 // take care 1st time launch
399 AGL_DEBUG("waiting for notification: surafce created");
400 m_pending_create = true;
407 pointer_handle_enter (void *data, struct wl_pointer *pointer,
408 uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy)
410 fprintf(stderr, "%s called. \n", __func__);
411 // GstWlDemo *priv = data;
413 // priv->focused_surface = surface;
417 pointer_handle_leave (void *data, struct wl_pointer *pointer,
418 uint32_t serial, struct wl_surface *surface)
420 fprintf(stderr, "%s called. \n", __func__);
421 // GstWlDemo *priv = data;
423 // priv->focused_surface = NULL;
427 pointer_handle_motion (void *data, struct wl_pointer *pointer,
428 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
430 fprintf(stderr, "%s called. \n", __func__);
434 pointer_handle_button (void *data, struct wl_pointer *wl_pointer,
435 uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
437 fprintf(stderr, "%s called. \n", __func__);
438 // GstWlDemo *priv = data;
439 // struct wl_shell_surface *shell_surface;
441 // if (!priv->focused_surface)
444 // shell_surface = wl_surface_get_user_data (priv->focused_surface);
446 // if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
447 // wl_shell_surface_move (shell_surface, priv->seat, serial);
451 pointer_handle_axis (void *data, struct wl_pointer *wl_pointer,
452 uint32_t time, uint32_t axis, wl_fixed_t value)
454 fprintf(stderr, "%s called. \n", __func__);
457 static const struct wl_pointer_listener pointer_listener = {
458 pointer_handle_enter,
459 pointer_handle_leave,
460 pointer_handle_motion,
461 pointer_handle_button,
466 touch_handle_down (void *data, struct wl_touch *wl_touch,
467 uint32_t serial, uint32_t time, struct wl_surface *surface,
468 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
470 fprintf(stderr, "%s called. \n", __func__);
472 double cx = wl_fixed_to_double(x_w);
473 double cy = wl_fixed_to_double(y_w);
474 fprintf(stderr, "log: %s: cx=%f cy=%f", __func__, cx, cy);
476 // GstWlDemo *priv = data;
477 // struct wl_shell_surface *shell_surface;
479 // shell_surface = wl_surface_get_user_data (surface);
481 // wl_shell_surface_move (shell_surface, priv->seat, serial);
482 lws_touch_handle_down(time, id, x_w, y_w);
486 touch_handle_up (void *data, struct wl_touch *wl_touch,
487 uint32_t serial, uint32_t time, int32_t id)
489 fprintf(stderr, "%s called. \n", __func__);
490 lws_touch_handle_up(time, id);
494 touch_handle_motion (void *data, struct wl_touch *wl_touch,
495 uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
497 fprintf(stderr, "%s called. \n", __func__);
498 lws_touch_handle_motion(time, id, x_w, y_w);
502 touch_handle_frame (void *data, struct wl_touch *wl_touch)
504 fprintf(stderr, "%s called. \n", __func__);
508 touch_handle_cancel (void *data, struct wl_touch *wl_touch)
510 fprintf(stderr, "%s called. \n", __func__);
513 static const struct wl_touch_listener touch_listener = {
522 seat_handle_capabilities (void *data, struct wl_seat *seat,
523 enum wl_seat_capability caps)
525 GstWlDemo *priv = data;
527 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !priv->pointer) {
528 priv->pointer = wl_seat_get_pointer (seat);
529 wl_proxy_set_queue ((struct wl_proxy *) priv->pointer, priv->queue);
530 wl_pointer_add_listener (priv->pointer, &pointer_listener, priv);
531 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && priv->pointer) {
532 wl_pointer_destroy (priv->pointer);
533 priv->pointer = NULL;
536 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !priv->touch) {
537 priv->touch = wl_seat_get_touch (seat);
538 wl_touch_set_user_data (priv->touch, priv);
539 wl_proxy_set_queue ((struct wl_proxy *) priv->touch, priv->queue);
540 wl_touch_add_listener (priv->touch, &touch_listener, priv);
541 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && priv->touch) {
542 wl_touch_destroy (priv->touch);
547 static const struct wl_seat_listener seat_listener = {
548 seat_handle_capabilities,
552 handle_ping (void *data, struct wl_shell_surface *shell_surface,
555 wl_shell_surface_pong (shell_surface, serial);
559 handle_configure (void *data, struct wl_shell_surface *shell_surface,
560 uint32_t edges, int32_t width, int32_t height)
565 handle_popup_done (void *data, struct wl_shell_surface *shell_surface)
569 static const struct wl_shell_surface_listener shell_surface_listener = {
576 shm_format (void *data, struct wl_shm *wl_shm, uint32_t format)
578 GST_DEBUG ("supported format=%08x", format);
581 static const struct wl_shm_listener shm_listener = {
586 display_handle_geometry (void *data, struct wl_output *wl_output, int x, int y,
587 int physical_width, int physical_height, int subpixel, const char *make,
588 const char *model, int transform)
593 display_handle_mode (void *data, struct wl_output *wl_output, uint32_t flags,
594 int width, int height, int refresh)
596 GstWlDemo *priv = data;
598 if (flags & WL_OUTPUT_MODE_CURRENT && priv->min_refresh > refresh)
599 priv->min_refresh = refresh;
603 display_handle_done (void *data, struct wl_output *wl_output)
608 display_handle_scale (void *data, struct wl_output *wl_output, int32_t scale)
612 static const struct wl_output_listener output_listener = {
613 display_handle_geometry,
620 registry_handle_global (void *data, struct wl_registry *registry,
621 uint32_t id, const char *interface, uint32_t version)
623 GstWlDemo *priv = data;
624 struct wl_output *output;
626 if (g_strcmp0 (interface, "wl_compositor") == 0) {
627 priv->compositor = wl_registry_bind (registry, id, &wl_compositor_interface,
629 } else if (g_strcmp0 (interface, "wl_shell") == 0) {
630 priv->shell = wl_registry_bind (registry, id, &wl_shell_interface, 1);
631 } else if (g_strcmp0 (interface, "wl_shm") == 0) {
632 priv->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1);
633 } else if (g_strcmp0 (interface, "wl_seat") == 0) {
634 priv->seat = wl_registry_bind (registry, id, &wl_seat_interface, 1);
635 wl_proxy_set_queue ((struct wl_proxy *) priv->seat, priv->queue);
636 wl_seat_add_listener (priv->seat, &seat_listener, priv);
637 } else if (g_strcmp0 (interface, "wl_output") == 0) {
638 output = wl_registry_bind (registry, id, &wl_output_interface, 1);
639 wl_proxy_set_queue ((struct wl_proxy *) output, priv->queue);
640 wl_output_add_listener (output, &output_listener, priv);
641 priv->outputs = g_list_append (priv->outputs, output);
645 static const struct wl_registry_listener registry_listener = {
646 registry_handle_global
650 setup_surface (GstWlDemo * priv, struct wl_surface *surface,
651 struct wl_shell_surface *shell_surface, gint width, gint height)
658 struct wl_shm_pool *shm_pool;
659 struct wl_buffer *wlbuffer;
662 * waylandsink creates a wl_subsurface from an external wl_surface passed by
663 * the application and attaches buffers from the upstream to
664 * the wl_subsurface. A wl_subsurface becomes visible by mapping
665 * its parent wl_surface, so we have to draw the wl_surface that will be passed
668 /* Transparently draw the area of the same size as the video resolution
669 by using a shm buffer. */
670 gst_video_info_set_format (&vinfo, GST_VIDEO_FORMAT_BGRA, width, height);
672 snprintf (filename, 1024, "%s/%s-demo-%d-%s", g_get_user_runtime_dir (),
673 "wayland-shm", cnt++, "XXXXXX");
675 fd = mkstemp (filename);
677 g_printerr ("temp file %s creation failed: %s\n", filename,
682 if (ftruncate (fd, vinfo.size) < 0) {
683 g_printerr ("ftruncate failed: %s\n", strerror (errno));
688 data = mmap (NULL, vinfo.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
689 if (data == MAP_FAILED) {
690 g_printerr ("mmap failed: %s\n", strerror (errno));
695 memset (data, 0, vinfo.size);
697 munmap (data, vinfo.size);
699 shm_pool = wl_shm_create_pool (priv->shm, fd, vinfo.size);
701 wl_shm_pool_create_buffer (shm_pool, 0, GST_VIDEO_INFO_WIDTH (&vinfo),
702 GST_VIDEO_INFO_HEIGHT (&vinfo),
703 GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, 0), WL_SHM_FORMAT_ARGB8888);
704 wl_shm_pool_destroy (shm_pool);
708 wl_proxy_set_queue ((struct wl_proxy *) shell_surface, priv->queue);
710 wl_shell_surface_add_listener (shell_surface, &shell_surface_listener, priv);
711 wl_shell_surface_set_toplevel (shell_surface);
713 wl_surface_set_user_data (surface, shell_surface);
715 if (priv->fullscreen != -1) {
716 struct wl_event_queue *queue;
717 struct wl_region *region;
718 struct wl_output *output;
720 region = wl_compositor_create_region (priv->compositor);
721 wl_region_add (region, 0, 0, width, height);
722 wl_surface_set_opaque_region (surface, region);
723 wl_region_destroy (region);
725 output = g_list_nth_data (priv->outputs, priv->fullscreen);
728 ("failed to get wl_output object, so could not set fullscreen\n");
732 queue = wl_display_create_queue (priv->display);
734 wl_shell_surface_set_fullscreen (shell_surface,
735 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, output);
736 wl_display_roundtrip_queue (priv->display, queue);
738 wl_event_queue_destroy (queue);
741 wl_surface_attach (surface, wlbuffer, 0, 0);
742 wl_surface_damage (surface, 0, 0, GST_VIDEO_INFO_WIDTH (&vinfo),
743 GST_VIDEO_INFO_HEIGHT (&vinfo));
744 wl_surface_commit (surface);
745 wl_display_flush (priv->display);
750 static GstBusSyncReply
751 bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data)
753 GstWlDemo *priv = user_data;
755 if (gst_is_wayland_display_handle_need_context_message (message)) {
758 context = gst_wayland_display_handle_context_new (priv->display);
759 gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (message)), context);
762 } else if (gst_is_video_overlay_prepare_window_handle_message (message)) {
765 GstStructure *structure;
766 struct wl_surface *surface;
767 struct wl_shell_surface *shell_surface;
770 if (!g_str_has_prefix (GST_MESSAGE_SRC_NAME (message), "waylandsink"))
773 pad = gst_element_get_static_pad ((GstElement *) GST_MESSAGE_SRC (message),
775 caps = gst_pad_get_current_caps (pad);
776 structure = gst_caps_get_structure (caps, 0);
777 gst_structure_get_int (structure, "width", &width);
778 gst_structure_get_int (structure, "height", &height);
779 gst_caps_unref (caps);
780 gst_object_unref (pad);
782 surface = wl_compositor_create_surface (priv->compositor);
783 shell_surface = wl_shell_get_shell_surface (priv->shell, surface);
785 if (!setup_surface (priv, surface, shell_surface, width, height)) {
786 wl_shell_surface_destroy (shell_surface);
787 wl_surface_destroy (surface);
791 priv->surfaces = g_list_append (priv->surfaces, surface);
792 priv->shell_surfaces = g_list_append (priv->shell_surfaces, shell_surface);
794 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC
795 (message)), (guintptr) surface);
796 gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC
797 (message)), 0, 0, width, height);
805 gst_message_unref (message);
810 bus_async_handler (GstBus * bus, GstMessage * message, gpointer user_data)
812 GstWlDemo *priv = user_data;
814 switch (GST_MESSAGE_TYPE (message)) {
815 case GST_MESSAGE_ERROR:{
819 gst_message_parse_error (message, &err, &debug);
820 g_print ("Error: %s\n", err->message);
826 case GST_MESSAGE_APPLICATION:
828 const GstStructure *s;
830 s = gst_message_get_structure (message);
832 if (gst_structure_has_name (s, "GstWaylandDemoInterrupt"))
836 case GST_MESSAGE_EOS:
837 if (priv->nloop > 1 || priv->nloop == INFINITE_LOOP_PLAYBACK) {
838 if (!gst_element_seek (priv->pipeline,
839 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
840 GST_SEEK_TYPE_SET, 0,
841 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
842 g_printerr ("seek event sending failed\n");
846 if (priv->nloop != INFINITE_LOOP_PLAYBACK)
859 g_main_loop_quit (priv->loop);
860 g_source_destroy (priv->source);
865 typedef struct _GstWaylandEventSource
869 struct wl_display *display;
870 struct wl_event_queue *queue;
872 } GstWaylandEventSource;
875 event_source_prepare (GSource * source, gint * timeout)
877 GstWaylandEventSource *wl_source = (GstWaylandEventSource *) source;
881 if (wl_source->reading)
884 while (wl_display_prepare_read_queue (wl_source->display,
885 wl_source->queue) != 0) {
886 wl_display_dispatch_queue_pending (wl_source->display, wl_source->queue);
888 wl_display_flush (wl_source->display);
890 wl_source->reading = TRUE;
896 event_source_check (GSource * source)
898 GstWaylandEventSource *wl_source = (GstWaylandEventSource *) source;
900 return ! !(wl_source->pfd.revents & G_IO_IN);
904 event_source_dispatch (GSource * source, GSourceFunc callback,
907 GstWaylandEventSource *wl_source = (GstWaylandEventSource *) source;
909 wl_display_read_events (wl_source->display);
910 wl_display_dispatch_queue_pending (wl_source->display, wl_source->queue);
912 wl_source->reading = FALSE;
918 event_source_finalize (GSource * source)
920 GstWaylandEventSource *wl_source = (GstWaylandEventSource *) source;
922 if (wl_source->reading) {
923 wl_display_cancel_read (wl_source->display);
924 wl_source->reading = FALSE;
928 static GSourceFuncs GstWaylandEventSourceFuncs = {
929 event_source_prepare,
931 event_source_dispatch,
932 event_source_finalize
936 setup_framerate_adjustment (const GValue * item, gpointer user_data)
938 GstWlDemo *priv = user_data;
940 GstElement *peer_elem;
945 elem = g_value_get_object (item);
947 if (g_str_has_prefix (GST_ELEMENT_NAME (elem), "videorate")) {
948 /* Get the element immediately after this videorate */
949 pad = gst_element_get_static_pad (elem, "src");
950 peer_pad = gst_pad_get_peer (pad);
951 peer_elem = gst_pad_get_parent_element (peer_pad);
952 gst_object_unref (pad);
953 gst_object_unref (peer_pad);
955 caps = gst_caps_new_simple ("video/x-raw", "framerate",
956 GST_TYPE_FRACTION, priv->min_refresh / 1000, 1, NULL);
958 gst_element_unlink (elem, peer_elem);
959 gst_element_link_filtered (elem, peer_elem, caps);
960 gst_object_unref (peer_elem);
964 static GstPadProbeReturn
965 cb_have_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
967 GstWlDemo *priv = user_data;
972 static gint64 prev_time = 0;
973 static gint64 prev_cnt = 0;
977 if (prev_time == 0) {
978 prev_time = g_get_monotonic_time ();
979 return GST_PAD_PROBE_OK;
982 cur_time = g_get_monotonic_time ();
984 if (cur_time - prev_time >= 1000000) {
985 framesinsec = priv->frame_cnt - prev_cnt;
989 g_print ("FPS: %3ld TIME %02d:%02d:%02d\n", framesinsec, tm->tm_hour,
990 tm->tm_min, tm->tm_sec);
992 prev_cnt = priv->frame_cnt;
993 prev_time = cur_time;
996 return GST_PAD_PROBE_OK;
1000 sigint_handler (gpointer user_data)
1002 GstWlDemo *priv = user_data;
1004 gst_element_post_message (GST_ELEMENT (priv->pipeline),
1005 gst_message_new_application (GST_OBJECT (priv->pipeline),
1006 gst_structure_new ("GstWaylandDemoInterrupt", "message",
1007 G_TYPE_STRING, "Pipeline interrupted", NULL)));
1009 priv->signal_watch_id = 0;
1015 shell_surface_destroy (struct wl_shell_surface *shell_surface)
1017 wl_shell_surface_destroy (shell_surface);
1021 surface_destroy (struct wl_surface *surface)
1023 wl_surface_destroy (surface);
1027 output_destroy (struct wl_output *output)
1029 wl_output_destroy (output);
1033 main (int argc, char **argv)
1035 GstWaylandEventSource *wl_source;
1037 GOptionContext *context;
1042 GstStateChangeReturn state_ret;
1043 GTimer *timer = NULL;
1044 GError *error = NULL;
1046 gint fullscreen = -1;
1048 gchar *measuring_pad = NULL;
1054 int ret = EXIT_FAILURE;
1055 GOptionEntry options[] = {
1056 {"fullscreen", 'f', 0, G_OPTION_ARG_INT, &fullscreen,
1057 "Display in fullscreen mode on dest_num output [-f dest_num]", NULL},
1058 {"loop", 'l', 0, G_OPTION_ARG_INT, &nloop,
1059 "Loop Playback for loop_count [-l loop_count]", NULL},
1060 {"fps", 'p', 0, G_OPTION_ARG_STRING, &measuring_pad,
1061 "Framerate display (specify a measuring point as regular format [-p element:pad])",
1068 //char *static_options[] = { argv[0], "filesrc", "location=/home/0/3.mp4", "!", "decodebin", "!", "videoconvert", "!", "waylandsink", "sync=false", NULL };
1069 //char **static_argv = static_options;
1070 //int static_argc = 10;
1071 char **static_argv = NULL;
1072 int static_argc = 0;
1079 const char *afm_id = getenv("AFM_ID");
1080 if (afm_id == NULL || !afm_id[0]) {
1084 // Get pipeline information
1085 auto path = std::string(getenv("AFM_APP_INSTALL_DIR"));
1086 path = path + "/pipeline.ini";
1092 // Read pipeline from file
1093 pFile = fopen ( path.c_str() , "rb" );
1095 fprintf(stderr, "failed to open file\n");
1100 fseek (pFile , 0 , SEEK_END);
1101 lSize = ftell (pFile);
1104 // allocate memory to contain the whole file
1105 pipe = (char*) malloc (sizeof(char)*lSize);
1107 fprintf(stderr,"Cannot allocate memory\n");
1111 // copy the file into the buffer
1112 res = fread (pipe,1,lSize,pFile);
1114 fprintf(stderr,"File read error\n");
1117 //fprintf(stderr,pipe);
1124 static_argv = charlist;
1127 memlen = strlen(argv[0])+1;
1128 charlist[0] = (char*) malloc (memlen);
1129 memset(charlist[0],0,memlen);
1130 strcpy(charlist[0],argv[0]);
1134 char *substr= strtok(pipe,seg);
1135 while (substr != NULL) {
1136 memlen = strlen(substr)+1;
1137 charlist[cnt] = (char*) malloc (memlen);
1138 memset(charlist[cnt],0,memlen);
1139 strcpy(charlist[cnt],substr);
1141 substr = strtok(NULL,seg);
1147 port = std::stol(argv[1]);
1150 fprintf(stderr, "port: { %d }, token: { %s}, id: { %s } \n", port, token, afm_id);
1153 gst_init (&static_argc, &static_argv);
1155 RunXDG runxdg(port, token, afm_id);
1159 GST_ERROR("[%s] [%s] end", "WebSocket_Debug", __func__);
1163 gst_init (&argc, &argv);
1166 context = g_option_context_new ("PIPELINE-DESCRIPTION");
1167 g_option_context_add_main_entries (context, options, NULL);
1168 g_option_context_add_group (context, gst_init_get_option_group ());
1170 if (!g_option_context_parse (context, &static_argc, &static_argv, &error)) {
1172 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1174 g_printerr ("option parsing failed: %s\n",
1175 (error) ? error->message : "Unknown error");
1176 return EXIT_FAILURE;
1178 g_option_context_free (context);
1180 priv = g_slice_new0 (GstWlDemo);
1182 priv->fullscreen = fullscreen;
1183 priv->nloop = nloop;
1184 priv->min_refresh = G_MAXINT;
1186 priv->loop = g_main_loop_new (NULL, FALSE);
1188 /* Construct a pipeline from the result of parsing argv
1189 similarly to gst-launch. */
1191 argvn = g_new0 (char *, static_argc);
1192 memcpy (argvn, static_argv + 1, sizeof (char *) * (static_argc - 1));
1194 argvn = g_new0 (char *, argc);
1195 memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));
1198 priv->pipeline = gst_parse_launchv ((const gchar **) argvn, &error);
1201 if (!priv->pipeline) {
1202 g_printerr ("pipeline could not be constructed: %s\n",
1203 (error) ? error->message : "Unknown error");
1204 return EXIT_FAILURE;
1207 priv->signal_watch_id =
1208 g_unix_signal_add (SIGINT, (GSourceFunc) sigint_handler, priv);
1210 bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
1211 gst_bus_set_sync_handler (bus, bus_sync_handler, priv, NULL);
1212 bus_watch_id = gst_bus_add_watch (bus, bus_async_handler, priv);
1213 gst_object_unref (bus);
1215 priv->display = wl_display_connect (NULL);
1216 if (!priv->display) {
1217 g_printerr ("display connection failed\n");
1221 priv->queue = wl_display_create_queue (priv->display);
1223 priv->registry = wl_display_get_registry (priv->display);
1224 wl_proxy_set_queue ((struct wl_proxy *) priv->registry, priv->queue);
1225 wl_registry_add_listener (priv->registry, ®istry_listener, priv);
1227 /* Need 2 roundtrips to do all the global objects processing. */
1228 for (i = 0; i < 2; i++)
1229 wl_display_roundtrip_queue (priv->display, priv->queue);
1231 priv->source = g_source_new (&GstWaylandEventSourceFuncs,
1232 sizeof (GstWaylandEventSource));
1233 wl_source = (GstWaylandEventSource *) priv->source;
1235 wl_source->pfd.fd = wl_display_get_fd (priv->display);
1236 wl_source->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP;
1237 g_source_add_poll (priv->source, &wl_source->pfd);
1239 wl_source->display = priv->display;
1240 wl_source->queue = priv->queue;
1241 wl_source->reading = FALSE;
1242 g_source_attach (priv->source, NULL);
1243 g_source_unref (priv->source);
1245 /* Setup the framerate adjustment by videorate. */
1246 it = gst_bin_iterate_elements (GST_BIN (priv->pipeline));
1247 gst_iterator_foreach (it, setup_framerate_adjustment, priv);
1248 gst_iterator_free (it);
1250 if (measuring_pad) {
1251 elem_name = strtok (measuring_pad, ":");
1252 pad_name = strtok (NULL, ":");
1253 if (!elem_name || !pad_name) {
1254 g_printerr ("tokens extraction failed\n");
1258 elem = gst_bin_get_by_name (GST_BIN (priv->pipeline), elem_name);
1260 g_printerr ("failed to get the element by name\n");
1264 pad = gst_element_get_static_pad (elem, pad_name);
1266 g_printerr ("failed to get the static pad by name\n");
1267 gst_object_unref (elem);
1271 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
1272 (GstPadProbeCallback) cb_have_data, priv, NULL);
1274 gst_object_unref (pad);
1275 gst_object_unref (elem);
1277 /* To calculate the average framerate throughout the playback. */
1278 timer = g_timer_new ();
1281 state_ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
1282 while (state_ret == GST_STATE_CHANGE_ASYNC) {
1283 state_ret = gst_element_get_state (priv->pipeline, NULL, NULL,
1284 GST_CLOCK_TIME_NONE);
1288 g_timer_start (timer);
1290 gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
1292 g_main_loop_run (priv->loop);
1295 g_timer_stop (timer);
1296 elapsed = g_timer_elapsed (timer, NULL);
1297 g_timer_destroy (timer);
1298 g_print ("Avg. FPS: %.2lf\n", priv->frame_cnt / elapsed);
1301 gst_element_set_state (priv->pipeline, GST_STATE_NULL);
1306 GST_ERROR ("log: gst_wl_display_finalize");
1309 g_source_destroy (priv->source);
1311 gst_object_unref (priv->pipeline);
1313 if (priv->shell_surfaces) {
1314 g_list_foreach (priv->shell_surfaces, (GFunc) shell_surface_destroy, NULL);
1315 g_list_free (priv->shell_surfaces);
1318 if (priv->surfaces) {
1319 g_list_foreach (priv->surfaces, (GFunc) surface_destroy, NULL);
1320 g_list_free (priv->surfaces);
1323 if (priv->outputs) {
1324 g_list_foreach (priv->outputs, (GFunc) output_destroy, NULL);
1325 g_list_free (priv->outputs);
1329 wl_shm_destroy (priv->shm);
1331 wl_shell_destroy (priv->shell);
1333 wl_registry_destroy (priv->registry);
1334 if (priv->compositor)
1335 wl_compositor_destroy (priv->compositor);
1337 wl_event_queue_destroy (priv->queue);
1339 wl_display_disconnect (priv->display);
1341 g_source_remove (bus_watch_id);
1342 if (priv->signal_watch_id > 0)
1343 g_source_remove (priv->signal_watch_id);
1344 g_main_loop_unref (priv->loop);
1345 g_slice_free (GstWlDemo, priv);
1348 g_free (measuring_pad);
1351 for(int i=0;i<cnt;i++)
1353 if(charlist[i]!=NULL)