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