plugins: cope with new GstVaapiMiniObject objects.
[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-2013 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/video/videocontext.h>
34
35 #include "gstvaapidecode.h"
36 #include "gstvaapipluginutil.h"
37 #include "gstvaapivideobuffer.h"
38 #if GST_CHECK_VERSION(1,0,0)
39 #include "gstvaapivideobufferpool.h"
40 #include "gstvaapivideomemory.h"
41 #endif
42
43 #include <gst/vaapi/gstvaapidecoder_h264.h>
44 #include <gst/vaapi/gstvaapidecoder_jpeg.h>
45 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
46 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
47 #include <gst/vaapi/gstvaapidecoder_vc1.h>
48
49 #define GST_PLUGIN_NAME "vaapidecode"
50 #define GST_PLUGIN_DESC "A VA-API based video decoder"
51
52 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode);
53 #define GST_CAT_DEFAULT gst_debug_vaapidecode
54
55 /* Default templates */
56 #define GST_CAPS_CODEC(CODEC) CODEC "; "
57
58 static const char gst_vaapidecode_sink_caps_str[] =
59     GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
60     GST_CAPS_CODEC("video/mpeg, mpegversion=4")
61     GST_CAPS_CODEC("video/x-divx")
62     GST_CAPS_CODEC("video/x-xvid")
63     GST_CAPS_CODEC("video/x-h263")
64     GST_CAPS_CODEC("video/x-h264")
65     GST_CAPS_CODEC("video/x-wmv")
66     GST_CAPS_CODEC("image/jpeg")
67     ;
68
69 static const char gst_vaapidecode_src_caps_str[] =
70     GST_VAAPI_SURFACE_CAPS;
71
72 static GstStaticPadTemplate gst_vaapidecode_sink_factory =
73     GST_STATIC_PAD_TEMPLATE(
74         "sink",
75         GST_PAD_SINK,
76         GST_PAD_ALWAYS,
77         GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));
78
79 static GstStaticPadTemplate gst_vaapidecode_src_factory =
80     GST_STATIC_PAD_TEMPLATE(
81         "src",
82         GST_PAD_SRC,
83         GST_PAD_ALWAYS,
84         GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
85
86 /* GstImplementsInterface interface */
87 #if !GST_CHECK_VERSION(1,0,0)
88 static gboolean
89 gst_vaapidecode_implements_interface_supported(
90     GstImplementsInterface *iface,
91     GType                   type
92 )
93 {
94     return (type == GST_TYPE_VIDEO_CONTEXT);
95 }
96
97 static void
98 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface)
99 {
100     iface->supported = gst_vaapidecode_implements_interface_supported;
101 }
102 #endif
103
104 /* GstVideoContext interface */
105 static void
106 gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
107     const GValue *value)
108 {
109     GstVaapiDecode *decode = GST_VAAPIDECODE (context);
110     gst_vaapi_set_display (type, value, &decode->display);
111 }
112
113 static void
114 gst_video_context_interface_init(GstVideoContextInterface *iface)
115 {
116     iface->set_context = gst_vaapidecode_set_video_context;
117 }
118
119 #define GstVideoContextClass GstVideoContextInterface
120 G_DEFINE_TYPE_WITH_CODE(
121     GstVaapiDecode,
122     gst_vaapidecode,
123     GST_TYPE_VIDEO_DECODER,
124 #if !GST_CHECK_VERSION(1,0,0)
125     G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
126                           gst_vaapidecode_implements_iface_init);
127 #endif
128     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
129                           gst_video_context_interface_init))
130
131 static gboolean
132 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
133     const GstVideoCodecState *ref_state);
134
135 static void
136 gst_vaapi_decoder_state_changed(GstVaapiDecoder *decoder,
137     const GstVideoCodecState *codec_state, gpointer user_data)
138 {
139     GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
140
141     g_assert(decode->decoder == decoder);
142
143     gst_vaapidecode_update_src_caps(decode, codec_state);
144 }
145
146 static inline gboolean
147 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
148 {
149     gst_caps_replace(&decode->sinkpad_caps, caps);
150     return TRUE;
151 }
152
153 static gboolean
154 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
155     const GstVideoCodecState *ref_state)
156 {
157     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
158     GstVideoCodecState *state;
159     GstVideoInfo *vi, vis;
160
161     state = gst_video_decoder_set_output_state(vdec,
162         GST_VIDEO_INFO_FORMAT(&ref_state->info),
163         ref_state->info.width, ref_state->info.height,
164         (GstVideoCodecState *)ref_state);
165     if (!state)
166         return FALSE;
167
168     vi = &state->info;
169     if (GST_VIDEO_INFO_FORMAT(vi) == GST_VIDEO_FORMAT_ENCODED) {
170         gst_video_info_init(&vis);
171         gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12,
172             GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
173         vi->size = vis.size;
174     }
175     gst_video_codec_state_unref(state);
176
177     /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
178        reconstruct suitable caps for "encoded" video formats */
179     state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
180     if (!state->caps)
181         return FALSE;
182
183     gst_caps_set_simple(state->caps,
184         "type", G_TYPE_STRING, "vaapi",
185         "opengl", G_TYPE_BOOLEAN, USE_GLX,
186         "width", G_TYPE_INT, vi->width,
187         "height", G_TYPE_INT, vi->height,
188         "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
189         "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d,
190         NULL);
191
192     if (GST_VIDEO_INFO_IS_INTERLACED(vi)) {
193         GstStructure * const structure =
194             gst_caps_get_structure(state->caps, 0);
195         gst_structure_set_interlaced(structure, TRUE);
196     }
197     gst_caps_replace(&decode->srcpad_caps, state->caps);
198     return TRUE;
199 }
200
201 static void
202 gst_vaapidecode_release(GstVaapiDecode *decode)
203 {
204     g_mutex_lock(&decode->decoder_mutex);
205     g_cond_signal(&decode->decoder_ready);
206     g_mutex_unlock(&decode->decoder_mutex);
207 }
208
209 static GstFlowReturn
210 gst_vaapidecode_decode_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
211 {
212     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
213     GstVaapiDecoderStatus status;
214     GstFlowReturn ret;
215     gint64 end_time;
216
217     if (decode->render_time_base)
218         end_time = decode->render_time_base;
219     else
220         end_time = g_get_monotonic_time();
221     end_time += GST_TIME_AS_USECONDS(decode->last_buffer_time);
222     end_time += G_TIME_SPAN_SECOND;
223
224     /* Decode current frame */
225     for (;;) {
226         status = gst_vaapi_decoder_decode(decode->decoder, frame);
227         if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
228             gboolean was_signalled;
229             GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
230             g_mutex_lock(&decode->decoder_mutex);
231             was_signalled = g_cond_wait_until(
232                 &decode->decoder_ready,
233                 &decode->decoder_mutex,
234                 end_time
235             );
236             g_mutex_unlock(&decode->decoder_mutex);
237             GST_VIDEO_DECODER_STREAM_LOCK(vdec);
238             if (was_signalled)
239                 continue;
240             goto error_decode_timeout;
241         }
242         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
243             goto error_decode;
244         break;
245     }
246     return GST_FLOW_OK;
247
248     /* ERRORS */
249 error_decode_timeout:
250     {
251         GST_WARNING("decode timeout. Decoder required a VA surface but none "
252                     "got available within one second");
253         return GST_FLOW_EOS;
254     }
255 error_decode:
256     {
257         GST_ERROR("decode error %d", status);
258         switch (status) {
259         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
260         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
261         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
262             ret = GST_FLOW_NOT_SUPPORTED;
263             break;
264         default:
265             ret = GST_FLOW_EOS;
266             break;
267         }
268         gst_video_decoder_drop_frame(vdec, frame);
269         return ret;
270     }
271 }
272
273 static GstFlowReturn
274 gst_vaapidecode_push_decoded_frame(GstVideoDecoder *vdec)
275 {
276     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
277     GstVaapiSurfaceProxy *proxy;
278     GstVaapiDecoderStatus status;
279     GstVaapiVideoMeta *meta;
280     GstVideoCodecFrame *out_frame;
281     GstFlowReturn ret;
282     guint flags;
283
284     status = gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
285         &out_frame, 100000);
286     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
287         return GST_VIDEO_DECODER_FLOW_NEED_DATA;
288
289     if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
290         proxy = gst_video_codec_frame_get_user_data(out_frame);
291
292         gst_vaapi_surface_proxy_set_destroy_notify(proxy,
293             (GDestroyNotify)gst_vaapidecode_release, decode);
294
295 #if GST_CHECK_VERSION(1,0,0)
296         ret = gst_video_decoder_allocate_output_frame(vdec, out_frame);
297         if (ret != GST_FLOW_OK)
298             goto error_create_buffer;
299
300         meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer);
301         if (!meta)
302             goto error_get_meta;
303         gst_vaapi_video_meta_set_surface_proxy(meta, proxy);
304
305         flags = gst_vaapi_surface_proxy_get_flags(proxy);
306         if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
307             guint out_flags = GST_VIDEO_BUFFER_FLAG_INTERLACED;
308             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
309                 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
310             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
311                 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
312             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
313                 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
314             GST_BUFFER_FLAG_SET(out_frame->output_buffer, out_flags);
315         }
316 #else
317         out_frame->output_buffer =
318             gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
319         if (!out_frame->output_buffer)
320             goto error_create_buffer;
321 #endif
322     }
323
324     ret = gst_video_decoder_finish_frame(vdec, out_frame);
325     if (ret != GST_FLOW_OK)
326         goto error_commit_buffer;
327
328     /* Estimate when this frame would no longer be needed for rendering */
329     if (GST_CLOCK_TIME_IS_VALID(out_frame->pts)) {
330         if (!decode->render_time_base)
331             decode->render_time_base = g_get_monotonic_time() -
332                 GST_TIME_AS_USECONDS(out_frame->pts);
333         decode->last_buffer_time = out_frame->pts;
334         if (GST_CLOCK_TIME_IS_VALID(out_frame->duration))
335             decode->last_buffer_time += out_frame->duration;
336         else
337             decode->last_buffer_time += GST_SECOND;
338     }
339     else {
340         decode->render_time_base = 0;
341         decode->last_buffer_time = 0;
342     }
343
344     gst_video_codec_frame_unref(out_frame);
345     return GST_FLOW_OK;
346
347     /* ERRORS */
348 error_create_buffer:
349     {
350         const GstVaapiID surface_id =
351             gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
352
353         GST_ERROR("video sink failed to create video buffer for proxy'ed "
354                   "surface %" GST_VAAPI_ID_FORMAT,
355                   GST_VAAPI_ID_ARGS(surface_id));
356         gst_video_decoder_drop_frame(vdec, out_frame);
357         gst_video_codec_frame_unref(out_frame);
358         return GST_FLOW_EOS;
359     }
360 #if GST_CHECK_VERSION(1,0,0)
361 error_get_meta:
362     {
363         GST_ERROR("failed to get vaapi video meta attached to video buffer");
364         gst_video_decoder_drop_frame(vdec, out_frame);
365         gst_video_codec_frame_unref(out_frame);
366         return GST_FLOW_EOS;
367     }
368 #endif
369 error_commit_buffer:
370     {
371         if (ret != GST_FLOW_FLUSHING)
372             GST_ERROR("video sink rejected the video buffer (error %d)", ret);
373         gst_video_codec_frame_unref(out_frame);
374         return GST_FLOW_EOS;
375     }
376 }
377
378 static GstFlowReturn
379 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
380 {
381     GstFlowReturn ret;
382
383     /* Make sure to release the base class stream lock so that decode
384        loop can call gst_video_decoder_finish_frame() without blocking */
385     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
386     ret = gst_vaapidecode_decode_frame(vdec, frame);
387     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
388     return ret;
389 }
390
391 static void
392 gst_vaapidecode_decode_loop(GstVaapiDecode *decode)
393 {
394     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
395     GstFlowReturn ret;
396
397     ret = gst_vaapidecode_push_decoded_frame(vdec);
398     if (ret == GST_FLOW_OK || ret == GST_VIDEO_DECODER_FLOW_NEED_DATA)
399         return;
400
401     /* ERRORS */
402     gst_pad_pause_task(decode->srcpad);
403 }
404
405 static GstFlowReturn
406 gst_vaapidecode_finish(GstVideoDecoder *vdec)
407 {
408     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
409     GstVaapiDecoderStatus status;
410
411     status = gst_vaapi_decoder_flush(decode->decoder);
412     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
413         goto error_flush;
414
415     /* Make sure the decode loop function has a chance to return, thus
416        possibly unlocking gst_video_decoder_finish_frame() */
417     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
418     gst_pad_stop_task(decode->srcpad);
419     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
420
421     /* Submit all frames that got decoded so far */
422     while (gst_vaapidecode_push_decoded_frame(vdec) == GST_FLOW_OK)
423         ;
424     return GST_FLOW_OK;
425
426     /* ERRORS */
427 error_flush:
428     {
429         GST_ERROR("failed to flush decoder (status %d)", status);
430         return GST_FLOW_EOS;
431     }
432 }
433
434 #if GST_CHECK_VERSION(1,0,0)
435 static gboolean
436 gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
437 {
438     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
439     GstCaps *caps = NULL;
440     GstBufferPool *pool;
441     GstStructure *config;
442     GstVideoInfo vi;
443     guint size, min, max;
444     gboolean need_pool, update_pool;
445
446     gst_query_parse_allocation(query, &caps, &need_pool);
447
448     if (!caps)
449         goto error_no_caps;
450
451     gst_video_info_init(&vi);
452     gst_video_info_from_caps(&vi, caps);
453     if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED)
454         gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
455             GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
456
457     g_return_val_if_fail(decode->display != NULL, FALSE);
458
459     if (gst_query_get_n_allocation_pools(query) > 0) {
460         gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
461         size = MAX(size, vi.size);
462         update_pool = TRUE;
463     }
464     else {
465         pool = NULL;
466         size = vi.size;
467         min = max = 0;
468         update_pool = FALSE;
469     }
470
471     if (!pool || !gst_buffer_pool_has_option(pool,
472             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
473         GST_INFO("no pool or doesn't support GstVaapiVideoMeta, "
474             "making new pool");
475         pool = gst_vaapi_video_buffer_pool_new(decode->display);
476         if (!pool)
477             goto error_create_pool;
478
479         config = gst_buffer_pool_get_config(pool);
480         gst_buffer_pool_config_set_params(config, caps, size, min, max);
481         gst_buffer_pool_config_add_option(config,
482             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
483         gst_buffer_pool_set_config(pool, config);
484     }
485
486     if (update_pool)
487         gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
488     else
489         gst_query_add_allocation_pool(query, pool, size, min, max);
490     if (pool)
491         gst_object_unref(pool);
492     return TRUE;
493
494     /* ERRORS */
495 error_no_caps:
496     {
497         GST_ERROR("no caps specified");
498         return FALSE;
499     }
500 error_create_pool:
501     {
502         GST_ERROR("failed to create buffer pool");
503         return FALSE;
504     }
505 }
506 #endif
507
508 static inline gboolean
509 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
510 {
511     return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY,
512         &decode->display);
513 }
514
515 static inline guint
516 gst_vaapi_codec_from_caps(GstCaps *caps)
517 {
518     return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
519 }
520
521 static gboolean
522 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
523 {
524     GstVaapiDisplay *dpy;
525
526     if (!gst_vaapidecode_ensure_display(decode))
527         return FALSE;
528     dpy = decode->display;
529
530     switch (gst_vaapi_codec_from_caps(caps)) {
531     case GST_VAAPI_CODEC_MPEG2:
532         decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
533         break;
534     case GST_VAAPI_CODEC_MPEG4:
535     case GST_VAAPI_CODEC_H263:
536         decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
537         break;
538     case GST_VAAPI_CODEC_H264:
539         decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
540         break;
541     case GST_VAAPI_CODEC_WMV3:
542     case GST_VAAPI_CODEC_VC1:
543         decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
544         break;
545 #if USE_JPEG_DECODER
546     case GST_VAAPI_CODEC_JPEG:
547         decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
548         break;
549 #endif
550     default:
551         decode->decoder = NULL;
552         break;
553     }
554     if (!decode->decoder)
555         return FALSE;
556
557     gst_vaapi_decoder_set_codec_state_changed_func(decode->decoder,
558         gst_vaapi_decoder_state_changed, decode);
559
560     decode->decoder_caps = gst_caps_ref(caps);
561     return gst_pad_start_task(decode->srcpad,
562         (GstTaskFunction)gst_vaapidecode_decode_loop, decode, NULL);
563 }
564
565 static void
566 gst_vaapidecode_destroy(GstVaapiDecode *decode)
567 {
568     gst_pad_stop_task(decode->srcpad);
569     gst_vaapi_decoder_replace(&decode->decoder, NULL);
570     gst_caps_replace(&decode->decoder_caps, NULL);
571     gst_vaapidecode_release(decode);
572 }
573
574 static gboolean
575 gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
576 {
577     GstVaapiCodec codec;
578
579     /* Reset timers if hard reset was requested (e.g. seek) */
580     if (hard) {
581         decode->render_time_base = 0;
582         decode->last_buffer_time = 0;
583     }
584
585     /* Only reset decoder if codec type changed */
586     else if (decode->decoder && decode->decoder_caps) {
587         if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
588             return TRUE;
589         codec = gst_vaapi_codec_from_caps(caps);
590         if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
591             return TRUE;
592     }
593
594     gst_vaapidecode_destroy(decode);
595     return gst_vaapidecode_create(decode, caps);
596 }
597
598 static void
599 gst_vaapidecode_finalize(GObject *object)
600 {
601     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
602
603     gst_caps_replace(&decode->sinkpad_caps, NULL);
604     gst_caps_replace(&decode->srcpad_caps,  NULL);
605     gst_caps_replace(&decode->allowed_caps, NULL);
606
607     gst_vaapi_display_replace(&decode->display, NULL);
608
609     g_cond_clear(&decode->decoder_ready);
610     g_mutex_clear(&decode->decoder_mutex);
611
612     G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
613 }
614
615 static gboolean
616 gst_vaapidecode_open(GstVideoDecoder *vdec)
617 {
618     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
619     GstVaapiDisplay * const old_display = decode->display;
620     gboolean success;
621
622     /* Let GstVideoContext ask for a proper display to its neighbours */
623     /* Note: steal old display that may be allocated from get_caps()
624        so that to retain a reference to it, thus avoiding extra
625        initialization steps if we turn out to simply re-use the
626        existing (cached) VA display */
627     decode->display = NULL;
628     success = gst_vaapidecode_ensure_display(decode);
629     if (old_display)
630         gst_vaapi_display_unref(old_display);
631     return success;
632 }
633
634 static gboolean
635 gst_vaapidecode_close(GstVideoDecoder *vdec)
636 {
637     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
638
639     gst_vaapidecode_destroy(decode);
640     gst_vaapi_display_replace(&decode->display, NULL);
641     return TRUE;
642 }
643
644 static gboolean
645 gst_vaapidecode_reset(GstVideoDecoder *vdec, gboolean hard)
646 {
647     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
648
649     return gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, hard);
650 }
651
652 static gboolean
653 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
654 {
655     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
656
657     if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
658         return FALSE;
659     if (!gst_vaapidecode_update_src_caps(decode, state))
660         return FALSE;
661     if (!gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, FALSE))
662         return FALSE;
663     return TRUE;
664 }
665
666 static GstFlowReturn
667 gst_vaapidecode_parse(GstVideoDecoder *vdec,
668     GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
669 {
670     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
671     GstVaapiDecoderStatus status;
672     GstFlowReturn ret;
673     guint got_unit_size;
674     gboolean got_frame;
675
676     status = gst_vaapi_decoder_parse(decode->decoder, frame,
677         adapter, at_eos, &got_unit_size, &got_frame);
678
679     switch (status) {
680     case GST_VAAPI_DECODER_STATUS_SUCCESS:
681         if (got_unit_size > 0)
682             gst_video_decoder_add_to_frame(vdec, got_unit_size);
683         if (got_frame)
684             ret = gst_video_decoder_have_frame(vdec);
685         else
686             ret = GST_FLOW_OK;
687         break;
688     case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
689         ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
690         break;
691     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
692     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
693     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
694         GST_WARNING("parse error %d", status);
695         ret = GST_FLOW_NOT_SUPPORTED;
696         break;
697     default:
698         GST_ERROR("parse error %d", status);
699         ret = GST_FLOW_EOS;
700         break;
701     }
702     return ret;
703 }
704
705 static void
706 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
707 {
708     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
709     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
710     GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
711     GstPadTemplate *pad_template;
712
713     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
714                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
715
716     object_class->finalize   = gst_vaapidecode_finalize;
717
718     vdec_class->open         = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
719     vdec_class->close        = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
720     vdec_class->set_format   = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
721     vdec_class->reset        = GST_DEBUG_FUNCPTR(gst_vaapidecode_reset);
722     vdec_class->parse        = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
723     vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
724     vdec_class->finish       = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish);
725
726 #if GST_CHECK_VERSION(1,0,0)
727     vdec_class->decide_allocation =
728         GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
729 #endif
730
731     gst_element_class_set_static_metadata(element_class,
732         "VA-API decoder",
733         "Codec/Decoder/Video",
734         GST_PLUGIN_DESC,
735         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
736
737     /* sink pad */
738     pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
739     gst_element_class_add_pad_template(element_class, pad_template);
740
741     /* src pad */
742     pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
743     gst_element_class_add_pad_template(element_class, pad_template);
744 }
745
746 static gboolean
747 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
748 {
749     GstCaps *decode_caps;
750     guint i, n_decode_caps;
751
752     if (decode->allowed_caps)
753         return TRUE;
754
755     if (!gst_vaapidecode_ensure_display(decode))
756         goto error_no_display;
757
758     decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
759     if (!decode_caps)
760         goto error_no_decode_caps;
761     n_decode_caps = gst_caps_get_size(decode_caps);
762
763     decode->allowed_caps = gst_caps_new_empty();
764     if (!decode->allowed_caps)
765         goto error_no_memory;
766
767     for (i = 0; i < n_decode_caps; i++) {
768         GstStructure *structure;
769         structure = gst_caps_get_structure(decode_caps, i);
770         if (!structure)
771             continue;
772         structure = gst_structure_copy(structure);
773         if (!structure)
774             continue;
775         gst_structure_remove_field(structure, "profile");
776         gst_structure_set(
777             structure,
778             "width",  GST_TYPE_INT_RANGE, 1, G_MAXINT,
779             "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
780             NULL
781         );
782         decode->allowed_caps =
783             gst_caps_merge_structure(decode->allowed_caps, structure);
784     }
785
786     gst_caps_unref(decode_caps);
787     return TRUE;
788
789     /* ERRORS */
790 error_no_display:
791     {
792         GST_ERROR("failed to retrieve VA display");
793         return FALSE;
794     }
795 error_no_decode_caps:
796     {
797         GST_ERROR("failed to retrieve VA decode caps");
798         return FALSE;
799     }
800 error_no_memory:
801     {
802         GST_ERROR("failed to allocate allowed-caps set");
803         gst_caps_unref(decode_caps);
804         return FALSE;
805     }
806 }
807
808 static GstCaps *
809 gst_vaapidecode_get_caps(GstPad *pad)
810 {
811     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
812
813     if (!gst_vaapidecode_ensure_allowed_caps(decode))
814         return gst_caps_new_empty();
815
816     return gst_caps_ref(decode->allowed_caps);
817 }
818
819 static gboolean
820 gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
821 {
822     GstVaapiDecode * const decode =
823         GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
824     gboolean res;
825
826     GST_DEBUG("sharing display %p", decode->display);
827
828     if (gst_vaapi_reply_to_query(query, decode->display))
829         res = TRUE;
830     else if (GST_PAD_IS_SINK(pad)) {
831         switch (GST_QUERY_TYPE(query)) {
832 #if GST_CHECK_VERSION(1,0,0)
833         case GST_QUERY_CAPS: {
834             GstCaps * const caps = gst_vaapidecode_get_caps(pad);
835             gst_query_set_caps_result(query, caps);
836             gst_caps_unref(caps);
837             res = TRUE;
838             break;
839         }
840 #endif
841         default:
842             res = GST_PAD_QUERY_FUNCTION_CALL(decode->sinkpad_query,
843                 decode->sinkpad, parent, query);
844             break;
845         }
846     }
847     else
848         res = GST_PAD_QUERY_FUNCTION_CALL(decode->srcpad_query,
849             decode->srcpad, parent, query);
850
851     gst_object_unref(decode);
852     return res;
853 }
854
855 static void
856 gst_vaapidecode_init(GstVaapiDecode *decode)
857 {
858     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
859
860     decode->display             = NULL;
861     decode->decoder             = NULL;
862     decode->decoder_caps        = NULL;
863     decode->allowed_caps        = NULL;
864     decode->render_time_base    = 0;
865     decode->last_buffer_time    = 0;
866
867     g_mutex_init(&decode->decoder_mutex);
868     g_cond_init(&decode->decoder_ready);
869
870     gst_video_decoder_set_packetized(vdec, FALSE);
871
872     /* Pad through which data comes in to the element */
873     decode->sinkpad = GST_VIDEO_DECODER_SINK_PAD(vdec);
874     decode->sinkpad_query = GST_PAD_QUERYFUNC(decode->sinkpad);
875     gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
876 #if !GST_CHECK_VERSION(1,0,0)
877     gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
878 #endif
879
880     /* Pad through which data goes out of the element */
881     decode->srcpad = GST_VIDEO_DECODER_SRC_PAD(vdec);
882     decode->srcpad_query = GST_PAD_QUERYFUNC(decode->srcpad);
883     gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);
884 }