From 110215ad40cd0c24ed5ae70430e45304d5c60fe1 Mon Sep 17 00:00:00 2001 From: zheng_wenlong Date: Wed, 14 Nov 2018 12:49:40 +0900 Subject: Add waltham server for horizontal mode. Add waltham server for horizontal mode. This application is used for receive video from waltham transmitter. Change-Id: I794abf014eb014a4f0b42175093bf5c898e261f5 Signed-off-by: zheng_wenlong --- .../waltham-server/orig/src/wth-server-gst.c | 1151 ++++++++++++++++++++ 1 file changed, 1151 insertions(+) create mode 100644 demo3/horizontal/waltham-server/orig/src/wth-server-gst.c (limited to 'demo3/horizontal/waltham-server/orig/src/wth-server-gst.c') diff --git a/demo3/horizontal/waltham-server/orig/src/wth-server-gst.c b/demo3/horizontal/waltham-server/orig/src/wth-server-gst.c new file mode 100644 index 0000000..572a04d --- /dev/null +++ b/demo3/horizontal/waltham-server/orig/src/wth-server-gst.c @@ -0,0 +1,1151 @@ +/** + * @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 "wth-server-waltham-comm.h" +#include "os-compatibility.h" +#include "ivi-application-client-protocol.h" +#include "bitmap.h" + +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; + 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 = 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; +} + +/** + * 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; + + memset(&gstctx, 0, sizeof(gstctx)); + /* Initialization for window creation */ + gstctx.display = create_display(); + init_egl(gstctx.display); + /* ToDo: fix the hardcoded value of width, height */ + create_window(window, gstctx.display,1920,1080); + 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); + + 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; +} -- cgit 1.2.3-korg