vaapidecode: improve "no free surface" conditions.
[platform/upstream/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     if (!decode->decoder_mutex || !decode->decoder_ready)
178         return;
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 GstFlowReturn
186 gst_vaapidecode_step(GstVaapiDecode *decode)
187 {
188     GstVaapiSurfaceProxy *proxy;
189     GstVaapiDecoderStatus status;
190     GstBuffer *buffer;
191     GstFlowReturn ret;
192     GstClockTime timestamp;
193     gint64 end_time;
194
195     for (;;) {
196         end_time = decode->render_time_base;
197         if (!end_time)
198             end_time = g_get_monotonic_time();
199         end_time += GST_TIME_AS_USECONDS(decode->last_buffer_time);
200         end_time += G_TIME_SPAN_SECOND;
201
202         proxy = gst_vaapi_decoder_get_surface(decode->decoder, &status);
203         if (!proxy) {
204             if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
205                 gboolean was_signalled;
206                 g_mutex_lock(decode->decoder_mutex);
207                 was_signalled = g_cond_wait_until(
208                     decode->decoder_ready,
209                     decode->decoder_mutex,
210                     end_time
211                 );
212                 g_mutex_unlock(decode->decoder_mutex);
213                 if (was_signalled)
214                     continue;
215                 goto error_decode_timeout;
216             }
217             if (status != GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA)
218                 goto error_decode;
219             /* More data is needed */
220             break;
221         }
222
223         g_object_weak_ref(
224             G_OBJECT(proxy),
225             (GWeakNotify)gst_vaapidecode_release,
226             decode
227         );
228
229         buffer = gst_vaapi_video_buffer_new(decode->display);
230         if (!buffer)
231             goto error_create_buffer;
232
233         timestamp = GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy);
234         if (!decode->render_time_base)
235             decode->render_time_base = g_get_monotonic_time();
236         decode->last_buffer_time = timestamp;
237
238         GST_BUFFER_TIMESTAMP(buffer) = timestamp;
239         GST_BUFFER_DURATION(buffer) = GST_VAAPI_SURFACE_PROXY_DURATION(proxy);
240         gst_buffer_set_caps(buffer, GST_PAD_CAPS(decode->srcpad));
241
242         if (GST_VAAPI_SURFACE_PROXY_TFF(proxy))
243             GST_BUFFER_FLAG_SET(buffer, GST_VIDEO_BUFFER_TFF);
244
245         gst_vaapi_video_buffer_set_surface_proxy(
246             GST_VAAPI_VIDEO_BUFFER(buffer),
247             proxy
248         );
249
250         ret = gst_pad_push(decode->srcpad, buffer);
251         if (ret != GST_FLOW_OK)
252             goto error_commit_buffer;
253
254         g_object_unref(proxy);
255     }
256     return GST_FLOW_OK;
257
258     /* ERRORS */
259 error_decode_timeout:
260     {
261         GST_DEBUG("decode timeout. Decoder required a VA surface but none "
262                   "got available within one second");
263         return GST_FLOW_UNEXPECTED;
264     }
265 error_decode:
266     {
267         GST_DEBUG("decode error %d", status);
268         switch (status) {
269         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
270         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
271         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
272             ret = GST_FLOW_NOT_SUPPORTED;
273             break;
274         default:
275             ret = GST_FLOW_UNEXPECTED;
276             break;
277         }
278         return ret;
279     }
280 error_create_buffer:
281     {
282         const GstVaapiID surface_id =
283             gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
284
285         GST_DEBUG("video sink failed to create video buffer for proxy'ed "
286                   "surface %" GST_VAAPI_ID_FORMAT " (error %d)",
287                   GST_VAAPI_ID_ARGS(surface_id), ret);
288         g_object_unref(proxy);
289         return GST_FLOW_UNEXPECTED;
290     }
291 error_commit_buffer:
292     {
293         GST_DEBUG("video sink rejected the video buffer (error %d)", ret);
294         g_object_unref(proxy);
295         return GST_FLOW_UNEXPECTED;
296     }
297 }
298
299 static inline gboolean
300 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
301 {
302     return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY,
303         &decode->display);
304 }
305
306 static gboolean
307 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
308 {
309     GstVaapiDisplay *dpy;
310     GstStructure *structure;
311     int version;
312
313     if (!gst_vaapidecode_ensure_display(decode))
314         return FALSE;
315     dpy = decode->display;
316
317     decode->decoder_mutex = g_mutex_new();
318     if (!decode->decoder_mutex)
319         return FALSE;
320
321     decode->decoder_ready = g_cond_new();
322     if (!decode->decoder_ready)
323         return FALSE;
324
325     structure = gst_caps_get_structure(caps, 0);
326     if (!structure)
327         return FALSE;
328
329     if (gst_structure_has_name(structure, "video/x-h264"))
330         decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
331     else if (gst_structure_has_name(structure, "video/mpeg")) {
332         if (!gst_structure_get_int(structure, "mpegversion", &version))
333             return FALSE;
334         if (version == 2)
335             decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
336         else if (version == 4)
337             decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
338     }
339     else if (gst_structure_has_name(structure, "video/x-wmv"))
340         decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
341     else if (gst_structure_has_name(structure, "video/x-h263") ||
342              gst_structure_has_name(structure, "video/x-divx") ||
343              gst_structure_has_name(structure, "video/x-xvid"))
344         decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
345 #if USE_JPEG_DECODER
346     else if (gst_structure_has_name(structure, "image/jpeg"))
347         decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
348 #endif
349     if (!decode->decoder)
350         return FALSE;
351
352     g_signal_connect(
353         G_OBJECT(decode->decoder),
354         "notify::caps",
355         G_CALLBACK(gst_vaapi_decoder_notify_caps),
356         decode
357     );
358
359     decode->decoder_caps = gst_caps_ref(caps);
360     return TRUE;
361 }
362
363 static void
364 gst_vaapidecode_destroy(GstVaapiDecode *decode)
365 {
366     if (decode->decoder) {
367         gst_vaapi_decoder_put_buffer(decode->decoder, NULL);
368         g_object_unref(decode->decoder);
369         decode->decoder = NULL;
370     }
371
372     if (decode->decoder_caps) {
373         gst_caps_unref(decode->decoder_caps);
374         decode->decoder_caps = NULL;
375     }
376
377     if (decode->decoder_ready) {
378         gst_vaapidecode_release(decode, NULL);
379         g_cond_free(decode->decoder_ready);
380         decode->decoder_ready = NULL;
381     }
382
383     if (decode->decoder_mutex) {
384         g_mutex_free(decode->decoder_mutex);
385         decode->decoder_mutex = NULL;
386     }
387 }
388
389 static gboolean
390 gst_vaapidecode_reset(GstVaapiDecode *decode, GstCaps *caps)
391 {
392     if (decode->decoder &&
393         decode->decoder_caps &&
394         gst_caps_is_always_compatible(caps, decode->decoder_caps))
395         return TRUE;
396
397     gst_vaapidecode_destroy(decode);
398     return gst_vaapidecode_create(decode, caps);
399 }
400
401 /* GstImplementsInterface interface */
402
403 static gboolean
404 gst_vaapidecode_implements_interface_supported(
405     GstImplementsInterface *iface,
406     GType                   type
407 )
408 {
409     return (type == GST_TYPE_VIDEO_CONTEXT);
410 }
411
412 static void
413 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface)
414 {
415     iface->supported = gst_vaapidecode_implements_interface_supported;
416 }
417
418 /* GstVideoContext interface */
419
420 static void
421 gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
422     const GValue *value)
423 {
424     GstVaapiDecode *decode = GST_VAAPIDECODE (context);
425     gst_vaapi_set_display (type, value, &decode->display);
426 }
427
428 static void
429 gst_video_context_interface_init(GstVideoContextInterface *iface)
430 {
431     iface->set_context = gst_vaapidecode_set_video_context;
432 }
433
434 static void
435 gst_vaapidecode_finalize(GObject *object)
436 {
437     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
438
439     gst_vaapidecode_destroy(decode);
440
441     if (decode->sinkpad_caps) {
442         gst_caps_unref(decode->sinkpad_caps);
443         decode->sinkpad_caps = NULL;
444     }
445
446     if (decode->srcpad_caps) {
447         gst_caps_unref(decode->srcpad_caps);
448         decode->srcpad_caps = NULL;
449     }
450
451     g_clear_object(&decode->display);
452
453     if (decode->allowed_caps) {
454         gst_caps_unref(decode->allowed_caps);
455         decode->allowed_caps = NULL;
456     }
457
458     if (decode->delayed_new_seg) {
459         gst_event_unref(decode->delayed_new_seg);
460         decode->delayed_new_seg = NULL;
461     }
462
463     G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
464 }
465
466 static GstStateChangeReturn
467 gst_vaapidecode_change_state(GstElement *element, GstStateChange transition)
468 {
469     GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
470     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
471
472     switch (transition) {
473     case GST_STATE_CHANGE_NULL_TO_READY:
474         decode->is_ready = TRUE;
475         break;
476     case GST_STATE_CHANGE_READY_TO_PAUSED:
477         break;
478     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
479         break;
480     default:
481         break;
482     }
483
484     ret = GST_ELEMENT_CLASS(gst_vaapidecode_parent_class)->change_state(element, transition);
485     if (ret != GST_STATE_CHANGE_SUCCESS)
486         return ret;
487
488     switch (transition) {
489     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
490         break;
491     case GST_STATE_CHANGE_PAUSED_TO_READY:
492         break;
493     case GST_STATE_CHANGE_READY_TO_NULL:
494         gst_vaapidecode_destroy(decode);
495         g_clear_object(&decode->display);
496         decode->is_ready = FALSE;
497         break;
498     default:
499         break;
500     }
501     return GST_STATE_CHANGE_SUCCESS;
502 }
503
504 static void
505 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
506 {
507     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
508     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
509     GstPadTemplate *pad_template;
510
511     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
512                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
513
514     object_class->finalize      = gst_vaapidecode_finalize;
515
516     element_class->change_state = gst_vaapidecode_change_state;
517
518     gst_element_class_set_details_simple(
519         element_class,
520         gst_vaapidecode_details.longname,
521         gst_vaapidecode_details.klass,
522         gst_vaapidecode_details.description,
523         gst_vaapidecode_details.author
524     );
525
526     /* sink pad */
527     pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
528     gst_element_class_add_pad_template(element_class, pad_template);
529     gst_object_unref(pad_template);
530
531     /* src pad */
532     pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
533     gst_element_class_add_pad_template(element_class, pad_template);
534     gst_object_unref(pad_template);
535 }
536
537 static gboolean
538 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
539 {
540     GstCaps *decode_caps;
541     guint i, n_decode_caps;
542
543     if (decode->allowed_caps)
544         return TRUE;
545
546     if (!gst_vaapidecode_ensure_display(decode))
547         goto error_no_display;
548
549     decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
550     if (!decode_caps)
551         goto error_no_decode_caps;
552     n_decode_caps = gst_caps_get_size(decode_caps);
553
554     decode->allowed_caps = gst_caps_new_empty();
555     if (!decode->allowed_caps)
556         goto error_no_memory;
557
558     for (i = 0; i < n_decode_caps; i++) {
559         GstStructure *structure;
560         structure = gst_caps_get_structure(decode_caps, i);
561         if (!structure)
562             continue;
563         structure = gst_structure_copy(structure);
564         if (!structure)
565             continue;
566         gst_structure_remove_field(structure, "profile");
567         gst_structure_set(
568             structure,
569             "width",  GST_TYPE_INT_RANGE, 1, G_MAXINT,
570             "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
571             NULL
572         );
573         gst_caps_merge_structure(decode->allowed_caps, structure);
574     }
575
576     gst_caps_unref(decode_caps);
577     return TRUE;
578
579     /* ERRORS */
580 error_no_display:
581     {
582         GST_DEBUG("failed to retrieve VA display");
583         return FALSE;
584     }
585 error_no_decode_caps:
586     {
587         GST_DEBUG("failed to retrieve VA decode caps");
588         return FALSE;
589     }
590 error_no_memory:
591     {
592         GST_DEBUG("failed to allocate allowed-caps set");
593         gst_caps_unref(decode_caps);
594         return FALSE;
595     }
596 }
597
598 static GstCaps *
599 gst_vaapidecode_get_caps(GstPad *pad)
600 {
601     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
602
603     if (!decode->is_ready)
604         return gst_static_pad_template_get_caps(&gst_vaapidecode_sink_factory);
605
606     if (!gst_vaapidecode_ensure_allowed_caps(decode))
607         return gst_caps_new_empty();
608
609     return gst_caps_ref(decode->allowed_caps);
610 }
611
612 static gboolean
613 gst_vaapidecode_set_caps(GstPad *pad, GstCaps *caps)
614 {
615     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
616
617     g_return_val_if_fail(pad == decode->sinkpad, FALSE);
618
619     if (!gst_vaapidecode_update_sink_caps(decode, caps))
620         return FALSE;
621     if (!gst_vaapidecode_update_src_caps(decode, caps))
622         return FALSE;
623     if (!gst_vaapidecode_reset(decode, decode->sinkpad_caps))
624         return FALSE;
625
626     /* Propagate NEWSEGMENT event downstream, now that pads are linked */
627     if (decode->delayed_new_seg) {
628         if (gst_pad_push_event(decode->srcpad, decode->delayed_new_seg))
629             gst_event_unref(decode->delayed_new_seg);
630         decode->delayed_new_seg = NULL;
631     }
632     return TRUE;
633 }
634
635 static GstFlowReturn
636 gst_vaapidecode_chain(GstPad *pad, GstBuffer *buf)
637 {
638     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
639
640     if (!gst_vaapi_decoder_put_buffer(decode->decoder, buf))
641         goto error_push_buffer;
642
643     gst_buffer_unref(buf);
644     return gst_vaapidecode_step(decode);
645
646     /* ERRORS */
647 error_push_buffer:
648     {
649         GST_DEBUG("failed to push input buffer to decoder");
650         gst_buffer_unref(buf);
651         return GST_FLOW_UNEXPECTED;
652     }
653 }
654
655 static gboolean
656 gst_vaapidecode_sink_event(GstPad *pad, GstEvent *event)
657 {
658     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
659
660     GST_DEBUG("handle sink event '%s'", GST_EVENT_TYPE_NAME(event));
661
662     /* Propagate event downstream */
663     switch (GST_EVENT_TYPE(event)) {
664     case GST_EVENT_NEWSEGMENT:
665         if (decode->delayed_new_seg) {
666             gst_event_unref(decode->delayed_new_seg);
667             decode->delayed_new_seg = NULL;
668         }
669         if (!GST_PAD_PEER(decode->srcpad)) {
670             decode->delayed_new_seg = gst_event_ref(event);
671             return TRUE;
672         }
673         break;
674     default:
675         break;
676     }
677     return gst_pad_push_event(decode->srcpad, event);
678 }
679
680 static gboolean
681 gst_vaapidecode_src_event(GstPad *pad, GstEvent *event)
682 {
683     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
684
685     GST_DEBUG("handle src event '%s'", GST_EVENT_TYPE_NAME(event));
686
687     /* Propagate event upstream */
688     return gst_pad_push_event(decode->sinkpad, event);
689 }
690
691 static gboolean
692 gst_vaapidecode_query (GstPad *pad, GstQuery *query) {
693     GstVaapiDecode *decode = GST_VAAPIDECODE (gst_pad_get_parent_element (pad));
694     gboolean res;
695
696     GST_DEBUG ("sharing display %p", decode->display);
697
698     if (gst_vaapi_reply_to_query (query, decode->display))
699       res = TRUE;
700     else
701       res = gst_pad_query_default (pad, query);
702
703     g_object_unref (decode);
704     return res;
705 }
706
707 static void
708 gst_vaapidecode_init(GstVaapiDecode *decode)
709 {
710     GstVaapiDecodeClass *klass = GST_VAAPIDECODE_GET_CLASS(decode);
711     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
712
713     decode->display             = NULL;
714     decode->decoder             = NULL;
715     decode->decoder_mutex       = NULL;
716     decode->decoder_ready       = NULL;
717     decode->decoder_caps        = NULL;
718     decode->allowed_caps        = NULL;
719     decode->delayed_new_seg     = NULL;
720     decode->render_time_base    = 0;
721     decode->last_buffer_time    = 0;
722     decode->is_ready            = FALSE;
723
724     /* Pad through which data comes in to the element */
725     decode->sinkpad = gst_pad_new_from_template(
726         gst_element_class_get_pad_template(element_class, "sink"),
727         "sink"
728     );
729     decode->sinkpad_caps = NULL;
730
731     gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
732     gst_pad_set_setcaps_function(decode->sinkpad, gst_vaapidecode_set_caps);
733     gst_pad_set_chain_function(decode->sinkpad, gst_vaapidecode_chain);
734     gst_pad_set_event_function(decode->sinkpad, gst_vaapidecode_sink_event);
735     gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
736     gst_element_add_pad(GST_ELEMENT(decode), decode->sinkpad);
737
738     /* Pad through which data goes out of the element */
739     decode->srcpad = gst_pad_new_from_template(
740         gst_element_class_get_pad_template(element_class, "src"),
741         "src"
742     );
743     decode->srcpad_caps = NULL;
744
745     gst_pad_use_fixed_caps(decode->srcpad);
746     gst_pad_set_event_function(decode->srcpad, gst_vaapidecode_src_event);
747     gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);
748     gst_element_add_pad(GST_ELEMENT(decode), decode->srcpad);
749 }