/** * @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 #include #include #include #include //#include #include #include #include #include #include #include #include #include // 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 #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, ®istry_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; }