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