plugins: add support for video cropping.
[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     GstVideoCodecFrame *out_frame;
280     GstFlowReturn ret;
281 #if GST_CHECK_VERSION(1,0,0)
282     const GstVaapiRectangle *crop_rect;
283     GstVaapiVideoMeta *meta;
284     guint flags;
285 #endif
286
287     status = gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
288         &out_frame, 100000);
289     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
290         return GST_VIDEO_DECODER_FLOW_NEED_DATA;
291
292     if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
293         proxy = gst_video_codec_frame_get_user_data(out_frame);
294
295         gst_vaapi_surface_proxy_set_destroy_notify(proxy,
296             (GDestroyNotify)gst_vaapidecode_release, decode);
297
298 #if GST_CHECK_VERSION(1,0,0)
299         ret = gst_video_decoder_allocate_output_frame(vdec, out_frame);
300         if (ret != GST_FLOW_OK)
301             goto error_create_buffer;
302
303         meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer);
304         if (!meta)
305             goto error_get_meta;
306         gst_vaapi_video_meta_set_surface_proxy(meta, proxy);
307
308         flags = gst_vaapi_surface_proxy_get_flags(proxy);
309         if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
310             guint out_flags = GST_VIDEO_BUFFER_FLAG_INTERLACED;
311             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
312                 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
313             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
314                 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
315             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
316                 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
317             GST_BUFFER_FLAG_SET(out_frame->output_buffer, out_flags);
318         }
319
320         crop_rect = gst_vaapi_surface_proxy_get_crop_rect(proxy);
321         if (crop_rect) {
322             GstVideoCropMeta * const crop_meta =
323                 gst_buffer_add_video_crop_meta(out_frame->output_buffer);
324             if (crop_meta) {
325                 crop_meta->x = crop_rect->x;
326                 crop_meta->y = crop_rect->y;
327                 crop_meta->width = crop_rect->width;
328                 crop_meta->height = crop_rect->height;
329             }
330         }
331 #else
332         out_frame->output_buffer =
333             gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
334         if (!out_frame->output_buffer)
335             goto error_create_buffer;
336 #endif
337     }
338
339     ret = gst_video_decoder_finish_frame(vdec, out_frame);
340     if (ret != GST_FLOW_OK)
341         goto error_commit_buffer;
342
343     /* Estimate when this frame would no longer be needed for rendering */
344     if (GST_CLOCK_TIME_IS_VALID(out_frame->pts)) {
345         if (!decode->render_time_base)
346             decode->render_time_base = g_get_monotonic_time() -
347                 GST_TIME_AS_USECONDS(out_frame->pts);
348         decode->last_buffer_time = out_frame->pts;
349         if (GST_CLOCK_TIME_IS_VALID(out_frame->duration))
350             decode->last_buffer_time += out_frame->duration;
351         else
352             decode->last_buffer_time += GST_SECOND;
353     }
354     else {
355         decode->render_time_base = 0;
356         decode->last_buffer_time = 0;
357     }
358
359     gst_video_codec_frame_unref(out_frame);
360     return GST_FLOW_OK;
361
362     /* ERRORS */
363 error_create_buffer:
364     {
365         const GstVaapiID surface_id =
366             gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
367
368         GST_ERROR("video sink failed to create video buffer for proxy'ed "
369                   "surface %" GST_VAAPI_ID_FORMAT,
370                   GST_VAAPI_ID_ARGS(surface_id));
371         gst_video_decoder_drop_frame(vdec, out_frame);
372         gst_video_codec_frame_unref(out_frame);
373         return GST_FLOW_EOS;
374     }
375 #if GST_CHECK_VERSION(1,0,0)
376 error_get_meta:
377     {
378         GST_ERROR("failed to get vaapi video meta attached to video buffer");
379         gst_video_decoder_drop_frame(vdec, out_frame);
380         gst_video_codec_frame_unref(out_frame);
381         return GST_FLOW_EOS;
382     }
383 #endif
384 error_commit_buffer:
385     {
386         if (ret != GST_FLOW_FLUSHING)
387             GST_ERROR("video sink rejected the video buffer (error %d)", ret);
388         gst_video_codec_frame_unref(out_frame);
389         return GST_FLOW_EOS;
390     }
391 }
392
393 static GstFlowReturn
394 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
395 {
396     GstFlowReturn ret;
397
398     /* Make sure to release the base class stream lock so that decode
399        loop can call gst_video_decoder_finish_frame() without blocking */
400     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
401     ret = gst_vaapidecode_decode_frame(vdec, frame);
402     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
403     return ret;
404 }
405
406 static void
407 gst_vaapidecode_decode_loop(GstVaapiDecode *decode)
408 {
409     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
410     GstFlowReturn ret;
411
412     ret = gst_vaapidecode_push_decoded_frame(vdec);
413     if (ret == GST_FLOW_OK || ret == GST_VIDEO_DECODER_FLOW_NEED_DATA)
414         return;
415
416     /* ERRORS */
417     gst_pad_pause_task(decode->srcpad);
418 }
419
420 static GstFlowReturn
421 gst_vaapidecode_finish(GstVideoDecoder *vdec)
422 {
423     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
424     GstVaapiDecoderStatus status;
425
426     status = gst_vaapi_decoder_flush(decode->decoder);
427     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
428         goto error_flush;
429
430     /* Make sure the decode loop function has a chance to return, thus
431        possibly unlocking gst_video_decoder_finish_frame() */
432     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
433     gst_pad_stop_task(decode->srcpad);
434     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
435
436     /* Submit all frames that got decoded so far */
437     while (gst_vaapidecode_push_decoded_frame(vdec) == GST_FLOW_OK)
438         ;
439     return GST_FLOW_OK;
440
441     /* ERRORS */
442 error_flush:
443     {
444         GST_ERROR("failed to flush decoder (status %d)", status);
445         return GST_FLOW_EOS;
446     }
447 }
448
449 #if GST_CHECK_VERSION(1,0,0)
450 static gboolean
451 gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
452 {
453     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
454     GstCaps *caps = NULL;
455     GstBufferPool *pool;
456     GstStructure *config;
457     GstVideoInfo vi;
458     guint size, min, max;
459     gboolean need_pool, update_pool;
460
461     gst_query_parse_allocation(query, &caps, &need_pool);
462
463     if (!caps)
464         goto error_no_caps;
465
466     gst_video_info_init(&vi);
467     gst_video_info_from_caps(&vi, caps);
468     if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED)
469         gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
470             GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
471
472     g_return_val_if_fail(decode->display != NULL, FALSE);
473
474     if (gst_query_get_n_allocation_pools(query) > 0) {
475         gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
476         size = MAX(size, vi.size);
477         update_pool = TRUE;
478     }
479     else {
480         pool = NULL;
481         size = vi.size;
482         min = max = 0;
483         update_pool = FALSE;
484     }
485
486     if (!pool || !gst_buffer_pool_has_option(pool,
487             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
488         GST_INFO("no pool or doesn't support GstVaapiVideoMeta, "
489             "making new pool");
490         pool = gst_vaapi_video_buffer_pool_new(decode->display);
491         if (!pool)
492             goto error_create_pool;
493
494         config = gst_buffer_pool_get_config(pool);
495         gst_buffer_pool_config_set_params(config, caps, size, min, max);
496         gst_buffer_pool_config_add_option(config,
497             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
498         gst_buffer_pool_set_config(pool, config);
499     }
500
501     if (update_pool)
502         gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
503     else
504         gst_query_add_allocation_pool(query, pool, size, min, max);
505     if (pool)
506         gst_object_unref(pool);
507     return TRUE;
508
509     /* ERRORS */
510 error_no_caps:
511     {
512         GST_ERROR("no caps specified");
513         return FALSE;
514     }
515 error_create_pool:
516     {
517         GST_ERROR("failed to create buffer pool");
518         return FALSE;
519     }
520 }
521 #endif
522
523 static inline gboolean
524 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
525 {
526     return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY,
527         &decode->display);
528 }
529
530 static inline guint
531 gst_vaapi_codec_from_caps(GstCaps *caps)
532 {
533     return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
534 }
535
536 static gboolean
537 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
538 {
539     GstVaapiDisplay *dpy;
540
541     if (!gst_vaapidecode_ensure_display(decode))
542         return FALSE;
543     dpy = decode->display;
544
545     switch (gst_vaapi_codec_from_caps(caps)) {
546     case GST_VAAPI_CODEC_MPEG2:
547         decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
548         break;
549     case GST_VAAPI_CODEC_MPEG4:
550     case GST_VAAPI_CODEC_H263:
551         decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
552         break;
553     case GST_VAAPI_CODEC_H264:
554         decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
555         break;
556     case GST_VAAPI_CODEC_WMV3:
557     case GST_VAAPI_CODEC_VC1:
558         decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
559         break;
560 #if USE_JPEG_DECODER
561     case GST_VAAPI_CODEC_JPEG:
562         decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
563         break;
564 #endif
565     default:
566         decode->decoder = NULL;
567         break;
568     }
569     if (!decode->decoder)
570         return FALSE;
571
572     gst_vaapi_decoder_set_codec_state_changed_func(decode->decoder,
573         gst_vaapi_decoder_state_changed, decode);
574
575     decode->decoder_caps = gst_caps_ref(caps);
576     return gst_pad_start_task(decode->srcpad,
577         (GstTaskFunction)gst_vaapidecode_decode_loop, decode, NULL);
578 }
579
580 static void
581 gst_vaapidecode_destroy(GstVaapiDecode *decode)
582 {
583     gst_pad_stop_task(decode->srcpad);
584     gst_vaapi_decoder_replace(&decode->decoder, NULL);
585     gst_caps_replace(&decode->decoder_caps, NULL);
586     gst_vaapidecode_release(decode);
587 }
588
589 static gboolean
590 gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
591 {
592     GstVaapiCodec codec;
593
594     /* Reset timers if hard reset was requested (e.g. seek) */
595     if (hard) {
596         decode->render_time_base = 0;
597         decode->last_buffer_time = 0;
598     }
599
600     /* Only reset decoder if codec type changed */
601     else if (decode->decoder && decode->decoder_caps) {
602         if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
603             return TRUE;
604         codec = gst_vaapi_codec_from_caps(caps);
605         if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
606             return TRUE;
607     }
608
609     gst_vaapidecode_destroy(decode);
610     return gst_vaapidecode_create(decode, caps);
611 }
612
613 static void
614 gst_vaapidecode_finalize(GObject *object)
615 {
616     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
617
618     gst_caps_replace(&decode->sinkpad_caps, NULL);
619     gst_caps_replace(&decode->srcpad_caps,  NULL);
620     gst_caps_replace(&decode->allowed_caps, NULL);
621
622     gst_vaapi_display_replace(&decode->display, NULL);
623
624     g_cond_clear(&decode->decoder_ready);
625     g_mutex_clear(&decode->decoder_mutex);
626
627     G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
628 }
629
630 static gboolean
631 gst_vaapidecode_open(GstVideoDecoder *vdec)
632 {
633     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
634     GstVaapiDisplay * const old_display = decode->display;
635     gboolean success;
636
637     /* Let GstVideoContext ask for a proper display to its neighbours */
638     /* Note: steal old display that may be allocated from get_caps()
639        so that to retain a reference to it, thus avoiding extra
640        initialization steps if we turn out to simply re-use the
641        existing (cached) VA display */
642     decode->display = NULL;
643     success = gst_vaapidecode_ensure_display(decode);
644     if (old_display)
645         gst_vaapi_display_unref(old_display);
646     return success;
647 }
648
649 static gboolean
650 gst_vaapidecode_close(GstVideoDecoder *vdec)
651 {
652     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
653
654     gst_vaapidecode_destroy(decode);
655     gst_vaapi_display_replace(&decode->display, NULL);
656     return TRUE;
657 }
658
659 static gboolean
660 gst_vaapidecode_reset(GstVideoDecoder *vdec, gboolean hard)
661 {
662     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
663
664     return gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, hard);
665 }
666
667 static gboolean
668 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
669 {
670     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
671
672     if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
673         return FALSE;
674     if (!gst_vaapidecode_update_src_caps(decode, state))
675         return FALSE;
676     if (!gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, FALSE))
677         return FALSE;
678     return TRUE;
679 }
680
681 static GstFlowReturn
682 gst_vaapidecode_parse(GstVideoDecoder *vdec,
683     GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
684 {
685     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
686     GstVaapiDecoderStatus status;
687     GstFlowReturn ret;
688     guint got_unit_size;
689     gboolean got_frame;
690
691     status = gst_vaapi_decoder_parse(decode->decoder, frame,
692         adapter, at_eos, &got_unit_size, &got_frame);
693
694     switch (status) {
695     case GST_VAAPI_DECODER_STATUS_SUCCESS:
696         if (got_unit_size > 0)
697             gst_video_decoder_add_to_frame(vdec, got_unit_size);
698         if (got_frame)
699             ret = gst_video_decoder_have_frame(vdec);
700         else
701             ret = GST_FLOW_OK;
702         break;
703     case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
704         ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
705         break;
706     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
707     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
708     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
709         GST_WARNING("parse error %d", status);
710         ret = GST_FLOW_NOT_SUPPORTED;
711         break;
712     default:
713         GST_ERROR("parse error %d", status);
714         ret = GST_FLOW_EOS;
715         break;
716     }
717     return ret;
718 }
719
720 static void
721 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
722 {
723     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
724     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
725     GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
726     GstPadTemplate *pad_template;
727
728     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
729                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
730
731     object_class->finalize   = gst_vaapidecode_finalize;
732
733     vdec_class->open         = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
734     vdec_class->close        = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
735     vdec_class->set_format   = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
736     vdec_class->reset        = GST_DEBUG_FUNCPTR(gst_vaapidecode_reset);
737     vdec_class->parse        = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
738     vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
739     vdec_class->finish       = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish);
740
741 #if GST_CHECK_VERSION(1,0,0)
742     vdec_class->decide_allocation =
743         GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
744 #endif
745
746     gst_element_class_set_static_metadata(element_class,
747         "VA-API decoder",
748         "Codec/Decoder/Video",
749         GST_PLUGIN_DESC,
750         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
751
752     /* sink pad */
753     pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
754     gst_element_class_add_pad_template(element_class, pad_template);
755
756     /* src pad */
757     pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
758     gst_element_class_add_pad_template(element_class, pad_template);
759 }
760
761 static gboolean
762 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
763 {
764     GstCaps *decode_caps;
765     guint i, n_decode_caps;
766
767     if (decode->allowed_caps)
768         return TRUE;
769
770     if (!gst_vaapidecode_ensure_display(decode))
771         goto error_no_display;
772
773     decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
774     if (!decode_caps)
775         goto error_no_decode_caps;
776     n_decode_caps = gst_caps_get_size(decode_caps);
777
778     decode->allowed_caps = gst_caps_new_empty();
779     if (!decode->allowed_caps)
780         goto error_no_memory;
781
782     for (i = 0; i < n_decode_caps; i++) {
783         GstStructure *structure;
784         structure = gst_caps_get_structure(decode_caps, i);
785         if (!structure)
786             continue;
787         structure = gst_structure_copy(structure);
788         if (!structure)
789             continue;
790         gst_structure_remove_field(structure, "profile");
791         gst_structure_set(
792             structure,
793             "width",  GST_TYPE_INT_RANGE, 1, G_MAXINT,
794             "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
795             NULL
796         );
797         decode->allowed_caps =
798             gst_caps_merge_structure(decode->allowed_caps, structure);
799     }
800
801     gst_caps_unref(decode_caps);
802     return TRUE;
803
804     /* ERRORS */
805 error_no_display:
806     {
807         GST_ERROR("failed to retrieve VA display");
808         return FALSE;
809     }
810 error_no_decode_caps:
811     {
812         GST_ERROR("failed to retrieve VA decode caps");
813         return FALSE;
814     }
815 error_no_memory:
816     {
817         GST_ERROR("failed to allocate allowed-caps set");
818         gst_caps_unref(decode_caps);
819         return FALSE;
820     }
821 }
822
823 static GstCaps *
824 gst_vaapidecode_get_caps(GstPad *pad)
825 {
826     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
827
828     if (!gst_vaapidecode_ensure_allowed_caps(decode))
829         return gst_caps_new_empty();
830
831     return gst_caps_ref(decode->allowed_caps);
832 }
833
834 static gboolean
835 gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
836 {
837     GstVaapiDecode * const decode =
838         GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
839     gboolean res;
840
841     GST_DEBUG("sharing display %p", decode->display);
842
843     if (gst_vaapi_reply_to_query(query, decode->display))
844         res = TRUE;
845     else if (GST_PAD_IS_SINK(pad)) {
846         switch (GST_QUERY_TYPE(query)) {
847 #if GST_CHECK_VERSION(1,0,0)
848         case GST_QUERY_CAPS: {
849             GstCaps * const caps = gst_vaapidecode_get_caps(pad);
850             gst_query_set_caps_result(query, caps);
851             gst_caps_unref(caps);
852             res = TRUE;
853             break;
854         }
855 #endif
856         default:
857             res = GST_PAD_QUERY_FUNCTION_CALL(decode->sinkpad_query,
858                 decode->sinkpad, parent, query);
859             break;
860         }
861     }
862     else
863         res = GST_PAD_QUERY_FUNCTION_CALL(decode->srcpad_query,
864             decode->srcpad, parent, query);
865
866     gst_object_unref(decode);
867     return res;
868 }
869
870 static void
871 gst_vaapidecode_init(GstVaapiDecode *decode)
872 {
873     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
874
875     decode->display             = NULL;
876     decode->decoder             = NULL;
877     decode->decoder_caps        = NULL;
878     decode->allowed_caps        = NULL;
879     decode->render_time_base    = 0;
880     decode->last_buffer_time    = 0;
881
882     g_mutex_init(&decode->decoder_mutex);
883     g_cond_init(&decode->decoder_ready);
884
885     gst_video_decoder_set_packetized(vdec, FALSE);
886
887     /* Pad through which data comes in to the element */
888     decode->sinkpad = GST_VIDEO_DECODER_SINK_PAD(vdec);
889     decode->sinkpad_query = GST_PAD_QUERYFUNC(decode->sinkpad);
890     gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
891 #if !GST_CHECK_VERSION(1,0,0)
892     gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
893 #endif
894
895     /* Pad through which data goes out of the element */
896     decode->srcpad = GST_VIDEO_DECODER_SRC_PAD(vdec);
897     decode->srcpad_query = GST_PAD_QUERYFUNC(decode->srcpad);
898     gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);
899 }