emotion: remove useless warning.
[profile/ivi/emotion.git] / src / modules / gstreamer / emotion_sink.c
1 #include <Ecore.h>
2
3 #include "emotion_gstreamer.h"
4
5 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink",
6                                                                    GST_PAD_SINK, GST_PAD_ALWAYS,
7                                                                    GST_STATIC_CAPS(GST_VIDEO_CAPS_YUV("{ I420, YV12, YUY2, NV12, ST12, TM12 }") ";"
8                                                                                    GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_BGR ";" GST_VIDEO_CAPS_BGRA));
9
10 GST_DEBUG_CATEGORY_STATIC(evas_video_sink_debug);
11 #define GST_CAT_DEFAULT evas_video_sink_debug
12
13 enum {
14   REPAINT_REQUESTED,
15   LAST_SIGNAL
16 };
17
18 enum {
19   PROP_0,
20   PROP_EVAS_OBJECT,
21   PROP_WIDTH,
22   PROP_HEIGHT,
23   PROP_EV,
24   PROP_LAST
25 };
26
27 static guint evas_video_sink_signals[LAST_SIGNAL] = { 0, };
28
29 #define _do_init(bla)                                   \
30   GST_DEBUG_CATEGORY_INIT(evas_video_sink_debug,        \
31                           "emotion-sink",               \
32                           0,                            \
33                           "emotion video sink")
34
35 GST_BOILERPLATE_FULL(EvasVideoSink,
36                      evas_video_sink,
37                      GstVideoSink,
38                      GST_TYPE_VIDEO_SINK,
39                      _do_init);
40
41
42 static void unlock_buffer_mutex(EvasVideoSinkPrivate* priv);
43 static void evas_video_sink_main_render(void *data);
44 static void evas_video_sink_samsung_main_render(void *data);
45
46 static void
47 _evas_video_bgrx_step(unsigned char *evas_data, const unsigned char *gst_data,
48                       unsigned int w, unsigned int h __UNUSED__, unsigned int output_height, unsigned int step)
49 {
50    unsigned int x;
51    unsigned int y;
52
53    for (y = 0; y < output_height; ++y)
54      {
55         for (x = 0; x < w; x++)
56           {
57              evas_data[0] = gst_data[0];
58              evas_data[1] = gst_data[1];
59              evas_data[2] = gst_data[2];
60              evas_data[3] = 255;
61              gst_data += step;
62              evas_data += 4;
63           }
64      }
65 }
66
67 static void
68 _evas_video_bgr(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
69 {
70    _evas_video_bgrx_step(evas_data, gst_data, w, h, output_height, 3);
71 }
72
73 static void
74 _evas_video_bgrx(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
75 {
76    _evas_video_bgrx_step(evas_data, gst_data, w, h, output_height, 4);
77 }
78
79 static void
80 _evas_video_bgra(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h __UNUSED__, unsigned int output_height)
81 {
82    unsigned int x;
83    unsigned int y;
84
85    for (y = 0; y < output_height; ++y)
86      {
87         unsigned char alpha;
88
89         for (x = 0; x < w; ++x)
90           {
91              alpha = gst_data[3];
92              evas_data[0] = (gst_data[0] * alpha) / 255;
93              evas_data[1] = (gst_data[1] * alpha) / 255;
94              evas_data[2] = (gst_data[2] * alpha) / 255;
95              evas_data[3] = alpha;
96              gst_data += 4;
97              evas_data += 4;
98           }
99      }
100 }
101
102 static void
103 _evas_video_i420(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
104 {
105    const unsigned char **rows;
106    unsigned int i, j;
107    unsigned int rh;
108
109    rh = output_height;
110
111    rows = (const unsigned char **)evas_data;
112
113    for (i = 0; i < rh; i++)
114      rows[i] = &gst_data[i * w];
115
116    for (j = 0; j < (rh / 2); j++, i++)
117      rows[i] = &gst_data[h * w + j * (w / 2)];
118
119    for (j = 0; j < (rh / 2); j++, i++)
120      rows[i] = &gst_data[h * w + h * (w / 4) + j * (w / 2)];
121 }
122
123 static void
124 _evas_video_yv12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
125 {
126    const unsigned char **rows;
127    unsigned int i, j;
128    unsigned int rh;
129
130    rh = output_height;
131
132    rows = (const unsigned char **)evas_data;
133
134    for (i = 0; i < rh; i++)
135      rows[i] = &gst_data[i * w];
136
137    for (j = 0; j < (rh / 2); j++, i++)
138      rows[i] = &gst_data[h * w + h * (w / 4) + j * (w / 2)];
139
140    for (j = 0; j < (rh / 2); j++, i++)
141      rows[i] = &gst_data[h * w + j * (w / 2)];
142 }
143
144 static void
145 _evas_video_yuy2(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h __UNUSED__, unsigned int output_height)
146 {
147    const unsigned char **rows;
148    unsigned int i;
149
150    rows = (const unsigned char **)evas_data;
151
152    for (i = 0; i < output_height; i++)
153      rows[i] = &gst_data[i * w * 2];
154 }
155
156 static void
157 _evas_video_nv12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height)
158 {
159    const unsigned char **rows;
160    unsigned int i, j;
161    unsigned int rh;
162
163    rh = output_height;
164
165    rows = (const unsigned char **)evas_data;
166
167    for (i = 0; i < rh; i++)
168      rows[i] = &gst_data[i * w];
169
170    for (j = 0; j < (rh / 2); j++, i++)
171      rows[i] = &gst_data[h * w + j * w];
172 }
173
174 static void
175 _evas_video_mt12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height __UNUSED__)
176 {
177    const unsigned char **rows;
178    unsigned int i;
179    unsigned int j;
180
181    rows = (const unsigned char **)evas_data;
182
183    for (i = 0; i < (h / 32) / 2; i++)
184      rows[i] = &gst_data[i * w * 2 * 32];
185
186    if ((h / 32) % 2)
187      {
188         rows[i] = &gst_data[i * w * 2 * 32];
189         i++;
190      }
191
192    for (j = 0; j < ((h / 2) / 32) / 2; ++j, ++i)
193      rows[i] = &gst_data[h * w + j * (w / 2) * 2 * 16];
194 }
195
196 static void
197 _evas_video_st12_multiplane(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height __UNUSED__)
198 {
199    const GstMultiPlaneImageBuffer *mp_buf = (const GstMultiPlaneImageBuffer *) gst_data;
200    const unsigned char **rows;
201    unsigned int i;
202    unsigned int j;
203
204    rows = (const unsigned char **)evas_data;
205
206    for (i = 0; i < (h / 32) / 2; i++)
207      rows[i] = mp_buf->uaddr[0] + i * w * 2 * 32;
208    if ((h / 32) % 2)
209      {
210         rows[i] = mp_buf->uaddr[0] + i * w * 2 * 32;
211         i++;
212      }
213
214    for (j = 0; j < ((h / 2) / 16) / 2; j++, i++)
215      rows[i] = mp_buf->uaddr[1] + j * w * 2 * 16;
216    if (((h / 2) / 16) % 2)
217      rows[i] = mp_buf->uaddr[0] + j * w * 2 * 16;
218 }
219
220 static void
221 _evas_video_st12(unsigned char *evas_data, const unsigned char *gst_data, unsigned int w, unsigned int h, unsigned int output_height __UNUSED__)
222 {
223    const SCMN_IMGB *imgb = (const SCMN_IMGB *) gst_data;
224    const unsigned char **rows;
225    unsigned int i, j;
226
227    rows = (const unsigned char **)evas_data;
228
229    for (i = 0; i < (h / 32) / 2; i++)
230      rows[i] = imgb->uaddr[0] + i * w * 2 * 32;
231    if ((h / 32) % 2)
232      {
233         rows[i] = imgb->uaddr[0] + i * w * 2 * 32;
234         i++;
235      }
236
237    for (j = 0; j < ((h / 2) / 16) / 2; j++, i++)
238      rows[i] = imgb->uaddr[1] + j * w * 2 * 16;
239    if (((h / 2) / 16) % 2)
240      rows[i] = imgb->uaddr[1] + j * w * 2 * 16;
241 }
242
243 static const struct {
244    guint32 fourcc;
245    Evas_Colorspace eformat;
246    Evas_Video_Convert_Cb func;
247    Eina_Bool force_height;
248 } colorspace_fourcc_convertion[] = {
249   { GST_MAKE_FOURCC('I', '4', '2', '0'), EVAS_COLORSPACE_YCBCR422P601_PL, _evas_video_i420, EINA_TRUE },
250   { GST_MAKE_FOURCC('Y', 'V', '1', '2'), EVAS_COLORSPACE_YCBCR422P601_PL, _evas_video_yv12, EINA_TRUE },
251   { GST_MAKE_FOURCC('Y', 'U', 'Y', '2'), EVAS_COLORSPACE_YCBCR422601_PL, _evas_video_yuy2, EINA_FALSE },
252   { GST_MAKE_FOURCC('N', 'V', '1', '2'), EVAS_COLORSPACE_YCBCR420NV12601_PL, _evas_video_nv12, EINA_TRUE },
253   { GST_MAKE_FOURCC('T', 'M', '1', '2'), EVAS_COLORSPACE_YCBCR420TM12601_PL, _evas_video_mt12, EINA_TRUE }
254 };
255
256 static const struct {
257    GstVideoFormat format;
258    Evas_Colorspace eformat;
259    Evas_Video_Convert_Cb func;
260 } colorspace_format_convertion[] = {
261   { GST_VIDEO_FORMAT_BGR, EVAS_COLORSPACE_ARGB8888, _evas_video_bgr },
262   { GST_VIDEO_FORMAT_BGRx, EVAS_COLORSPACE_ARGB8888, _evas_video_bgrx },
263   { GST_VIDEO_FORMAT_BGRA, EVAS_COLORSPACE_ARGB8888, _evas_video_bgra }
264 };
265
266 static void
267 evas_video_sink_base_init(gpointer g_class)
268 {
269    GstElementClass* element_class;
270
271    element_class = GST_ELEMENT_CLASS(g_class);
272    gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinktemplate));
273    gst_element_class_set_details_simple(element_class, "Evas video sink",
274                                         "Sink/Video", "Sends video data from a GStreamer pipeline to an Evas object",
275                                         "Vincent Torri <vtorri@univ-evry.fr>");
276 }
277
278 static void
279 evas_video_sink_init(EvasVideoSink* sink, EvasVideoSinkClass* klass __UNUSED__)
280 {
281    EvasVideoSinkPrivate* priv;
282
283    INF("sink init");
284    sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, EVAS_TYPE_VIDEO_SINK, EvasVideoSinkPrivate);
285    priv->o = NULL;
286    priv->last_buffer = NULL;
287    priv->width = 0;
288    priv->height = 0;
289    priv->func = NULL;
290    priv->eformat = EVAS_COLORSPACE_ARGB8888;
291    priv->samsung = EINA_FALSE;
292    eina_lock_new(&priv->m);
293    eina_condition_new(&priv->c, &priv->m);
294    priv->unlocked = EINA_FALSE;
295 }
296
297 /**** Object methods ****/
298 static void
299 _cleanup_priv(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
300 {
301    EvasVideoSinkPrivate* priv;
302
303    priv = data;
304
305    eina_lock_take(&priv->m);
306    if (priv->o == obj)
307      priv->o = NULL;
308    eina_lock_release(&priv->m);
309 }
310
311 static void
312 evas_video_sink_set_property(GObject * object, guint prop_id,
313                              const GValue * value, GParamSpec * pspec)
314 {
315    EvasVideoSink* sink;
316    EvasVideoSinkPrivate* priv;
317
318    sink = EVAS_VIDEO_SINK (object);
319    priv = sink->priv;
320
321    switch (prop_id) {
322     case PROP_EVAS_OBJECT:
323        eina_lock_take(&priv->m);
324        evas_object_event_callback_del(priv->o, EVAS_CALLBACK_FREE, _cleanup_priv);
325        priv->o = g_value_get_pointer (value);
326        INF("sink set Evas_Object %p.", priv->o);
327        evas_object_event_callback_add(priv->o, EVAS_CALLBACK_FREE, _cleanup_priv, priv);
328        eina_lock_release(&priv->m);
329        break;
330     case PROP_EV:
331        INF("sink set ev.");
332        eina_lock_take(&priv->m);
333        priv->ev = g_value_get_pointer (value);
334        eina_lock_release(&priv->m);
335        break;
336     default:
337        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
338        ERR("invalid property");
339        break;
340    }
341 }
342
343 static void
344 evas_video_sink_get_property(GObject * object, guint prop_id,
345                              GValue * value, GParamSpec * pspec)
346 {
347    EvasVideoSink* sink;
348    EvasVideoSinkPrivate* priv;
349
350    sink = EVAS_VIDEO_SINK (object);
351    priv = sink->priv;
352
353    switch (prop_id) {
354     case PROP_EVAS_OBJECT:
355        INF("sink get property.");
356        eina_lock_take(&priv->m);
357        g_value_set_pointer(value, priv->o);
358        eina_lock_release(&priv->m);
359        break;
360     case PROP_WIDTH:
361        INF("sink get width.");
362        eina_lock_take(&priv->m);
363        g_value_set_int(value, priv->width);
364        eina_lock_release(&priv->m);
365        break;
366     case PROP_HEIGHT:
367        INF("sink get height.");
368        eina_lock_take(&priv->m);
369        g_value_set_int (value, priv->height);
370        eina_lock_release(&priv->m);
371        break;
372     case PROP_EV:
373        INF("sink get ev.");
374        eina_lock_take(&priv->m);
375        g_value_set_pointer (value, priv->ev);
376        eina_lock_release(&priv->m);
377        break;
378     default:
379        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
380        ERR("invalide property");
381        break;
382    }
383 }
384
385 static void
386 evas_video_sink_dispose(GObject* object)
387 {
388    EvasVideoSink* sink;
389    EvasVideoSinkPrivate* priv;
390
391    INF("dispose.");
392
393    sink = EVAS_VIDEO_SINK(object);
394    priv = sink->priv;
395
396    eina_lock_free(&priv->m);
397    eina_condition_free(&priv->c);
398
399    if (priv->last_buffer) {
400       gst_buffer_unref(priv->last_buffer);
401       priv->last_buffer = NULL;
402    }
403
404    G_OBJECT_CLASS(parent_class)->dispose(object);
405 }
406
407
408 /**** BaseSink methods ****/
409
410 gboolean evas_video_sink_set_caps(GstBaseSink *bsink, GstCaps *caps)
411 {
412    EvasVideoSink* sink;
413    EvasVideoSinkPrivate* priv;
414    GstStructure *structure;
415    GstVideoFormat format;
416    guint32 fourcc;
417    unsigned int i;
418
419    sink = EVAS_VIDEO_SINK(bsink);
420    priv = sink->priv;
421
422    structure = gst_caps_get_structure(caps, 0);
423
424    if (gst_structure_get_int(structure, "width", (int*) &priv->width)
425        && gst_structure_get_int(structure, "height", (int*) &priv->height)
426        && gst_structure_get_fourcc(structure, "format", &fourcc))
427      {
428         priv->source_height = priv->height;
429
430         for (i = 0; i < sizeof (colorspace_fourcc_convertion) / sizeof (colorspace_fourcc_convertion[0]); ++i)
431           if (fourcc == colorspace_fourcc_convertion[i].fourcc)
432             {
433                priv->eformat = colorspace_fourcc_convertion[i].eformat;
434                priv->func = colorspace_fourcc_convertion[i].func;
435                if (colorspace_fourcc_convertion[i].force_height)
436                  {
437                     priv->height = (priv->height >> 1) << 1;
438                  }
439                return TRUE;
440             }
441
442         if (fourcc == GST_MAKE_FOURCC('S', 'T', '1', '2'))
443           {
444              priv->eformat = EVAS_COLORSPACE_YCBCR420TM12601_PL;
445              priv->samsung = EINA_TRUE;
446              priv->func = NULL;
447              return TRUE;
448           }
449      }
450
451    INF("fallback code !");
452    if (!gst_video_format_parse_caps(caps, &format, (int*) &priv->width, (int*) &priv->height))
453      {
454         ERR("Unable to parse caps.");
455         return FALSE;
456      }
457
458    priv->source_height = priv->height;
459
460    for (i = 0; i < sizeof (colorspace_format_convertion) / sizeof (colorspace_format_convertion[0]); ++i)
461      if (format == colorspace_format_convertion[i].format)
462        {
463           priv->eformat = colorspace_format_convertion[i].eformat;
464           priv->func = colorspace_format_convertion[i].func;
465           return TRUE;
466        }
467
468    ERR("unsupported : %d\n", format);
469    return FALSE;
470 }
471
472 static gboolean
473 evas_video_sink_start(GstBaseSink* base_sink)
474 {
475    EvasVideoSinkPrivate* priv;
476    gboolean res = TRUE;
477
478    INF("sink start");
479
480    priv = EVAS_VIDEO_SINK(base_sink)->priv;
481    eina_lock_take(&priv->m);
482    if (!priv->o)
483      res = FALSE;
484    else
485      priv->unlocked = EINA_FALSE;
486    eina_lock_release(&priv->m);
487    return res;
488 }
489
490 static gboolean
491 evas_video_sink_stop(GstBaseSink* base_sink)
492 {
493    EvasVideoSinkPrivate* priv = EVAS_VIDEO_SINK(base_sink)->priv;
494
495    INF("sink stop");
496
497    unlock_buffer_mutex(priv);
498    return TRUE;
499 }
500
501 static gboolean
502 evas_video_sink_unlock(GstBaseSink* object)
503 {
504    EvasVideoSink* sink;
505
506    INF("sink unlock");
507
508    sink = EVAS_VIDEO_SINK(object);
509
510    unlock_buffer_mutex(sink->priv);
511
512    return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock,
513                                        (object), TRUE);
514 }
515
516 static gboolean
517 evas_video_sink_unlock_stop(GstBaseSink* object)
518 {
519    EvasVideoSink* sink;
520    EvasVideoSinkPrivate* priv;
521
522    sink = EVAS_VIDEO_SINK(object);
523    priv = sink->priv;
524
525    INF("sink unlock stop");
526
527    eina_lock_take(&priv->m);
528    priv->unlocked = FALSE;
529    eina_lock_release(&priv->m);
530
531    return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop,
532                                        (object), TRUE);
533 }
534
535 static GstFlowReturn
536 evas_video_sink_preroll(GstBaseSink* bsink, GstBuffer* buffer)
537 {
538    Emotion_Gstreamer_Buffer *send;
539    EvasVideoSinkPrivate *priv;
540    EvasVideoSink *sink;
541
542    INF("sink preroll %p [%i]", GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
543
544    sink = EVAS_VIDEO_SINK(bsink);
545    priv = sink->priv;
546
547    if (GST_BUFFER_SIZE(buffer) <= 0 && !priv->samsung)
548      {
549         WRN("empty buffer");
550         return GST_FLOW_OK;
551      }
552
553    send = emotion_gstreamer_buffer_alloc(priv, buffer, EINA_TRUE);
554
555    if (send)
556      {
557         if (priv->samsung)
558           {
559              if (!priv->func)
560                {
561                   GstStructure *structure;
562                   GstCaps *caps;
563                   gboolean is_multiplane = FALSE;
564
565                   caps = GST_BUFFER_CAPS(buffer);
566                   structure = gst_caps_get_structure (caps, 0);
567                   gst_structure_get_boolean(structure, "multiplane", &is_multiplane);
568
569                   if (is_multiplane)
570                     priv->func = _evas_video_st12_multiplane;
571                   else
572                     priv->func = _evas_video_st12;
573                }
574
575              ecore_main_loop_thread_safe_call_async(evas_video_sink_samsung_main_render, send);
576           }
577         else
578           ecore_main_loop_thread_safe_call_async(evas_video_sink_main_render, send);
579      }
580
581    return GST_FLOW_OK;
582 }
583
584 static GstFlowReturn
585 evas_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
586 {
587    Emotion_Gstreamer_Buffer *send;
588    EvasVideoSinkPrivate *priv;
589    EvasVideoSink *sink;
590
591    INF("sink render %p [%i]", GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
592
593    sink = EVAS_VIDEO_SINK(bsink);
594    priv = sink->priv;
595
596    eina_lock_take(&priv->m);
597
598    if (priv->unlocked) {
599       ERR("LOCKED");
600       eina_lock_release(&priv->m);
601       return GST_FLOW_OK;
602    }
603
604    send = emotion_gstreamer_buffer_alloc(priv, buffer, EINA_FALSE);
605    if (!send) {
606       eina_lock_release(&priv->m);
607       return GST_FLOW_ERROR;
608    }
609
610    if (priv->samsung)
611      {
612         if (!priv->func)
613           {
614              GstStructure *structure;
615              GstCaps *caps;
616              gboolean is_multiplane = FALSE;
617
618              caps = GST_BUFFER_CAPS(buffer);
619              structure = gst_caps_get_structure (caps, 0);
620              gst_structure_get_boolean(structure, "multiplane", &is_multiplane);
621
622              if (is_multiplane)
623                priv->func = _evas_video_st12_multiplane;
624              else
625                priv->func = _evas_video_st12;
626           }
627
628         ecore_main_loop_thread_safe_call_async(evas_video_sink_samsung_main_render, send);
629      }
630    else
631      ecore_main_loop_thread_safe_call_async(evas_video_sink_main_render, send);
632
633    eina_condition_wait(&priv->c);
634    eina_lock_release(&priv->m);
635
636    return GST_FLOW_OK;
637 }
638
639 static void
640 evas_video_sink_samsung_main_render(void *data)
641 {
642    Emotion_Gstreamer_Buffer *send;
643    Emotion_Video_Stream *vstream;
644    EvasVideoSinkPrivate* priv;
645    GstBuffer* buffer;
646    unsigned char *evas_data;
647    const guint8 *gst_data;
648    GstFormat fmt = GST_FORMAT_TIME;
649    gint64 pos;
650    Eina_Bool preroll;
651    int stride, elevation;
652    Evas_Coord w, h;
653
654    send = data;
655
656    if (!send) goto exit_point;
657
658    priv = send->sink;
659    buffer = send->frame;
660    preroll = send->preroll;
661
662    if (!priv || !priv->o || priv->unlocked || !send->ev)
663      goto exit_point;
664
665    _emotion_gstreamer_video_pipeline_parse(send->ev, EINA_TRUE);
666
667    /* Getting stride to compute the right size and then fill the object properly */
668    /* Y => [0] and UV in [1] */
669    if (priv->func == _evas_video_st12_multiplane)
670      {
671         const GstMultiPlaneImageBuffer *mp_buf = (const GstMultiPlaneImageBuffer *) buffer;
672
673         stride = mp_buf->stride[0];
674         elevation = mp_buf->elevation[0];
675         priv->width = mp_buf->width[0];
676         priv->height = mp_buf->height[0];
677
678         gst_data = (const guint8 *) mp_buf;
679      }
680    else
681      {
682         const SCMN_IMGB *imgb = (const SCMN_IMGB *) GST_BUFFER_MALLOCDATA(buffer);
683
684         stride = imgb->stride[0];
685         elevation = imgb->elevation[0];
686         priv->width = imgb->width[0];
687         priv->height = imgb->height[0];
688
689         gst_data = (const guint8 *) imgb;
690      }
691
692    INF("sink main render [%i, %i] - [%i, %i]", priv->width, priv->height, stride, elevation);
693
694    evas_object_image_alpha_set(priv->o, 0);
695    evas_object_image_colorspace_set(priv->o, priv->eformat);
696    evas_object_image_size_set(priv->o, stride, elevation);
697    evas_object_geometry_get(priv->o, NULL, NULL, &w, &h);
698    evas_object_image_fill_set(priv->o, 0, 0, stride * w / priv->width, elevation * h / priv->height);
699
700    evas_data = evas_object_image_data_get(priv->o, 1);
701
702    if (priv->func)
703      priv->func(evas_data, gst_data, stride, elevation, elevation);
704    else
705      WRN("No way to decode %x colorspace !", priv->eformat);
706
707    evas_object_image_data_set(priv->o, evas_data);
708    evas_object_image_data_update_add(priv->o, 0, 0, priv->width, priv->height);
709    evas_object_image_pixels_dirty_set(priv->o, 0);
710
711    _emotion_frame_new(send->ev->obj);
712
713    vstream = eina_list_nth(send->ev->video_streams, send->ev->video_stream_nbr - 1);
714
715    gst_element_query_position(send->ev->pipeline, &fmt, &pos);
716    send->ev->position = (double)pos / (double)GST_SECOND;
717
718    vstream->width = priv->width;
719    vstream->height = priv->height;
720    send->ev->ratio = (double) priv->width / (double) priv->height;
721
722    _emotion_video_pos_update(send->ev->obj, send->ev->position, vstream->length_time);
723    _emotion_frame_resize(send->ev->obj, priv->width, priv->height, send->ev->ratio);
724
725    if (priv->last_buffer) gst_buffer_unref(priv->last_buffer);
726    priv->last_buffer = gst_buffer_ref(buffer);
727
728  exit_point:
729    emotion_gstreamer_buffer_free(send);
730
731    if (preroll || !priv->o || !send->ev) return ;
732
733    eina_lock_take(&priv->m);
734    if (!priv->unlocked)
735      eina_condition_signal(&priv->c);
736
737    eina_lock_release(&priv->m);
738 }
739
740 static void
741 evas_video_sink_main_render(void *data)
742 {
743    Emotion_Gstreamer_Buffer *send;
744    Emotion_Gstreamer_Video *ev = NULL;
745    Emotion_Video_Stream *vstream;
746    EvasVideoSinkPrivate* priv;
747    GstBuffer* buffer;
748    unsigned char *evas_data;
749    GstFormat fmt = GST_FORMAT_TIME;
750    gint64 pos;
751    Eina_Bool preroll;
752
753    send = data;
754
755    if (!send) goto exit_point;
756
757    priv = send->sink;
758    buffer = send->frame;
759    preroll = send->preroll;
760    ev = send->ev;
761
762    if (!priv || !priv->o || priv->unlocked || !ev)
763      goto exit_point;
764
765    _emotion_gstreamer_video_pipeline_parse(ev, EINA_TRUE);
766
767    INF("sink main render [%i, %i] (source height: %i)", priv->width, priv->height, priv->source_height);
768
769    evas_object_image_alpha_set(priv->o, 0);
770    evas_object_image_colorspace_set(priv->o, priv->eformat);
771    evas_object_image_size_set(priv->o, priv->width, priv->height);
772
773    evas_data = evas_object_image_data_get(priv->o, 1);
774
775    if (priv->func)
776      priv->func(evas_data, GST_BUFFER_DATA(buffer), priv->width, priv->source_height, priv->height);
777    else
778      WRN("No way to decode %x colorspace !", priv->eformat);
779
780    evas_object_image_data_set(priv->o, evas_data);
781    evas_object_image_data_update_add(priv->o, 0, 0, priv->width, priv->height);
782    evas_object_image_pixels_dirty_set(priv->o, 0);
783
784    _emotion_frame_new(ev->obj);
785
786    vstream = eina_list_nth(ev->video_streams, ev->video_stream_nbr - 1);
787
788    gst_element_query_position(ev->pipeline, &fmt, &pos);
789    ev->position = (double)pos / (double)GST_SECOND;
790
791    vstream->width = priv->width;
792    vstream->height = priv->height;
793    ev->ratio = (double) priv->width / (double) priv->height;
794
795    _emotion_video_pos_update(ev->obj, ev->position, vstream->length_time);
796    _emotion_frame_resize(ev->obj, priv->width, priv->height, ev->ratio);
797
798    if (priv->last_buffer) gst_buffer_unref(priv->last_buffer);
799    priv->last_buffer = gst_buffer_ref(buffer);
800
801  exit_point:
802    emotion_gstreamer_buffer_free(send);
803
804    if (preroll || !priv->o || !ev) return ;
805
806    eina_lock_take(&priv->m);
807    if (!priv->unlocked)
808      eina_condition_signal(&priv->c);
809
810    eina_lock_release(&priv->m);
811 }
812
813 static void
814 unlock_buffer_mutex(EvasVideoSinkPrivate* priv)
815 {
816    eina_lock_take(&priv->m);
817    priv->unlocked = EINA_TRUE;
818
819    eina_condition_signal(&priv->c);
820    eina_lock_release(&priv->m);
821 }
822
823 static void
824 marshal_VOID__MINIOBJECT(GClosure * closure, GValue * return_value __UNUSED__,
825                          guint n_param_values, const GValue * param_values,
826                          gpointer invocation_hint __UNUSED__, gpointer marshal_data)
827 {
828    typedef void (*marshalfunc_VOID__MINIOBJECT) (gpointer obj, gpointer arg1, gpointer data2);
829    marshalfunc_VOID__MINIOBJECT callback;
830    GCClosure *cc;
831    gpointer data1, data2;
832
833    cc = (GCClosure *) closure;
834
835    g_return_if_fail(n_param_values == 2);
836
837    if (G_CCLOSURE_SWAP_DATA(closure)) {
838       data1 = closure->data;
839       data2 = g_value_peek_pointer(param_values + 0);
840    } else {
841       data1 = g_value_peek_pointer(param_values + 0);
842       data2 = closure->data;
843    }
844    callback = (marshalfunc_VOID__MINIOBJECT) (marshal_data ? marshal_data : cc->callback);
845
846    callback(data1, gst_value_get_mini_object(param_values + 1), data2);
847 }
848
849 static void
850 evas_video_sink_class_init(EvasVideoSinkClass* klass)
851 {
852    GObjectClass* gobject_class;
853    GstBaseSinkClass* gstbase_sink_class;
854
855    gobject_class = G_OBJECT_CLASS(klass);
856    gstbase_sink_class = GST_BASE_SINK_CLASS(klass);
857
858    g_type_class_add_private(klass, sizeof(EvasVideoSinkPrivate));
859
860    gobject_class->set_property = evas_video_sink_set_property;
861    gobject_class->get_property = evas_video_sink_get_property;
862
863    g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT,
864                                     g_param_spec_pointer ("evas-object", "Evas Object",
865                                                           "The Evas object where the display of the video will be done",
866                                                           G_PARAM_READWRITE));
867
868    g_object_class_install_property (gobject_class, PROP_WIDTH,
869                                     g_param_spec_int ("width", "Width",
870                                                       "The width of the video",
871                                                       0, 65536, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
872
873    g_object_class_install_property (gobject_class, PROP_HEIGHT,
874                                     g_param_spec_int ("height", "Height",
875                                                       "The height of the video",
876                                                       0, 65536, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
877    g_object_class_install_property (gobject_class, PROP_EV,
878                                     g_param_spec_pointer ("ev", "Emotion_Gstreamer_Video",
879                                                           "THe internal data of the emotion object",
880                                                           G_PARAM_READWRITE));
881
882    gobject_class->dispose = evas_video_sink_dispose;
883
884    gstbase_sink_class->set_caps = evas_video_sink_set_caps;
885    gstbase_sink_class->stop = evas_video_sink_stop;
886    gstbase_sink_class->start = evas_video_sink_start;
887    gstbase_sink_class->unlock = evas_video_sink_unlock;
888    gstbase_sink_class->unlock_stop = evas_video_sink_unlock_stop;
889    gstbase_sink_class->render = evas_video_sink_render;
890    gstbase_sink_class->preroll = evas_video_sink_preroll;
891
892    evas_video_sink_signals[REPAINT_REQUESTED] = g_signal_new("repaint-requested",
893                                                              G_TYPE_FROM_CLASS(klass),
894                                                              (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
895                                                              0,
896                                                              0,
897                                                              0,
898                                                              marshal_VOID__MINIOBJECT,
899                                                              G_TYPE_NONE, 1, GST_TYPE_BUFFER);
900 }
901
902 gboolean
903 gstreamer_plugin_init (GstPlugin * plugin)
904 {
905    return gst_element_register (plugin,
906                                 "emotion-sink",
907                                 GST_RANK_NONE,
908                                 EVAS_TYPE_VIDEO_SINK);
909 }
910
911 static void
912 _emotion_gstreamer_pause(void *data, Ecore_Thread *thread)
913 {
914    Emotion_Gstreamer_Video *ev = data;
915
916    if (ecore_thread_check(thread) || !ev->pipeline) return ;
917
918    gst_element_set_state(ev->pipeline, GST_STATE_PAUSED);
919 }
920
921 static void
922 _emotion_gstreamer_cancel(void *data, Ecore_Thread *thread)
923 {
924    Emotion_Gstreamer_Video *ev = data;
925
926    ev->threads = eina_list_remove(ev->threads, thread);
927
928    if (getenv("EMOTION_GSTREAMER_DOT")) GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(ev->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, getenv("EMOTION_GSTREAMER_DOT"));
929
930    if (ev->in == ev->out && ev->threads == NULL && ev->delete_me)
931      em_shutdown(ev);
932 }
933
934 static void
935 _emotion_gstreamer_end(void *data, Ecore_Thread *thread)
936 {
937    Emotion_Gstreamer_Video *ev = data;
938
939    ev->threads = eina_list_remove(ev->threads, thread);
940
941    if (ev->play)
942      {
943         gst_element_set_state(ev->pipeline, GST_STATE_PLAYING);
944         ev->play_started = 1;
945      }
946
947    if (getenv("EMOTION_GSTREAMER_DOT")) GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(ev->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, getenv("EMOTION_GSTREAMER_DOT"));
948
949    if (ev->in == ev->out && ev->threads == NULL && ev->delete_me)
950      em_shutdown(ev);
951    else
952      _emotion_gstreamer_video_pipeline_parse(data, EINA_TRUE);
953 }
954
955 GstElement *
956 gstreamer_video_sink_new(Emotion_Gstreamer_Video *ev,
957                          Evas_Object *o,
958                          const char *uri)
959 {
960    GstElement *playbin;
961    GstElement *sink;
962    Evas_Object *obj;
963    int flags;
964
965    obj = emotion_object_image_get(o);
966    if (!obj)
967      {
968         ERR("Not Evas_Object specified");
969         return NULL;
970      }
971
972    playbin = gst_element_factory_make("playbin2", "playbin");
973    if (!playbin)
974      {
975         ERR("Unable to create 'playbin' GstElement.");
976         return NULL;
977      }
978
979    sink = gst_element_factory_make("emotion-sink", "sink");
980    if (!sink)
981      {
982         ERR("Unable to create 'emotion-sink' GstElement.");
983         goto unref_pipeline;
984      }
985
986 #define GST_PLAY_FLAG_NATIVE_VIDEO  (1 << 6)
987 #define GST_PLAY_FLAG_DOWNLOAD      (1 << 7)
988 #define GST_PLAY_FLAG_BUFFERING     (1 << 8)
989
990    g_object_set(G_OBJECT(sink), "evas-object", obj, NULL);
991    g_object_set(G_OBJECT(sink), "ev", ev, NULL);
992
993    evas_object_image_pixels_get_callback_set(obj, NULL, NULL);
994
995    g_object_get(G_OBJECT(playbin), "flags", &flags, NULL);
996    g_object_set(G_OBJECT(playbin), "flags", flags | GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_DOWNLOAD | GST_PLAY_FLAG_BUFFERING, NULL);
997    g_object_set(G_OBJECT(playbin), "video-sink", sink, NULL);
998    g_object_set(G_OBJECT(playbin), "uri", uri, NULL);
999
1000    ev->pipeline = playbin;
1001    ev->sink = sink;
1002    ev->threads = eina_list_append(ev->threads,
1003                                   ecore_thread_run(_emotion_gstreamer_pause,
1004                                                    _emotion_gstreamer_end,
1005                                                    _emotion_gstreamer_cancel,
1006                                                    ev));
1007
1008    /** NOTE: you need to set: GST_DEBUG_DUMP_DOT_DIR=/tmp EMOTION_ENGINE=gstreamer to save the $EMOTION_GSTREAMER_DOT file in '/tmp' */
1009    /** then call dot -Tpng -oemotion_pipeline.png /tmp/$TIMESTAMP-$EMOTION_GSTREAMER_DOT.dot */
1010    if (getenv("EMOTION_GSTREAMER_DOT")) GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(playbin), GST_DEBUG_GRAPH_SHOW_ALL, getenv("EMOTION_GSTREAMER_DOT"));
1011
1012    return playbin;
1013
1014  unref_pipeline:
1015    gst_object_unref(playbin);
1016    return NULL;
1017 }