plugins: use g_clear_object() wherever applicable.
[vaapi: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/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 static void
108 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface);
109
110 static void
111 gst_video_context_interface_init(GstVideoContextInterface *iface);
112
113 #define GstVideoContextClass GstVideoContextInterface
114 G_DEFINE_TYPE_WITH_CODE(
115     GstVaapiDecode,
116     gst_vaapidecode,
117     GST_TYPE_ELEMENT,
118     G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
119                           gst_vaapidecode_implements_iface_init);
120     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
121                           gst_video_context_interface_init));
122
123 enum {
124     PROP_0,
125
126     PROP_USE_FFMPEG,
127 };
128
129 static gboolean
130 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, GstCaps *caps);
131
132 static void
133 gst_vaapi_decoder_notify_caps(GObject *obj, GParamSpec *pspec, void *user_data)
134 {
135     GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
136     GstCaps *caps;
137
138     g_assert(decode->decoder == GST_VAAPI_DECODER(obj));
139
140     caps = gst_vaapi_decoder_get_caps(decode->decoder);
141     gst_vaapidecode_update_src_caps(decode, caps);
142 }
143
144 static inline gboolean
145 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
146 {
147     if (decode->sinkpad_caps)
148         gst_caps_unref(decode->sinkpad_caps);
149     decode->sinkpad_caps = gst_caps_ref(caps);
150     return TRUE;
151 }
152
153 static gboolean
154 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, GstCaps *caps)
155 {
156     GstCaps *other_caps;
157     GstStructure *structure;
158     const GValue *v_width, *v_height, *v_framerate, *v_par, *v_interlaced;
159     gboolean success;
160
161     if (!decode->srcpad_caps) {
162         decode->srcpad_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
163         if (!decode->srcpad_caps)
164             return FALSE;
165     }
166
167     structure    = gst_caps_get_structure(caps, 0);
168     v_width      = gst_structure_get_value(structure, "width");
169     v_height     = gst_structure_get_value(structure, "height");
170     v_framerate  = gst_structure_get_value(structure, "framerate");
171     v_par        = gst_structure_get_value(structure, "pixel-aspect-ratio");
172     v_interlaced = gst_structure_get_value(structure, "interlaced");
173
174     structure = gst_caps_get_structure(decode->srcpad_caps, 0);
175     if (v_width && v_height) {
176         gst_structure_set_value(structure, "width", v_width);
177         gst_structure_set_value(structure, "height", v_height);
178     }
179     if (v_framerate)
180         gst_structure_set_value(structure, "framerate", v_framerate);
181     if (v_par)
182         gst_structure_set_value(structure, "pixel-aspect-ratio", v_par);
183     if (v_interlaced)
184         gst_structure_set_value(structure, "interlaced", v_interlaced);
185
186     gst_structure_set(structure, "type", G_TYPE_STRING, "vaapi", NULL);
187     gst_structure_set(structure, "opengl", G_TYPE_BOOLEAN, USE_VAAPI_GLX, NULL);
188
189     other_caps = gst_caps_copy(decode->srcpad_caps);
190     success = gst_pad_set_caps(decode->srcpad, other_caps);
191     gst_caps_unref(other_caps);
192     return success;
193 }
194
195 static void
196 gst_vaapidecode_release(GstVaapiDecode *decode, GObject *dead_object)
197 {
198     g_mutex_lock(decode->decoder_mutex);
199     g_cond_signal(decode->decoder_ready);
200     g_mutex_unlock(decode->decoder_mutex);
201 }
202
203 static GstFlowReturn
204 gst_vaapidecode_step(GstVaapiDecode *decode)
205 {
206     GstVaapiSurfaceProxy *proxy;
207     GstVaapiDecoderStatus status;
208     GstBuffer *buffer;
209     GstFlowReturn ret;
210     guint tries;
211
212     for (;;) {
213         tries = 0;
214     again:
215         proxy = gst_vaapi_decoder_get_surface(decode->decoder, &status);
216         if (!proxy) {
217             if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
218                 /* Wait for a VA surface to be displayed and free'd */
219                 if (++tries > 100)
220                     goto error_decode_timeout;
221                 GTimeVal timeout;
222                 g_get_current_time(&timeout);
223                 g_time_val_add(&timeout, 10000); /* 10 ms each step */
224                 g_mutex_lock(decode->decoder_mutex);
225                 g_cond_timed_wait(
226                     decode->decoder_ready,
227                     decode->decoder_mutex,
228                     &timeout
229                 );
230                 g_mutex_unlock(decode->decoder_mutex);
231                 goto again;
232             }
233             if (status != GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA)
234                 goto error_decode;
235             /* More data is needed */
236             break;
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) = GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy);
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 gboolean
310 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
311 {
312     GstVaapiDisplay *dpy;
313     GstStructure *structure;
314     int version;
315
316     if (!gst_vaapi_ensure_display(decode, &decode->display))
317         return FALSE;
318
319     decode->decoder_mutex = g_mutex_new();
320     if (!decode->decoder_mutex)
321         return FALSE;
322
323     decode->decoder_ready = g_cond_new();
324     if (!decode->decoder_ready)
325         return FALSE;
326
327     dpy = decode->display;
328     if (decode->use_ffmpeg) {
329 #if USE_FFMPEG
330         decode->decoder = gst_vaapi_decoder_ffmpeg_new(dpy, caps);
331 #endif
332     }
333     else {
334 #if USE_CODEC_PARSERS
335         structure = gst_caps_get_structure(caps, 0);
336         if (!structure)
337             return FALSE;
338         if (gst_structure_has_name(structure, "video/x-h264"))
339             decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
340         else if (gst_structure_has_name(structure, "video/mpeg")) {
341             if (!gst_structure_get_int(structure, "mpegversion", &version))
342                 return FALSE;
343             if (version == 2)
344                 decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
345             else if (version == 4)
346                 decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
347         }
348         else if (gst_structure_has_name(structure, "video/x-wmv"))
349             decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
350         else if (gst_structure_has_name(structure, "video/x-h263") ||
351                  gst_structure_has_name(structure, "video/x-divx") ||
352                  gst_structure_has_name(structure, "video/x-xvid"))
353             decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
354 #if USE_JPEG_DECODER
355         else if (gst_structure_has_name(structure, "image/jpeg"))
356             decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
357 #endif
358 #endif
359     }
360     if (!decode->decoder)
361         return FALSE;
362
363     g_signal_connect(
364         G_OBJECT(decode->decoder),
365         "notify::caps",
366         G_CALLBACK(gst_vaapi_decoder_notify_caps),
367         decode
368     );
369
370     decode->decoder_caps = gst_caps_ref(caps);
371     return TRUE;
372 }
373
374 static void
375 gst_vaapidecode_destroy(GstVaapiDecode *decode)
376 {
377     if (decode->decoder) {
378         gst_vaapi_decoder_put_buffer(decode->decoder, NULL);
379         g_object_unref(decode->decoder);
380         decode->decoder = NULL;
381     }
382
383     if (decode->decoder_caps) {
384         gst_caps_unref(decode->decoder_caps);
385         decode->decoder_caps = NULL;
386     }
387
388     if (decode->decoder_ready) {
389         gst_vaapidecode_release(decode, NULL);
390         g_cond_free(decode->decoder_ready);
391         decode->decoder_ready = NULL;
392     }
393
394     if (decode->decoder_mutex) {
395         g_mutex_free(decode->decoder_mutex);
396         decode->decoder_mutex = NULL;
397     }
398 }
399
400 static gboolean
401 gst_vaapidecode_reset(GstVaapiDecode *decode, GstCaps *caps)
402 {
403     if (decode->decoder &&
404         decode->decoder_caps &&
405         gst_caps_is_always_compatible(caps, decode->decoder_caps))
406         return TRUE;
407
408     gst_vaapidecode_destroy(decode);
409     return gst_vaapidecode_create(decode, caps);
410 }
411
412 /* GstImplementsInterface interface */
413
414 static gboolean
415 gst_vaapidecode_implements_interface_supported(
416     GstImplementsInterface *iface,
417     GType                   type
418 )
419 {
420     return (type == GST_TYPE_VIDEO_CONTEXT);
421 }
422
423 static void
424 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface)
425 {
426     iface->supported = gst_vaapidecode_implements_interface_supported;
427 }
428
429 /* GstVideoContext interface */
430
431 static void
432 gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
433     const GValue *value)
434 {
435     GstVaapiDecode *decode = GST_VAAPIDECODE (context);
436     gst_vaapi_set_display (type, value, &decode->display);
437 }
438
439 static void
440 gst_video_context_interface_init(GstVideoContextInterface *iface)
441 {
442     iface->set_context = gst_vaapidecode_set_video_context;
443 }
444
445 static void
446 gst_vaapidecode_finalize(GObject *object)
447 {
448     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
449
450     gst_vaapidecode_destroy(decode);
451
452     if (decode->sinkpad_caps) {
453         gst_caps_unref(decode->sinkpad_caps);
454         decode->sinkpad_caps = NULL;
455     }
456
457     if (decode->srcpad_caps) {
458         gst_caps_unref(decode->srcpad_caps);
459         decode->srcpad_caps = NULL;
460     }
461
462     g_clear_object(&decode->display);
463
464     if (decode->allowed_caps) {
465         gst_caps_unref(decode->allowed_caps);
466         decode->allowed_caps = NULL;
467     }
468
469     if (decode->delayed_new_seg) {
470         gst_event_unref(decode->delayed_new_seg);
471         decode->delayed_new_seg = NULL;
472     }
473
474     G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
475 }
476
477 static void
478 gst_vaapidecode_set_property(
479     GObject      *object,
480     guint         prop_id,
481     const GValue *value,
482     GParamSpec   *pspec
483 )
484 {
485     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
486
487     switch (prop_id) {
488     case PROP_USE_FFMPEG:
489         decode->use_ffmpeg = g_value_get_boolean(value);
490         break;
491     default:
492         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
493         break;
494     }
495 }
496
497 static void
498 gst_vaapidecode_get_property(
499     GObject    *object,
500     guint       prop_id,
501     GValue     *value,
502     GParamSpec *pspec
503 )
504 {
505     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
506
507     switch (prop_id) {
508     case PROP_USE_FFMPEG:
509         g_value_set_boolean(value, decode->use_ffmpeg);
510         break;
511     default:
512         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
513         break;
514     }
515 }
516
517 static GstStateChangeReturn
518 gst_vaapidecode_change_state(GstElement *element, GstStateChange transition)
519 {
520     GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
521     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
522
523     switch (transition) {
524     case GST_STATE_CHANGE_NULL_TO_READY:
525         decode->is_ready = TRUE;
526         break;
527     case GST_STATE_CHANGE_READY_TO_PAUSED:
528         break;
529     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
530         break;
531     default:
532         break;
533     }
534
535     ret = GST_ELEMENT_CLASS(gst_vaapidecode_parent_class)->change_state(element, transition);
536     if (ret != GST_STATE_CHANGE_SUCCESS)
537         return ret;
538
539     switch (transition) {
540     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
541         break;
542     case GST_STATE_CHANGE_PAUSED_TO_READY:
543         break;
544     case GST_STATE_CHANGE_READY_TO_NULL:
545         gst_vaapidecode_destroy(decode);
546         g_clear_object(&decode->display);
547         decode->is_ready = FALSE;
548         break;
549     default:
550         break;
551     }
552     return GST_STATE_CHANGE_SUCCESS;
553 }
554
555 static void
556 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
557 {
558     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
559     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
560     GstPadTemplate *pad_template;
561
562     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
563                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
564
565     object_class->finalize      = gst_vaapidecode_finalize;
566     object_class->set_property  = gst_vaapidecode_set_property;
567     object_class->get_property  = gst_vaapidecode_get_property;
568
569     element_class->change_state = gst_vaapidecode_change_state;
570
571     gst_element_class_set_details_simple(
572         element_class,
573         gst_vaapidecode_details.longname,
574         gst_vaapidecode_details.klass,
575         gst_vaapidecode_details.description,
576         gst_vaapidecode_details.author
577     );
578
579     /* sink pad */
580     pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
581     gst_element_class_add_pad_template(element_class, pad_template);
582     gst_object_unref(pad_template);
583
584     /* src pad */
585     pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
586     gst_element_class_add_pad_template(element_class, pad_template);
587     gst_object_unref(pad_template);
588
589 #if USE_FFMPEG
590     g_object_class_install_property
591         (object_class,
592          PROP_USE_FFMPEG,
593          g_param_spec_boolean("use-ffmpeg",
594                               "Use FFmpeg/VAAPI for decoding",
595                               "Uses FFmpeg/VAAPI for decoding",
596                               USE_FFMPEG_DEFAULT,
597                               G_PARAM_READWRITE));
598 #endif
599 }
600
601 static gboolean
602 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
603 {
604     GstCaps *decode_caps;
605     guint i, n_decode_caps;
606
607     if (decode->allowed_caps)
608         return TRUE;
609
610     if (!gst_vaapi_ensure_display(decode, &decode->display))
611         goto error_no_display;
612
613     decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
614     if (!decode_caps)
615         goto error_no_decode_caps;
616     n_decode_caps = gst_caps_get_size(decode_caps);
617
618     decode->allowed_caps = gst_caps_new_empty();
619     if (!decode->allowed_caps)
620         goto error_no_memory;
621
622     for (i = 0; i < n_decode_caps; i++) {
623         GstStructure *structure;
624         structure = gst_caps_get_structure(decode_caps, i);
625         if (!structure)
626             continue;
627         structure = gst_structure_copy(structure);
628         if (!structure)
629             continue;
630         gst_structure_remove_field(structure, "profile");
631         gst_structure_set(
632             structure,
633             "width",  GST_TYPE_INT_RANGE, 1, G_MAXINT,
634             "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
635             NULL
636         );
637         gst_caps_merge_structure(decode->allowed_caps, structure);
638     }
639
640     gst_caps_unref(decode_caps);
641     return TRUE;
642
643     /* ERRORS */
644 error_no_display:
645     {
646         GST_DEBUG("failed to retrieve VA display");
647         return FALSE;
648     }
649 error_no_decode_caps:
650     {
651         GST_DEBUG("failed to retrieve VA decode caps");
652         return FALSE;
653     }
654 error_no_memory:
655     {
656         GST_DEBUG("failed to allocate allowed-caps set");
657         gst_caps_unref(decode_caps);
658         return FALSE;
659     }
660 }
661
662 static GstCaps *
663 gst_vaapidecode_get_caps(GstPad *pad)
664 {
665     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
666
667     if (!decode->is_ready)
668         return gst_static_pad_template_get_caps(&gst_vaapidecode_sink_factory);
669
670     if (!gst_vaapidecode_ensure_allowed_caps(decode))
671         return gst_caps_new_empty();
672
673     return gst_caps_ref(decode->allowed_caps);
674 }
675
676 static gboolean
677 gst_vaapidecode_set_caps(GstPad *pad, GstCaps *caps)
678 {
679     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
680
681     g_return_val_if_fail(pad == decode->sinkpad, FALSE);
682
683     if (!gst_vaapidecode_update_sink_caps(decode, caps))
684         return FALSE;
685     if (!gst_vaapidecode_update_src_caps(decode, caps))
686         return FALSE;
687     if (!gst_vaapidecode_reset(decode, decode->sinkpad_caps))
688         return FALSE;
689
690     /* Propagate NEWSEGMENT event downstream, now that pads are linked */
691     if (decode->delayed_new_seg) {
692         if (gst_pad_push_event(decode->srcpad, decode->delayed_new_seg))
693             gst_event_unref(decode->delayed_new_seg);
694         decode->delayed_new_seg = NULL;
695     }
696     return TRUE;
697 }
698
699 static GstFlowReturn
700 gst_vaapidecode_chain(GstPad *pad, GstBuffer *buf)
701 {
702     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
703
704     if (!gst_vaapi_decoder_put_buffer(decode->decoder, buf))
705         goto error_push_buffer;
706
707     gst_buffer_unref(buf);
708     return gst_vaapidecode_step(decode);
709
710     /* ERRORS */
711 error_push_buffer:
712     {
713         GST_DEBUG("failed to push input buffer to decoder");
714         gst_buffer_unref(buf);
715         return GST_FLOW_UNEXPECTED;
716     }
717 }
718
719 static gboolean
720 gst_vaapidecode_sink_event(GstPad *pad, GstEvent *event)
721 {
722     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
723
724     GST_DEBUG("handle sink event '%s'", GST_EVENT_TYPE_NAME(event));
725
726     /* Propagate event downstream */
727     switch (GST_EVENT_TYPE(event)) {
728     case GST_EVENT_NEWSEGMENT:
729         if (decode->delayed_new_seg) {
730             gst_event_unref(decode->delayed_new_seg);
731             decode->delayed_new_seg = NULL;
732         }
733         if (!GST_PAD_PEER(decode->srcpad)) {
734             decode->delayed_new_seg = gst_event_ref(event);
735             return TRUE;
736         }
737         break;
738     default:
739         break;
740     }
741     return gst_pad_push_event(decode->srcpad, event);
742 }
743
744 static gboolean
745 gst_vaapidecode_src_event(GstPad *pad, GstEvent *event)
746 {
747     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
748
749     GST_DEBUG("handle src event '%s'", GST_EVENT_TYPE_NAME(event));
750
751     /* Propagate event upstream */
752     return gst_pad_push_event(decode->sinkpad, event);
753 }
754
755 static gboolean
756 gst_vaapidecode_query (GstPad *pad, GstQuery *query) {
757     GstVaapiDecode *decode = GST_VAAPIDECODE (gst_pad_get_parent_element (pad));
758     gboolean res;
759
760     GST_DEBUG ("sharing display %p", decode->display);
761
762     if (gst_vaapi_reply_to_query (query, decode->display))
763       res = TRUE;
764     else
765       res = gst_pad_query_default (pad, query);
766
767     g_object_unref (decode);
768     return res;
769 }
770
771 static void
772 gst_vaapidecode_init(GstVaapiDecode *decode)
773 {
774     GstVaapiDecodeClass *klass = GST_VAAPIDECODE_GET_CLASS(decode);
775     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
776
777     decode->display             = NULL;
778     decode->decoder             = NULL;
779     decode->decoder_mutex       = NULL;
780     decode->decoder_ready       = NULL;
781     decode->decoder_caps        = NULL;
782     decode->allowed_caps        = NULL;
783     decode->delayed_new_seg     = NULL;
784     decode->use_ffmpeg          = USE_FFMPEG_DEFAULT;
785     decode->is_ready            = FALSE;
786
787     /* Pad through which data comes in to the element */
788     decode->sinkpad = gst_pad_new_from_template(
789         gst_element_class_get_pad_template(element_class, "sink"),
790         "sink"
791     );
792     decode->sinkpad_caps = NULL;
793
794     gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
795     gst_pad_set_setcaps_function(decode->sinkpad, gst_vaapidecode_set_caps);
796     gst_pad_set_chain_function(decode->sinkpad, gst_vaapidecode_chain);
797     gst_pad_set_event_function(decode->sinkpad, gst_vaapidecode_sink_event);
798     gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
799     gst_element_add_pad(GST_ELEMENT(decode), decode->sinkpad);
800
801     /* Pad through which data goes out of the element */
802     decode->srcpad = gst_pad_new_from_template(
803         gst_element_class_get_pad_template(element_class, "src"),
804         "src"
805     );
806     decode->srcpad_caps = NULL;
807
808     gst_pad_use_fixed_caps(decode->srcpad);
809     gst_pad_set_event_function(decode->srcpad, gst_vaapidecode_src_event);
810     gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);
811     gst_element_add_pad(GST_ELEMENT(decode), decode->srcpad);
812 }