vout: invert default for event thread
[vlc.git] / modules / video_output / evas.c
1 /*****************************************************************************
2  * evas.c: EFL Evas video output
3  *****************************************************************************
4  * Copyright (C) 2015 VLC authors, VideoLAN, and VideoLabs
5  *
6  * Authors: Thomas Guillem <thomas@gllm.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <assert.h>
28
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_vout_display.h>
32 #include <vlc_picture_pool.h>
33 #include <vlc_filter.h>
34
35 #include <Evas.h>
36 #include <Ecore.h>
37
38 /* Deactivate TBM surface for now: it's impossible to specify a crop (visible
39  * lines/pitch) and to avoid green borders. */
40 #undef HAVE_TIZEN_SDK
41
42 #ifdef HAVE_TIZEN_SDK
43 # include <tbm_surface.h>
44 #endif
45
46 #if defined(EVAS_VERSION_MAJOR) && defined(EVAS_VERSION_MINOR)
47 # if EVAS_VERSION_MAJOR > 1 || ( EVAS_VERSION_MAJOR == 1 && EVAS_VERSION_MINOR >= 10 )
48 #  define HAVE_EVAS_CALLBACK_KEY_UP
49 # endif
50 #endif
51
52 /*****************************************************************************
53  * Module descriptor
54  *****************************************************************************/
55 #define CHROMA_TEXT "Chroma used"
56 #define CHROMA_LONGTEXT "Force use of a specific chroma for evas image"
57
58 static int  Open ( vlc_object_t * );
59 static void Close( vlc_object_t * );
60
61 vlc_module_begin()
62     set_category( CAT_VIDEO )
63     set_subcategory( SUBCAT_VIDEO_VOUT )
64     set_shortname( "evas" )
65     set_description( "evas video output" )
66     set_capability( "vout display", 220 )
67     add_shortcut( "evas" )
68     add_string( "evas-image-chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
69     set_callbacks( Open, Close )
70 vlc_module_end()
71
72 /*****************************************************************************
73  * Local prototypes
74  *****************************************************************************/
75
76 static int EvasImageSetup( vout_display_t * );
77 #ifdef HAVE_TIZEN_SDK
78 static bool EvasIsOpenGLSupported( vout_display_t * );
79 static int TbmSurfaceSetup( vout_display_t * );
80 #endif
81
82 /* Buffer and Event Fifo */
83
84 struct fifo_item
85 {
86     struct fifo_item *p_next;
87 };
88
89 struct fifo
90 {
91     vlc_mutex_t lock;
92     struct fifo_item *p_first;
93     struct fifo_item *p_last;
94 };
95
96 struct buffer
97 {
98     struct fifo_item fifo_item;
99     uint8_t *p[PICTURE_PLANE_MAX];
100     bool b_locked;
101 #ifdef HAVE_TIZEN_SDK
102     tbm_surface_h p_tbm_surface;
103 #endif
104 };
105
106 struct event
107 {
108     struct fifo_item fifo_item;
109     int i_type;
110     union {
111         int i_key;
112         int i_button;
113         struct {
114             int i_x, i_y;
115         } point;
116     } u;
117 };
118
119 struct vout_display_sys_t
120 {
121     picture_pool_t  *p_pool;
122
123     int              i_width, i_height;
124
125     /* Planes */
126     plane_t          p_planes[PICTURE_PLANE_MAX];
127     int              i_planes_order[PICTURE_PLANE_MAX];
128     unsigned int     i_nb_planes;
129
130     /* Array of video buffers */
131     struct buffer   *p_buffers;
132     unsigned int     i_nb_buffers;
133
134     /* FIFO of unlocked video buffers */
135     struct fifo      buffer_fifo;
136
137     /* New buffer to display */
138     struct buffer   *p_new_buffer;
139     /* Buffer being displayed */
140     struct buffer   *p_current_buffer;
141
142     /* Evas */
143     Evas_Object     *p_evas;
144     Ecore_Animator  *p_anim;
145
146     /* If true: this module doesn't own the Evas_Object anymore */
147     bool             b_evas_changed;
148     /* If true: apply rotation to vd->fmt */
149     bool             b_apply_rotation;
150
151     /* FIFO of events */
152     struct fifo      event_fifo;
153
154     /* lock and cond used by EcoreMainLoopCallSync */
155     vlc_mutex_t      cb_lock;
156     vlc_cond_t       cb_wait;
157
158     union {
159         struct evas
160         {
161             Evas_Colorspace     i_colorspace;
162             bool                b_yuv;
163         } evas;
164 #ifdef HAVE_TIZEN_SDK
165         struct {
166             tbm_format          i_format;
167             int                 i_angle;
168         } tbm;
169 #endif
170     } u;
171
172     /* Specific callbacks for EvasImage or TBMSurface */
173     int     (*pf_set_data)( vout_display_t * );
174     int     (*pf_buffers_alloc)( vout_display_t *, video_format_t * );
175     void    (*pf_buffers_free)( vout_display_t * );
176 };
177
178 struct picture_sys_t
179 {
180     vout_display_sys_t *p_vd_sys;
181     struct buffer *p_buffer;
182 };
183
184 static void
185 fifo_push( struct fifo *p_fifo, struct fifo_item *p_new )
186 {
187     struct fifo_item *p_last;
188
189     vlc_mutex_lock( &p_fifo->lock );
190
191     p_new->p_next = NULL;
192     p_last = p_fifo->p_last;
193
194     if( p_last )
195         p_last->p_next = p_new;
196     else
197         p_fifo->p_first = p_new;
198     p_fifo->p_last = p_new;
199
200     vlc_mutex_unlock( &p_fifo->lock );
201 }
202
203 static struct fifo_item *
204 fifo_pop( struct fifo *p_fifo )
205 {
206     struct fifo_item *p_new;
207
208     vlc_mutex_lock( &p_fifo->lock );
209
210     p_new = p_fifo->p_first;
211
212     if( p_new )
213     {
214         if( p_fifo->p_last == p_fifo->p_first )
215             p_fifo->p_first = p_fifo->p_last = NULL;
216         else
217             p_fifo->p_first = p_new->p_next;
218     }
219
220     vlc_mutex_unlock( &p_fifo->lock );
221     return p_new;
222 }
223
224 static void
225 fifo_init( struct fifo *p_fifo )
226 {
227     vlc_mutex_init( &p_fifo->lock );
228     p_fifo->p_first = p_fifo->p_last = NULL;
229 }
230
231 static void
232 fifo_deinit( struct fifo *p_fifo )
233 {
234     vlc_mutex_destroy( &p_fifo->lock );
235 }
236
237 #define BUFFER_FIFO_PUSH( buffer ) fifo_push( &sys->buffer_fifo, (struct fifo_item *)(buffer) )
238 #define BUFFER_FIFO_POP() (struct buffer *) fifo_pop( &sys->buffer_fifo )
239 #define EVENT_FIFO_PUSH( event ) fifo_push( &sys->event_fifo, (struct fifo_item *)(event) )
240 #define EVENT_FIFO_POP() (struct event *) fifo_pop( &sys->event_fifo )
241
242 typedef int (*mainloop_cb)( vout_display_t *vd );
243
244 struct mainloop_cb_args
245 {
246     vout_display_t *vd;
247     mainloop_cb p_cb;
248     int i_ret;
249     bool b_signal;
250 };
251
252 static void
253 EcoreMainLoopCb( void *p_opaque )
254 {
255     struct mainloop_cb_args *p_args = p_opaque;
256     vout_display_sys_t *sys = p_args->vd->sys;
257
258     p_args->i_ret = p_args->p_cb( p_args->vd );
259
260     vlc_mutex_lock( &sys->cb_lock );
261     p_args->b_signal = true;
262     vlc_cond_signal( &sys->cb_wait );
263     vlc_mutex_unlock( &sys->cb_lock );
264 }
265
266 static int
267 EcoreMainLoopCallSync( vout_display_t *vd, mainloop_cb p_cb )
268 {
269     vout_display_sys_t *sys = vd->sys;
270     struct mainloop_cb_args args = { .vd = vd, .p_cb = p_cb, .b_signal = false };
271     ecore_main_loop_thread_safe_call_async( EcoreMainLoopCb, &args );
272
273     vlc_mutex_lock( &sys->cb_lock );
274     while( !args.b_signal )
275         vlc_cond_wait( &sys->cb_wait, &sys->cb_lock );
276     vlc_mutex_unlock( &sys->cb_lock );
277
278     return args.i_ret;
279 }
280
281 #ifdef HAVE_EVAS_CALLBACK_KEY_UP
282 static void
283 EventSendKey( vout_display_t *vd, int i_key )
284 {
285     vout_display_sys_t *sys = vd->sys;
286     struct event *p_event = malloc( sizeof(struct event) );
287
288     if( !p_event )
289         return;
290     p_event->i_type = VOUT_DISPLAY_EVENT_KEY;
291     p_event->u.i_key = i_key;
292     EVENT_FIFO_PUSH( p_event );
293 }
294
295 static void
296 EvasKeyUpCb( void *data, Evas *e, Evas_Object *obj, void *event )
297 {
298     (void) e; (void) obj;
299     Evas_Event_Key_Up *p_key_up = (Evas_Event_Key_Up *) event;
300
301     EventSendKey( data, p_key_up->keycode );
302 }
303 #endif
304
305 static void
306 EventSendMouseMoved( vout_display_t *vd, int i_x, int i_y )
307 {
308     vout_display_sys_t *sys = vd->sys;
309     Evas_Coord i_ox, i_oy, i_ow, i_oh;
310     struct event *p_event = malloc( sizeof(struct event) );
311
312     if( !p_event )
313         return;
314     evas_object_geometry_get( sys->p_evas, &i_ox, &i_oy, &i_ow, &i_oh );
315     p_event->i_type = VOUT_DISPLAY_EVENT_MOUSE_MOVED;
316     p_event->u.point.i_x = ( ( i_x - i_ox ) * sys->i_width ) / i_ow;
317     p_event->u.point.i_y = ( ( i_y - i_oy ) * sys->i_height ) / i_oh;
318     EVENT_FIFO_PUSH( p_event );
319 }
320
321 static void
322 EventSendMouseButton( vout_display_t *vd, int i_type, int i_button )
323 {
324     vout_display_sys_t *sys = vd->sys;
325     struct event *p_event = malloc( sizeof(struct event) );
326
327     if( !p_event )
328         return;
329     p_event->i_type = i_type;
330     p_event->u.i_button = i_button;
331     EVENT_FIFO_PUSH( p_event );
332 }
333
334 static void
335 EventMouseDownCb( void *data, Evas *e, Evas_Object *obj, void *event )
336 {
337     (void) e; (void) obj;
338     Evas_Event_Mouse_Down *p_mouse_down = (Evas_Event_Mouse_Down *) event;
339
340     EventSendMouseButton( data, VOUT_DISPLAY_EVENT_MOUSE_PRESSED,
341                              p_mouse_down->button - 1 );
342 }
343
344 static void
345 EvasMouseUpCb( void *data, Evas *e, Evas_Object *obj, void *event )
346 {
347     (void) e; (void) obj;
348     Evas_Event_Mouse_Up *p_mouse_up = (Evas_Event_Mouse_Up *) event;
349
350     EventSendMouseButton( data, VOUT_DISPLAY_EVENT_MOUSE_RELEASED,
351                              p_mouse_up->button - 1 );
352 }
353
354 static void
355 EvasMouseMoveCb( void *data, Evas *e, Evas_Object *obj, void *event )
356 {
357     (void) e; (void) obj;
358     Evas_Event_Mouse_Move *p_mouse_move = (Evas_Event_Mouse_Move *) event;
359     EventSendMouseMoved( data, p_mouse_move->cur.canvas.x,
360                             p_mouse_move->cur.canvas.y );
361 }
362
363 static void
364 EvasMultiDownCb( void *data, Evas *e, Evas_Object *obj, void *event )
365 {
366     (void) e; (void) obj; (void) event;
367     EventSendMouseButton( data, VOUT_DISPLAY_EVENT_MOUSE_PRESSED, 1 );
368 }
369
370 static void
371 EvasMultiUpCb( void *data, Evas *e, Evas_Object *obj, void *event )
372 {
373     (void) e; (void) obj; (void) event;
374     EventSendMouseButton( data, VOUT_DISPLAY_EVENT_MOUSE_RELEASED, 1 );
375 }
376
377 static void
378 EvasMultiMoveCb( void *data, Evas *e, Evas_Object *obj, void *event )
379 {
380     (void) e; (void) obj;
381     Evas_Event_Multi_Move *p_multi_move = (Evas_Event_Multi_Move *) event;
382
383     EventSendMouseMoved( data, p_multi_move->cur.canvas.x,
384                             p_multi_move->cur.canvas.y );
385 }
386
387 static void
388 FmtUpdate( vout_display_t *vd )
389 {
390     vout_display_sys_t *sys = vd->sys;
391     vout_display_place_t place;
392     video_format_t src;
393
394     vout_display_PlacePicture( &place, &vd->source, vd->cfg, false );
395
396     if( sys->b_apply_rotation )
397     {
398         video_format_ApplyRotation( &src, &vd->source );
399         vd->fmt.orientation = 0;
400     }
401     else
402         src = vd->source;
403
404     vd->fmt.i_width  = src.i_width  * place.width / src.i_visible_width;
405     vd->fmt.i_height = src.i_height * place.height / src.i_visible_height;
406
407     vd->fmt.i_visible_width  = place.width;
408     vd->fmt.i_visible_height = place.height;
409     vd->fmt.i_x_offset = src.i_x_offset * place.width / src.i_visible_width;
410     vd->fmt.i_y_offset = src.i_y_offset * place.height / src.i_visible_height;
411
412     sys->i_width  = vd->fmt.i_visible_width;
413     sys->i_height = vd->fmt.i_visible_height;
414 }
415
416 static Eina_Bool
417 mainloop_evas_anim_cb( void *p_opaque )
418 {
419     vout_display_t *vd = p_opaque;
420     vout_display_sys_t *sys = vd->sys;
421     evas_object_image_pixels_dirty_set( sys->p_evas, 1 );
422
423     sys->p_anim = NULL;
424     return false;
425 }
426
427 static void
428 EvasResizeCb( void *data, Evas *e, Evas_Object *obj, void *event )
429 {
430     (void) e; (void) obj; (void) event;
431     vout_display_t *vd = data;
432     vout_display_sys_t *sys = vd->sys;
433
434     sys->b_evas_changed = true;
435 }
436
437 static int
438 EvasDisplayMainloopCb( vout_display_t *vd )
439 {
440     vout_display_sys_t *sys = vd->sys;
441
442     if( sys->b_evas_changed || sys->pf_set_data( vd ) )
443         return -1;
444
445     evas_object_image_data_update_add( sys->p_evas, 0, 0,
446                                        sys->i_width, sys->i_height );
447     evas_object_image_pixels_dirty_set( sys->p_evas, 0 );
448
449     if( !sys->p_anim )
450         sys->p_anim = ecore_animator_add( mainloop_evas_anim_cb, vd );
451
452     if( sys->p_current_buffer )
453         BUFFER_FIFO_PUSH( sys->p_current_buffer );
454
455     sys->p_current_buffer = sys->p_new_buffer;
456     sys->p_new_buffer = NULL;
457     return 0;
458 }
459
460 static int
461 EvasInitMainloopCb( vout_display_t *vd )
462 {
463     vout_display_sys_t *sys = vd->sys;
464
465 #ifdef HAVE_TIZEN_SDK
466     if( !EvasIsOpenGLSupported( vd ) || TbmSurfaceSetup( vd ) )
467 #endif
468     if( EvasImageSetup( vd ) )
469         return -1;
470
471     evas_object_image_alpha_set( sys->p_evas, 0 );
472     evas_object_image_size_set( sys->p_evas, sys->i_width, sys->i_height );
473
474     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MOUSE_DOWN,
475                                     EventMouseDownCb, vd );
476     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MOUSE_UP,
477                                     EvasMouseUpCb, vd );
478     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MOUSE_MOVE,
479                                     EvasMouseMoveCb, vd );
480     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MULTI_DOWN,
481                                     EvasMultiDownCb, vd );
482     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MULTI_UP,
483                                     EvasMultiUpCb, vd );
484     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_MULTI_MOVE,
485                                     EvasMultiMoveCb, vd );
486 #ifdef HAVE_EVAS_CALLBACK_KEY_UP
487     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_KEY_UP,
488                                     EvasKeyUpCb, sys );
489 #endif
490
491     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_IMAGE_RESIZE,
492                                     EvasResizeCb, vd );
493
494     return 0;
495 }
496
497 static int
498 EvasDeinitMainloopCb( vout_display_t *vd )
499 {
500     vout_display_sys_t *sys = vd->sys;
501
502     if( sys->p_anim )
503     {
504         ecore_animator_del( sys->p_anim );
505         sys->p_anim = NULL;
506     }
507
508     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_IMAGE_RESIZE,
509                                          EvasResizeCb, vd );
510
511     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MOUSE_DOWN,
512                                          EventMouseDownCb, vd );
513     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MOUSE_UP,
514                                          EvasMouseUpCb, vd );
515     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MOUSE_MOVE,
516                                          EvasMouseMoveCb, vd );
517     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MULTI_DOWN,
518                                          EvasMultiDownCb, vd );
519     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MULTI_UP,
520                                          EvasMultiUpCb, vd );
521     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_MULTI_MOVE,
522                                          EvasMultiMoveCb, vd );
523 #ifdef HAVE_EVAS_CALLBACK_KEY_UP
524     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_KEY_UP,
525                                          EvasKeyUpCb, vd );
526 #endif
527
528     if( !sys->b_evas_changed )
529     {
530         evas_object_image_data_set( sys->p_evas, NULL );
531         evas_object_image_pixels_dirty_set( sys->p_evas, 0 );
532     }
533
534     return 0;
535 }
536
537 static int
538 EvasResetMainloopCb( vout_display_t *vd )
539 {
540     vout_display_sys_t *sys = vd->sys;
541
542     if( sys->b_evas_changed )
543         return -1;
544
545     if( sys->p_anim )
546     {
547         ecore_animator_del( sys->p_anim );
548         sys->p_anim = NULL;
549     }
550
551     evas_object_event_callback_del_full( sys->p_evas, EVAS_CALLBACK_IMAGE_RESIZE,
552                                          EvasResizeCb, vd );
553
554     FmtUpdate( vd );
555
556     evas_object_image_data_set( sys->p_evas, NULL );
557     evas_object_image_size_set( sys->p_evas, sys->i_width, sys->i_height );
558
559     evas_object_event_callback_add( sys->p_evas, EVAS_CALLBACK_IMAGE_RESIZE,
560                                     EvasResizeCb, vd );
561     return 0;
562 }
563
564 static int
565 BuffersSetup( vout_display_t *vd, video_format_t *p_fmt,
566               unsigned int *p_requested_count )
567 {
568     vout_display_sys_t *sys = vd->sys;
569
570     sys->i_nb_buffers = *p_requested_count;
571     if( sys->pf_buffers_alloc( vd, p_fmt ) )
572     {
573         sys->i_nb_planes = 0;
574         return VLC_EGENERIC;
575     }
576     *p_requested_count = sys->i_nb_buffers;
577
578     for( unsigned int i = 0; i < sys->i_nb_buffers; ++i )
579         BUFFER_FIFO_PUSH( &sys->p_buffers[i] );
580     return VLC_SUCCESS;
581 }
582
583 static void
584 BuffersClean( vout_display_t *vd )
585 {
586     vout_display_sys_t *sys = vd->sys;
587
588     if( sys->p_buffers )
589         sys->pf_buffers_free( vd );
590     sys->buffer_fifo.p_first = sys->buffer_fifo.p_last = NULL;
591 }
592
593 static picture_t *
594 PictureAlloc( vout_display_t *vd )
595 {
596     vout_display_sys_t *sys = vd->sys;
597     picture_resource_t rsc;
598     picture_t *p_pic = NULL;
599     picture_sys_t *p_picsys = calloc(1, sizeof(*p_picsys));
600
601     if( !p_picsys )
602         return NULL;
603
604     p_picsys->p_vd_sys = vd->sys;
605     memset(&rsc, 0, sizeof(picture_resource_t));
606     rsc.p_sys = p_picsys;
607     for( unsigned int i = 0; i < sys->i_nb_planes; ++i )
608     {
609         rsc.p[i].i_lines = sys->p_planes[i].i_lines;
610         rsc.p[i].i_pitch = sys->p_planes[i].i_pitch;
611     }
612
613     p_pic = picture_NewFromResource( &vd->fmt, &rsc );
614     if( !p_pic )
615     {
616         free( p_picsys );
617         return NULL;
618     }
619
620     return p_pic;
621 }
622
623 static int
624 PoolLockPicture(picture_t *p_pic)
625 {
626     picture_sys_t *p_picsys = p_pic->p_sys;
627     vout_display_sys_t *sys = p_picsys->p_vd_sys;
628
629     struct buffer *p_buffer = BUFFER_FIFO_POP();
630     if( !p_buffer || !p_buffer->p[0] )
631         return -1;
632
633     p_picsys->p_buffer = p_buffer;
634     for( unsigned int i = 0; i < sys->i_nb_planes; ++i )
635         p_pic->p[i].p_pixels = p_buffer->p[i];
636     return 0;
637 }
638
639 static void
640 PoolUnlockPicture(picture_t *p_pic)
641 {
642     picture_sys_t *p_picsys = p_pic->p_sys;
643     vout_display_sys_t *sys = p_picsys->p_vd_sys;
644
645     if( p_picsys->p_buffer )
646     {
647         BUFFER_FIFO_PUSH( p_picsys->p_buffer );
648         p_picsys->p_buffer = NULL;
649     }
650 }
651
652 static picture_pool_t *
653 PoolAlloc( vout_display_t *vd, unsigned i_requested_count )
654 {
655     picture_t **pp_pics = NULL;
656     picture_pool_t *p_pool;
657     picture_pool_configuration_t pool_cfg;
658
659     msg_Dbg(vd, "PoolAlloc, requested_count: %d", i_requested_count);
660
661     i_requested_count++; /* picture owned by evas */
662
663     if( BuffersSetup( vd, &vd->fmt, &i_requested_count) )
664     {
665         msg_Err( vd, "BuffersSetup failed" );
666         return NULL;
667     }
668     if( i_requested_count <= 1 )
669     {
670         msg_Err( vd, "not enough buffers allocated" );
671         goto error;
672     }
673     i_requested_count--;
674
675     msg_Dbg( vd, "PoolAlloc, got: %d", i_requested_count );
676
677     if( !( pp_pics = calloc( i_requested_count, sizeof(picture_t) ) ) )
678         goto error;
679
680     for( unsigned int i = 0; i < i_requested_count; ++i )
681     {
682         if( !( pp_pics[i] = PictureAlloc( vd ) ) )
683         {
684             i_requested_count = i;
685             msg_Err( vd, "PictureAlloc failed" );
686             goto error;
687         }
688     }
689
690     memset( &pool_cfg, 0, sizeof(pool_cfg) );
691     pool_cfg.picture_count = i_requested_count;
692     pool_cfg.picture       = pp_pics;
693     pool_cfg.lock          = PoolLockPicture;
694     pool_cfg.unlock        = PoolUnlockPicture;
695
696     p_pool = picture_pool_NewExtended( &pool_cfg );
697     if( p_pool )
698         return p_pool;
699
700 error:
701     if( pp_pics )
702     {
703         for( unsigned int i = 0; i < i_requested_count; ++i )
704             picture_Release( pp_pics[i] );
705         free( pp_pics );
706     }
707     BuffersClean( vd );
708     return NULL;
709 }
710
711 static picture_pool_t *
712 Pool( vout_display_t *vd, unsigned i_requested_count )
713 {
714     vout_display_sys_t *sys = vd->sys;
715
716     if( sys->p_pool == NULL )
717         sys->p_pool = PoolAlloc( vd, i_requested_count );
718     return sys->p_pool;
719 }
720
721 static void
722 Display( vout_display_t *vd, picture_t *p_pic, subpicture_t *p_subpic )
723 {
724     (void) p_subpic;
725     vout_display_sys_t *sys = vd->sys;
726     picture_sys_t *p_picsys = p_pic->p_sys;
727
728     if( p_picsys->p_buffer )
729     {
730         sys->p_new_buffer = p_picsys->p_buffer;
731         p_picsys->p_buffer = NULL;
732
733         EcoreMainLoopCallSync( vd, EvasDisplayMainloopCb );
734     }
735     picture_Release( p_pic );
736 }
737
738 static int
739 Control( vout_display_t *vd, int i_query, va_list ap )
740 {
741     vout_display_sys_t *sys = vd->sys;
742
743     switch( i_query )
744     {
745     case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
746     {
747         const video_format_t *p_source;
748         vout_display_place_t place;
749         video_format_t fmt;
750
751         msg_Dbg( vd, "VOUT_DISPLAY_CHANGE_SOURCE_ASPECT" );
752
753         p_source = (const video_format_t *)va_arg( ap, const video_format_t * );
754
755         video_format_ApplyRotation( &fmt, p_source );
756         vout_display_PlacePicture( &place, &fmt, vd->cfg, false );
757
758         if( place.width != (unsigned) sys->i_width
759          && place.height != (unsigned) sys->i_height )
760         {
761             if( vd->info.has_pictures_invalid )
762             {
763                 msg_Warn( vd, "ratio changed: invalidate pictures" );
764                 vout_display_SendEventPicturesInvalid( vd );
765             }
766             else
767                 return VLC_EGENERIC;
768         }
769         return VLC_SUCCESS;
770     }
771     case VOUT_DISPLAY_CHANGE_FULLSCREEN:
772         return VLC_SUCCESS;
773     case VOUT_DISPLAY_RESET_PICTURES:
774         msg_Dbg( vd, "VOUT_DISPLAY_RESET_PICTURES" );
775
776         EcoreMainLoopCallSync( vd, EvasResetMainloopCb );
777
778         BuffersClean( vd );
779
780         if( sys->p_pool )
781         {
782             picture_pool_Release( sys->p_pool );
783             sys->p_pool = NULL;
784         }
785         return VLC_SUCCESS;
786     case VOUT_DISPLAY_CHANGE_ZOOM:
787     case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
788     case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
789     case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
790     case VOUT_DISPLAY_HIDE_MOUSE:
791         return VLC_EGENERIC;
792     default:
793         msg_Warn( vd, "Unknown request in evas_output" );
794         return VLC_EGENERIC;
795     }
796 }
797
798 static void
799 Manage( vout_display_t *vd )
800 {
801     vout_display_sys_t *sys = vd->sys;
802     struct event *p_event;
803
804     while( ( p_event = EVENT_FIFO_POP() ) )
805     {
806         switch( p_event->i_type )
807         {
808             case VOUT_DISPLAY_EVENT_MOUSE_MOVED:
809                 vout_display_SendEventMouseMoved( vd, p_event->u.point.i_x,
810                                                   p_event->u.point.i_y );
811                 break;
812             case VOUT_DISPLAY_EVENT_MOUSE_PRESSED:
813             case VOUT_DISPLAY_EVENT_MOUSE_RELEASED:
814                 vout_display_SendEvent( vd, p_event->i_type,
815                                         p_event->u.i_button );
816                 break;
817             case VOUT_DISPLAY_EVENT_KEY:
818                 vout_display_SendEventKey( vd, p_event->u.i_key );
819                 break;
820         }
821         free( p_event );
822     }
823 }
824
825 static void
826 Close( vlc_object_t *p_this )
827 {
828     vout_display_t *vd = (vout_display_t *)p_this;
829     vout_display_sys_t *sys = vd->sys;
830     struct event *p_event;
831
832     if (!sys)
833         return;
834
835     EcoreMainLoopCallSync( vd, EvasDeinitMainloopCb );
836
837     BuffersClean( vd );
838     fifo_deinit( &sys->buffer_fifo );
839
840     if( sys->p_pool )
841         picture_pool_Release(sys->p_pool);
842
843     while( ( p_event = EVENT_FIFO_POP() ) )
844         free( p_event );
845
846     vlc_mutex_destroy( &sys->cb_lock );
847     vlc_cond_destroy( &sys->cb_wait );
848
849     free( sys );
850 }
851
852 static int
853 Open( vlc_object_t *p_this )
854 {
855     vout_display_t *vd = (vout_display_t*)p_this;
856     vout_display_sys_t *sys;
857     Evas_Object *p_evas;
858
859     if( vout_display_IsWindowed( vd ) )
860         return VLC_EGENERIC;
861
862     p_evas = var_InheritAddress( p_this, "drawable-evasobject" );
863     if( !p_evas )
864         return VLC_EGENERIC;
865
866     vd->sys = sys = (struct vout_display_sys_t *) calloc( 1, sizeof(*sys) );
867     if( !sys )
868         return VLC_ENOMEM;
869
870     vlc_mutex_init( &sys->cb_lock );
871     vlc_cond_init( &sys->cb_wait );
872     fifo_init( &sys->buffer_fifo );
873     fifo_init( &sys->event_fifo );
874
875     sys->p_evas = p_evas;
876
877     msg_Dbg( vd, "request video format: %4.4s",
878              (const char *)&vd->fmt.i_chroma );
879
880     /* Evas Initialisation must be done from the Mainloop */
881     if( EcoreMainLoopCallSync( vd, EvasInitMainloopCb ) )
882     {
883         msg_Err( vd, "EvasInitMainloopCb failed" );
884         Close( p_this );
885         return VLC_EGENERIC;
886     }
887
888     for( unsigned int i = 0; i < PICTURE_PLANE_MAX; ++i )
889         sys->i_planes_order[i] = i;
890
891     switch( vd->fmt.i_chroma )
892     {
893         case VLC_CODEC_RGB32:
894         case VLC_CODEC_RGB16:
895             video_format_FixRgb(&vd->fmt);
896             break;
897         case VLC_CODEC_YV12:
898             sys->i_planes_order[1] = 2;
899             sys->i_planes_order[2] = 1;
900         default:
901             break;
902     }
903
904     msg_Dbg( vd, "got video format: %4.4s, size: %dx%d",
905              (const char *)&vd->fmt.i_chroma,
906              sys->i_width, sys->i_height );
907
908     /* Setup vout_display */
909     vd->pool    = Pool;
910     vd->prepare = NULL;
911     vd->display = Display;
912     vd->control = Control;
913     vd->manage  = Manage;
914
915     /* Fix initial state */
916     vout_display_SendEventFullscreen( vd, true );
917
918     return VLC_SUCCESS;
919 }
920
921 static int
922 EvasImageSetData( vout_display_t *vd )
923 {
924     vout_display_sys_t *sys = vd->sys;
925     struct buffer *p_buffer = sys->p_new_buffer;
926
927     if( sys->u.evas.b_yuv )
928     {
929         void *p_data = evas_object_image_data_get( sys->p_evas, 1 );
930         const uint8_t **pp_rows = (const uint8_t **) p_data;
931
932         if( !p_data )
933             return -1;
934
935         for( unsigned int i = 0; i < sys->i_nb_planes; ++i )
936         {
937             plane_t *p_plane = &sys->p_planes[sys->i_planes_order[i]];
938
939             for( int j = 0; j < p_plane->i_visible_lines; ++j )
940                 *(pp_rows++) = &p_buffer->p[i][j * p_plane->i_pitch];
941         }
942
943         evas_object_image_data_set( sys->p_evas, p_data );
944     }
945     else
946         evas_object_image_data_set( sys->p_evas, p_buffer->p[0] );
947
948     return 0;
949 }
950
951 static void
952 EvasImageBuffersFree( vout_display_t *vd )
953 {
954     vout_display_sys_t *sys = vd->sys;
955
956     for( unsigned int i = 0; i < sys->i_nb_buffers; i++ )
957         free( sys->p_buffers[i].p[0] );
958     free( sys->p_buffers );
959     sys->p_buffers = NULL;
960     sys->i_nb_buffers = 0;
961     sys->i_nb_planes = 0;
962 }
963
964 static int
965 EvasImageBuffersAlloc( vout_display_t *vd, video_format_t *p_fmt )
966 {
967     vout_display_sys_t *sys = vd->sys;
968     picture_t *p_pic = NULL;
969     picture_resource_t rsc;
970     size_t i_bytes = 0;
971
972     memset(&rsc, 0, sizeof(picture_resource_t));
973     if( !( p_pic = picture_NewFromResource( p_fmt, &rsc ) ) )
974         return -1;
975
976     if( picture_Setup( p_pic, p_fmt ) )
977     {
978         picture_Release( p_pic );
979         return -1;
980     }
981
982     for( int i = 0; i < p_pic->i_planes; ++i )
983         memcpy( &sys->p_planes[i], &p_pic->p[i], sizeof(plane_t));
984     sys->i_nb_planes = p_pic->i_planes;
985     picture_Release( p_pic );
986
987     if( !( sys->p_buffers = calloc( sys->i_nb_buffers, sizeof(struct buffer) ) ) )
988         goto error;
989
990     /* Calculate how big the new image should be */
991     for( unsigned int i = 0; i < sys->i_nb_planes; i++ )
992     {
993         const plane_t *p = &sys->p_planes[i];
994
995         if( p->i_pitch < 0 || p->i_lines <= 0 ||
996             (size_t)p->i_pitch > (SIZE_MAX - i_bytes)/p->i_lines )
997             goto error;
998         i_bytes += p->i_pitch * p->i_lines;
999     }
1000
1001     if( !i_bytes )
1002         goto error;
1003
1004     for( unsigned int i = 0; i < sys->i_nb_buffers; ++i )
1005     {
1006         struct buffer *p_buffer = &sys->p_buffers[i];
1007
1008         p_buffer->p[0] = vlc_memalign( 16, i_bytes );
1009
1010         if( !p_buffer->p[0] )
1011         {
1012             sys->i_nb_buffers = i;
1013             break;
1014         }
1015
1016         for( unsigned int j = 1; j < sys->i_nb_planes; j++ )
1017             p_buffer->p[j] = &p_buffer->p[j-1][ sys->p_planes[j-1].i_lines *
1018                                                 sys->p_planes[j-1].i_pitch ];
1019     }
1020
1021     return 0;
1022
1023 error:
1024     if( sys->p_buffers )
1025         EvasImageBuffersFree( vd );
1026     return -1;
1027 }
1028
1029 static int
1030 EvasImageSetup( vout_display_t *vd )
1031 {
1032     vout_display_sys_t *sys = vd->sys;
1033     char *psz_fcc = var_InheritString( vd, "evas-image-chroma" );
1034
1035     if( psz_fcc )
1036     {
1037         vd->fmt.i_chroma = vlc_fourcc_GetCodecFromString( VIDEO_ES, psz_fcc );
1038         free( psz_fcc );
1039     }
1040
1041     switch( vd->fmt.i_chroma )
1042     {
1043         case VLC_CODEC_RGB32:
1044             sys->u.evas.i_colorspace = EVAS_COLORSPACE_ARGB8888;
1045             break;
1046         /* Not implemented yet */
1047 #if 0
1048         case VLC_CODEC_RGB16:
1049             sys->u.evas.i_colorspace = EVAS_COLORSPACE_RGB565_A5P;
1050             break;
1051 #endif
1052         case VLC_CODEC_YUYV:
1053             sys->u.evas.i_colorspace = EVAS_COLORSPACE_YCBCR422601_PL;
1054             sys->u.evas.b_yuv = true;
1055             break;
1056         /* FIXME: SIGSEGV in evas_gl_common_texture_nv12_update */
1057 #if 0
1058         case VLC_CODEC_NV12:
1059             sys->u.evas.i_colorspace = EVAS_COLORSPACE_YCBCR420NV12601_PL;
1060             sys->u.evas.b_yuv = true;
1061             break;
1062 #endif
1063         case VLC_CODEC_YV12:
1064             sys->u.evas.i_colorspace = EVAS_COLORSPACE_YCBCR422P601_PL;
1065             sys->u.evas.b_yuv = true;
1066             break;
1067         default:
1068         case VLC_CODEC_I420:
1069             sys->u.evas.i_colorspace = EVAS_COLORSPACE_YCBCR422P601_PL;
1070             vd->fmt.i_chroma = VLC_CODEC_I420;
1071             sys->u.evas.b_yuv = true;
1072             break;
1073     }
1074
1075     evas_object_image_colorspace_set( sys->p_evas, sys->u.evas.i_colorspace );
1076     evas_object_image_data_set( sys->p_evas, NULL );
1077
1078     /* No rotation support with EvasImage */
1079     sys->b_apply_rotation = true;
1080     FmtUpdate( vd );
1081
1082     /* No aspect ratio support with EvasImage */
1083     vd->info.has_pictures_invalid = true;
1084
1085     sys->pf_set_data = EvasImageSetData;
1086     sys->pf_buffers_alloc = EvasImageBuffersAlloc;
1087     sys->pf_buffers_free = EvasImageBuffersFree;
1088
1089     msg_Dbg( vd, "using evas_image" );
1090     return 0;
1091 }
1092
1093 #ifdef HAVE_TIZEN_SDK
1094
1095 struct tbm_format_to_vlc
1096 {
1097    tbm_format  i_tbm_format;
1098    vlc_fourcc_t i_vlc_chroma;
1099 };
1100
1101 struct tbm_format_to_vlc tbm_format_to_vlc_list[] = {
1102    { TBM_FORMAT_NV12, VLC_CODEC_NV12 },
1103    { TBM_FORMAT_YUV420, VLC_CODEC_I420 },
1104    { TBM_FORMAT_BGRA8888, VLC_CODEC_RGB32 },
1105 };
1106 #define TBM_FORMAT_TO_VLC_LIST_COUNT \
1107   ( sizeof(tbm_format_to_vlc_list) / sizeof(struct tbm_format_to_vlc) )
1108
1109 static bool
1110 EvasIsOpenGLSupported( vout_display_t *vd )
1111 {
1112     vout_display_sys_t *sys = vd->sys;
1113     Evas *p_canvas = evas_object_evas_get(sys->p_evas);
1114     Eina_List *p_engine_list, *p_l;
1115     int i_render_id;
1116     char *psz_render_name;
1117     bool b_is_gl = false;
1118
1119     if( !p_canvas )
1120         return false;
1121     i_render_id = evas_output_method_get( p_canvas );
1122
1123     p_engine_list = evas_render_method_list();
1124     if( !p_engine_list )
1125         return false;
1126
1127     EINA_LIST_FOREACH( p_engine_list, p_l, psz_render_name )
1128     {
1129         if( evas_render_method_lookup( psz_render_name ) == i_render_id )
1130         {
1131             b_is_gl = strncmp( psz_render_name, "gl", 2 ) == 0;
1132             break;
1133         }
1134     }
1135
1136     evas_render_method_list_free( p_engine_list );
1137     return b_is_gl;
1138 }
1139
1140 static int
1141 TbmSurfaceBufferLock( struct buffer *p_buffer )
1142 {
1143     tbm_surface_info_s tbm_surface_info;
1144     if( tbm_surface_map( p_buffer->p_tbm_surface, TBM_SURF_OPTION_WRITE,
1145                          &tbm_surface_info ) )
1146         return -1;
1147
1148     for( unsigned i = 0; i < tbm_surface_info.num_planes; ++i )
1149         p_buffer->p[i] = tbm_surface_info.planes[i].ptr;
1150     return 0;
1151 }
1152
1153 static int
1154 TbmSurfaceBufferUnlock( struct buffer *p_buffer )
1155 {
1156     tbm_surface_unmap( p_buffer->p_tbm_surface );
1157     p_buffer->p[0] = NULL;
1158     return 0;
1159 }
1160
1161 static int
1162 TbmSurfaceSetData( vout_display_t *vd )
1163 {
1164     vout_display_sys_t *sys = vd->sys;
1165     Evas_Native_Surface surf;
1166
1167     TbmSurfaceBufferUnlock( sys->p_new_buffer );
1168
1169     surf.version = EVAS_NATIVE_SURFACE_VERSION;
1170     surf.type = EVAS_NATIVE_SURFACE_TBM;
1171     surf.data.tizen.buffer = sys->p_new_buffer->p_tbm_surface;
1172     surf.data.tizen.rot = sys->u.tbm.i_angle;
1173     surf.data.tizen.ratio = 0;
1174     surf.data.tizen.flip = 0;
1175     evas_object_image_native_surface_set( sys->p_evas, &surf );
1176
1177     if( sys->p_current_buffer )
1178         TbmSurfaceBufferLock( sys->p_current_buffer );
1179     return 0;
1180 }
1181
1182 static void
1183 TbmSurfaceBuffersFree( vout_display_t *vd )
1184 {
1185     vout_display_sys_t *sys = vd->sys;
1186
1187     for( unsigned int i = 0; i < sys->i_nb_buffers; i++ )
1188     {
1189         if( sys->p_buffers[i].p[0] )
1190             tbm_surface_unmap( sys->p_buffers[i].p_tbm_surface );
1191         tbm_surface_destroy( sys->p_buffers[i].p_tbm_surface );
1192     }
1193     free( sys->p_buffers );
1194     sys->p_buffers = NULL;
1195     sys->i_nb_buffers = 0;
1196     sys->i_nb_planes = 0;
1197 }
1198
1199 static int
1200 TbmSurfaceBuffersAllocMainloopCb( vout_display_t *vd )
1201 {
1202     vout_display_sys_t *sys = vd->sys;
1203     tbm_surface_info_s tbm_surface_info;
1204
1205     sys->i_nb_buffers = 2;
1206
1207     if( !( sys->p_buffers = calloc( sys->i_nb_buffers, sizeof(struct buffer) ) ) )
1208         return -1;
1209
1210     for( unsigned i = 0; i < sys->i_nb_buffers; ++i )
1211     {
1212         struct buffer *p_buffer = &sys->p_buffers[i];
1213         tbm_surface_h p_tbm_surface = tbm_surface_create( sys->i_width,
1214                                                           sys->i_height,
1215                                                           sys->u.tbm.i_format );
1216         if( !p_tbm_surface
1217          || tbm_surface_get_info( p_tbm_surface, &tbm_surface_info ) )
1218         {
1219             tbm_surface_destroy( p_tbm_surface );
1220             p_tbm_surface = NULL;
1221         }
1222
1223         if( !p_tbm_surface )
1224         {
1225             sys->i_nb_buffers = i;
1226             break;
1227         }
1228         p_buffer->p_tbm_surface = p_tbm_surface;
1229         TbmSurfaceBufferLock( p_buffer );
1230     }
1231
1232     sys->i_nb_planes = tbm_surface_info.num_planes;
1233     for( unsigned i = 0; i < tbm_surface_info.num_planes; ++i )
1234     {
1235         sys->p_planes[i].i_lines = tbm_surface_info.planes[i].size
1236                                  / tbm_surface_info.planes[i].stride;
1237         sys->p_planes[i].i_visible_lines = sys->p_planes[i].i_lines;
1238         sys->p_planes[i].i_pitch = tbm_surface_info.planes[i].stride;
1239         sys->p_planes[i].i_visible_pitch = sys->p_planes[i].i_pitch;
1240     }
1241
1242     return 0;
1243 }
1244
1245 static int
1246 TbmSurfaceBuffersAlloc( vout_display_t *vd, video_format_t *p_fmt )
1247 {
1248     (void) p_fmt;
1249     return EcoreMainLoopCallSync( vd, TbmSurfaceBuffersAllocMainloopCb );
1250 }
1251
1252 static int
1253 TbmSurfaceSetup( vout_display_t *vd )
1254 {
1255     vout_display_sys_t *sys = vd->sys;
1256     tbm_format i_tbm_format = 0;
1257     bool b_found = false;
1258     uint32_t *p_formats;
1259     uint32_t i_format_num;
1260
1261     for( unsigned int i = 0; i < TBM_FORMAT_TO_VLC_LIST_COUNT; ++i )
1262     {
1263         if( tbm_format_to_vlc_list[i].i_vlc_chroma == vd->fmt.i_chroma )
1264         {
1265             i_tbm_format = tbm_format_to_vlc_list[i].i_tbm_format;
1266             break;
1267         }
1268      }
1269      if( !i_tbm_format )
1270      {
1271         msg_Err( vd, "no tbm format found" );
1272         return -1;
1273      }
1274
1275     if( tbm_surface_query_formats( &p_formats, &i_format_num ) )
1276     {
1277         msg_Warn( vd, "tbm_surface_query_formats failed" );
1278         return -1;
1279     }
1280
1281     for( unsigned int i = 0; i < i_format_num; i++ )
1282     {
1283         if( p_formats[i] == i_tbm_format )
1284         {
1285             b_found = true;
1286             break;
1287         }
1288     }
1289     if( !b_found )
1290     {
1291         if( i_tbm_format != TBM_FORMAT_YUV420 )
1292         {
1293             msg_Warn( vd, "vlc format not matching any tbm format: trying with I420");
1294             i_tbm_format = TBM_FORMAT_YUV420;
1295             for( uint32_t i = 0; i < i_format_num; i++ )
1296             {
1297                 if( p_formats[i] == i_tbm_format )
1298                 {
1299                     vd->fmt.i_chroma = VLC_CODEC_I420;
1300                     b_found = true;
1301                     break;
1302                 }
1303             }
1304         }
1305     }
1306     free( p_formats );
1307
1308     if( !b_found )
1309     {
1310         msg_Warn( vd, "can't find any compatible tbm format" );
1311         return -1;
1312     }
1313     sys->u.tbm.i_format = i_tbm_format;
1314
1315     switch( vd->fmt.orientation )
1316     {
1317         case ORIENT_ROTATED_90:
1318             sys->u.tbm.i_angle = 270;
1319             break;
1320         case ORIENT_ROTATED_180:
1321             sys->u.tbm.i_angle = 180;
1322             break;
1323         case ORIENT_ROTATED_270:
1324             sys->u.tbm.i_angle = 90;
1325             break;
1326         default:
1327             sys->u.tbm.i_angle = 0;
1328     }
1329
1330     sys->b_apply_rotation = false;
1331
1332     FmtUpdate( vd );
1333
1334     vd->info.has_pictures_invalid = true;
1335
1336     sys->pf_set_data = TbmSurfaceSetData;
1337     sys->pf_buffers_alloc = TbmSurfaceBuffersAlloc;
1338     sys->pf_buffers_free = TbmSurfaceBuffersFree;
1339
1340     msg_Dbg( vd, "using tbm_surface" );
1341
1342     return 0;
1343 }
1344 #endif