summaryrefslogtreecommitdiffstats
path: root/demo3/horizontal/waltham-server/src/wth-server-gst.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'demo3/horizontal/waltham-server/src/wth-server-gst.cpp')
-rw-r--r--demo3/horizontal/waltham-server/src/wth-server-gst.cpp1326
1 files changed, 1326 insertions, 0 deletions
diff --git a/demo3/horizontal/waltham-server/src/wth-server-gst.cpp b/demo3/horizontal/waltham-server/src/wth-server-gst.cpp
new file mode 100644
index 0000000..c282773
--- /dev/null
+++ b/demo3/horizontal/waltham-server/src/wth-server-gst.cpp
@@ -0,0 +1,1326 @@
+/**
+ * @licence app begin@
+ *
+ *
+ * TBD
+ *
+ *
+ * @licence end@
+ */
+/*******************************************************************************
+ ** **
+ ** SRC-MODULE: **
+ ** **
+ ** TARGET : linux **
+ ** **
+ ** PROJECT : waltham-server **
+ ** **
+ ** AUTHOR : **
+ ** **
+ ** **
+ ** **
+ ** PURPOSE : This file is acts as interface to weston compositor at server **
+ ** side **
+ ** **
+ ** REMARKS : **
+ ** **
+ ** PLATFORM DEPENDANT [yes/no]: yes **
+ ** **
+ ** TO BE CHANGED BY USER [yes/no]: no **
+ ** **
+ *******************************************************************************/
+
+#include <sys/mman.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <gst/gst.h>
+#include <gst/gl/gl.h>
+//#include <GL/gl.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/allocators/gstdmabuf.h>
+#include <gst/app/gstappsink.h>
+#include <pthread.h>
+
+#include <xf86drm.h>
+#include <drm.h>
+#include <drm_fourcc.h>
+
+#include <string>
+
+// Error avoidance for dual declaration of strchrnul()
+#define HAVE_STRCHRNUL 1
+
+extern "C" {
+#include "wth-server-waltham-comm.h"
+#include "os-compatibility.h"
+#include "ivi-application-client-protocol.h"
+#include "bitmap.h"
+}
+
+// Applied to Windowmanager, HomeScreen
+#include "libwindowmanager.h"
+#include <libhomescreen.hpp>
+#include "hmi-debug.h"
+
+
+LibHomeScreen* hs;
+LibWindowmanager *wm;
+extern bool gIsDraw;
+extern uint32_t g_id_ivisurf;
+
+long port = 1700;
+std::string token = "wm";
+std::string app_name = "receiver";
+
+static int running = 1;
+
+extern bool get_verbosity(void);
+extern int verbose;
+
+typedef struct _GstAppContext
+{
+ GMainLoop *loop;
+ GstBus *bus;
+ GstElement *pipeline;
+ GstElement *sink;
+ GstSample *sample;
+ GstBuffer *gstbuffer;
+ GstVideoMeta *vmeta;
+
+ int dma_fd[2];
+
+ struct display *display;
+ struct window *window;
+
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int wait;
+
+ GstVideoInfo info;
+ uint32_t format;
+ bool no_dma_buf;
+}GstAppContext;
+
+static const gchar *vertex_shader_str =
+"attribute vec4 a_position; \n"
+"attribute vec2 a_texCoord; \n"
+"varying vec2 v_texCoord; \n"
+"void main() \n"
+"{ \n"
+" gl_Position = a_position; \n"
+" v_texCoord = a_texCoord; \n"
+"} \n";
+
+static const gchar *fragment_shader_str =
+"#ifdef GL_ES \n"
+"precision mediump float; \n"
+"#endif \n"
+"varying vec2 v_texCoord; \n"
+"uniform sampler2D tex; \n"
+"void main() \n"
+"{ \n"
+"vec2 uv; \n"
+"uv = v_texCoord.xy; \n"
+"vec4 c = texture2D(tex, uv); \n"
+"gl_FragColor = c; \n"
+"} \n";
+
+/*
+ * pointer callbcak functions
+ */
+ static void
+pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, struct wl_surface *wl_surface,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ wth_verbose("data [%p]\n", data);
+
+ struct display *display = data;
+ struct window *window = display->window;
+ struct surface *surface = window->server_surf;
+ struct seat *seat = window->server_seat;
+
+ waltham_pointer_enter(window, serial, sx, sy);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+pointer_handle_leave(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ wth_verbose("data [%p]\n", data);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_leave(window, serial);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+pointer_handle_motion(void *data, struct wl_pointer *pointer,
+ uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_motion(window, time, sx, sy);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, uint32_t time, uint32_t button,
+ uint32_t state)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_button(window, serial, time, button, state);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_pointer_axis(window, time, axis, value);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+};
+
+/*
+ * touch callbcak functions
+ */
+
+static void
+touch_handle_down(void *data, struct wl_touch *touch, uint32_t serial,
+ uint32_t time, struct wl_surface *surface, int32_t id,
+ wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ int x = (int)wl_fixed_to_double(x_w);
+ int y = (int)wl_fixed_to_double(y_w);
+ wth_verbose("%p x %d y %d\n",window, x, y);
+
+ waltham_touch_down(window, serial, time, id, x_w, y_w);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+touch_handle_up(void *data, struct wl_touch *touch, uint32_t serial,
+ uint32_t time, int32_t id)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_up(window, serial, time, id);
+}
+
+static void
+touch_handle_motion(void *data, struct wl_touch *touch, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_motion(window, time, id, x_w, y_w);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+touch_handle_frame(void *data, struct wl_touch *touch)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_frame(window);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+touch_handle_cancel(void *data, struct wl_touch *touch)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+ struct window *window = display->window;
+
+ waltham_touch_cancel(window);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static const struct wl_touch_listener touch_listener = {
+ touch_handle_down,
+ touch_handle_up,
+ touch_handle_motion,
+ touch_handle_frame,
+ touch_handle_cancel
+};
+
+/*
+ * seat callback
+ */
+static void
+seat_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display = data;
+
+ wth_verbose("caps = %d\n", caps);
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !display->wl_pointer)
+ {
+ wth_verbose("WL_SEAT_CAPABILITY_POINTER\n");
+ display->wl_pointer = wl_seat_get_pointer(wl_seat);
+ wl_pointer_set_user_data(display->wl_pointer, display);
+ wl_pointer_add_listener(display->wl_pointer, &pointer_listener, display);
+ wl_display_roundtrip(display->display);
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && display->wl_pointer) {
+ wth_verbose("!WL_SEAT_CAPABILITY_POINTER\n");
+ wl_pointer_destroy(display->wl_pointer);
+ display->wl_pointer = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !display->wl_touch)
+ {
+ wth_verbose("WL_SEAT_CAPABILITY_TOUCH\n");
+ display->wl_touch = wl_seat_get_touch(wl_seat);
+ wl_touch_set_user_data(display->wl_touch, display);
+ wl_touch_add_listener(display->wl_touch, &touch_listener, display);
+ wl_display_roundtrip(display->display);
+ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && display->wl_touch) {
+ wth_verbose("!WL_SEAT_CAPABILITY_TOUCH\n");
+ wl_touch_destroy(display->wl_touch);
+ display->wl_touch = NULL;
+ }
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_capabilities,
+ NULL
+};
+
+static void
+add_seat(struct display *display, uint32_t id, uint32_t version)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ display->wl_pointer = NULL;
+ display->seat = wl_registry_bind(display->registry, id,
+ &wl_seat_interface, 1);
+ wl_seat_add_listener(display->seat, &seat_listener, display);
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static int
+drm_fourcc_from_gst_format(GstVideoFormat format)
+{
+ switch (format) {
+ case GST_VIDEO_FORMAT_RGB16:
+ case GST_VIDEO_FORMAT_BGR16:
+ return DRM_FORMAT_RGB565;
+
+ case GST_VIDEO_FORMAT_RGB:
+ case GST_VIDEO_FORMAT_BGR:
+ return DRM_FORMAT_BGR888;
+
+ case GST_VIDEO_FORMAT_RGBA:
+ case GST_VIDEO_FORMAT_RGBx:
+ case GST_VIDEO_FORMAT_BGRA:
+ case GST_VIDEO_FORMAT_BGRx:
+ case GST_VIDEO_FORMAT_ARGB:
+ case GST_VIDEO_FORMAT_xRGB:
+ case GST_VIDEO_FORMAT_ABGR:
+ case GST_VIDEO_FORMAT_xBGR:
+ case GST_VIDEO_FORMAT_AYUV:
+ return DRM_FORMAT_ARGB8888;
+
+ case GST_VIDEO_FORMAT_GRAY8:
+ return DRM_FORMAT_R8;
+
+ case GST_VIDEO_FORMAT_YUY2:
+ case GST_VIDEO_FORMAT_UYVY:
+ case GST_VIDEO_FORMAT_GRAY16_LE:
+ case GST_VIDEO_FORMAT_GRAY16_BE:
+ return DRM_FORMAT_GR88;
+
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ case GST_VIDEO_FORMAT_Y41B:
+ case GST_VIDEO_FORMAT_Y42B:
+ case GST_VIDEO_FORMAT_Y444:
+ return DRM_FORMAT_R8;
+
+ case GST_VIDEO_FORMAT_NV12:
+ return DRM_FORMAT_NV12;
+
+ default:
+ return -1;
+ }
+}
+
+gboolean bus_message(GstBus *bus, GstMessage *message, gpointer p)
+{
+ GstAppContext *gstctx = p;
+
+ fprintf(stderr, "mesage: %s\n", GST_MESSAGE_TYPE_NAME(message));
+
+ switch( GST_MESSAGE_TYPE(message)) {
+ case GST_MESSAGE_ERROR:
+ {
+ GError *err;
+ gchar *debug;
+
+ gst_message_parse_error(message, &err, &debug);
+ g_print("ERROR: %s\n", err->message);
+
+ g_error_free(err);
+ g_free(debug);
+ g_main_loop_quit(gstctx->loop);
+ break;
+ }
+
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ GstState oldstate, newstate;
+
+ gst_message_parse_state_changed(message, &oldstate, &newstate, NULL);
+ fprintf(stderr, "#%s state changed\n", GST_MESSAGE_SRC_NAME(message));
+ switch (newstate){
+ case GST_STATE_NULL:
+ fprintf(stderr, "%s: state is NULL\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ case GST_STATE_READY:
+ fprintf(stderr, "%s: state is READY\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ case GST_STATE_PAUSED:
+ fprintf(stderr, "%s: state is PAUSED\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ case GST_STATE_PLAYING:
+ fprintf(stderr, "%s: state is PLAYING\n", GST_MESSAGE_SRC_NAME(message));
+ break;
+ }
+ break;
+ }
+ default:
+ fprintf(stderr, "Unhandled message\n");
+ break;
+ }
+ fprintf(stderr, "-----------------\n");
+}
+
+EGLImageKHR create_eglImage(GstAppContext* gstctx)
+{
+ struct display *display = gstctx->display;
+ GstVideoMeta *vmeta = gstctx->vmeta;
+
+ uint32_t n_planes = vmeta->n_planes;
+ EGLint attribs[30];
+ int fourcc;
+ int atti = 0;
+
+ fourcc = drm_fourcc_from_gst_format(vmeta->format);
+
+ n_planes = GST_VIDEO_INFO_N_PLANES(&(gstctx->info));
+
+ int width = GST_VIDEO_INFO_WIDTH(&(gstctx->info));
+ int height = GST_VIDEO_INFO_HEIGHT(&(gstctx->info));
+
+ attribs[atti++] = EGL_WIDTH;
+ attribs[atti++] = vmeta->width;
+ attribs[atti++] = EGL_HEIGHT;
+ attribs[atti++] = vmeta->height;
+ attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+ attribs[atti++] = fourcc;
+
+ /*
+ * Offset value for both the planes i.e Y and UV is "0"
+ * The omxdec gives the output is 2 different memory blocks,
+ * One for Y -> dmafd[0] and other for UV -> dmafd[1]
+ */
+
+ if (n_planes > 0) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+ attribs[atti++] = gstctx->dma_fd[0];
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+ attribs[atti++] = 0;
+ attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+ attribs[atti++] = vmeta->stride[0];
+ }
+
+ if (n_planes > 1) {
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
+ attribs[atti++] = gstctx->dma_fd[1];
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
+ attribs[atti++] = 0;
+ attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
+ attribs[atti++] = vmeta->stride[1];
+ }
+
+ attribs[atti++] = EGL_NONE;
+
+ return display->egl.create_image(display->egl.dpy, EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT, (EGLClientBuffer)NULL,
+ attribs);
+}
+
+static int
+redraw(GstAppContext* gstctx)
+{
+ struct display *display = gstctx->display;
+ GstVideoMeta *vmeta = gstctx->vmeta;
+ struct window *window = display->window;
+ GLfloat vVertices[] = { -1.0f, 1.0f, 1.0f, // Position 0
+ 0.0f, 0.0f, // TexCoord 0
+ -1.0f, -1.0f, 1.0f, // Position 1
+ 0.0f, 1.0f, // TexCoord 1
+ 1.0f, -1.0f, 1.0f, // Position 2
+ 1.0f, 1.0f, // TexCoord 2
+ 1.0f, 1.0f, 1.0f, // Position 3, skewed a bit
+ 1.0f, 0.0f // TexCoord 3
+ };
+
+ GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+ glViewport(0,0,vmeta->width,vmeta->height);
+ wl_egl_window_resize(window->native,vmeta->width,vmeta->height,0,0);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glUseProgram(display->gl.program_object);
+
+ /* Load the vertex position */
+ GLint positionLoc = glGetAttribLocation(display->gl.program_object, "a_position");
+ glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vVertices);
+ /* Load the texture coordinate */
+ GLint texCoordLoc = glGetAttribLocation(display->gl.program_object, "a_texCoord");
+ glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]);
+ glEnableVertexAttribArray(positionLoc);
+ glEnableVertexAttribArray(texCoordLoc);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, display->gl.texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+
+ if(gstctx->no_dma_buf == false && window->egl_img != NULL )
+ {
+ display->egl.image_texture_2d(GL_TEXTURE_2D, window->egl_img);
+ }
+ else
+ {
+ GstMapInfo map;
+ gst_buffer_map(gstctx->gstbuffer, &map, GST_MAP_READ);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, vmeta->width, vmeta->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)map.data);
+ gst_buffer_unmap(gstctx->gstbuffer, &map);
+ }
+
+ /* Set the texture sampler to texture unit 0 */
+ GLint tex = glGetUniformLocation(display->gl.program_object, "tex");
+ glUniform1i(tex, 0);
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+ eglSwapBuffers(display->egl.dpy, window->egl_surface);
+}
+
+static GstFlowReturn
+appsink_callback(GstElement *object, gpointer *data)
+{
+ wth_verbose("%s >>> \n",__func__);
+ int ret;
+ //GstAppContext *gstctx = (struct gstApplContext *)data;
+ GstAppContext *gstctx = (GstAppContext *)data;
+ GstSample *sample;
+ GstBuffer *gstbuffer;
+ GstMemory *mem;
+ int i;
+ int n_mem;
+
+ sample = gst_app_sink_pull_sample((GstAppSink*)((void*)object));
+ if(sample == NULL) {
+ wth_error("No frame received\n");
+ return -1;
+ }
+ else {
+ wth_verbose("Frame received\n");
+ }
+
+ /* get dmabuf fd from gstbuffer */
+ gstbuffer = gst_sample_get_buffer(sample);
+ if(!gstbuffer){
+ wth_error("Cannot get buffer from sample\n");
+ }
+ gstctx->vmeta = gst_buffer_get_video_meta(gstbuffer);
+ if(gstctx->vmeta==NULL){
+ wth_error("no metadata on buffer\n");
+ }
+
+ n_mem = gst_buffer_n_memory(gstbuffer);
+ if (n_mem < 1) {
+ wth_error("Buffer with no mem!\n");
+ }
+
+ for (i = 0; i < n_mem; i++) {
+ /* get dmabuf fd from gstbuffer */
+ mem = gst_buffer_peek_memory (gstbuffer, i);
+ if (!gst_is_dmabuf_memory(mem)) {
+ wth_verbose("Memory is not of dmabuf type \n");
+ gstctx->no_dma_buf = true;
+
+ gst_buffer_ref(gstbuffer);
+ gstctx->gstbuffer = gstbuffer;
+ gstctx->sample = sample;
+
+ /* wake render thread up */
+ gstctx->wait = 0;
+ pthread_cond_signal(&gstctx->cond);
+ wth_verbose(" <<< %s \n",__func__);
+ return GST_FLOW_OK;
+ }
+ gstctx->dma_fd[i] = gst_dmabuf_memory_get_fd(mem);
+ }
+
+ if (gstctx->dma_fd[0] < 0 || gstctx->dma_fd[1] < 0 ) {
+ wth_error("dma fd is null \n");
+ return GST_FLOW_ERROR;
+ }
+
+ gst_buffer_ref(gstbuffer);
+ gstctx->gstbuffer = gstbuffer;
+ gstctx->sample = sample;
+
+ /* wake render thread up */
+ gstctx->wait = 0;
+ pthread_cond_signal(&gstctx->cond);
+ wth_verbose(" <<< %s \n",__func__);
+ return GST_FLOW_OK;
+}
+
+/*
+ * registry callback
+ */
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *d = data;
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ d->compositor =
+ wl_registry_bind(registry,
+ id, &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, id,
+ &ivi_application_interface, 1);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ add_seat(d, id, version);
+ }
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+ /* stub */
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+wth_server_weston_shm_attach(struct window *window, uint32_t data_sz, void * data,
+ int32_t width, int32_t height, int32_t stride, uint32_t format)
+{
+ /* stub */
+}
+void
+wth_server_weston_shm_damage(struct window *window)
+{
+ /* stub */
+}
+
+void
+wth_server_weston_shm_commit(struct window *window)
+{
+ /* stub */
+}
+
+static struct display *
+create_display(void)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct display *display;
+
+ display = malloc(sizeof *display);
+ if (display == NULL) {
+ wth_error("out of memory\n");
+ exit(1);
+ }
+ display->display = wl_display_connect(NULL);
+ assert(display->display);
+
+ display->has_xrgb = false;
+ display->registry = wl_display_get_registry(display->display);
+ wl_registry_add_listener(display->registry,
+ &registry_listener, display);
+ wl_display_roundtrip(display->display);
+
+ wth_verbose(" <<< %s \n",__func__);
+ return display;
+}
+
+static void
+destroy_display(struct display *display)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ if (display->compositor)
+ wl_compositor_destroy(display->compositor);
+
+ wl_registry_destroy(display->registry);
+ wl_display_flush(display->display);
+ wl_display_disconnect(display->display);
+ free(display);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+/*
+ * ivi surface callback
+ */
+static void
+handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface,
+ int32_t width, int32_t height)
+{
+ /* Simple-shm is resizable */
+}
+
+static const struct ivi_surface_listener ivi_surface_listener = {
+ handle_ivi_surface_configure,
+};
+
+static void
+init_egl(struct display *display)
+{
+ wth_verbose("%s >>> \n",__func__);
+ EGLint config_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+ static const EGLint context_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ EGLint major, minor, count;
+ EGLBoolean ret;
+
+ display->egl.dpy = eglGetDisplay(display->display);
+ assert(display->egl.dpy);
+
+ ret = eglInitialize(display->egl.dpy, &major, &minor);
+ assert(ret == EGL_TRUE);
+ ret = eglBindAPI(EGL_OPENGL_ES_API);
+ assert(ret == EGL_TRUE);
+
+ ret = eglChooseConfig(display->egl.dpy, config_attribs,
+ &display->egl.conf, 1, &count);
+ assert(ret && count >= 1);
+
+ display->egl.ctx = eglCreateContext(display->egl.dpy,
+ display->egl.conf,
+ EGL_NO_CONTEXT, context_attribs);
+ assert(display->egl.ctx);
+
+ eglSwapInterval(display->egl.dpy, 1);
+
+ display->egl.create_image =
+ (void *) eglGetProcAddress("eglCreateImageKHR");
+ assert(display->egl.create_image);
+
+ display->egl.image_texture_2d =
+ (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
+ assert(display->egl.image_texture_2d);
+
+ display->egl.destroy_image =
+ (void *) eglGetProcAddress("eglDestroyImageKHR");
+ assert(display->egl.destroy_image);
+}
+
+GLuint load_shader(GLenum type, const char *shaderSrc)
+{
+ wth_verbose("%s >>> \n",__func__);
+ GLuint shader;
+ GLint compiled;
+
+ /* Create the shader object */
+ shader = glCreateShader(type);
+ if (shader == 0)
+ {
+ printf("\n Failed to create shader \n");
+ return 0;
+ }
+ /* Load the shader source */
+ glShaderSource(shader, 1, &shaderSrc, NULL);
+ /* Compile the shader */
+ glCompileShader(shader);
+ /* Check the compile status */
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled)
+ {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char*)malloc (sizeof(char) * infoLen );
+ glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
+ fprintf(stderr, "Error compiling shader:%s\n",infoLog);
+ free(infoLog);
+ }
+ glDeleteShader(shader);
+ return 0;
+ }
+ return shader;
+}
+
+void init_gl(struct display *display)
+{
+ wth_verbose("%s >>> \n",__func__);
+ GLint linked;
+
+ /* load vertext/fragment shader */
+ display->gl.vertex_shader = load_shader(GL_VERTEX_SHADER, vertex_shader_str);
+ display->gl.fragment_shader = load_shader(GL_FRAGMENT_SHADER, fragment_shader_str);
+
+ /* Create the program object */
+ display->gl.program_object = glCreateProgram();
+ if (display->gl.program_object == 0)
+ {
+ fprintf(stderr, "error program object\n");
+ return;
+ }
+
+ glAttachShader(display->gl.program_object, display->gl.vertex_shader);
+ glAttachShader(display->gl.program_object, display->gl.fragment_shader);
+ /* Bind vPosition to attribute 0 */
+ glBindAttribLocation(display->gl.program_object, 0, "a_position");
+ /* Link the program */
+ glLinkProgram(display->gl.program_object);
+ /* Check the link status */
+ glGetProgramiv(display->gl.program_object, GL_LINK_STATUS, &linked);
+ if (!linked)
+ {
+ GLint infoLen = 0;
+ glGetProgramiv(display->gl.program_object, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1)
+ {
+ char* infoLog = (char*)malloc(sizeof(char) * infoLen);
+ glGetProgramInfoLog(display->gl.program_object, infoLen, NULL, infoLog);
+ fprintf(stderr, "Error linking program:%s\n", infoLog);
+ free(infoLog);
+ }
+ glDeleteProgram(display->gl.program_object);
+ }
+
+ glGenTextures(1, &display->gl.texture);
+
+ return;
+}
+
+static void
+create_surface(struct window *window)
+{
+ wth_verbose("%s >>> \n",__func__);
+ struct display *display = window->display;
+ int ret;
+
+ window->surface = wl_compositor_create_surface(display->compositor);
+ assert(window->surface);
+
+ window->native = wl_egl_window_create(window->surface,
+ window->width, window->height);
+ assert(window->native);
+
+ window->egl_surface = eglCreateWindowSurface(display->egl.dpy,
+ display->egl.conf,
+ (NativeWindowType)window->native, NULL);
+
+ wl_display_roundtrip(display->display);
+ if (display->ivi_application ) {
+ uint32_t id_ivisurf = g_id_ivisurf; //window->id_ivisurf;
+ window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ wth_error("Failed to create ivi_client_surface\n");
+ abort();
+ }
+
+ ivi_surface_add_listener(window->ivi_surface,
+ &ivi_surface_listener, window);
+ } else {
+ assert(0);
+ }
+ ret = eglMakeCurrent(display->egl.dpy, window->egl_surface,
+ window->egl_surface, display->egl.ctx);
+ assert(ret == EGL_TRUE);
+
+ glClearColor(0.5, 0.5, 0.5, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ eglSwapBuffers(display->egl.dpy, window->egl_surface);
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+create_window(struct window *window, struct display *display, int width, int height)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ window->callback = NULL;
+
+ window->display = display;
+ window->width = width;
+ window->height = height;
+ window->window_frames = 0;
+ window->window_benchmark_time = 0;
+
+ create_surface(window);
+
+ wth_verbose(" <<< %s \n",__func__);
+ return;
+}
+
+static void
+destroy_window(struct window *window)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ if (window->callback)
+ wl_callback_destroy(window->callback);
+
+ if (window->buffers[0].buffer)
+ wl_buffer_destroy(window->buffers[0].buffer);
+ if (window->buffers[1].buffer)
+ wl_buffer_destroy(window->buffers[1].buffer);
+
+ wl_surface_destroy(window->surface);
+ free(window);
+
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+static void
+signal_int(int signum)
+{
+ running = 0;
+}
+
+void *stream_thread(void *data)
+{
+ wth_verbose("%s >>> \n",__func__);
+ GMainLoop *loop = data;
+ g_main_loop_run(loop);
+ wth_verbose(" <<< %s \n",__func__);
+}
+
+
+
+static GstPadProbeReturn
+pad_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
+{
+ wth_verbose("%s >>> \n",__func__);
+ GstAppContext *dec = user_data;
+ GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
+ GstCaps *caps;
+
+ (void)pad;
+
+ if (GST_EVENT_TYPE(event) != GST_EVENT_CAPS)
+ return GST_PAD_PROBE_OK;
+
+ gst_event_parse_caps(event, &caps);
+
+ if (!caps) {
+ GST_ERROR("caps event without caps");
+ return GST_PAD_PROBE_OK;
+ }
+
+ if (!gst_video_info_from_caps(&dec->info, caps)) {
+ GST_ERROR("caps event with invalid video caps");
+ return GST_PAD_PROBE_OK;
+ }
+
+ switch (GST_VIDEO_INFO_FORMAT(&(dec->info))) {
+ case GST_VIDEO_FORMAT_I420:
+ dec->format = DRM_FORMAT_YUV420;
+ break;
+ case GST_VIDEO_FORMAT_NV12:
+ dec->format = DRM_FORMAT_NV12;
+ break;
+ case GST_VIDEO_FORMAT_YUY2:
+ dec->format = DRM_FORMAT_YUYV;
+ break;
+ default:
+ GST_ERROR("unknown format\n");
+ return GST_PAD_PROBE_OK;
+ }
+ wth_verbose(" <<< %s \n",__func__);
+ return GST_PAD_PROBE_OK;
+}
+
+// Applied to WM, HS
+int
+init_wm(LibWindowmanager *wm, struct window *window)
+{
+ HMI_DEBUG("waltham-server","called");
+ char* surfaceIdStr;
+
+ wth_verbose("app:%s port:%d token:%s \n", app_name.c_str(), port, token.c_str());
+
+ if (wm->init(port, token.c_str()) != 0) {
+ HMI_ERROR("waltham-server","wm init failed. ");
+ return -1;
+ }
+
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, wm->kKeyDrawingName, json_object_new_string(app_name.c_str()));
+ g_id_ivisurf = wm->requestSurface(obj);
+ if(g_id_ivisurf < 0)
+ {
+ HMI_ERROR("waltham-server","requestSurface failed: %d ", g_id_ivisurf);
+ return -1;
+ }
+ HMI_DEBUG("waltham-server","IVI_SURFACE_ID: %d ", g_id_ivisurf);
+
+ wm->set_event_handler(LibWindowmanager::Event_Active, [wm](json_object *object) {
+ const char *label = json_object_get_string(
+ json_object_object_get(object, wm->kKeyDrawingName));
+ HMI_DEBUG("waltham-server","Surface %s got activated! ", label);
+ });
+
+ wm->set_event_handler(LibWindowmanager::Event_Inactive, [wm](json_object *object) {
+ const char *label = json_object_get_string(
+ json_object_object_get(object, wm->kKeyDrawingName));
+ HMI_DEBUG("waltham-server","Surface %s got inactivated!", label);
+ });
+
+ wm->set_event_handler(LibWindowmanager::Event_Visible, [wm](json_object *object) {
+ const char *label = json_object_get_string(
+ json_object_object_get(object, wm->kKeyDrawingName));
+ HMI_DEBUG("waltham-server","Surface %s got visibled!", label);
+ });
+
+ wm->set_event_handler(LibWindowmanager::Event_Invisible, [wm](json_object *object) {
+ const char *label = json_object_get_string(
+ json_object_object_get(object, wm->kKeyDrawingName));
+ HMI_DEBUG("waltham-server","Surface %s got invisibled!", label);
+ gIsDraw = false;
+ });
+
+ wm->set_event_handler(LibWindowmanager::Event_SyncDraw, [wm, window](json_object *object) {
+ const char *label = json_object_get_string(
+ json_object_object_get(object, wm->kKeyDrawingName));
+ const char *area = json_object_get_string(
+ json_object_object_get(object, wm->kKeyDrawingArea));
+
+ HMI_DEBUG("waltham-server","Layout:%s x:%d y:%d w:%d h:%d ", area, 0, 0, 640, 720);
+ wl_egl_window_resize(window->native, 640, 720, 0, 0);
+ window->width = 640;
+ window->height = 720;
+ //if (!window->fullscreen)
+ // window->window_size = window->geometry;
+ gIsDraw = true;
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, wm->kKeyDrawingName, json_object_new_string(app_name.c_str()));
+ wm->endDraw(obj);
+ });
+
+ wm->set_event_handler(LibWindowmanager::Event_FlushDraw, [wm](json_object *object) {
+ const char *label = json_object_get_string(
+ json_object_object_get(object, wm->kKeyDrawingName));
+ HMI_DEBUG("waltham-server","Surface %s got flushdraw! ", label);
+ });
+
+ return 0;
+}
+
+int
+init_hs(LibHomeScreen* hs)
+{
+ if(hs->init(port, token)!=0)
+ {
+ HMI_ERROR("waltham-server","homescreen init failed. ");
+ return -1;
+ }
+
+ hs->set_event_handler(LibHomeScreen::Event_TapShortcut, [](json_object *object){
+ const char *application_name = json_object_get_string(
+ json_object_object_get(object, "application_name"));
+ HMI_DEBUG("waltham-server","Event_TapShortcut application_name = %s ", application_name);
+ if(strcmp(application_name, app_name.c_str()) == 0)
+ {
+ HMI_DEBUG("waltham-server","try to activesurface %s ", app_name.c_str());
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, wm->kKeyDrawingName, json_object_new_string(app_name.c_str()));
+ json_object_object_add(obj, wm->kKeyDrawingArea, json_object_new_string("split.sub"));
+ gIsDraw = false;
+ fprintf(stderr, "@@@@@ called activate in tapshortcut handler\n");
+ wm->activateWindow(obj);
+ }
+ });
+
+ hs->set_event_handler(LibHomeScreen::Event_OnScreenMessage, [](json_object *object){
+ const char *display_message = json_object_get_string(
+ json_object_object_get(object, "display_message"));
+ HMI_DEBUG("waltham-server","Event_OnScreenMessage display_message = %s ", display_message);
+ });
+
+ return 0;
+}
+
+GstAppContext gstctx; // @@@@@
+void init_receiver(struct window *window)
+{
+ struct sigaction sigint;
+ GError *gerror = NULL;
+ char * pipe = NULL;
+ FILE *pFile;
+ long lSize;
+ size_t res;
+
+ memset(&gstctx, 0, sizeof(gstctx));
+ /* Initialization for window creation */
+ gstctx.display = create_display();
+ init_egl(gstctx.display);
+
+ /* windowmanager, homescreen */
+ wm = new LibWindowmanager();
+ hs = new LibHomeScreen();
+
+ if(init_wm(wm, window)!=0){
+ // error process
+ wth_verbose("Error in init_wm.\n");
+ return -1;
+ }
+
+ if(init_hs(hs)!=0){
+ // error process
+ wth_verbose("Error in init_hs.\n");
+ return -1;
+ }
+
+ /* ToDo: fix the hardcoded value of width, height */
+// create_window(window, gstctx.display,1920,1080);
+ create_window(window, gstctx.display,640,720);
+ init_gl(gstctx.display);
+ gstctx.window = window;
+
+ gstctx.display->window = window;
+
+ wth_verbose("display %p\n", gstctx.display);
+ wth_verbose("display->window %p\n", gstctx.display->window);
+ wth_verbose("window %p\n", window);
+
+ sigint.sa_handler = signal_int;
+ sigemptyset(&sigint.sa_mask);
+ sigint.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &sigint, NULL);
+
+ /* create gstreamer pipeline */
+ gst_init(NULL, NULL);
+ gstctx.loop = g_main_loop_new(NULL, FALSE);
+
+ /* Read pipeline from file */
+ pFile = fopen ( "/etc/xdg/weston/pipeline.cfg" , "rb" );
+ if (pFile==NULL){
+ fprintf(stderr, "failed to open file\n");
+ return -1;
+ }
+
+ /* obtain file size */
+ fseek (pFile , 0 , SEEK_END);
+ lSize = ftell (pFile);
+ rewind (pFile);
+
+ /* allocate memory to contain the whole file */
+ pipe = (char*) zalloc (sizeof(char)*lSize);
+ if (pipe == NULL){
+ fprintf(stderr,"Cannot allocate memory\n");
+ return -1;
+ }
+
+ /* copy the file into the buffer */
+ res = fread (pipe,1,lSize,pFile);
+ if (res != lSize){
+ fprintf(stderr,"File read error\n");
+ return -1;
+ }
+
+ wth_verbose("Gst Pipeline=%s",pipe);
+ /* close file */
+ fclose (pFile);
+
+ /* parse the pipeline */
+ gstctx.pipeline = gst_parse_launch(pipe, &gerror);
+
+ if(!gstctx.pipeline)
+ fprintf(stderr,"Could not create gstreamer pipeline.\n");
+ free(pipe);
+
+ gstctx.bus = gst_pipeline_get_bus((GstPipeline*)((void*)gstctx.pipeline));
+ gst_bus_add_watch(gstctx.bus, bus_message, &gstctx);
+ fprintf(stderr, "registered bus signal\n");
+
+ gstctx.sink = gst_bin_get_by_name(GST_BIN(gstctx.pipeline), "sink");
+ g_object_set(G_OBJECT(gstctx.sink), "emit-signals", TRUE, NULL);
+ g_signal_connect(gstctx.sink, "new-sample", G_CALLBACK(appsink_callback), &gstctx);
+ g_object_set(G_OBJECT(gstctx.sink), "drop", TRUE, "max-buffers",-1, NULL);
+ gst_pad_add_probe(gst_element_get_static_pad(gstctx.sink, "sink"),
+ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+ pad_probe, &gstctx, NULL);
+
+ fprintf(stderr, "set state as playing\n");
+ gst_element_set_state((GstElement*)((void*)gstctx.pipeline), GST_STATE_PLAYING);
+
+ wth_verbose("wl_display_dispatch_pending >>>\n");
+ wl_display_dispatch_pending(gstctx.display->display);
+ wth_verbose("<<< wl_display_dispatch_pending; redraw >>>\n");
+ //redraw(&gstctx);
+ wth_verbose("<<< redraw\n");
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, wm->kKeyDrawingName, json_object_new_string(app_name.c_str()));
+ json_object_object_add(obj, wm->kKeyDrawingArea, json_object_new_string("normal.full"));
+ wth_verbose("activateWindow >>>\n");
+ fprintf(stderr, "@@@@@ called activate in init_receiver\n");
+ wm->activateWindow(obj);
+}
+
+/**
+ * wth_server_weston_main
+ *
+ * This is the main function which will handle connection to the compositor at server side
+ *
+ * @param names void *data
+ * @param value struct window data
+ * @return 0 on success, -1 on error
+ */
+int
+wth_server_weston_main(struct window *window)
+{
+ wth_verbose("%s >>> \n",__func__);
+
+ struct sigaction sigint;
+ pthread_t pthread;
+// GstAppContext gstctx;
+ int ret = 0;
+ GError *gerror = NULL;
+ char * pipe = NULL;
+ FILE *pFile;
+ long lSize;
+ size_t res;
+
+ pthread_mutex_init(&gstctx.mutex, NULL);
+ pthread_cond_init(&gstctx.cond, NULL);
+
+ pthread_create(&pthread, NULL, &stream_thread, gstctx.loop);
+
+ fprintf(stderr, "rendering part\n");
+
+ gstctx.wait = 1;
+ pthread_mutex_lock(&gstctx.mutex);
+
+ while (running && ret != -1) {
+ wth_verbose("in render loop\n");
+ ret = wl_display_dispatch(gstctx.display->display);
+ if(gstctx.wait == 1) {
+ wth_verbose("cond wait\n");
+ pthread_cond_wait(&gstctx.cond, &gstctx.mutex);
+ }
+
+ if(gstctx.no_dma_buf == false)
+ {
+ wth_verbose("create egl image\n");
+ window->egl_img = create_eglImage(&gstctx);
+ }
+
+ wth_verbose("redraw\n");
+ redraw(&gstctx);
+ wth_verbose("fin redraw\n");
+ gstctx.display->egl.destroy_image(gstctx.display->egl.dpy, window->egl_img);
+ gst_buffer_unref(gstctx.gstbuffer);
+ gst_sample_unref(gstctx.sample);
+ gstctx.wait = 1;
+ }
+ pthread_mutex_unlock(&gstctx.mutex);
+
+ wth_verbose("wth_server_gst_main exiting\n");
+
+ if (window->display->ivi_application) {
+ ivi_surface_destroy(window->ivi_surface);
+ ivi_application_destroy(window->display->ivi_application);
+ }
+
+ destroy_window(window);
+ destroy_display(gstctx.display);
+
+ wth_verbose(" <<< %s \n",__func__);
+
+ return 0;
+}