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