modules: add Evas video output
authorThomas Guillem <thomas@gllm.fr>
Fri, 23 Oct 2015 16:45:38 +0000 (18:45 +0200)
committerThomas Guillem <thomas@gllm.fr>
Fri, 23 Oct 2015 17:28:15 +0000 (19:28 +0200)
NEWS
configure.ac
modules/MODULES_LIST
modules/video_output/Makefile.am
modules/video_output/evas.c [new file with mode: 0644]
po/POTFILES.in

diff --git a/NEWS b/NEWS
index 16ea9e3..b5615c0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -93,6 +93,7 @@ Video ouput:
  * Renamed the Direct3D output module to Direct3D9
  * Added Direct3D11 video mode supporting both Windows desktop and WinRT modes,
    supporting subpicture blending and hardware acceleration
+ * EFL Evas video output
 
 Text renderer:
  * CTL support through Harfbuzz in the Freetype module
index 2f57256..2438472 100644 (file)
@@ -3464,6 +3464,25 @@ fi
 AM_CONDITIONAL([HAVE_MMAL], [test "${have_mmal}" = "yes"])
 
 dnl
+dnl evas plugin
+dnl
+AC_ARG_ENABLE(evas,
+  [AS_HELP_STRING([--enable-evas],
+    [use evas output module (default disabled)])])
+have_evas="no"
+AS_IF([test "${enable_evas}" = "yes"], [
+  PKG_CHECK_MODULES(EVAS, [evas >= 1.15.99 ecore >= 1.15.99], [
+      have_evas="yes"
+      AC_DEFINE([HAVE_EVAS], [1], [Define to 1 if evas is enabled.])
+    ],[
+    AS_IF([test "x${enable_evas}" != "x"], [
+      AC_MSG_ERROR([$EVAS_PKG_ERRORS. libevas and libecore 1.15.99 or later required.])
+    ])
+  ])
+])
+AM_CONDITIONAL([HAVE_EVAS], [test "${have_evas}" = "yes"])
+
+dnl
 dnl  Audio plugins
 dnl
 
index a34dc6e..8a45602 100644 (file)
@@ -134,6 +134,7 @@ $Id$
  * equalizer: a equalizer audio filter
  * erase: Logo erase video filter
  * es: input module for MPEG ES decapsulation
+ * evas: EFL Evas video output
  * export: playlist export module
  * extract: Extract RGB components video filter
  * faad: AAC decoder using libfaad2
index b7179c2..896791c 100644 (file)
@@ -340,6 +340,16 @@ EXTRA_LTLIBRARIES += libcaca_plugin.la
 vout_LTLIBRARIES += $(LTLIBcaca)
 
 
+### EFL Evas video output ###
+libevas_plugin_la_SOURCES = video_output/evas.c
+libevas_plugin_la_CFLAGS = $(AM_CFLAGS) $(EVAS_CFLAGS)
+libevas_plugin_la_LIBADD = $(EVAS_LIBS)
+libevas_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
+if HAVE_EVAS
+vout_LTLIBRARIES += libevas_plugin.la
+endif
+
+
 ### Common ###
 libvdummy_plugin_la_SOURCES = video_output/vdummy.c
 libvmem_plugin_la_SOURCES = video_output/vmem.c
diff --git a/modules/video_output/evas.c b/modules/video_output/evas.c
new file mode 100644 (file)
index 0000000..e6c1f18
--- /dev/null
@@ -0,0 +1,1073 @@
+/*****************************************************************************
+ * evas.c: EFL Evas video output
+ *****************************************************************************
+ * Copyright (C) 2015 VLC authors, VideoLAN, and VideoLabs
+ *
+ * Authors: Thomas Guillem <thomas@gllm.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_vout_display.h>
+#include <vlc_picture_pool.h>
+#include <vlc_filter.h>
+
+#include <Evas.h>
+#include <Ecore.h>
+
+#if defined(EVAS_VERSION_MAJOR) && defined(EVAS_VERSION_MINOR)
+# if EVAS_VERSION_MAJOR > 1 || ( EVAS_VERSION_MAJOR == 1 && EVAS_VERSION_MINOR >= 10 )
+#  define HAVE_EVAS_CALLBACK_KEY_UP
+# endif
+#endif
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+#define CHROMA_TEXT "Chroma used"
+#define CHROMA_LONGTEXT "Force use of a specific chroma for evas image"
+
+static int  Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+vlc_module_begin()
+    set_category( CAT_VIDEO )
+    set_subcategory( SUBCAT_VIDEO_VOUT )
+    set_shortname( "evas" )
+    set_description( "evas video output" )
+    set_capability( "vout display", 220 )
+    add_shortcut( "evas" )
+    add_string( "evas-image-chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
+    set_callbacks( Open, Close )
+vlc_module_end()
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+static int EvasImageSetup( vout_display_t *vd );
+
+/* Buffer and Event Fifo */
+
+struct fifo_item
+{
+    struct fifo_item *p_next;
+};
+
+struct fifo
+{
+    vlc_mutex_t lock;
+    struct fifo_item *p_first;
+    struct fifo_item *p_last;
+};
+
+struct buffer
+{
+    struct fifo_item fifo_item;
+    uint8_t *p[PICTURE_PLANE_MAX];
+    bool b_locked;
+};
+
+struct event
+{
+    struct fifo_item fifo_item;
+    int i_type;
+    union {
+        int i_key;
+        int i_button;
+        struct {
+            int i_x, i_y;
+        } point;
+    } u;
+};
+
+struct vout_display_sys_t
+{
+    picture_pool_t  *p_pool;
+
+    int              i_width, i_height;
+
+    /* Planes */
+    plane_t          p_planes[PICTURE_PLANE_MAX];
+    int              i_planes_order[PICTURE_PLANE_MAX];
+    unsigned int     i_nb_planes;
+
+    /* Array of video buffers */
+    struct buffer   *p_buffers;
+    unsigned int     i_nb_buffers;
+
+    /* FIFO of unlocked video buffers */
+    struct fifo      buffer_fifo;
+
+    /* New buffer to display */
+    struct buffer   *p_new_buffer;
+    /* Buffer being displayed */
+    struct buffer   *p_current_buffer;
+
+    /* Evas */
+    Evas_Object     *p_evas;
+    Ecore_Animator  *p_anim;
+
+    /* If true: this module doesn't own the Evas_Object anymore */
+    bool             b_evas_changed;
+    /* If true: apply rotation to vd->fmt */
+    bool             b_apply_rotation;
+
+    /* FIFO of events */
+    struct fifo      event_fifo;
+
+    /* lock and cond used by EcoreMainLoopCallSync */
+    vlc_mutex_t      cb_lock;
+    vlc_cond_t       cb_wait;
+
+    union {
+        struct evas
+        {
+            Evas_Colorspace     i_colorspace;
+            bool                b_yuv;
+        } evas;
+    } u;
+
+    /* Specific callbacks for EvasImage or TBMSurface */
+    int     (*pf_set_data)( vout_display_t * );
+    int     (*pf_buffers_alloc)( vout_display_t *, video_format_t * );
+    void    (*pf_buffers_free)( vout_display_t * );
+    void    (*pf_update_ratio)( vout_display_t *, double );
+};
+
+struct picture_sys_t
+{
+    vout_display_sys_t *p_vd_sys;
+    struct buffer *p_buffer;
+};
+
+static void
+fifo_push( struct fifo *p_fifo, struct fifo_item *p_new )
+{
+    struct fifo_item *p_last;
+
+    vlc_mutex_lock( &p_fifo->lock );
+
+    p_new->p_next = NULL;
+    p_last = p_fifo->p_last;
+
+    if( p_last )
+        p_last->p_next = p_new;
+    else
+        p_fifo->p_first = p_new;
+    p_fifo->p_last = p_new;
+
+    vlc_mutex_unlock( &p_fifo->lock );
+}
+
+static struct fifo_item *
+fifo_pop( struct fifo *p_fifo )
+{
+    struct fifo_item *p_new;
+
+    vlc_mutex_lock( &p_fifo->lock );
+
+    p_new = p_fifo->p_first;
+
+    if( p_new )
+    {
+        if( p_fifo->p_last == p_fifo->p_first )
+            p_fifo->p_first = p_fifo->p_last = NULL;
+        else
+            p_fifo->p_first = p_new->p_next;
+    }
+
+    vlc_mutex_unlock( &p_fifo->lock );
+    return p_new;
+}
+
+static void
+fifo_init( struct fifo *p_fifo )
+{
+    vlc_mutex_init( &p_fifo->lock );
+    p_fifo->p_first = p_fifo->p_last = NULL;
+}
+
+static void
+fifo_deinit( struct fifo *p_fifo )
+{
+    vlc_mutex_destroy( &p_fifo->lock );
+}
+
+#define BUFFER_FIFO_PUSH( buffer ) fifo_push( &sys->buffer_fifo, (struct fifo_item *)(buffer) )
+#define BUFFER_FIFO_POP() (struct buffer *) fifo_pop( &sys->buffer_fifo )
+#define EVENT_FIFO_PUSH( event ) fifo_push( &sys->event_fifo, (struct fifo_item *)(event) )
+#define EVENT_FIFO_POP() (struct event *) fifo_pop( &sys->event_fifo )
+
+typedef int (*mainloop_cb)( vout_display_t *vd );
+
+struct mainloop_cb_args
+{
+    vout_display_t *vd;
+    mainloop_cb p_cb;
+    int i_ret;
+    bool b_signal;
+};
+
+static void
+EcoreMainLoopCb( void *p_opaque )
+{
+    struct mainloop_cb_args *p_args = p_opaque;
+    vout_display_sys_t *sys = p_args->vd->sys;
+
+    p_args->i_ret = p_args->p_cb( p_args->vd );
+
+    vlc_mutex_lock( &sys->cb_lock );
+    p_args->b_signal = true;
+    vlc_cond_signal( &sys->cb_wait );
+    vlc_mutex_unlock( &sys->cb_lock );
+}
+
+static int
+EcoreMainLoopCallSync( vout_display_t *vd, mainloop_cb p_cb )
+{
+    vout_display_sys_t *sys = vd->sys;
+    struct mainloop_cb_args args = { .vd = vd, .p_cb = p_cb, .b_signal = false };
+    ecore_main_loop_thread_safe_call_async( EcoreMainLoopCb, &args );
+
+    vlc_mutex_lock( &sys->cb_lock );
+    while( !args.b_signal )
+        vlc_cond_wait( &sys->cb_wait, &sys->cb_lock );
+    vlc_mutex_unlock( &sys->cb_lock );
+
+    return args.i_ret;
+}
+
+#ifdef HAVE_EVAS_CALLBACK_KEY_UP
+static void
+EventSendKey( vout_display_t *vd, int i_key )
+{
+    vout_display_sys_t *sys = vd->sys;
+    struct event *p_event = malloc( sizeof(struct event) );
+
+    if( !p_event )
+        return;
+    p_event->i_type = VOUT_DISPLAY_EVENT_KEY;
+    p_event->u.i_key = i_key;
+    EVENT_FIFO_PUSH( p_event );
+}
+
+static void
+EvasKeyUpCb( void *data, Evas *e, Evas_Object *obj, void *event )
+{
+    (void) e; (void) obj;
+    Evas_Event_Key_Up *p_key_up = (Evas_Event_Key_Up *) event;
+
+    EventSendKey( data, p_key_up->keycode );
+}
+#endif
+
+static void
+EventSendMouseMoved( vout_display_t *vd, int i_x, int i_y )
+{
+    vout_display_sys_t *sys = vd->sys;
+    Evas_Coord i_ox, i_oy, i_ow, i_oh;
+    struct event *p_event = malloc( sizeof(struct event) );
+
+    if( !p_event )
+        return;
+    evas_object_geometry_get( sys->p_evas, &i_ox, &i_oy, &i_ow, &i_oh );
+    p_event->i_type = VOUT_DISPLAY_EVENT_MOUSE_MOVED;
+    p_event->u.point.i_x = ( ( i_x - i_ox ) * sys->i_width ) / i_ow;
+    p_event->u.point.i_y = ( ( i_y - i_oy ) * sys->i_height ) / i_oh;
+    EVENT_FIFO_PUSH( p_event );
+}
+
+static void
+EventSendMouseButton( vout_display_t *vd, int i_type, int i_button )
+{
+    vout_display_sys_t *sys = vd->sys;
+    struct event *p_event = malloc( sizeof(struct event) );
+
+    if( !p_event )
+        return;
+    p_event->i_type = i_type;
+    p_event->u.i_button = i_button;
+    EVENT_FIFO_PUSH( p_event );
+}
+
+static void
+EventMouseDownCb( void *data, Evas *e, Evas_Object *obj, void *event )
+{
+    (void) e; (void) obj;
+    Evas_Event_Mouse_Down *p_mouse_down = (Evas_Event_Mouse_Down *) event;
+
+    EventSendMouseButton( data, VOUT_DISPLAY_EVENT_MOUSE_PRESSED,
+                             p_mouse_down->button - 1 );
+}
+
+static void
+EvasMouseUpCb( void *data, Evas *e, Evas_Object *obj, void *event )
+{
+    (void) e; (void) obj;
+    Evas_Event_Mouse_Up *p_mouse_up = (Evas_Event_Mouse_Up *) event;
+
+    EventSendMouseButton( data, VOUT_DISPLAY_EVENT_MOUSE_RELEASED,
+                             p_mouse_up->button - 1 );
+}
+
+static void
+EvasMouseMoveCb( void *data, Evas *e, Evas_Object *obj, void *event )
+{
+    (void) e; (void) obj;
+    Evas_Event_Mouse_Move *p_mouse_move = (Evas_Event_Mouse_Move *) event;
+    EventSendMouseMoved( data, p_mouse_move->cur.canvas.x,
+                            p_mouse_move->cur.canvas.y );
+}
+
+static void
+EvasMultiDownCb( void *data, Evas *e, Evas_Object *obj, void *event )
+{
+    (void) e; (void) obj; (void) event;
+    EventSendMouseButton( data, VOUT_DISPLAY_EVENT_MOUSE_PRESSED, 1 );
+}
+
+static void
+EvasMultiUpCb( void *data, Evas *e, Evas_Object *obj, void *event )
+{
+    (void) e; (void) obj; (void) event;
+    EventSendMouseButton( data, VOUT_DISPLAY_EVENT_MOUSE_RELEASED, 1 );
+}
+
+static void
+EvasMultiMoveCb( void *data, Evas *e, Evas_Object *obj, void *event )
+{
+    (void) e; (void) obj;
+    Evas_Event_Multi_Move *p_multi_move = (Evas_Event_Multi_Move *) event;
+
+    EventSendMouseMoved( data, p_multi_move->cur.canvas.x,
+                            p_multi_move->cur.canvas.y );
+}
+
+static void
+FmtUpdate( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+    vout_display_place_t place;
+    video_format_t src;
+
+    vout_display_PlacePicture( &place, &vd->source, vd->cfg, false );
+
+    if( sys->b_apply_rotation )
+    {
+        video_format_ApplyRotation( &src, &vd->source );
+        vd->fmt.orientation = 0;
+    }
+    else
+        src = vd->source;
+
+    vd->fmt.i_width  = src.i_width  * place.width / src.i_visible_width;
+    vd->fmt.i_height = src.i_height * place.height / src.i_visible_height;
+
+    vd->fmt.i_visible_width  = place.width;
+    vd->fmt.i_visible_height = place.height;
+    vd->fmt.i_x_offset = src.i_x_offset * place.width / src.i_visible_width;
+    vd->fmt.i_y_offset = src.i_y_offset * place.height / src.i_visible_height;
+
+    sys->i_width  = vd->fmt.i_visible_width;
+    sys->i_height = vd->fmt.i_visible_height;
+}
+
+static Eina_Bool
+mainloop_evas_anim_cb( void *p_opaque )
+{
+    vout_display_t *vd = p_opaque;
+    vout_display_sys_t *sys = vd->sys;
+    evas_object_image_pixels_dirty_set( sys->p_evas, 1 );
+
+    sys->p_anim = NULL;
+    return false;
+}
+
+static void
+EvasResizeCb( void *data, Evas *e, Evas_Object *obj, void *event )
+{
+    (void) e; (void) obj; (void) event;
+    vout_display_t *vd = data;
+    vout_display_sys_t *sys = vd->sys;
+
+    sys->b_evas_changed = true;
+}
+
+static int
+EvasDisplayMainloopCb( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if( sys->b_evas_changed || sys->pf_set_data( vd ) )
+        return -1;
+
+    evas_object_image_data_update_add( sys->p_evas, 0, 0,
+                                       sys->i_width, sys->i_height );
+    evas_object_image_pixels_dirty_set( sys->p_evas, 0 );
+
+    if( !sys->p_anim )
+        sys->p_anim = ecore_animator_add( mainloop_evas_anim_cb, vd );
+
+    if( sys->p_current_buffer )
+        BUFFER_FIFO_PUSH( sys->p_current_buffer );
+
+    sys->p_current_buffer = sys->p_new_buffer;
+    sys->p_new_buffer = NULL;
+    return 0;
+}
+
+static int
+EvasInitMainloopCb( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if( EvasImageSetup( vd ) )
+        return -1;
+
+    evas_object_image_alpha_set( sys->p_evas, 0 );
+    evas_object_image_size_set( sys->p_evas, sys->i_width, sys->i_height );
+
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MOUSE_DOWN,
+                                    EventMouseDownCb, vd );
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MOUSE_UP,
+                                    EvasMouseUpCb, vd );
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MOUSE_MOVE,
+                                    EvasMouseMoveCb, vd );
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MULTI_DOWN,
+                                    EvasMultiDownCb, vd );
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MULTI_UP,
+                                    EvasMultiUpCb, vd );
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MULTI_MOVE,
+                                    EvasMultiMoveCb, vd );
+#ifdef HAVE_EVAS_CALLBACK_KEY_UP
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_KEY_UP,
+                                    EvasKeyUpCb, sys );
+#endif
+
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_IMAGE_RESIZE,
+                                    EvasResizeCb, vd );
+
+    return 0;
+}
+
+static int
+EvasDeinitMainloopCb( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if( sys->p_anim )
+    {
+        ecore_animator_del( sys->p_anim );
+        sys->p_anim = NULL;
+    }
+
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_IMAGE_RESIZE,
+                                         EvasResizeCb, vd );
+
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MOUSE_DOWN,
+                                         EventMouseDownCb, vd );
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MOUSE_UP,
+                                         EvasMouseUpCb, vd );
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MOUSE_MOVE,
+                                         EvasMouseMoveCb, vd );
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MULTI_DOWN,
+                                         EvasMultiDownCb, vd );
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MULTI_UP,
+                                         EvasMultiUpCb, vd );
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MULTI_MOVE,
+                                         EvasMultiMoveCb, vd );
+#ifdef HAVE_EVAS_CALLBACK_KEY_UP
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_KEY_UP,
+                                         EvasKeyUpCb, vd );
+#endif
+
+    if( !sys->b_evas_changed )
+    {
+        evas_object_image_data_set( sys->p_evas, NULL );
+        evas_object_image_pixels_dirty_set( sys->p_evas, 0 );
+    }
+
+    return 0;
+}
+
+static int
+EvasResetMainloopCb( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if( sys->b_evas_changed )
+        return -1;
+
+    if( sys->p_anim )
+    {
+        ecore_animator_del( sys->p_anim );
+        sys->p_anim = NULL;
+    }
+
+    evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_IMAGE_RESIZE,
+                                         EvasResizeCb, vd );
+
+    FmtUpdate( vd );
+
+    evas_object_image_data_set( sys->p_evas, NULL );
+    evas_object_image_size_set( sys->p_evas, sys->i_width, sys->i_height );
+
+    evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_IMAGE_RESIZE,
+                                    EvasResizeCb, vd );
+    return 0;
+}
+
+static int
+BuffersSetup( vout_display_t *vd, video_format_t *p_fmt,
+              unsigned int *p_requested_count )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    sys->i_nb_buffers = *p_requested_count;
+    if( sys->pf_buffers_alloc( vd, p_fmt ) )
+    {
+        sys->i_nb_planes = 0;
+        return VLC_EGENERIC;
+    }
+    *p_requested_count = sys->i_nb_buffers;
+
+    for( unsigned int i = 0; i < sys->i_nb_buffers; ++i )
+        BUFFER_FIFO_PUSH( &sys->p_buffers[i] );
+    return VLC_SUCCESS;
+}
+
+static void
+BuffersClean( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if( sys->p_buffers )
+        sys->pf_buffers_free( vd );
+    sys->buffer_fifo.p_first = sys->buffer_fifo.p_last = NULL;
+}
+
+static picture_t *
+PictureAlloc( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+    picture_resource_t rsc;
+    picture_t *p_pic = NULL;
+    picture_sys_t *p_picsys = calloc(1, sizeof(*p_picsys));
+
+    if( !p_picsys )
+        return NULL;
+
+    p_picsys->p_vd_sys = vd->sys;
+    memset(&rsc, 0, sizeof(picture_resource_t));
+    rsc.p_sys = p_picsys;
+    for( unsigned int i = 0; i < sys->i_nb_planes; ++i )
+    {
+        rsc.p[i].i_lines = sys->p_planes[i].i_lines;
+        rsc.p[i].i_pitch = sys->p_planes[i].i_pitch;
+    }
+
+    p_pic = picture_NewFromResource( &vd->fmt, &rsc );
+    if( !p_pic )
+    {
+        free( p_picsys );
+        return NULL;
+    }
+
+    return p_pic;
+}
+
+static int
+PoolLockPicture(picture_t *p_pic)
+{
+    picture_sys_t *p_picsys = p_pic->p_sys;
+    vout_display_sys_t *sys = p_picsys->p_vd_sys;
+
+    struct buffer *p_buffer = BUFFER_FIFO_POP();
+    if( !p_buffer || !p_buffer->p[0] )
+        return -1;
+
+    p_picsys->p_buffer = p_buffer;
+    for( unsigned int i = 0; i < sys->i_nb_planes; ++i )
+        p_pic->p[i].p_pixels = p_buffer->p[i];
+    return 0;
+}
+
+static void
+PoolUnlockPicture(picture_t *p_pic)
+{
+    picture_sys_t *p_picsys = p_pic->p_sys;
+    vout_display_sys_t *sys = p_picsys->p_vd_sys;
+
+    if( p_picsys->p_buffer )
+    {
+        BUFFER_FIFO_PUSH( p_picsys->p_buffer );
+        p_picsys->p_buffer = NULL;
+    }
+}
+
+static picture_pool_t *
+PoolAlloc( vout_display_t *vd, unsigned i_requested_count )
+{
+    picture_t **pp_pics = NULL;
+    picture_pool_t *p_pool;
+    picture_pool_configuration_t pool_cfg;
+
+    msg_Dbg(vd, "PoolAlloc, requested_count: %d", i_requested_count);
+
+    i_requested_count++; /* picture owned by evas */
+
+    if( BuffersSetup( vd, &vd->fmt, &i_requested_count) )
+    {
+        msg_Err( vd, "BuffersSetup failed" );
+        return NULL;
+    }
+    if( i_requested_count <= 1 )
+    {
+        msg_Err( vd, "not enough buffers allocated" );
+        goto error;
+    }
+    i_requested_count--;
+
+    msg_Dbg( vd, "PoolAlloc, got: %d", i_requested_count );
+
+    if( !( pp_pics = calloc( i_requested_count, sizeof(picture_t) ) ) )
+        goto error;
+
+    for( unsigned int i = 0; i < i_requested_count; ++i )
+    {
+        if( !( pp_pics[i] = PictureAlloc( vd ) ) )
+        {
+            i_requested_count = i;
+            msg_Err( vd, "PictureAlloc failed" );
+            goto error;
+        }
+    }
+
+    memset( &pool_cfg, 0, sizeof(pool_cfg) );
+    pool_cfg.picture_count = i_requested_count;
+    pool_cfg.picture       = pp_pics;
+    pool_cfg.lock          = PoolLockPicture;
+    pool_cfg.unlock        = PoolUnlockPicture;
+
+    p_pool = picture_pool_NewExtended( &pool_cfg );
+    if( p_pool )
+        return p_pool;
+
+error:
+    if( pp_pics )
+    {
+        for( unsigned int i = 0; i < i_requested_count; ++i )
+            picture_Release( pp_pics[i] );
+        free( pp_pics );
+    }
+    BuffersClean( vd );
+    return NULL;
+}
+
+static picture_pool_t *
+Pool( vout_display_t *vd, unsigned i_requested_count )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if( sys->p_pool == NULL )
+        sys->p_pool = PoolAlloc( vd, i_requested_count );
+    return sys->p_pool;
+}
+
+static void
+Display( vout_display_t *vd, picture_t *p_pic, subpicture_t *p_subpic )
+{
+    (void) p_subpic;
+    vout_display_sys_t *sys = vd->sys;
+    picture_sys_t *p_picsys = p_pic->p_sys;
+
+    if( p_picsys->p_buffer )
+    {
+        sys->p_new_buffer = p_picsys->p_buffer;
+        p_picsys->p_buffer = NULL;
+
+        EcoreMainLoopCallSync( vd, EvasDisplayMainloopCb );
+    }
+    picture_Release( p_pic );
+}
+
+static int
+Control( vout_display_t *vd, int i_query, va_list ap )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    switch( i_query )
+    {
+    case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
+    {
+        const video_format_t *p_source;
+        vout_display_place_t place;
+        video_format_t fmt;
+
+        msg_Dbg( vd, "VOUT_DISPLAY_CHANGE_SOURCE_ASPECT" );
+
+        p_source = (const video_format_t *)va_arg( ap, const video_format_t * );
+
+        video_format_ApplyRotation( &fmt, p_source );
+        vout_display_PlacePicture( &place, &fmt, vd->cfg, false );
+
+        if( place.width != (unsigned) sys->i_width
+         && place.height != (unsigned) sys->i_height )
+        {
+            if( vd->info.has_pictures_invalid )
+            {
+                msg_Warn( vd, "ratio changed: invalidate pictures" );
+                vout_display_SendEventPicturesInvalid( vd );
+            }
+            else if( sys->pf_update_ratio )
+                sys->pf_update_ratio( vd, place.width / (double) place.height );
+            else
+                return VLC_EGENERIC;
+        }
+        return VLC_SUCCESS;
+    }
+    case VOUT_DISPLAY_CHANGE_FULLSCREEN:
+        return VLC_SUCCESS;
+    case VOUT_DISPLAY_RESET_PICTURES:
+        msg_Dbg( vd, "VOUT_DISPLAY_RESET_PICTURES" );
+
+        EcoreMainLoopCallSync( vd, EvasResetMainloopCb );
+
+        BuffersClean( vd );
+
+        if( sys->p_pool )
+        {
+            picture_pool_Release( sys->p_pool );
+            sys->p_pool = NULL;
+        }
+        return VLC_SUCCESS;
+    case VOUT_DISPLAY_CHANGE_ZOOM:
+    case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
+    case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
+    case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
+    case VOUT_DISPLAY_HIDE_MOUSE:
+        return VLC_EGENERIC;
+    default:
+        msg_Warn( vd, "Unknown request in evas_output" );
+        return VLC_EGENERIC;
+    }
+}
+
+static void
+Manage( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+    struct event *p_event;
+
+    while( ( p_event = EVENT_FIFO_POP() ) )
+    {
+        switch( p_event->i_type )
+        {
+            case VOUT_DISPLAY_EVENT_MOUSE_MOVED:
+                vout_display_SendEventMouseMoved( vd, p_event->u.point.i_x,
+                                                  p_event->u.point.i_y );
+                break;
+            case VOUT_DISPLAY_EVENT_MOUSE_PRESSED:
+            case VOUT_DISPLAY_EVENT_MOUSE_RELEASED:
+                vout_display_SendEvent( vd, p_event->i_type,
+                                        p_event->u.i_button );
+                break;
+            case VOUT_DISPLAY_EVENT_KEY:
+                vout_display_SendEventKey( vd, p_event->u.i_key );
+                break;
+        }
+        free( p_event );
+    }
+}
+
+static void
+Close( vlc_object_t *p_this )
+{
+    vout_display_t *vd = (vout_display_t *)p_this;
+    vout_display_sys_t *sys = vd->sys;
+    struct event *p_event;
+
+    if (!sys)
+        return;
+
+    EcoreMainLoopCallSync( vd, EvasDeinitMainloopCb );
+
+    BuffersClean( vd );
+    fifo_deinit( &sys->buffer_fifo );
+
+    if( sys->p_pool )
+        picture_pool_Release(sys->p_pool);
+
+    while( ( p_event = EVENT_FIFO_POP() ) )
+        free( p_event );
+
+    vlc_mutex_destroy( &sys->cb_lock );
+    vlc_cond_destroy( &sys->cb_wait );
+
+    free( sys );
+}
+
+static int
+Open( vlc_object_t *p_this )
+{
+    vout_display_t *vd = (vout_display_t*)p_this;
+    vout_display_sys_t *sys;
+    Evas_Object *p_evas;
+
+    if( vout_display_IsWindowed( vd ) )
+        return VLC_EGENERIC;
+
+    p_evas = var_InheritAddress( p_this, "drawable-evasobject" );
+    if( !p_evas )
+        return VLC_EGENERIC;
+
+    vd->sys = sys = (struct vout_display_sys_t *) calloc( 1, sizeof(*sys) );
+    if( !sys )
+        return VLC_ENOMEM;
+
+    vlc_mutex_init( &sys->cb_lock );
+    vlc_cond_init( &sys->cb_wait );
+    fifo_init( &sys->buffer_fifo );
+    fifo_init( &sys->event_fifo );
+
+    sys->p_evas = p_evas;
+
+    msg_Dbg( vd, "request video format: %4.4s",
+             (const char *)&vd->fmt.i_chroma );
+
+    /* Evas Initialisation must be done from the Mainloop */
+    if( EcoreMainLoopCallSync( vd, EvasInitMainloopCb ) )
+    {
+        msg_Err( vd, "EvasInitMainloopCb failed" );
+        Close( p_this );
+        return VLC_EGENERIC;
+    }
+
+    for( unsigned int i = 0; i < PICTURE_PLANE_MAX; ++i )
+        sys->i_planes_order[i] = i;
+
+    switch( vd->fmt.i_chroma )
+    {
+        case VLC_CODEC_RGB32:
+        case VLC_CODEC_RGB16:
+            video_format_FixRgb(&vd->fmt);
+            break;
+        case VLC_CODEC_YV12:
+            sys->i_planes_order[1] = 2;
+            sys->i_planes_order[2] = 1;
+        default:
+            break;
+    }
+
+    msg_Dbg( vd, "got video format: %4.4s, size: %dx%d",
+             (const char *)&vd->fmt.i_chroma,
+             sys->i_width, sys->i_height );
+
+    /* Setup vout_display */
+    vd->pool    = Pool;
+    vd->prepare = NULL;
+    vd->display = Display;
+    vd->control = Control;
+    vd->manage  = Manage;
+
+    vd->info.has_event_thread = true;
+
+    /* Fix initial state */
+    vout_display_SendEventFullscreen( vd, true );
+
+    return VLC_SUCCESS;
+}
+
+static int
+EvasImageSetData( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+    struct buffer *p_buffer = sys->p_new_buffer;
+
+    if( sys->u.evas.b_yuv )
+    {
+        void *p_data = evas_object_image_data_get( sys->p_evas, 1 );
+        const uint8_t **pp_rows = (const uint8_t **) p_data;
+
+        if( !p_data )
+            return -1;
+
+        for( unsigned int i = 0; i < sys->i_nb_planes; ++i )
+        {
+            plane_t *p_plane = &sys->p_planes[sys->i_planes_order[i]];
+
+            for( int j = 0; j < p_plane->i_visible_lines; ++j )
+                *(pp_rows++) = &p_buffer->p[i][j * p_plane->i_pitch];
+        }
+
+        evas_object_image_data_set( sys->p_evas, p_data );
+    }
+    else
+        evas_object_image_data_set( sys->p_evas, p_buffer->p[0] );
+
+    return 0;
+}
+
+static void
+EvasImageBuffersFree( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    for( unsigned int i = 0; i < sys->i_nb_buffers; i++ )
+        free( sys->p_buffers[i].p[0] );
+    free( sys->p_buffers );
+    sys->p_buffers = NULL;
+    sys->i_nb_buffers = 0;
+    sys->i_nb_planes = 0;
+}
+
+static int
+EvasImageBuffersAlloc( vout_display_t *vd, video_format_t *p_fmt )
+{
+    vout_display_sys_t *sys = vd->sys;
+    picture_t *p_pic = NULL;
+    picture_resource_t rsc;
+    size_t i_bytes = 0;
+
+    memset(&rsc, 0, sizeof(picture_resource_t));
+    if( !( p_pic = picture_NewFromResource( p_fmt, &rsc ) ) )
+        return -1;
+
+    if( picture_Setup( p_pic, p_fmt ) )
+    {
+        picture_Release( p_pic );
+        return -1;
+    }
+
+    for( int i = 0; i < p_pic->i_planes; ++i )
+        memcpy( &sys->p_planes[i], &p_pic->p[i], sizeof(plane_t));
+    sys->i_nb_planes = p_pic->i_planes;
+    picture_Release( p_pic );
+
+    if( !( sys->p_buffers = calloc( sys->i_nb_buffers, sizeof(struct buffer) ) ) )
+        goto error;
+
+    /* Calculate how big the new image should be */
+    for( unsigned int i = 0; i < sys->i_nb_planes; i++ )
+    {
+        const plane_t *p = &sys->p_planes[i];
+
+        if( p->i_pitch < 0 || p->i_lines <= 0 ||
+            (size_t)p->i_pitch > (SIZE_MAX - i_bytes)/p->i_lines )
+            goto error;
+        i_bytes += p->i_pitch * p->i_lines;
+    }
+
+    if( !i_bytes )
+        goto error;
+
+    for( unsigned int i = 0; i < sys->i_nb_buffers; ++i )
+    {
+        struct buffer *p_buffer = &sys->p_buffers[i];
+
+        p_buffer->p[0] = vlc_memalign( 16, i_bytes );
+
+        if( !p_buffer->p[0] )
+        {
+            sys->i_nb_buffers = i;
+            break;
+        }
+
+        for( unsigned int j = 1; j < sys->i_nb_planes; j++ )
+            p_buffer->p[j] = &p_buffer->p[j-1][ sys->p_planes[j-1].i_lines *
+                                                sys->p_planes[j-1].i_pitch ];
+    }
+
+    return 0;
+
+error:
+    if( sys->p_buffers )
+        EvasImageBuffersFree( vd );
+    return -1;
+}
+
+static int
+EvasImageSetup( vout_display_t *vd )
+{
+    vout_display_sys_t *sys = vd->sys;
+    char *psz_fcc = var_InheritString( vd, "evas-image-chroma" );
+
+    if( psz_fcc )
+    {
+        vd->fmt.i_chroma = vlc_fourcc_GetCodecFromString( VIDEO_ES, psz_fcc );
+        free( psz_fcc );
+    }
+
+    switch( vd->fmt.i_chroma )
+    {
+        case VLC_CODEC_RGB32:
+            sys->u.evas.i_colorspace = EVAS_COLORSPACE_ARGB8888;
+            break;
+        /* Not implemented yet */
+#if 0
+        case VLC_CODEC_RGB16:
+            sys->u.evas.i_colorspace = EVAS_COLORSPACE_RGB565_A5P;
+            break;
+#endif
+        case VLC_CODEC_YUYV:
+            sys->u.evas.i_colorspace = EVAS_COLORSPACE_YCBCR422601_PL;
+            sys->u.evas.b_yuv = true;
+            break;
+        /* FIXME: SIGSEGV in evas_gl_common_texture_nv12_update */
+#if 0
+        case VLC_CODEC_NV12:
+            sys->u.evas.i_colorspace = EVAS_COLORSPACE_YCBCR420NV12601_PL;
+            sys->u.evas.b_yuv = true;
+            break;
+#endif
+        case VLC_CODEC_YV12:
+            sys->u.evas.i_colorspace = EVAS_COLORSPACE_YCBCR422P601_PL;
+            sys->u.evas.b_yuv = true;
+            break;
+        default:
+        case VLC_CODEC_I420:
+            sys->u.evas.i_colorspace = EVAS_COLORSPACE_YCBCR422P601_PL;
+            vd->fmt.i_chroma = VLC_CODEC_I420;
+            sys->u.evas.b_yuv = true;
+            break;
+    }
+
+    evas_object_image_colorspace_set( sys->p_evas, sys->u.evas.i_colorspace );
+    evas_object_image_data_set( sys->p_evas, NULL );
+
+    /* No rotation support with EvasImage */
+    sys->b_apply_rotation = true;
+    FmtUpdate( vd );
+
+    /* No aspect ratio support with EvasImage */
+    vd->info.has_pictures_invalid = true;
+
+    sys->pf_set_data = EvasImageSetData;
+    sys->pf_buffers_alloc = EvasImageBuffersAlloc;
+    sys->pf_buffers_free = EvasImageBuffersFree;
+    sys->pf_update_ratio = NULL;
+
+    msg_Dbg( vd, "using evas_image" );
+    return 0;
+}
index c8bebfd..efc46bb 100644 (file)
@@ -1157,6 +1157,7 @@ modules/video_output/caopengllayer.m
 modules/video_output/decklink.cpp
 modules/video_output/directfb.c
 modules/video_output/drawable.c
+modules/video_output/evas.c
 modules/video_output/egl.c
 modules/video_output/fb.c
 modules/video_output/gl.c