fabde7715fabd2814336512e135d7111d01b188e
[platform/upstream/enlightenment.git] / src / bin / video / e_client_video.c
1 #include "e_zone_video_intern.h"
2 #include "e_client_video_intern.h"
3 #include "e_comp_wl_intern.h"
4 #include "e_zone_intern.h"
5 #include "e_comp_wl_subsurface_intern.h"
6 #include "e_video_debug_intern.h"
7 #include "iface/e_video_hwc_intern.h"
8 #include "iface/e_video_external_intern.h"
9 #include "iface/e_video_fallback_intern.h"
10 #include "e_comp_wl_rsm_intern.h"
11 #include "e_eom_intern.h"
12
13 #define EO_DATA_KEY  "E_Client_Video"
14
15 #define INTERNAL_DATA_GET                             \
16    E_Client_Video *ecv;                               \
17    ecv = evas_object_data_get(ec->frame, EO_DATA_KEY)
18
19 #define IFACE_CHECK_RET(iname, ret)                                        \
20    INTERNAL_DATA_GET;                                                      \
21    EINA_SAFETY_ON_NULL_RETURN_VAL(ecv, ret);                               \
22    do                                                                      \
23      {                                                                     \
24         if (!ecv->iface->iname)                                            \
25           {                                                                \
26              VER("No implementation for this interface(%s)", ec, #iname);  \
27              return ret;                                                   \
28           }                                                                \
29      } while (0)
30
31 struct _E_Client_Video
32 {
33    /* Composite interface ( hwc planes / hwc windows / fallback ) */
34    E_Video_Comp_Iface *iface;
35
36    E_Client *ec;
37    E_Zone *zone;
38
39    Eina_List *event_handlers;
40
41    struct
42      {
43         E_Comp_Wl_Hook *subsurf_create;
44         E_Client_Hook *ec_del;
45      } hook;
46
47    Eina_Bool hw_composition;
48    Eina_Bool follow_topmost_visibility;
49    Eina_Bool allowed_property;
50 };
51
52 static void
53 _e_client_video_comp_iface_deinit(E_Client_Video *ecv)
54 {
55    if (!ecv->iface) return;
56
57    ecv->iface->destroy(ecv->iface);
58    ecv->iface = NULL;
59 }
60
61 static void
62 _e_client_video_cb_hwc_render_fail(E_Client_Video *ecv)
63 {
64    E_Video_Comp_Iface *new_iface;
65    E_Comp_Wl_Buffer *buffer;
66
67    VIN("Callback Called HWC Render Fail: Try to create fallback interface",
68        ecv->ec);
69
70    new_iface = e_video_fallback_iface_create(ecv);
71    if (!new_iface)
72      {
73         VER("Failed to create fallback interface", ecv->ec);
74         /* It does maintain HWC interface since creating fallback interface has
75          * been failed. */
76         return;
77      }
78
79    ecv->iface->destroy(ecv->iface);
80    ecv->iface = new_iface;
81
82    /* workaround:
83     * For redrawing compositor's canvas for video buffer. */
84    buffer = e_pixmap_resource_get(ecv->ec->pixmap);
85    if (buffer)
86      {
87         buffer->type = E_COMP_WL_BUFFER_TYPE_TBM;
88         e_comp_wl_surface_commit(ecv->ec);
89      }
90 }
91
92 static Eina_Bool
93 _e_client_video_comp_iface_init(E_Client_Video *ecv)
94 {
95    E_Video_Comp_Iface *iface = NULL;
96    E_Hwc_Policy hwc_pol;
97
98    hwc_pol = e_zone_video_hwc_policy_get(ecv->zone);
99
100    if ((e_config->eom_enable == EINA_TRUE) && (e_eom_is_ec_external(ecv->ec)) &&
101        (hwc_pol == E_HWC_POLICY_PLANES))
102      {
103         VIN("Try to intialize external interface", ecv->ec);
104         iface = e_video_external_iface_create(ecv);
105         goto end;
106      }
107
108    if (e_video_debug_display_primary_plane_value_get())
109      {
110         VIN("Select SW Compositing mode according to configuration", ecv->ec);
111         goto end;
112      }
113
114    if (hwc_pol != E_HWC_POLICY_NONE)
115      {
116         VIN("Initialize the interface of the client_video for HWC mode", ecv->ec);
117         iface = e_video_hwc_iface_create(ecv);
118         if (iface)
119           e_video_hwc_render_fail_callback_set(iface, _e_client_video_cb_hwc_render_fail);
120      }
121
122 end:
123    if (!iface)
124      {
125         iface = e_video_fallback_iface_create(ecv);
126         if (!iface)
127           {
128              VER("Failed to create 'E_Video_Comp_Iface'", ecv->ec);
129              return EINA_FALSE;
130           }
131      }
132
133    ecv->iface = iface;
134
135    return EINA_TRUE;
136 }
137
138 static void
139 _e_client_video_deinit(E_Client_Video *ecv)
140 {
141    _e_client_video_comp_iface_deinit(ecv);
142
143    E_FREE_LIST(ecv->event_handlers, ecore_event_handler_del);
144    E_FREE_FUNC(ecv->hook.subsurf_create, e_comp_wl_hook_del);
145    E_FREE_FUNC(ecv->hook.ec_del, e_client_hook_del);
146 }
147
148 static void
149 _e_client_video_del(E_Client_Video *ecv)
150 {
151    _e_client_video_deinit(ecv);
152
153    evas_object_data_del(ecv->ec->frame, EO_DATA_KEY);
154    e_object_unref(E_OBJECT(ecv->ec));
155
156    free(ecv);
157 }
158
159 static Eina_Bool
160 _e_client_video_cb_zone_del(void *data, int type EINA_UNUSED, void *event)
161 {
162    E_Client_Video *ecv;
163    E_Event_Zone_Del *ev;
164
165    ecv = data;
166    ev = event;
167
168    if (ecv->zone != ev->zone)
169      goto end;
170
171    VIN("Zone(%p) deleted.", ecv->ec, ecv->zone);
172
173    _e_client_video_comp_iface_deinit(ecv);
174
175    ecv->zone = NULL;
176 end:
177    return ECORE_CALLBACK_PASS_ON;
178 }
179
180 static Eina_Bool
181 _e_client_video_cb_ec_zone_set(void *data, int type EINA_UNUSED, void *event)
182 {
183    E_Client_Video *ecv;
184    E_Event_Client_Zone_Set *ev;
185    Eina_Bool res;
186
187    ecv = data;
188    ev = event;
189
190    if (ecv->ec != ev->ec)
191      goto end;
192
193    if (ecv->zone == ev->zone)
194      goto end;
195
196    VIN("Zone changed: old(%p) new(%p)", ecv->ec, ecv->zone, ev->zone);
197
198    ecv->zone = ev->zone;
199
200    _e_client_video_comp_iface_deinit(ecv);
201
202    res = _e_client_video_comp_iface_init(ecv);
203    if (!res)
204      {
205         VER("Failed to initialize the composition interface for video", ev->ec);
206         return ECORE_CALLBACK_PASS_ON;
207      }
208
209 end:
210    return ECORE_CALLBACK_PASS_ON;
211 }
212
213 static void
214 _e_client_video_cb_hook_ec_del(void *data, E_Client *ec)
215 {
216    E_Client_Video *ecv;
217
218    ecv = data;
219    if (ec != ecv->ec)
220      return;
221
222    _e_client_video_del(ecv);
223 }
224
225 static void
226 _e_client_video_ec_visibility_event_free(void *d EINA_UNUSED, E_Event_Client *ev)
227 {
228    e_object_unref(E_OBJECT(ev->ec));
229    free(ev);
230 }
231
232 static void
233 _e_client_video_visibility_event_send(E_Client_Video *ecv)
234 {
235    E_Event_Client *ev;
236    E_Client *ec;
237    int obscured;
238
239    ec = ecv->ec;
240    obscured = ec->visibility.obscured;
241    VIN("Signal visibility change event of video, type %d",
242        ec, obscured);
243
244    ev = E_NEW(E_Event_Client , 1);
245    EINA_SAFETY_ON_NULL_RETURN(ev);
246
247    ev->ec = ec;
248    e_object_ref(E_OBJECT(ec));
249    ecore_event_add(E_EVENT_CLIENT_VISIBILITY_CHANGE, ev,
250                    (Ecore_End_Cb)_e_client_video_ec_visibility_event_free, NULL);
251 }
252
253 static void
254 _e_client_video_visibility_set(E_Client_Video *ecv, E_Visibility vis)
255 {
256    E_Client *ec;
257
258    ec = ecv->ec;
259    if (ec->visibility.obscured == vis)
260      return;
261
262    ec->visibility.obscured = vis;
263    _e_client_video_visibility_event_send(ecv);
264 }
265
266 static Eina_Bool
267 _e_client_video_cb_ec_visibility_change(void *data, int type EINA_UNUSED, void *event)
268 {
269    E_Client_Video *ecv;
270    E_Event_Client *ev;
271    E_Client *topmost;
272
273    ecv = data;
274    if (!ecv->follow_topmost_visibility)
275      goto end;
276
277    topmost = e_comp_wl_topmost_parent_get(ecv->ec);
278    if ((!topmost) || (topmost == ecv->ec))
279      goto end;
280
281    ev = event;
282    if (ev->ec != topmost)
283      goto end;
284
285    _e_client_video_visibility_set(ecv, topmost->visibility.obscured);
286
287 end:
288    return ECORE_CALLBACK_PASS_ON;
289 }
290
291 static E_Client *
292 _e_client_video_offscreen_parent_get(E_Client_Video *ecv)
293 {
294    E_Client *ec, *parent = NULL;
295
296    ec = ecv->ec;
297    if (!e_comp_wl_subsurface_check(ec))
298      return NULL;
299
300    parent = e_comp_wl_subsurface_parent_get(ec);
301    while (parent)
302      {
303         if (!parent->comp_data || !parent->comp_data->sub.data)
304           return NULL;
305
306         if (parent->comp_data->sub.data->remote_surface.offscreen_parent)
307           return parent->comp_data->sub.data->remote_surface.offscreen_parent;
308
309         parent = e_comp_wl_subsurface_parent_get(parent);
310      }
311
312    return NULL;
313 }
314
315 static Eina_Bool
316 _e_client_video_cb_remote_surface_provider_visibility_change(void *data, int type EINA_UNUSED, void *event)
317 {
318    E_Client_Video *ecv;
319    E_Event_Remote_Surface_Provider *ev;
320    E_Client *offscreen_parent;
321
322    ecv = data;
323    offscreen_parent = _e_client_video_offscreen_parent_get(ecv);
324    if (!offscreen_parent)
325      goto end;
326
327    ev = event;
328    if (ev->ec != offscreen_parent)
329      goto end;
330
331    switch (ev->ec->visibility.obscured)
332      {
333       case E_VISIBILITY_FULLY_OBSCURED:
334          evas_object_hide(ecv->ec->frame);
335          break;
336       case E_VISIBILITY_UNOBSCURED:
337          evas_object_show(ecv->ec->frame);
338          break;
339       default:
340          VER("Not implemented", ecv->ec);
341          break;
342      }
343
344 end:
345    return ECORE_CALLBACK_PASS_ON;
346 }
347
348 static void
349 _e_client_video_cb_hook_subsurface_create(void *data, E_Client *ec)
350 {
351    E_Client_Video *ecv;
352    E_Client *topmost1, *topmost2;
353
354    ecv = data;
355    if (!ecv->follow_topmost_visibility)
356      return;
357
358    /* This is to raise an 'VISIBILITY_CHANGE' event to video client when its
359     * topmost ancestor is changed. The reason why it uses hook handler of
360     * creation of subsurface is that there is no event for like parent change,
361     * and being created subsurface that has common topmost parent means
362     * it implies topmost parent has been possibly changed. */
363    topmost1 = e_comp_wl_topmost_parent_get(ec);
364    topmost2 = e_comp_wl_topmost_parent_get(ecv->ec);
365    if (topmost1 && topmost2)
366      {
367         if (topmost1 == topmost2)
368           _e_client_video_visibility_set(ecv, topmost1->visibility.obscured);
369      }
370 }
371
372 static Eina_Bool
373 _e_client_video_init(E_Client_Video *ecv, E_Client *ec)
374 {
375    Eina_Bool res;
376
377    ecv->ec = ec;
378    ecv->zone = e_comp_zone_find_by_ec(ec);
379    EINA_SAFETY_ON_NULL_RETURN_VAL(ecv->zone, EINA_FALSE);
380
381    res = _e_client_video_comp_iface_init(ecv);
382    if (!res)
383      {
384         VER("Failed to initialize the composition interface for video", ec);
385         return EINA_FALSE;
386      }
387
388    E_LIST_HANDLER_APPEND(ecv->event_handlers, E_EVENT_ZONE_DEL,
389                          _e_client_video_cb_zone_del, ecv);
390    E_LIST_HANDLER_APPEND(ecv->event_handlers, E_EVENT_CLIENT_ZONE_SET,
391                          _e_client_video_cb_ec_zone_set, ecv);
392    E_LIST_HANDLER_APPEND(ecv->event_handlers, E_EVENT_CLIENT_VISIBILITY_CHANGE,
393                          _e_client_video_cb_ec_visibility_change, ecv);
394    E_LIST_HANDLER_APPEND(ecv->event_handlers, E_EVENT_REMOTE_SURFACE_PROVIDER_VISIBILITY_CHANGE,
395                          _e_client_video_cb_remote_surface_provider_visibility_change, ecv);
396
397    ecv->hook.subsurf_create =
398       e_comp_wl_hook_add(E_COMP_WL_HOOK_SUBSURFACE_CREATE,
399                          _e_client_video_cb_hook_subsurface_create, ecv);
400
401    ecv->hook.ec_del = e_client_hook_add(E_CLIENT_HOOK_DEL,
402                                         _e_client_video_cb_hook_ec_del,
403                                         ecv);
404
405    return EINA_TRUE;
406 }
407
408 E_API Eina_Bool
409 e_client_video_set(E_Client *ec)
410 {
411    E_Client_Video *ecv;
412    Eina_Bool res;
413
414    VIN("Set video client", ec);
415
416    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
417    EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
418
419    if (e_object_is_del(E_OBJECT(ec)))
420      {
421         VER("Can't handle deleted client", ec);
422         return EINA_FALSE;
423      }
424
425    ecv = evas_object_data_get(ec->frame, EO_DATA_KEY);
426    if (ecv)
427      {
428         VER("Given client was already set as Video client", ec);
429         return EINA_FALSE;
430      }
431
432    ecv = E_NEW(E_Client_Video, 1);
433    if (!ecv)
434      {
435         VER("Failed to allocate memory", ec);
436         return EINA_FALSE;
437      }
438
439    res = _e_client_video_init(ecv, ec);
440    if (!res)
441      {
442         VER("Failed to initialize video setting", ec);
443         free(ecv);
444         return EINA_FALSE;
445      }
446
447    evas_object_data_set(ec->frame, EO_DATA_KEY, ecv);
448    e_object_ref(E_OBJECT(ec));
449
450    return EINA_TRUE;
451 }
452
453 E_API void
454 e_client_video_unset(E_Client *ec)
455 {
456    INTERNAL_DATA_GET;
457
458    if (!ecv)
459      {
460         VWR("It's not video client or already deleted(%d)",
461             ec, e_object_is_del(E_OBJECT(ec)));
462         return;
463      }
464
465    VIN("Unset video client", ec);
466
467    _e_client_video_del(ecv);
468 }
469
470 E_API Eina_Bool
471 e_client_video_topmost_visibility_follow(E_Client *ec)
472 {
473    INTERNAL_DATA_GET;
474
475    EINA_SAFETY_ON_NULL_RETURN_VAL(ecv, EINA_FALSE);
476
477    ecv->follow_topmost_visibility = EINA_TRUE;
478    return EINA_TRUE;
479 }
480
481 E_API Eina_Bool
482 e_client_video_topmost_visibility_unfollow(E_Client *ec)
483 {
484    INTERNAL_DATA_GET;
485
486    EINA_SAFETY_ON_NULL_RETURN_VAL(ecv, EINA_FALSE);
487
488    ecv->follow_topmost_visibility = EINA_FALSE;
489
490    /* reset ec's visibility to unknown */
491    _e_client_video_visibility_set(ecv, E_VISIBILITY_UNKNOWN);
492    return EINA_TRUE;
493 }
494
495 EINTERN Eina_Bool
496 e_client_video_property_allow(E_Client *ec)
497 {
498    INTERNAL_DATA_GET;
499
500    EINA_SAFETY_ON_NULL_RETURN_VAL(ecv, EINA_FALSE);
501
502    ecv->allowed_property = EINA_TRUE;
503    return EINA_TRUE;
504 }
505
506 EINTERN Eina_Bool
507 e_client_video_property_disallow(E_Client *ec)
508 {
509    INTERNAL_DATA_GET;
510
511    EINA_SAFETY_ON_NULL_RETURN_VAL(ecv, EINA_FALSE);
512
513    ecv->allowed_property = EINA_FALSE;
514    return EINA_TRUE;
515 }
516
517 E_API Eina_Bool
518 e_client_video_property_get(E_Client *ec, unsigned int id, tdm_value *value)
519 {
520    IFACE_CHECK_RET(property_get, EINA_FALSE);
521
522    return ecv->iface->property_get(ecv->iface, id, value);
523 }
524
525 E_API Eina_Bool
526 e_client_video_property_set(E_Client *ec, unsigned int id, tdm_value value, Eina_Bool sync)
527 {
528    IFACE_CHECK_RET(property_set, EINA_FALSE);
529
530    return ecv->iface->property_set(ecv->iface, id, value, sync);
531 }
532
533 EINTERN Eina_Bool
534 e_client_video_property_delay_set(E_Client *ec, unsigned int id, tdm_value value)
535 {
536    IFACE_CHECK_RET(property_delay_set, EINA_FALSE);
537
538    return ecv->iface->property_delay_set(ecv->iface, id, value);
539 }
540
541 E_API Eina_Bool
542 e_client_video_available_properties_get(E_Client *ec, const tdm_prop **props, int *count)
543 {
544    IFACE_CHECK_RET(available_properties_get, EINA_FALSE);
545
546    return ecv->iface->available_properties_get(ecv->iface, props, count);
547 }
548
549 EINTERN Eina_Bool
550 e_client_video_info_get(E_Client *ec, E_Client_Video_Info *info)
551 {
552    IFACE_CHECK_RET(info_get, EINA_FALSE);
553
554    return ecv->iface->info_get(ecv->iface, info);
555 }
556
557 EINTERN Eina_Bool
558 e_client_video_commit_data_release(E_Client *ec, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
559 {
560    IFACE_CHECK_RET(commit_data_release, EINA_FALSE);
561
562    return ecv->iface->commit_data_release(ecv->iface, sequence, tv_sec, tv_usec);
563 }
564
565 EINTERN tbm_surface_h
566 e_client_video_tbm_surface_get(E_Client *ec)
567 {
568    IFACE_CHECK_RET(tbm_surface_get, EINA_FALSE);
569
570    return ecv->iface->tbm_surface_get(ecv->iface);
571 }
572
573 E_API Eina_Bool
574 e_client_is_video(E_Client *ec)
575 {
576    INTERNAL_DATA_GET;
577
578    return !!ecv;
579 }
580
581 EINTERN Eina_Bool
582 e_client_video_hw_composition_check(E_Client *ec)
583 {
584    INTERNAL_DATA_GET;
585
586    if (!ecv)
587      return EINA_FALSE;
588
589    return ecv->hw_composition;
590 }
591
592 /* Video Internal Functions */
593 EINTERN E_Client *
594 e_client_video_ec_get(E_Client_Video *ecv)
595 {
596    EINA_SAFETY_ON_NULL_RETURN_VAL(ecv, NULL);
597    return ecv->ec;
598 }
599
600 EINTERN void
601 e_client_video_hw_composition_set(E_Client_Video *ecv)
602 {
603    EINA_SAFETY_ON_NULL_RETURN(ecv);
604    ecv->hw_composition = EINA_TRUE;
605 }
606
607 EINTERN void
608 e_client_video_hw_composition_unset(E_Client_Video *ecv)
609 {
610    EINA_SAFETY_ON_NULL_RETURN(ecv);
611    ecv->hw_composition = EINA_FALSE;
612 }
613
614 EINTERN Eina_Bool
615 e_client_video_property_allow_get(E_Client_Video *ecv)
616 {
617    EINA_SAFETY_ON_NULL_RETURN_VAL(ecv, EINA_FALSE);
618    return ecv->allowed_property;
619 }