Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst / vaapi / gstvaapidecode.c
1 /*
2  *  gstvaapidecode.c - VA-API video decoder
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *  Copyright (C) 2011-2012 Intel Corporation
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21 */
22
23 /**
24  * SECTION:gstvaapidecode
25  * @short_description: A VA-API based video decoder
26  *
27  * vaapidecode decodes from raw bitstreams to surfaces suitable for
28  * the vaapisink element.
29  */
30
31 #include "config.h"
32
33 #include <gst/vaapi/gstvaapidisplay.h>
34 #include <gst/vaapi/gstvaapivideobuffer.h>
35 #include <gst/video/videocontext.h>
36
37 #include "gstvaapidecode.h"
38 #include "gstvaapipluginutil.h"
39 #include "gstvaapipluginbuffer.h"
40
41 #include <gst/vaapi/gstvaapidecoder_h264.h>
42 #include <gst/vaapi/gstvaapidecoder_jpeg.h>
43 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
44 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
45 #include <gst/vaapi/gstvaapidecoder_vc1.h>
46
47 #define GST_PLUGIN_NAME "vaapidecode"
48 #define GST_PLUGIN_DESC "A VA-API based video decoder"
49
50 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode);
51 #define GST_CAT_DEFAULT gst_debug_vaapidecode
52
53 /* ElementFactory information */
54 static const GstElementDetails gst_vaapidecode_details =
55     GST_ELEMENT_DETAILS(
56         "VA-API decoder",
57         "Codec/Decoder/Video",
58         GST_PLUGIN_DESC,
59         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
60
61 /* Default templates */
62 #define GST_CAPS_CODEC(CODEC) CODEC "; "
63
64 static const char gst_vaapidecode_sink_caps_str[] =
65     GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
66     GST_CAPS_CODEC("video/mpeg, mpegversion=4")
67     GST_CAPS_CODEC("video/x-divx")
68     GST_CAPS_CODEC("video/x-xvid")
69     GST_CAPS_CODEC("video/x-h263")
70     GST_CAPS_CODEC("video/x-h264")
71     GST_CAPS_CODEC("video/x-wmv")
72     GST_CAPS_CODEC("image/jpeg")
73     ;
74
75 static const char gst_vaapidecode_src_caps_str[] =
76     GST_VAAPI_SURFACE_CAPS;
77
78 static GstStaticPadTemplate gst_vaapidecode_sink_factory =
79     GST_STATIC_PAD_TEMPLATE(
80         "sink",
81         GST_PAD_SINK,
82         GST_PAD_ALWAYS,
83         GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));
84
85 static GstStaticPadTemplate gst_vaapidecode_src_factory =
86     GST_STATIC_PAD_TEMPLATE(
87         "src",
88         GST_PAD_SRC,
89         GST_PAD_ALWAYS,
90         GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
91
92 static void
93 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface);
94
95 static void
96 gst_video_context_interface_init(GstVideoContextInterface *iface);
97
98 #define GstVideoContextClass GstVideoContextInterface
99 G_DEFINE_TYPE_WITH_CODE(
100     GstVaapiDecode,
101     gst_vaapidecode,
102     GST_TYPE_ELEMENT,
103     G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
104                           gst_vaapidecode_implements_iface_init);
105     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
106                           gst_video_context_interface_init));
107
108 static gboolean
109 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, GstCaps *caps);
110
111 static void
112 gst_vaapi_decoder_notify_caps(GObject *obj, GParamSpec *pspec, void *user_data)
113 {
114     GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
115     GstCaps *caps;
116
117     g_assert(decode->decoder == GST_VAAPI_DECODER(obj));
118
119     caps = gst_vaapi_decoder_get_caps(decode->decoder);
120     gst_vaapidecode_update_src_caps(decode, caps);
121 }
122
123 static inline gboolean
124 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
125 {
126     if (decode->sinkpad_caps)
127         gst_caps_unref(decode->sinkpad_caps);
128     decode->sinkpad_caps = gst_caps_ref(caps);
129     return TRUE;
130 }
131
132 static gboolean
133 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, GstCaps *caps)
134 {
135     GstCaps *other_caps;
136     GstStructure *structure;
137     const GValue *v_width, *v_height, *v_framerate, *v_par, *v_interlaced;
138     gboolean success;
139
140     if (!decode->srcpad_caps) {
141         decode->srcpad_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
142         if (!decode->srcpad_caps)
143             return FALSE;
144     }
145
146     structure    = gst_caps_get_structure(caps, 0);
147     v_width      = gst_structure_get_value(structure, "width");
148     v_height     = gst_structure_get_value(structure, "height");
149     v_framerate  = gst_structure_get_value(structure, "framerate");
150     v_par        = gst_structure_get_value(structure, "pixel-aspect-ratio");
151     v_interlaced = gst_structure_get_value(structure, "interlaced");
152
153     structure = gst_caps_get_structure(decode->srcpad_caps, 0);
154     if (v_width && v_height) {
155         gst_structure_set_value(structure, "width", v_width);
156         gst_structure_set_value(structure, "height", v_height);
157     }
158     if (v_framerate)
159         gst_structure_set_value(structure, "framerate", v_framerate);
160     if (v_par)
161         gst_structure_set_value(structure, "pixel-aspect-ratio", v_par);
162     if (v_interlaced)
163         gst_structure_set_value(structure, "interlaced", v_interlaced);
164
165     gst_structure_set(structure, "type", G_TYPE_STRING, "vaapi", NULL);
166     gst_structure_set(structure, "opengl", G_TYPE_BOOLEAN, USE_GLX, NULL);
167
168     other_caps = gst_caps_copy(decode->srcpad_caps);
169     success = gst_pad_set_caps(decode->srcpad, other_caps);
170     gst_caps_unref(other_caps);
171     return success;
172 }
173
174 static void
175 gst_vaapidecode_release(GstVaapiDecode *decode, GObject *dead_object)
176 {
177     g_mutex_lock(decode->decoder_mutex);
178     g_cond_signal(decode->decoder_ready);
179     g_mutex_unlock(decode->decoder_mutex);
180 }
181
182 static gboolean
183 gst_vaapidecode_is_valid_time(GstVaapiDecode *decode, gint64 time)
184 {
185     if (decode->segment.format != GST_FORMAT_TIME)
186         return TRUE;
187     if (decode->segment.stop != -1 && time != -1 && time > decode->segment.stop)
188         return FALSE;
189     if (decode->segment.start != -1 && time != -1 && time < decode->segment.start)
190         return FALSE;
191
192     return TRUE;
193 }
194
195 static GstFlowReturn
196 gst_vaapidecode_step(GstVaapiDecode *decode)
197 {
198     GstVaapiSurfaceProxy *proxy;
199     GstVaapiDecoderStatus status;
200     GstBuffer *buffer;
201     GstClockTime timestamp;
202     GstFlowReturn ret;
203     guint tries;
204
205     for (;;) {
206         tries = 0;
207     again:
208         proxy = gst_vaapi_decoder_get_surface(decode->decoder, &status);
209         if (!proxy) {
210             if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
211                 /* Wait for a VA surface to be displayed and free'd */
212                 if (++tries > 100)
213                     goto error_decode_timeout;
214                 GTimeVal timeout;
215                 g_get_current_time(&timeout);
216                 g_time_val_add(&timeout, 10000); /* 10 ms each step */
217                 g_mutex_lock(decode->decoder_mutex);
218                 g_cond_timed_wait(
219                     decode->decoder_ready,
220                     decode->decoder_mutex,
221                     &timeout
222                 );
223                 g_mutex_unlock(decode->decoder_mutex);
224                 goto again;
225             }
226             if (status != GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA)
227                 goto error_decode;
228             /* More data is needed */
229             break;
230         }
231
232         timestamp = GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy);
233         if (GST_CLOCK_TIME_IS_VALID(timestamp) &&
234             !gst_vaapidecode_is_valid_time(decode, (gint64)timestamp)) {
235             g_object_unref(proxy);
236             continue;
237         }
238
239         g_object_weak_ref(
240             G_OBJECT(proxy),
241             (GWeakNotify)gst_vaapidecode_release,
242             decode
243         );
244
245         buffer = gst_vaapi_video_buffer_new(decode->display);
246         if (!buffer)
247             goto error_create_buffer;
248
249         GST_BUFFER_TIMESTAMP(buffer) = timestamp;
250         gst_buffer_set_caps(buffer, GST_PAD_CAPS(decode->srcpad));
251
252         if (GST_VAAPI_SURFACE_PROXY_TFF(proxy))
253             GST_BUFFER_FLAG_SET(buffer, GST_VIDEO_BUFFER_TFF);
254
255         gst_vaapi_video_buffer_set_surface_proxy(
256             GST_VAAPI_VIDEO_BUFFER(buffer),
257             proxy
258         );
259
260         ret = gst_pad_push(decode->srcpad, buffer);
261         if (ret != GST_FLOW_OK)
262             goto error_commit_buffer;
263
264         g_object_unref(proxy);
265     }
266     return GST_FLOW_OK;
267
268     /* ERRORS */
269 error_decode_timeout:
270     {
271         GST_DEBUG("decode timeout. Decoder required a VA surface but none "
272                   "got available within one second");
273         return GST_FLOW_UNEXPECTED;
274     }
275 error_decode:
276     {
277         GST_DEBUG("decode error %d", status);
278         switch (status) {
279         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
280         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
281         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
282             ret = GST_FLOW_NOT_SUPPORTED;
283             break;
284         default:
285             ret = GST_FLOW_UNEXPECTED;
286             break;
287         }
288         return ret;
289     }
290 error_create_buffer:
291     {
292         const GstVaapiID surface_id =
293             gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
294
295         GST_DEBUG("video sink failed to create video buffer for proxy'ed "
296                   "surface %" GST_VAAPI_ID_FORMAT " (error %d)",
297                   GST_VAAPI_ID_ARGS(surface_id), ret);
298         g_object_unref(proxy);
299         return GST_FLOW_UNEXPECTED;
300     }
301 error_commit_buffer:
302     {
303         GST_DEBUG("video sink rejected the video buffer (error %d)", ret);
304         g_object_unref(proxy);
305         return GST_FLOW_UNEXPECTED;
306     }
307 }
308
309 static inline gboolean
310 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
311 {
312     return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY,
313         &decode->display);
314 }
315
316 static gboolean
317 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
318 {
319     GstVaapiDisplay *dpy;
320     GstStructure *structure;
321     int version;
322
323     if (!gst_vaapidecode_ensure_display(decode))
324         return FALSE;
325     dpy = decode->display;
326
327     decode->decoder_mutex = g_mutex_new();
328     if (!decode->decoder_mutex)
329         return FALSE;
330
331     decode->decoder_ready = g_cond_new();
332     if (!decode->decoder_ready)
333         return FALSE;
334
335     structure = gst_caps_get_structure(caps, 0);
336     if (!structure)
337         return FALSE;
338
339     if (gst_structure_has_name(structure, "video/x-h264"))
340         decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
341     else if (gst_structure_has_name(structure, "video/mpeg")) {
342         if (!gst_structure_get_int(structure, "mpegversion", &version))
343             return FALSE;
344         if (version == 2)
345             decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
346         else if (version == 4)
347             decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
348     }
349     else if (gst_structure_has_name(structure, "video/x-wmv"))
350         decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
351     else if (gst_structure_has_name(structure, "video/x-h263") ||
352              gst_structure_has_name(structure, "video/x-divx") ||
353              gst_structure_has_name(structure, "video/x-xvid"))
354         decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
355 #if USE_JPEG_DECODER
356     else if (gst_structure_has_name(structure, "image/jpeg"))
357         decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
358 #endif
359     if (!decode->decoder)
360         return FALSE;
361
362     g_signal_connect(
363         G_OBJECT(decode->decoder),
364         "notify::caps",
365         G_CALLBACK(gst_vaapi_decoder_notify_caps),
366         decode
367     );
368
369     decode->decoder_caps = gst_caps_ref(caps);
370     return TRUE;
371 }
372
373 static void
374 gst_vaapidecode_destroy(GstVaapiDecode *decode)
375 {
376     if (decode->decoder) {
377         gst_vaapi_decoder_put_buffer(decode->decoder, NULL);
378         g_object_unref(decode->decoder);
379         decode->decoder = NULL;
380     }
381
382     if (decode->decoder_caps) {
383         gst_caps_unref(decode->decoder_caps);
384         decode->decoder_caps = NULL;
385     }
386
387     if (decode->decoder_ready) {
388         gst_vaapidecode_release(decode, NULL);
389         g_cond_free(decode->decoder_ready);
390         decode->decoder_ready = NULL;
391     }
392
393     if (decode->decoder_mutex) {
394         g_mutex_free(decode->decoder_mutex);
395         decode->decoder_mutex = NULL;
396     }
397 }
398
399 static gboolean
400 gst_vaapidecode_reset(GstVaapiDecode *decode, GstCaps *caps)
401 {
402     if (decode->decoder &&
403         decode->decoder_caps &&
404         gst_caps_is_always_compatible(caps, decode->decoder_caps))
405         return TRUE;
406
407     gst_vaapidecode_destroy(decode);
408     return gst_vaapidecode_create(decode, caps);
409 }
410
411 static void
412 gst_vaapidecode_configure_segment(
413     GstVaapiDecode *decode,
414     GstEvent *event
415 )
416 {
417     gboolean update;
418     gdouble rate, applied_rate;
419     GstFormat format;
420     gint64 start, stop, time;
421
422     gst_event_parse_new_segment_full(event, &update, &rate, &applied_rate,
423                                      &format, &start, &stop, &time);
424     if (format == GST_FORMAT_TIME) {
425         gst_segment_set_newsegment_full(&decode->segment, update, rate, applied_rate,
426                                         format, start, stop, time);
427         GST_DEBUG("configured new segment, update %d, rate %lf, applied rate %lf, "
428                   "format GST_FORMAT_TIME, "
429                   "start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT ", "
430                   "time %" GST_TIME_FORMAT,
431                   update, rate, applied_rate,
432                   GST_TIME_ARGS(start), GST_TIME_ARGS(stop),
433                   GST_TIME_ARGS(time));
434     }
435 }
436
437 /* GstImplementsInterface interface */
438
439 static gboolean
440 gst_vaapidecode_implements_interface_supported(
441     GstImplementsInterface *iface,
442     GType                   type
443 )
444 {
445     return (type == GST_TYPE_VIDEO_CONTEXT);
446 }
447
448 static void
449 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface)
450 {
451     iface->supported = gst_vaapidecode_implements_interface_supported;
452 }
453
454 /* GstVideoContext interface */
455
456 static void
457 gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
458     const GValue *value)
459 {
460     GstVaapiDecode *decode = GST_VAAPIDECODE (context);
461     gst_vaapi_set_display (type, value, &decode->display);
462 }
463
464 static void
465 gst_video_context_interface_init(GstVideoContextInterface *iface)
466 {
467     iface->set_context = gst_vaapidecode_set_video_context;
468 }
469
470 static void
471 gst_vaapidecode_finalize(GObject *object)
472 {
473     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
474
475     gst_vaapidecode_destroy(decode);
476
477     if (decode->sinkpad_caps) {
478         gst_caps_unref(decode->sinkpad_caps);
479         decode->sinkpad_caps = NULL;
480     }
481
482     if (decode->srcpad_caps) {
483         gst_caps_unref(decode->srcpad_caps);
484         decode->srcpad_caps = NULL;
485     }
486
487     g_clear_object(&decode->display);
488
489     if (decode->allowed_caps) {
490         gst_caps_unref(decode->allowed_caps);
491         decode->allowed_caps = NULL;
492     }
493
494     if (decode->delayed_new_seg) {
495         gst_event_unref(decode->delayed_new_seg);
496         decode->delayed_new_seg = NULL;
497     }
498
499     G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
500 }
501
502 static GstStateChangeReturn
503 gst_vaapidecode_change_state(GstElement *element, GstStateChange transition)
504 {
505     GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
506     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
507
508     switch (transition) {
509     case GST_STATE_CHANGE_NULL_TO_READY:
510         decode->is_ready = TRUE;
511         break;
512     case GST_STATE_CHANGE_READY_TO_PAUSED:
513         break;
514     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
515         break;
516     default:
517         break;
518     }
519
520     ret = GST_ELEMENT_CLASS(gst_vaapidecode_parent_class)->change_state(element, transition);
521     if (ret != GST_STATE_CHANGE_SUCCESS)
522         return ret;
523
524     switch (transition) {
525     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
526         break;
527     case GST_STATE_CHANGE_PAUSED_TO_READY:
528         break;
529     case GST_STATE_CHANGE_READY_TO_NULL:
530         gst_vaapidecode_destroy(decode);
531         g_clear_object(&decode->display);
532         decode->is_ready = FALSE;
533         break;
534     default:
535         break;
536     }
537     return GST_STATE_CHANGE_SUCCESS;
538 }
539
540 static void
541 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
542 {
543     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
544     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
545     GstPadTemplate *pad_template;
546
547     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
548                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
549
550     object_class->finalize      = gst_vaapidecode_finalize;
551
552     element_class->change_state = gst_vaapidecode_change_state;
553
554     gst_element_class_set_details_simple(
555         element_class,
556         gst_vaapidecode_details.longname,
557         gst_vaapidecode_details.klass,
558         gst_vaapidecode_details.description,
559         gst_vaapidecode_details.author
560     );
561
562     /* sink pad */
563     pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
564     gst_element_class_add_pad_template(element_class, pad_template);
565     gst_object_unref(pad_template);
566
567     /* src pad */
568     pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
569     gst_element_class_add_pad_template(element_class, pad_template);
570     gst_object_unref(pad_template);
571 }
572
573 static gboolean
574 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
575 {
576     GstCaps *decode_caps;
577     guint i, n_decode_caps;
578
579     if (decode->allowed_caps)
580         return TRUE;
581
582     if (!gst_vaapidecode_ensure_display(decode))
583         goto error_no_display;
584
585     decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
586     if (!decode_caps)
587         goto error_no_decode_caps;
588     n_decode_caps = gst_caps_get_size(decode_caps);
589
590     decode->allowed_caps = gst_caps_new_empty();
591     if (!decode->allowed_caps)
592         goto error_no_memory;
593
594     for (i = 0; i < n_decode_caps; i++) {
595         GstStructure *structure;
596         structure = gst_caps_get_structure(decode_caps, i);
597         if (!structure)
598             continue;
599         structure = gst_structure_copy(structure);
600         if (!structure)
601             continue;
602         gst_structure_remove_field(structure, "profile");
603         gst_structure_set(
604             structure,
605             "width",  GST_TYPE_INT_RANGE, 1, G_MAXINT,
606             "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
607             NULL
608         );
609         gst_caps_merge_structure(decode->allowed_caps, structure);
610     }
611
612     gst_caps_unref(decode_caps);
613     return TRUE;
614
615     /* ERRORS */
616 error_no_display:
617     {
618         GST_DEBUG("failed to retrieve VA display");
619         return FALSE;
620     }
621 error_no_decode_caps:
622     {
623         GST_DEBUG("failed to retrieve VA decode caps");
624         return FALSE;
625     }
626 error_no_memory:
627     {
628         GST_DEBUG("failed to allocate allowed-caps set");
629         gst_caps_unref(decode_caps);
630         return FALSE;
631     }
632 }
633
634 static GstCaps *
635 gst_vaapidecode_get_caps(GstPad *pad)
636 {
637     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
638
639     if (!decode->is_ready)
640         return gst_static_pad_template_get_caps(&gst_vaapidecode_sink_factory);
641
642     if (!gst_vaapidecode_ensure_allowed_caps(decode))
643         return gst_caps_new_empty();
644
645     return gst_caps_ref(decode->allowed_caps);
646 }
647
648 static gboolean
649 gst_vaapidecode_set_caps(GstPad *pad, GstCaps *caps)
650 {
651     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
652
653     g_return_val_if_fail(pad == decode->sinkpad, FALSE);
654
655     if (!gst_vaapidecode_update_sink_caps(decode, caps))
656         return FALSE;
657     if (!gst_vaapidecode_update_src_caps(decode, caps))
658         return FALSE;
659     if (!gst_vaapidecode_reset(decode, decode->sinkpad_caps))
660         return FALSE;
661
662     /* Propagate NEWSEGMENT event downstream, now that pads are linked */
663     if (decode->delayed_new_seg) {
664         if (gst_pad_push_event(decode->srcpad, decode->delayed_new_seg))
665             gst_event_unref(decode->delayed_new_seg);
666         decode->delayed_new_seg = NULL;
667     }
668     return TRUE;
669 }
670
671 static GstFlowReturn
672 gst_vaapidecode_chain(GstPad *pad, GstBuffer *buf)
673 {
674     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
675
676     if (!gst_vaapi_decoder_put_buffer(decode->decoder, buf))
677         goto error_push_buffer;
678
679     gst_buffer_unref(buf);
680     return gst_vaapidecode_step(decode);
681
682     /* ERRORS */
683 error_push_buffer:
684     {
685         GST_DEBUG("failed to push input buffer to decoder");
686         gst_buffer_unref(buf);
687         return GST_FLOW_UNEXPECTED;
688     }
689 }
690
691 static gboolean
692 gst_vaapidecode_sink_event(GstPad *pad, GstEvent *event)
693 {
694     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
695
696     GST_DEBUG("handle sink event '%s'", GST_EVENT_TYPE_NAME(event));
697
698     /* Propagate event downstream */
699     switch (GST_EVENT_TYPE(event)) {
700     case GST_EVENT_FLUSH_STOP:
701         gst_segment_init(&decode->segment, GST_FORMAT_UNDEFINED);
702         if (decode->decoder)
703             gst_vaapi_decoder_clear_buffer(decode->decoder);
704         break;
705     case GST_EVENT_NEWSEGMENT:
706         if (decode->delayed_new_seg) {
707             gst_event_unref(decode->delayed_new_seg);
708             decode->delayed_new_seg = NULL;
709         }
710         if (!GST_PAD_PEER(decode->srcpad)) {
711             decode->delayed_new_seg = gst_event_ref(event);
712             return TRUE;
713         }
714         gst_vaapidecode_configure_segment(decode, event);
715         break;
716     default:
717         break;
718     }
719     return gst_pad_push_event(decode->srcpad, event);
720 }
721
722 static gboolean
723 gst_vaapidecode_src_event(GstPad *pad, GstEvent *event)
724 {
725     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
726
727     GST_DEBUG("handle src event '%s'", GST_EVENT_TYPE_NAME(event));
728
729     /* Propagate event upstream */
730     return gst_pad_push_event(decode->sinkpad, event);
731 }
732
733 static gboolean
734 gst_vaapidecode_query (GstPad *pad, GstQuery *query) {
735     GstVaapiDecode *decode = GST_VAAPIDECODE (gst_pad_get_parent_element (pad));
736     gboolean res;
737
738     GST_DEBUG ("sharing display %p", decode->display);
739
740     if (gst_vaapi_reply_to_query (query, decode->display))
741       res = TRUE;
742     else
743       res = gst_pad_query_default (pad, query);
744
745     g_object_unref (decode);
746     return res;
747 }
748
749 static void
750 gst_vaapidecode_init(GstVaapiDecode *decode)
751 {
752     GstVaapiDecodeClass *klass = GST_VAAPIDECODE_GET_CLASS(decode);
753     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
754
755     decode->display             = NULL;
756     decode->decoder             = NULL;
757     decode->decoder_mutex       = NULL;
758     decode->decoder_ready       = NULL;
759     decode->decoder_caps        = NULL;
760     decode->allowed_caps        = NULL;
761     decode->delayed_new_seg     = NULL;
762     decode->is_ready            = FALSE;
763     gst_segment_init(&decode->segment, GST_FORMAT_UNDEFINED);
764
765     /* Pad through which data comes in to the element */
766     decode->sinkpad = gst_pad_new_from_template(
767         gst_element_class_get_pad_template(element_class, "sink"),
768         "sink"
769     );
770     decode->sinkpad_caps = NULL;
771
772     gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
773     gst_pad_set_setcaps_function(decode->sinkpad, gst_vaapidecode_set_caps);
774     gst_pad_set_chain_function(decode->sinkpad, gst_vaapidecode_chain);
775     gst_pad_set_event_function(decode->sinkpad, gst_vaapidecode_sink_event);
776     gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
777     gst_element_add_pad(GST_ELEMENT(decode), decode->sinkpad);
778
779     /* Pad through which data goes out of the element */
780     decode->srcpad = gst_pad_new_from_template(
781         gst_element_class_get_pad_template(element_class, "src"),
782         "src"
783     );
784     decode->srcpad_caps = NULL;
785
786     gst_pad_use_fixed_caps(decode->srcpad);
787     gst_pad_set_event_function(decode->srcpad, gst_vaapidecode_src_event);
788     gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);
789     gst_element_add_pad(GST_ELEMENT(decode), decode->srcpad);
790 }