Dear All,
I am using wayland video sink (i.e. imxeglvivsink) from
gstreamer1.0-plugins-imx [1] to play the video along with weston 1.8.0
and wayland-ivi-extenstion 1.4.0. I have modified “imxeglvivsink” to
have the ilm and touch input support [2]. Basically I am posting touch
events on GST bus and application want to have the touch can read the
messages and process the touch. This is working fine if I don’t load
the “ivi-input-controller.so”. If I load the “ivi-input-controller.so”
I am not able to get the touch event inside this plug-in. I have tried
setting touch input focus to the surface from this wayland video
plug-in using “LayermanagerControl” and ilm_setInputFocus” [3] but no
luck.
Also touch works fine even if I load “ivi-input-controller.so” with
other applications. So I suspect some modification are required to
”imxeglvivsink” [2] or “wayland-ivi-extension/weston”.
Do you know what might be going wrong? Could anyone here give some
suggestions/ideas to tryout and fix this?
Also “LayerManagerControl get surface 90 acceptance” doesn’t seem to
work for me. Any inputs for this?
I have tried modifying “gst_imx_egl_viv_sink_egl_platform_mainloop”
function in various ways but no luck and I think implementation is
correct (as it works well without ivi-input-controller)
Following is the platform setup and weston configuration.
i.MX6 Duallite
Linux 3.14.28
Weston 1.8.0 with (ivi-shell.so with fbdev backend and gal2d renderer)
Wayland-ivi-extension 1.4.0 (using ivi-controller.so, ivi-input-controller.so
gstreamer-imx plugin
QTwayland 5.4.2/Qt 5.4.2
Weston.ini contains:
[core]
shell=ivi-shell.so
[ivi-shell]
ivi-module=ivi-controller.so,ivi-input-controller.so
ivi-shell-user-interface=/usr/lib/weston/weston-ivi-shell-user-interface
[1] https://github.com/Freescale/gstreamer-imx/tree/master/src/eglvivsink
[2]See attached modified file “egl_platform_wayland.c” from imxeglvivsink
[3]
http://wiki.projects.genivi.org/index.php/Getting_Started_with_new_Input_Handling_APIs
Thanks & Regards,
Vikash
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <wayland-egl.h>
#include "egl_platform.h"
#include "egl_misc.h"
#include "gl_headers.h"
#define ILM_SUPPORT 1
#ifdef ILM_SUPPORT
#include "ilm/ilm_control.h"
#include "ilm/ilm_client.h"
#include "ilm/ilm_input.h"
//int width = 800;
//int height = 480;
t_ilm_layer ilmLayerId = 1000;
t_ilm_surface ilmSurfaceId = 90;
#endif
GST_DEBUG_CATEGORY_STATIC(imx_egl_platform_wl_debug);
#define GST_CAT_DEFAULT imx_egl_platform_wl_debug
struct _GstImxEglVivSinkEGLPlatform
{
EGLNativeDisplayType native_display;
EGLNativeWindowType native_main_window;
EGLNativeWindowType native_window;
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_main_surface;
EGLSurface egl_surface;
GstElement* sink;
GstImxEglVivSinkWindowResizedEventCallback window_resized_event_cb;
GstImxEglVivSinkWindowRenderFrameCallback render_frame_cb;
gpointer user_context;
gboolean fullscreen;
guint video_par_n, video_par_d;
guint fixed_window_width, fixed_window_height, video_width, video_height;
guint current_width, current_height;
guint screen_width, screen_height;
gint pending_x_coord, pending_y_coord;
gint x_coord, y_coord;
gboolean pending_subsurface_desync;
GMutex mutex;
struct wl_display *display;
struct wl_registry *registry;
int display_fd;
struct wl_compositor *compositor;
struct wl_subcompositor *subcompositor;
#ifndef ILM_SUPPORT
struct wl_shell *shell;
#endif
struct wl_output *output;
struct wl_surface *main_surface;
struct wl_surface *surface;
struct wl_subsurface *subsurface;
#ifndef ILM_SUPPORT
struct wl_shell_surface *shell_surface;
#endif
struct wl_seat *seat;
struct wl_touch *wl_touch;
struct wl_callback *frame_cb;
gboolean frame_callback_invoked;
int ctrl_pipe[2];
gboolean configured, do_render;
};
typedef enum
{
TOUCH_HANDLE_DOWN,
TOUCH_HANDLE_UP,
TOUCH_HANDLE_MOTION,
TOUCH_HANDLE_FRAME,
TOUCH_HANDLE_CANCEL
};
#define EGL_PLATFORM_LOCK(platform) g_mutex_lock(&((platform)->mutex))
#define EGL_PLATFORM_UNLOCK(platform) g_mutex_unlock(&((platform)->mutex))
typedef enum
{
GSTIMX_EGLWL_CMD_REDRAW,
GSTIMX_EGLWL_CMD_CALL_RESIZE_CB,
GSTIMX_EGLWL_CMD_STOP_MAINLOOP
}
GstImxEGLWLCmds;
static void log_handler(const char *format, va_list args)
{
gst_debug_log_valist(imx_egl_platform_wl_debug, GST_LEVEL_LOG, __FILE__, __func__, __LINE__, NULL, format, args);
}
static void static_global_init(void)
{
static gboolean initialized = FALSE;
if (!initialized)
{
GST_DEBUG_CATEGORY_INIT(imx_egl_platform_wl_debug, "imxeglplatform_wl", 0, "imxeglvivsink Wayland platform");
wl_log_set_handler_client(log_handler);
initialized = TRUE;
}
}
static void calculate_adjusted_window_size(GstImxEglVivSinkEGLPlatform *platform, guint *actual_width, guint *actual_height)
{
gboolean b;
guint window_par_n, window_par_d, display_ratio_n, display_ratio_d;
window_par_n = 4;
window_par_d = 3;
b = gst_video_calculate_display_ratio(
&display_ratio_n, &display_ratio_d,
platform->video_width, platform->video_height,
platform->video_par_n, platform->video_par_d,
window_par_n, window_par_d
);
if (b)
{
*actual_width = platform->video_width * platform->video_par_n / platform->video_par_d;
*actual_height = platform->video_height;
}
else
{
*actual_width = platform->video_width;
*actual_height = platform->video_height;
}
GST_LOG(
"calculate_adjusted_window_size: video size: %dx%d video ratio: %d/%d display ratio: %d/%d actual size: %ux%u",
platform->video_width, platform->video_height,
platform->video_par_n, platform->video_par_d,
display_ratio_n, display_ratio_d,
*actual_width, *actual_height
);
}
static void resize_window_to_video(GstImxEglVivSinkEGLPlatform *platform)
{
guint actual_width, actual_height;
calculate_adjusted_window_size(platform, &actual_width, &actual_height);
platform->current_width = ((platform->screen_width == 0) || (actual_width < platform->screen_width)) ? actual_width : platform->screen_width;
platform->current_height = ((platform->screen_height == 0) || (actual_height < platform->screen_height)) ? actual_height : platform->screen_height;
GST_LOG("final size: %dx%d", platform->current_width, platform->current_height);
wl_egl_window_resize(platform->native_window, platform->current_width, platform->current_height, 0, 0);
platform->pending_subsurface_desync = TRUE;
}
static void
touch_handle_down(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, struct wl_surface *surface,
int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
{
//float x = wl_fixed_to_double(x_w);
//float y = wl_fixed_to_double(y_w);
int x = wl_fixed_to_int(x_w);
int y = wl_fixed_to_int(y_w);
GstMessage *message;
GstStructure *structure;
GstImxEglVivSinkEGLPlatform *platform = data;
//printf("IMXEGLVIVSINK:touch_handle_down: (%d x %d), %d, %p \n", x, y, id, surface);
GST_LOG("GSTIMXEGLVIVSINK:touch_handle_down: (%d x %d), %d, %p \n", x, y, id, surface);
structure = gst_structure_new("wl_touch_event",
"type", G_TYPE_INT, TOUCH_HANDLE_DOWN,
"id", G_TYPE_INT, id,
"x-cord", G_TYPE_INT, x,
"y-cord", G_TYPE_INT, y, NULL);
message = gst_message_new_element (GST_OBJECT (platform->sink), structure);
gst_element_post_message (GST_ELEMENT (platform->sink), message);
}
static void
touch_handle_up(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, int32_t id)
{
GstMessage *message;
GstStructure *structure;
GstImxEglVivSinkEGLPlatform *platform = data;
//printf("IMXEGLVIVSINK:touch_handle_up: %d \n", id);
GST_LOG("GSTIMXEGLVIVSINK:touch_handle_up: %d \n", id);
structure = gst_structure_new("wl_touch_event",
"type", G_TYPE_INT, TOUCH_HANDLE_UP,
"id", G_TYPE_INT, id, NULL);
message = gst_message_new_element (GST_OBJECT (platform->sink), structure);
gst_element_post_message (GST_ELEMENT (platform->sink), message);
}
static void
touch_handle_motion(void *data, struct wl_touch *wl_touch,
uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
{
//float x = wl_fixed_to_double(x_w);
//float y = wl_fixed_to_double(y_w);
int x = wl_fixed_to_int(x_w);
int y = wl_fixed_to_int(y_w);
GstMessage *message;
GstStructure *structure;
GstImxEglVivSinkEGLPlatform *platform = data;
//printf("IMXEGLVIVSINK:touch_handle_motion: (%d x %d), %d \n", x, y, id);
GST_LOG("GSTIMXEGLVIVSINK:touch_handle_motion: (%d x %d), %d \n", x, y, id);
structure = gst_structure_new("wl_touch_event",
"type", G_TYPE_INT, TOUCH_HANDLE_MOTION,
"id", G_TYPE_INT, id,
"x-cord", G_TYPE_INT, x,
"y-cord", G_TYPE_INT, y, NULL);
message = gst_message_new_element (GST_OBJECT (platform->sink), structure);
gst_element_post_message (GST_ELEMENT (platform->sink), message);
}
static void
touch_handle_frame(void *data, struct wl_touch *wl_touch)
{
GstMessage *message;
GstStructure *structure;
GstImxEglVivSinkEGLPlatform *platform = data;
//printf("IMXEGLVIVSINK:touch_handle_frame\n");
GST_LOG("GSTIMXEGLVIVSINK:touch_handle_frame\n");
structure = gst_structure_new("wl_touch_event",
"type", G_TYPE_INT, TOUCH_HANDLE_FRAME, NULL);
message = gst_message_new_element (GST_OBJECT (platform->sink), structure);
gst_element_post_message (GST_ELEMENT (platform->sink), message);
}
static void
touch_handle_cancel(void *data, struct wl_touch *wl_touch)
{
GstMessage *message;
GstStructure *structure;
GstImxEglVivSinkEGLPlatform *platform = data;
//printf("IMXEGLVIVSINK:touch_handle_cancel\n");
GST_LOG("GSTIMXEGLVIVSINK:touch_handle_cancel\n");
structure = gst_structure_new("wl_touch_event",
"type", G_TYPE_INT, TOUCH_HANDLE_CANCEL, NULL);
message = gst_message_new_element (GST_OBJECT (platform->sink), structure);
gst_element_post_message (GST_ELEMENT (platform->sink), message);
}
static const struct wl_touch_listener touch_listener = {
touch_handle_down,
touch_handle_up,
touch_handle_motion,
touch_handle_frame,
touch_handle_cancel,
};
static void
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
enum wl_seat_capability caps)
{
GstImxEglVivSinkEGLPlatform *platform = data;
if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !platform->wl_touch) {
printf("Display has a touch screen\n");
GST_INFO("Display has a touch screen\n");
platform->wl_touch = wl_seat_get_touch(wl_seat);
wl_touch_set_user_data(platform->wl_touch, platform);
wl_touch_add_listener(platform->wl_touch, &touch_listener, platform);
} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && platform->wl_touch) {
wl_touch_destroy(platform->wl_touch);
platform->wl_touch = NULL;
}
}
static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
};
static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, char const *interface, G_GNUC_UNUSED uint32_t version)
{
GstImxEglVivSinkEGLPlatform *platform = data;
if (g_strcmp0(interface, "wl_compositor") == 0)
platform->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
#ifndef ILM_SUPPORT
else if (g_strcmp0(interface, "wl_shell") == 0)
platform->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
#endif
else if (g_strcmp0(interface, "wl_output") == 0)
platform->output = wl_registry_bind(registry, id, &wl_output_interface, 2);
else if (g_strcmp0(interface, "wl_subcompositor") == 0)
platform->subcompositor = wl_registry_bind(registry, id,
&wl_subcompositor_interface, 1);
else if (g_strcmp0(interface, "wl_seat") == 0)
{
platform->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
wl_seat_add_listener(platform->seat, &seat_listener, platform);
}
}
static void registry_handle_global_remove(G_GNUC_UNUSED void *data, G_GNUC_UNUSED struct wl_registry *registry, G_GNUC_UNUSED uint32_t name)
{
}
static const struct wl_registry_listener registry_listener =
{
registry_handle_global,
registry_handle_global_remove
};
static void output_geometry(G_GNUC_UNUSED void *data, G_GNUC_UNUSED struct wl_output *wl_output, G_GNUC_UNUSED int x, G_GNUC_UNUSED int y, G_GNUC_UNUSED int w, G_GNUC_UNUSED int h, G_GNUC_UNUSED int subpixel, G_GNUC_UNUSED const char *make, G_GNUC_UNUSED const char *model, G_GNUC_UNUSED int transform)
{
}
static void output_mode(G_GNUC_UNUSED void *data, G_GNUC_UNUSED struct wl_output *wl_output, G_GNUC_UNUSED unsigned int flags, int w, int h, G_GNUC_UNUSED int refresh)
{
GstImxEglVivSinkEGLPlatform *platform = data;
if (flags & WL_OUTPUT_MODE_CURRENT)
{
GST_LOG("reported screen size: %dx%d", w, h);
platform->screen_width = w;
platform->screen_height = h;
#if 0 /* This becomes unnecessary as the callback is dispatched before configuring the window. */
/* resize again in case the window is set to the video size
* (this makes sure the window is not larger than the screen) */
if (
!platform->fullscreen
&& (platform->fixed_window_width == 0) && (platform->fixed_window_height == 0)
&& (platform->video_width != 0) && (platform->video_height != 0)
//&& (platform->parent_window != 0) // TODO
)
{
resize_window_to_video(platform);
if (platform->window_resized_event_cb != NULL)
{
char const cmd = GSTIMX_EGLWL_CMD_CALL_RESIZE_CB;
write(platform->ctrl_pipe[1], &cmd, 1);
}
}
#endif
}
}
static void output_done(G_GNUC_UNUSED void *data, G_GNUC_UNUSED struct wl_output *output)
{
}
static void output_scale(G_GNUC_UNUSED void *data, G_GNUC_UNUSED struct wl_output *output, G_GNUC_UNUSED int scale)
{
}
static const struct wl_output_listener output_listener =
{
output_geometry,
output_mode,
output_done,
output_scale
};
static void handle_ping(G_GNUC_UNUSED void *data, struct wl_shell_surface *shell_surface, uint32_t serial)
{
wl_shell_surface_pong(shell_surface, serial);
}
static void handle_configure(void *data, G_GNUC_UNUSED struct wl_shell_surface *shell_surface, G_GNUC_UNUSED uint32_t edges, int32_t width, int32_t height)
{
GstImxEglVivSinkEGLPlatform *platform = data;
GST_LOG("reconfiguring window size to %dx%d pixels", width, height);
platform->current_width = width;
platform->current_height = height;
if (platform->native_window != NULL)
wl_egl_window_resize(platform->native_window, width, height, 0, 0);
if (platform->window_resized_event_cb != NULL)
platform->window_resized_event_cb(platform, width, height, platform->user_context);
else
glViewport(0, 0, width, height);
platform->pending_subsurface_desync = TRUE;
}
static void handle_popup_done(G_GNUC_UNUSED void *data, G_GNUC_UNUSED struct wl_shell_surface *shell_surface)
{
}
static const struct wl_shell_surface_listener shell_surface_listener =
{
handle_ping,
handle_configure,
handle_popup_done
};
static void frame_callback(void *data, struct wl_callback *callback, G_GNUC_UNUSED uint32_t time);
static const struct wl_callback_listener frame_listener =
{
frame_callback
};
static void background_draw(GstImxEglVivSinkEGLPlatform *platform);
static void frame_callback(void *data, struct wl_callback *callback, G_GNUC_UNUSED uint32_t time)
{
GstImxEglVivSinkEGLPlatform *platform = data;
/* Cleanup old callback */
if (callback != NULL)
wl_callback_destroy(callback);
platform->frame_callback_invoked = TRUE;
GST_LOG("frame_callback_invoked set to TRUE");
/* Setup new callback */
platform->frame_cb = wl_surface_frame(platform->surface);
wl_callback_add_listener(platform->frame_cb, &frame_listener, platform);
}
static void configure_callback(void *data, struct wl_callback *callback, uint32_t time)
{
GstImxEglVivSinkEGLPlatform *platform = data;
struct wl_region *input_region;
wl_callback_destroy(callback);
/* Position sub-surface. */
if (!platform->fullscreen &&
(platform->pending_x_coord != platform->x_coord ||
platform->pending_y_coord != platform->y_coord)) {
platform->x_coord = platform->pending_x_coord;
platform->y_coord = platform->pending_y_coord;
wl_subsurface_set_position(platform->subsurface,
platform->x_coord,
platform->y_coord);
}
/* Set the input region carefully so that we only receive events on the sub-surface. */
input_region = wl_compositor_create_region(platform->compositor);
wl_region_add(input_region, platform->x_coord, platform->y_coord,
platform->current_width, platform->current_height);
wl_surface_set_input_region(platform->main_surface, input_region);
wl_region_destroy(input_region);
platform->configured = TRUE;
background_draw(platform);
if (platform->frame_cb == NULL)
frame_callback(data, NULL, time);
}
static struct wl_callback_listener configure_callback_listener =
{
configure_callback,
};
static void background_draw(GstImxEglVivSinkEGLPlatform *platform)
{
if (!platform->configured || !platform->do_render)
return;
eglMakeCurrent(platform->egl_display,
platform->egl_main_surface,
platform->egl_main_surface,
platform->egl_context);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(platform->egl_display, platform->egl_main_surface);
}
static void redraw(GstImxEglVivSinkEGLPlatform *platform)
{
struct wl_region *region;
if (!platform->configured || !platform->do_render)
return;
eglMakeCurrent(platform->egl_display, platform->egl_surface, platform->egl_surface, platform->egl_context);
/* The actual rendering */
if (platform->render_frame_cb != NULL)
platform->render_frame_cb(platform, platform->user_context);
/* Define opaque region */
region = wl_compositor_create_region(platform->compositor);
wl_region_add(
region,
0, 0,
platform->current_width,
platform->current_height
);
wl_surface_set_opaque_region(platform->surface, region);
wl_region_destroy(region);
/* Finally, do the actual commit to the server */
wl_surface_commit(platform->main_surface);
eglSwapBuffers(platform->egl_display, platform->egl_surface);
}
GstImxEglVivSinkEGLPlatform* gst_imx_egl_viv_sink_egl_platform_create(gchar const *native_display_name, GstImxEglVivSinkWindowResizedEventCallback window_resized_event_cb, GstImxEglVivSinkWindowRenderFrameCallback render_frame_cb, gpointer user_context)
{
EGLint ver_major, ver_minor;
GstImxEglVivSinkEGLPlatform* platform;
g_assert(window_resized_event_cb != NULL);
g_assert(render_frame_cb != NULL);
static_global_init();
platform = (GstImxEglVivSinkEGLPlatform *)g_new0(GstImxEglVivSinkEGLPlatform, 1);
platform->window_resized_event_cb = window_resized_event_cb;
platform->render_frame_cb = render_frame_cb;
platform->user_context = user_context;
g_mutex_init(&(platform->mutex));
platform->ctrl_pipe[0] = -1;
platform->ctrl_pipe[1] = -1;
if (pipe(platform->ctrl_pipe) == -1)
{
GST_ERROR("error creating POSIX pipe: %s", strerror(errno));
goto cleanup;
}
platform->display = wl_display_connect(native_display_name);
if (platform->display == NULL)
{
GST_ERROR("wl_display_connect failed: %s", strerror(errno));
goto cleanup;
}
platform->registry = wl_display_get_registry(platform->display);
wl_registry_add_listener(platform->registry, ®istry_listener, platform);
if (wl_display_dispatch(platform->display) == -1)
{
GST_ERROR("wl_display_dispatch failed: %s", strerror(errno));
goto cleanup;
}
wl_output_add_listener(platform->output, &output_listener, platform);
if (wl_display_dispatch(platform->display) == -1)
{
GST_ERROR("wl_display_dispatch failed: %s", strerror(errno));
goto cleanup;
}
platform->display_fd = wl_display_get_fd(platform->display);
platform->egl_display = eglGetDisplay(platform->display);
if (platform->egl_display == EGL_NO_DISPLAY)
{
GST_ERROR("eglGetDisplay failed: %s", gst_imx_egl_viv_sink_egl_platform_get_last_error_string());
goto cleanup;
}
if (!eglInitialize(platform->egl_display, &ver_major, &ver_minor))
{
GST_ERROR("eglInitialize failed: %s", gst_imx_egl_viv_sink_egl_platform_get_last_error_string());
goto cleanup;
}
GST_INFO("Wayland EGL platform initialized, using EGL %d.%d", ver_major, ver_minor);
return platform;
cleanup:
/* either both are set, or none is */
if (platform->ctrl_pipe[0] != -1)
{
close(platform->ctrl_pipe[0]);
close(platform->ctrl_pipe[1]);
}
if (platform->display != NULL)
{
wl_display_flush(platform->display);
wl_display_disconnect(platform->display);
}
g_mutex_clear(&(platform->mutex));
g_free(platform);
return NULL;
}
void gst_imx_egl_viv_sink_egl_platform_destroy(GstImxEglVivSinkEGLPlatform *platform)
{
if (platform == NULL)
return;
eglMakeCurrent(platform->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (platform->egl_display != EGL_NO_DISPLAY)
eglTerminate(platform->egl_display);
#ifndef ILM_SUPPORT
if (platform->shell != NULL)
wl_shell_destroy(platform->shell);
#endif
if (platform->subcompositor != NULL)
wl_subcompositor_destroy(platform->subcompositor);
if (platform->compositor != NULL)
wl_compositor_destroy(platform->compositor);
if (platform->output != NULL)
wl_output_destroy(platform->output);
wl_display_flush(platform->display);
wl_display_disconnect(platform->display);
/* either both are set, or none is */
if (platform->ctrl_pipe[0] != -1)
{
close(platform->ctrl_pipe[0]);
close(platform->ctrl_pipe[1]);
}
g_mutex_clear(&(platform->mutex));
g_free(platform);
}
#ifdef ILM_SUPPORT
static int
create_ilm_surface(GstImxEglVivSinkEGLPlatform *platform)
{
int s_width = 0;
int s_height = 0;
ilmErrorTypes rtnv = 0;
s_width = platform->screen_width;
s_height = platform->screen_height;
ilm_initWithNativedisplay((t_ilm_nativedisplay)platform->display);
/* Creates ilm surfce */
rtnv = ilm_surfaceCreate((t_ilm_nativehandle)platform->main_surface,
s_width, s_height,
ILM_PIXELFORMAT_RGBA_8888, &ilmSurfaceId);
if (rtnv != ILM_SUCCESS)
{
printf("ilm_surfaceCreate Failed\n");
return 1;
}
rtnv = ilm_layerCreateWithDimension(&ilmLayerId, s_width, s_height);
rtnv = ilm_layerSetVisibility(ilmLayerId, ILM_TRUE);
rtnv = ilm_displaySetRenderOrder((t_ilm_display) 0, &ilmLayerId, 1);
rtnv = ilm_layerSetRenderOrder(ilmLayerId, &ilmSurfaceId, 1);
rtnv = ilm_surfaceSetDestinationRectangle(ilmSurfaceId, 0, 0, s_width, s_height);
rtnv = ilm_surfaceSetSourceRectangle(ilmSurfaceId, 0, 0, s_width, s_height);
rtnv = ilm_surfaceSetVisibility(ilmSurfaceId, ILM_TRUE);
rtnv = ilm_surfaceSetOpacity(ilmSurfaceId, 1.0f);
rtnv = ilm_setInputFocus(&ilmSurfaceId, 1, ILM_INPUT_DEVICE_TOUCH, ILM_TRUE);
rtnv = ilm_layerAddSurface(ilmLayerId, ilmSurfaceId);
rtnv = ilm_commitChanges();
if(rtnv != ILM_SUCCESS)
{
printf("create_ilm_surface Failed\n");
return 1;
}
printf("create_ilm_surface finished\n");
return rtnv;
}
#endif
gboolean gst_imx_egl_viv_sink_egl_platform_init_window(GstImxEglVivSinkEGLPlatform *platform, guintptr window_handle, gboolean event_handling, GstVideoInfo *video_info, gboolean fullscreen, gint x_coord, gint y_coord, guint width, guint height, G_GNUC_UNUSED gboolean borderless)
{
EGLint num_configs;
EGLConfig config;
guint chosen_width, chosen_height;
int actual_width, actual_height;
static EGLint const eglconfig_attribs[] =
{
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
static EGLint const ctx_attribs[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
EGL_PLATFORM_LOCK(platform);
if (!eglChooseConfig(platform->egl_display, eglconfig_attribs, &config, 1, &num_configs))
{
GST_ERROR("eglChooseConfig failed: %s", gst_imx_egl_viv_sink_egl_platform_get_last_error_string());
goto fail;
}
if (platform->compositor == NULL)
{
GST_ERROR("compositor pointer is NULL");
goto fail;
}
if (platform->subcompositor == NULL)
{
GST_ERROR("subcompositor pointer is NULL");
goto fail;
}
#ifndef ILM_SUPPORT
if (platform->shell == NULL)
{
GST_ERROR("shell pointer is NULL");
goto fail;
}
#endif
if ((platform->main_surface = wl_compositor_create_surface(platform->compositor)) == NULL)
{
GST_ERROR("creating main Wayland surface failed");
goto fail;
}
if ((platform->surface = wl_compositor_create_surface(platform->compositor)) == NULL)
{
GST_ERROR("creating Wayland surface failed");
goto fail;
}
if ((platform->subsurface = wl_subcompositor_get_subsurface(platform->subcompositor,
platform->surface, platform->main_surface)) == NULL)
{
GST_ERROR("creating Wayland subsurface failed");
goto fail;
}
#ifndef ILM_SUPPORT
if ((platform->shell_surface = wl_shell_get_shell_surface(platform->shell,
platform->main_surface)) == NULL)
{
GST_ERROR("creating Wayland shell surface failed");
goto fail;
}
wl_shell_surface_add_listener(platform->shell_surface, &shell_surface_listener, platform);
#endif
platform->pending_subsurface_desync = TRUE;
platform->fixed_window_width = width;
platform->fixed_window_height = height;
platform->video_par_n = GST_VIDEO_INFO_PAR_N(video_info);
platform->video_par_d = GST_VIDEO_INFO_PAR_D(video_info);
platform->video_width = GST_VIDEO_INFO_WIDTH(video_info);
platform->video_height = GST_VIDEO_INFO_HEIGHT(video_info);
platform->pending_x_coord = x_coord;
platform->pending_y_coord = y_coord;
platform->x_coord = -1;
platform->y_coord = -1;
platform->fullscreen = fullscreen;
/* If either no fixed size is set, or fullscreen is requested, use the video frame size
* In the fullscreen case, the size is actually irrelevant, since it will be overwritten
* with the screen size. But passing zero for the width/height values is invalid, the
* video frame size is used. */
if ((width == 0) || (height == 0) || fullscreen)
{
calculate_adjusted_window_size(platform, &chosen_width, &chosen_height);
/*chosen_width = platform->video_width;
chosen_height = platform->video_height;*/
}
else
{
chosen_width = width;
chosen_height = height;
}
platform->native_main_window = wl_egl_window_create(platform->main_surface,
platform->screen_width, platform->screen_height);
if (platform->native_main_window == NULL)
{
GST_ERROR("wl_egl_window_create failed to create the background window");
goto fail;
}
platform->native_window = wl_egl_window_create(platform->surface, chosen_width, chosen_height);
if (platform->native_window == NULL)
{
GST_ERROR("wl_egl_window_create failed to create a %dx%d window", width, height);
goto fail;
}
if (!eglBindAPI(EGL_OPENGL_ES_API))
{
GST_ERROR("eglBindAPI failed: %s", gst_imx_egl_viv_sink_egl_platform_get_last_error_string());
goto fail;
}
platform->egl_context = eglCreateContext(platform->egl_display, config, EGL_NO_CONTEXT, ctx_attribs);
if (platform->egl_context == EGL_NO_CONTEXT)
{
GST_ERROR("eglCreateContext failed: %s", gst_imx_egl_viv_sink_egl_platform_get_last_error_string());
goto fail;
}
platform->egl_main_surface = eglCreateWindowSurface(platform->egl_display, config, platform->native_main_window, NULL);
if (platform->egl_main_surface == EGL_NO_SURFACE)
{
GST_ERROR("eglCreateWindowSurface failed: %s", gst_imx_egl_viv_sink_egl_platform_get_last_error_string());
goto fail;
}
platform->egl_surface = eglCreateWindowSurface(platform->egl_display, config, platform->native_window, NULL);
if (platform->egl_surface == EGL_NO_SURFACE)
{
GST_ERROR("eglCreateWindowSurface failed: %s", gst_imx_egl_viv_sink_egl_platform_get_last_error_string());
goto fail;
}
if (!eglMakeCurrent(platform->egl_display, platform->egl_main_surface, platform->egl_main_surface, platform->egl_context))
{
GST_ERROR("eglMakeCurrent failed: %s", gst_imx_egl_viv_sink_egl_platform_get_last_error_string());
goto fail;
}
#ifndef ILM_SUPPORT
if (fullscreen)
wl_shell_surface_set_fullscreen(platform->shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);
else
wl_shell_surface_set_toplevel(platform->shell_surface);
#endif
{
struct wl_callback *callback = wl_display_sync(platform->display);
wl_callback_add_listener(callback, &configure_callback_listener, platform);
}
actual_width = chosen_width;
actual_height = chosen_height;
platform->current_width = actual_width;
platform->current_height = actual_height;
if (fullscreen || (platform->fixed_window_width != 0) || (platform->fixed_window_height != 0))
{
platform->fixed_window_width = actual_width;
platform->fixed_window_height = actual_height;
}
if (platform->window_resized_event_cb != NULL)
platform->window_resized_event_cb(platform, actual_width, actual_height, platform->user_context);
else
glViewport(0, 0, actual_width, actual_height);
#ifdef ILM_SUPPORT
create_ilm_surface(platform);
#endif
EGL_PLATFORM_UNLOCK(platform);
return TRUE;
fail:
EGL_PLATFORM_UNLOCK(platform);
return FALSE;
}
gboolean gst_imx_egl_viv_sink_egl_platform_shutdown_window(GstImxEglVivSinkEGLPlatform *platform)
{
if (platform->native_window == NULL)
return TRUE;
if (platform->frame_cb != NULL)
{
wl_callback_destroy(platform->frame_cb);
platform->frame_cb = NULL;
}
EGL_PLATFORM_LOCK(platform);
#ifdef ILM_SUPPORT
if (ilmSurfaceId > 0)
ilm_surfaceRemove(ilmSurfaceId);
//if(ilmLayerId > 0)
//ilm_layerRemove(ilmLayerId);
ilm_commitChanges();
ilm_destroy();
#endif
eglMakeCurrent(platform->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (platform->egl_context != EGL_NO_CONTEXT)
eglDestroyContext(platform->egl_display, platform->egl_context);
if (platform->egl_surface != EGL_NO_SURFACE)
eglDestroySurface(platform->egl_display, platform->egl_surface);
if (platform->egl_main_surface != EGL_NO_SURFACE)
eglDestroySurface(platform->egl_display, platform->egl_main_surface);
platform->egl_context = EGL_NO_CONTEXT;
platform->egl_surface = EGL_NO_SURFACE;
wl_egl_window_destroy(platform->native_window);
wl_egl_window_destroy(platform->native_main_window);
#ifndef ILM_SUPPORT
if (platform->shell_surface != NULL)
{
wl_shell_surface_destroy(platform->shell_surface);
platform->shell_surface = NULL;
}
#endif
if (platform->subsurface != NULL)
{
wl_subsurface_destroy(platform->subsurface);
platform->subsurface = NULL;
}
if (platform->surface != NULL)
{
wl_surface_destroy(platform->surface);
platform->surface = NULL;
}
if (platform->main_surface != NULL)
{
wl_surface_destroy(platform->main_surface);
platform->main_surface = NULL;
}
platform->native_window = NULL;
platform->native_main_window = NULL;
EGL_PLATFORM_UNLOCK(platform);
return TRUE;
}
void gst_imx_egl_viv_sink_egl_platform_set_event_handling(GstImxEglVivSinkEGLPlatform *platform, gboolean event_handling)
{
}
gboolean gst_imx_egl_viv_sink_egl_platform_set_gstreamer_element(GstImxEglVivSinkEGLPlatform *platform, GstElement *sink)
{
EGL_PLATFORM_LOCK(platform);
platform->sink = sink;
EGL_PLATFORM_UNLOCK(platform);
}
void gst_imx_egl_viv_sink_egl_platform_set_video_info(GstImxEglVivSinkEGLPlatform *platform, GstVideoInfo *video_info)
{
EGL_PLATFORM_LOCK(platform);
if (platform->native_window == 0)
{
GST_LOG("window not open - cannot set video info");
EGL_PLATFORM_UNLOCK(platform);
return;
}
platform->video_par_n = GST_VIDEO_INFO_PAR_N(video_info);
platform->video_par_d = GST_VIDEO_INFO_PAR_D(video_info);
platform->video_width = GST_VIDEO_INFO_WIDTH(video_info);
platform->video_height = GST_VIDEO_INFO_HEIGHT(video_info);
if (platform->fullscreen || (platform->fixed_window_width != 0) || (platform->fixed_window_height != 0)/* || (platform->parent_window != 0)*/) // TODO
{
}
else
{
resize_window_to_video(platform);
}
EGL_PLATFORM_UNLOCK(platform);
/* even though the window itself might not have been resized, the callback
* still needs to be invoked, because it depends on both the window and the
* video frame sizes */
if (platform->window_resized_event_cb != NULL)
{
// do not call the resize callback here directly; instead, notify the main loop about this change
// because here, the EGL context is not and cannot be set
char const cmd = GSTIMX_EGLWL_CMD_CALL_RESIZE_CB;
write(platform->ctrl_pipe[1], &cmd, 1);
}
}
gboolean gst_imx_egl_viv_sink_egl_platform_expose(GstImxEglVivSinkEGLPlatform *platform)
{
char const cmd = GSTIMX_EGLWL_CMD_REDRAW;
write(platform->ctrl_pipe[1], &cmd, 1);
return TRUE;
}
GstImxEglVivSinkMainloopRetval gst_imx_egl_viv_sink_egl_platform_mainloop(GstImxEglVivSinkEGLPlatform *platform)
{
struct pollfd fds[2];
int const nfds = sizeof(fds) / sizeof(struct pollfd);
gboolean continue_loop = TRUE;
platform->do_render = TRUE;
#ifdef ILM_SUPPORT
ilm_commitChanges();
#endif
while (continue_loop)
{
int ret;
gboolean do_redraw = FALSE;
/* Watch the display FD and a pipe that is used when poll() shall wake up
* (for example, when the pipeline is being shut down and run_mainloop has been set to FALSE) */
memset(&fds[0], 0, sizeof(fds));
fds[0].fd = platform->ctrl_pipe[0];
fds[0].events = POLLIN | POLLERR | POLLHUP;
fds[1].fd = platform->display_fd;
fds[1].events = POLLIN | POLLERR | POLLHUP;
//EGL_PLATFORM_LOCK(platform);
/* Start event handling; wl_display_prepare_read() announces the intention
* to read all events, taking care of race conditions that otherwise occur */
while (wl_display_prepare_read(platform->display) != 0)
wl_display_dispatch_pending(platform->display);
/* Flush requests, sending them to the server; if not all data could be sent to
* the server, have poll() also let it wait until it the display FD is writable again */
ret = wl_display_flush(platform->display);
if (ret < 0)
{
if (errno == EAGAIN)
{
fds[1].events |= POLLOUT;
}
else
{
EGL_PLATFORM_UNLOCK(platform);
GST_ERROR("error while flushing display: %s", strerror(errno));
break;
}
}
if (poll(&fds[0], nfds, -1) == -1)
{
GST_ERROR("error in poll() call: %s", strerror(errno));
wl_display_cancel_read(platform->display);
EGL_PLATFORM_UNLOCK(platform);
return GST_IMX_EGL_VIV_SINK_MAINLOOP_RETVAL_ERROR;
}
/* If there is something to read from the display FD, handle events */
if (fds[1].revents & POLLIN)
{
GST_LOG("There is something to read from the display FD - handling events");
wl_display_read_events(platform->display);
wl_display_dispatch(platform->display);
}
else
{
GST_LOG("Nothing to read from the display FD - canceling read");
wl_display_cancel_read(platform->display);
}
/* Read messages from the control pipe
* Note that this is done *after* reading from the display FD
* above, to make sure the event read block is finished by the
* time this place is reached */
if (fds[0].revents & POLLIN)
{
char cmd;
read(fds[0].fd, &cmd, sizeof(cmd));
GST_LOG("received cmd: %d", (int)cmd);
/* Stop if requested */
switch (cmd)
{
case GSTIMX_EGLWL_CMD_REDRAW:
do_redraw = TRUE;
break;
case GSTIMX_EGLWL_CMD_STOP_MAINLOOP:
continue_loop = FALSE;
GST_LOG("Mainloop stop requested");
break;
case GSTIMX_EGLWL_CMD_CALL_RESIZE_CB:
GST_LOG("Resize callback requested");
if (platform->window_resized_event_cb != NULL)
platform->window_resized_event_cb(platform, platform->current_width, platform->current_height, platform->user_context);
break;
default:
break;
}
}
if (do_redraw && platform->frame_callback_invoked)
{
redraw(platform);
platform->frame_callback_invoked = FALSE;
GST_LOG("frame_callback_invoked set to FALSE");
}
if (platform->pending_subsurface_desync)
{
wl_subsurface_set_desync(platform->subsurface);
platform->pending_subsurface_desync = FALSE;
}
//EGL_PLATFORM_UNLOCK(platform);
}
/* At this point, the sink is shutting down. Disable rendering in the frame callback. */
platform->do_render = FALSE;
return GST_IMX_EGL_VIV_SINK_MAINLOOP_RETVAL_OK;
}
void gst_imx_egl_viv_sink_egl_platform_stop_mainloop(GstImxEglVivSinkEGLPlatform *platform)
{
char cmd = GSTIMX_EGLWL_CMD_STOP_MAINLOOP;
write(platform->ctrl_pipe[1], &cmd, 1);
}
gboolean gst_imx_egl_viv_sink_egl_platform_set_coords(GstImxEglVivSinkEGLPlatform *platform, gint x_coord, gint y_coord)
{
EGL_PLATFORM_LOCK(platform);
platform->pending_x_coord = x_coord;
platform->pending_y_coord = y_coord;
EGL_PLATFORM_UNLOCK(platform);
return TRUE;
}
gboolean gst_imx_egl_viv_sink_egl_platform_set_size(GstImxEglVivSinkEGLPlatform *platform, guint width, guint height)
{
EGL_PLATFORM_LOCK(platform);
/* Only allow overwriting values if the window size can actually be modified */
if ((platform->fullscreen)/* || (platform->parent_window != 0)*/) // TODO
{
platform->fixed_window_width = width;
platform->fixed_window_height = height;
}
if ((platform->fullscreen)/* || (platform->parent_window != 0)*/) // TODO
{
// do nothing
}
else if ((width != 0) || (height != 0))
{
wl_egl_window_resize(platform->native_window, width, height, 0, 0);
platform->pending_subsurface_desync = TRUE;
}
else
{
resize_window_to_video(platform);
}
EGL_PLATFORM_UNLOCK(platform);
if (platform->window_resized_event_cb != NULL)
{
// do not call the resize callback here directly; instead, notify the main loop about this change
// because here, the EGL context is not and cannot be set
char const cmd = GSTIMX_EGLWL_CMD_CALL_RESIZE_CB;
write(platform->ctrl_pipe[1], &cmd, 1);
}
return TRUE;
}
gboolean gst_imx_egl_viv_sink_egl_platform_set_borderless(G_GNUC_UNUSED GstImxEglVivSinkEGLPlatform *platform, G_GNUC_UNUSED gboolean borderless)
{
/* Since borders are client-side in Wayland, nothing needs to be done here */
return TRUE;
}
_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel