vaapidecode: submit all decoded frames before decoding a new one.
[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     GstVideoCodecState *ref_state);
134
135 static void
136 gst_vaapi_decoder_notify_caps(GObject *obj, GParamSpec *pspec, void *user_data)
137 {
138     GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
139     GstVideoCodecState *codec_state;
140
141     g_assert(decode->decoder == GST_VAAPI_DECODER(obj));
142
143     codec_state = gst_vaapi_decoder_get_codec_state(decode->decoder);
144     gst_vaapidecode_update_src_caps(decode, codec_state);
145     gst_video_codec_state_unref(codec_state);
146 }
147
148 static inline gboolean
149 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
150 {
151     gst_caps_replace(&decode->sinkpad_caps, caps);
152     return TRUE;
153 }
154
155 static gboolean
156 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
157     GstVideoCodecState *ref_state)
158 {
159     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
160     GstVideoCodecState *state;
161     GstVideoInfo *vi, vis;
162
163     state = gst_video_decoder_set_output_state(vdec,
164         GST_VIDEO_INFO_FORMAT(&ref_state->info),
165         ref_state->info.width, ref_state->info.height, ref_state);
166     if (!state)
167         return FALSE;
168
169     vi = &state->info;
170     if (GST_VIDEO_INFO_FORMAT(vi) == GST_VIDEO_FORMAT_ENCODED) {
171         gst_video_info_init(&vis);
172         gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12,
173             GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
174         vi->size = vis.size;
175     }
176     gst_video_codec_state_unref(state);
177
178     /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
179        reconstruct suitable caps for "encoded" video formats */
180     state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
181     if (!state->caps)
182         return FALSE;
183
184     gst_caps_set_simple(state->caps,
185         "type", G_TYPE_STRING, "vaapi",
186         "opengl", G_TYPE_BOOLEAN, USE_GLX,
187         "width", G_TYPE_INT, vi->width,
188         "height", G_TYPE_INT, vi->height,
189         "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
190         "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d,
191         NULL);
192
193     if (GST_VIDEO_INFO_IS_INTERLACED(vi))
194         gst_caps_set_simple(state->caps, "interlaced", G_TYPE_BOOLEAN,
195             TRUE, NULL);
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         decode->render_time_base = g_get_monotonic_time();
219     end_time = decode->render_time_base;
220     end_time += GST_TIME_AS_USECONDS(decode->last_buffer_time);
221     end_time += G_TIME_SPAN_SECOND;
222
223     /* Decode current frame */
224     for (;;) {
225         status = gst_vaapi_decoder_decode(decode->decoder, frame);
226         if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
227             gboolean was_signalled;
228             g_mutex_lock(&decode->decoder_mutex);
229             was_signalled = g_cond_wait_until(
230                 &decode->decoder_ready,
231                 &decode->decoder_mutex,
232                 end_time
233             );
234             g_mutex_unlock(&decode->decoder_mutex);
235             if (was_signalled)
236                 continue;
237             goto error_decode_timeout;
238         }
239         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
240             goto error_decode;
241         break;
242     }
243     return GST_FLOW_OK;
244
245     /* ERRORS */
246 error_decode_timeout:
247     {
248         GST_WARNING("decode timeout. Decoder required a VA surface but none "
249                     "got available within one second");
250         return GST_FLOW_EOS;
251     }
252 error_decode:
253     {
254         GST_ERROR("decode error %d", status);
255         switch (status) {
256         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
257         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
258         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
259             ret = GST_FLOW_NOT_SUPPORTED;
260             break;
261         default:
262             ret = GST_FLOW_EOS;
263             break;
264         }
265         gst_video_decoder_drop_frame(vdec, frame);
266         return ret;
267     }
268 }
269
270 static GstFlowReturn
271 gst_vaapidecode_push_decoded_frames(GstVideoDecoder *vdec)
272 {
273     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
274     GstVaapiSurfaceProxy *proxy;
275     GstVaapiDecoderStatus status;
276     GstVaapiVideoMeta *meta;
277     GstVideoCodecFrame *out_frame;
278     GstFlowReturn ret;
279
280     /* Output all decoded frames */
281     for (;;) {
282         status = gst_vaapi_decoder_get_frame(decode->decoder, &out_frame);
283         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
284             return GST_FLOW_OK;
285
286         if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
287             proxy = gst_video_codec_frame_get_user_data(out_frame);
288
289             gst_vaapi_surface_proxy_set_user_data(proxy,
290                 decode, (GDestroyNotify)gst_vaapidecode_release);
291
292 #if GST_CHECK_VERSION(1,0,0)
293             ret = gst_video_decoder_allocate_output_frame(vdec, out_frame);
294             if (ret != GST_FLOW_OK)
295                 goto error_create_buffer;
296
297             meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer);
298             if (!meta)
299                 goto error_get_meta;
300             gst_vaapi_video_meta_set_surface_proxy(meta, proxy);
301 #else
302             out_frame->output_buffer =
303                 gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
304             if (!out_frame->output_buffer)
305                 goto error_create_buffer;
306 #endif
307         }
308
309         ret = gst_video_decoder_finish_frame(vdec, out_frame);
310         if (ret != GST_FLOW_OK)
311             goto error_commit_buffer;
312
313         if (GST_CLOCK_TIME_IS_VALID(out_frame->pts))
314             decode->last_buffer_time = out_frame->pts;
315         gst_video_codec_frame_unref(out_frame);
316     };
317     return GST_FLOW_OK;
318
319     /* ERRORS */
320 error_create_buffer:
321     {
322         const GstVaapiID surface_id =
323             gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
324
325         GST_ERROR("video sink failed to create video buffer for proxy'ed "
326                   "surface %" GST_VAAPI_ID_FORMAT,
327                   GST_VAAPI_ID_ARGS(surface_id));
328         gst_video_decoder_drop_frame(vdec, out_frame);
329         gst_video_codec_frame_unref(out_frame);
330         return GST_FLOW_EOS;
331     }
332 #if GST_CHECK_VERSION(1,0,0)
333 error_get_meta:
334     {
335         GST_ERROR("failed to get vaapi video meta attached to video buffer");
336         gst_video_decoder_drop_frame(vdec, out_frame);
337         gst_video_codec_frame_unref(out_frame);
338         return GST_FLOW_EOS;
339     }
340 #endif
341 error_commit_buffer:
342     {
343         GST_DEBUG("video sink rejected the video buffer (error %d)", ret);
344         gst_video_codec_frame_unref(out_frame);
345         return GST_FLOW_EOS;
346     }
347 }
348
349 static GstFlowReturn
350 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
351 {
352     GstFlowReturn ret;
353
354     /* Purge all pending frames we might have already. This helps
355        release VA surfaces as early as possible for _decode_frame() */
356     ret = gst_vaapidecode_push_decoded_frames(vdec);
357     if (ret != GST_FLOW_OK)
358         return ret;
359
360     ret = gst_vaapidecode_decode_frame(vdec, frame);
361     if (ret != GST_FLOW_OK)
362         return ret;
363
364     /* Purge any pending frame thay may have been decoded already */
365     return gst_vaapidecode_push_decoded_frames(vdec);
366 }
367
368 static GstFlowReturn
369 gst_vaapidecode_finish(GstVideoDecoder *vdec)
370 {
371     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
372     GstVaapiDecoderStatus status;
373
374     status = gst_vaapi_decoder_flush(decode->decoder);
375     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
376         goto error_flush;
377     return gst_vaapidecode_push_decoded_frames(vdec);
378
379     /* ERRORS */
380 error_flush:
381     {
382         GST_ERROR("failed to flush decoder (status %d)", status);
383         return GST_FLOW_EOS;
384     }
385 }
386
387 #if GST_CHECK_VERSION(1,0,0)
388 static gboolean
389 gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
390 {
391     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
392     GstCaps *caps = NULL;
393     GstBufferPool *pool;
394     GstStructure *config;
395     GstVideoInfo vi;
396     guint size, min, max;
397     gboolean need_pool, update_pool;
398
399     gst_query_parse_allocation(query, &caps, &need_pool);
400
401     if (!caps)
402         goto error_no_caps;
403
404     gst_video_info_init(&vi);
405     gst_video_info_from_caps(&vi, caps);
406     if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED)
407         gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
408             GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
409
410     g_return_val_if_fail(decode->display != NULL, FALSE);
411
412     if (gst_query_get_n_allocation_pools(query) > 0) {
413         gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
414         size = MAX(size, vi.size);
415         update_pool = TRUE;
416     }
417     else {
418         pool = NULL;
419         size = vi.size;
420         min = max = 0;
421         update_pool = FALSE;
422     }
423
424     if (!pool || !gst_buffer_pool_has_option(pool,
425             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
426         GST_INFO("no pool or doesn't support GstVaapiVideoMeta, "
427             "making new pool");
428         pool = gst_vaapi_video_buffer_pool_new(decode->display);
429         if (!pool)
430             goto error_create_pool;
431
432         config = gst_buffer_pool_get_config(pool);
433         gst_buffer_pool_config_set_params(config, caps, size, min, max);
434         gst_buffer_pool_config_add_option(config,
435             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
436         gst_buffer_pool_set_config(pool, config);
437     }
438
439     if (update_pool)
440         gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
441     else
442         gst_query_add_allocation_pool(query, pool, size, min, max);
443     if (pool)
444         g_object_unref(pool);
445     return TRUE;
446
447     /* ERRORS */
448 error_no_caps:
449     {
450         GST_ERROR("no caps specified");
451         return FALSE;
452     }
453 error_create_pool:
454     {
455         GST_ERROR("failed to create buffer pool");
456         return FALSE;
457     }
458 }
459 #endif
460
461 static inline gboolean
462 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
463 {
464     return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY,
465         &decode->display);
466 }
467
468 static inline guint
469 gst_vaapi_codec_from_caps(GstCaps *caps)
470 {
471     return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
472 }
473
474 static gboolean
475 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
476 {
477     GstVaapiDisplay *dpy;
478
479     if (!gst_vaapidecode_ensure_display(decode))
480         return FALSE;
481     dpy = decode->display;
482
483     switch (gst_vaapi_codec_from_caps(caps)) {
484     case GST_VAAPI_CODEC_MPEG2:
485         decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
486         break;
487     case GST_VAAPI_CODEC_MPEG4:
488     case GST_VAAPI_CODEC_H263:
489         decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
490         break;
491     case GST_VAAPI_CODEC_H264:
492         decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
493         break;
494     case GST_VAAPI_CODEC_WMV3:
495     case GST_VAAPI_CODEC_VC1:
496         decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
497         break;
498 #if USE_JPEG_DECODER
499     case GST_VAAPI_CODEC_JPEG:
500         decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
501         break;
502 #endif
503     default:
504         decode->decoder = NULL;
505         break;
506     }
507     if (!decode->decoder)
508         return FALSE;
509
510     g_signal_connect(
511         G_OBJECT(decode->decoder),
512         "notify::caps",
513         G_CALLBACK(gst_vaapi_decoder_notify_caps),
514         decode
515     );
516
517     decode->decoder_caps = gst_caps_ref(caps);
518     return TRUE;
519 }
520
521 static void
522 gst_vaapidecode_destroy(GstVaapiDecode *decode)
523 {
524     g_clear_object(&decode->decoder);
525     gst_caps_replace(&decode->decoder_caps, NULL);
526     gst_vaapidecode_release(decode);
527 }
528
529 static gboolean
530 gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
531 {
532     GstVaapiCodec codec;
533
534     /* Reset timers if hard reset was requested (e.g. seek) */
535     if (hard) {
536         decode->render_time_base = 0;
537         decode->last_buffer_time = 0;
538     }
539
540     /* Only reset decoder if codec type changed */
541     else if (decode->decoder && decode->decoder_caps) {
542         if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
543             return TRUE;
544         codec = gst_vaapi_codec_from_caps(caps);
545         if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
546             return TRUE;
547     }
548
549     gst_vaapidecode_destroy(decode);
550     return gst_vaapidecode_create(decode, caps);
551 }
552
553 static void
554 gst_vaapidecode_finalize(GObject *object)
555 {
556     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
557
558     gst_vaapidecode_destroy(decode);
559
560     gst_caps_replace(&decode->sinkpad_caps, NULL);
561     gst_caps_replace(&decode->srcpad_caps,  NULL);
562     gst_caps_replace(&decode->allowed_caps, NULL);
563
564     g_clear_object(&decode->display);
565
566     g_cond_clear(&decode->decoder_ready);
567     g_mutex_clear(&decode->decoder_mutex);
568
569     G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
570 }
571
572 static gboolean
573 gst_vaapidecode_open(GstVideoDecoder *vdec)
574 {
575     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
576     GstVaapiDisplay * const old_display = decode->display;
577     gboolean success;
578
579     /* Let GstVideoContext ask for a proper display to its neighbours */
580     /* Note: steal old display that may be allocated from get_caps()
581        so that to retain a reference to it, thus avoiding extra
582        initialization steps if we turn out to simply re-use the
583        existing (cached) VA display */
584     decode->display = NULL;
585     success = gst_vaapidecode_ensure_display(decode);
586     g_clear_object(&old_display);
587     return success;
588 }
589
590 static gboolean
591 gst_vaapidecode_close(GstVideoDecoder *vdec)
592 {
593     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
594
595     gst_vaapidecode_destroy(decode);
596     g_clear_object(&decode->display);
597     return TRUE;
598 }
599
600 static gboolean
601 gst_vaapidecode_reset(GstVideoDecoder *vdec, gboolean hard)
602 {
603     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
604
605     return gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, hard);
606 }
607
608 static gboolean
609 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
610 {
611     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
612
613     if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
614         return FALSE;
615     if (!gst_vaapidecode_update_src_caps(decode, state))
616         return FALSE;
617     if (!gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, FALSE))
618         return FALSE;
619     return TRUE;
620 }
621
622 static GstFlowReturn
623 gst_vaapidecode_parse(GstVideoDecoder *vdec,
624     GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
625 {
626     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
627     GstVaapiDecoderStatus status;
628     GstFlowReturn ret;
629     guint got_unit_size;
630     gboolean got_frame;
631
632     status = gst_vaapi_decoder_parse(decode->decoder, frame,
633         adapter, at_eos, &got_unit_size, &got_frame);
634
635     switch (status) {
636     case GST_VAAPI_DECODER_STATUS_SUCCESS:
637         if (got_unit_size > 0)
638             gst_video_decoder_add_to_frame(vdec, got_unit_size);
639         if (got_frame)
640             ret = gst_video_decoder_have_frame(vdec);
641         else
642             ret = GST_FLOW_OK;
643         break;
644     case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
645         ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
646         break;
647     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
648     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
649     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
650         GST_WARNING("parse error %d", status);
651         ret = GST_FLOW_NOT_SUPPORTED;
652         break;
653     default:
654         GST_ERROR("parse error %d", status);
655         ret = GST_FLOW_EOS;
656         break;
657     }
658     return ret;
659 }
660
661 static void
662 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
663 {
664     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
665     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
666     GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
667     GstPadTemplate *pad_template;
668
669     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
670                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
671
672     object_class->finalize   = gst_vaapidecode_finalize;
673
674     vdec_class->open         = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
675     vdec_class->close        = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
676     vdec_class->set_format   = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
677     vdec_class->reset        = GST_DEBUG_FUNCPTR(gst_vaapidecode_reset);
678     vdec_class->parse        = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
679     vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
680     vdec_class->finish       = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish);
681
682 #if GST_CHECK_VERSION(1,0,0)
683     vdec_class->decide_allocation =
684         GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
685 #endif
686
687     gst_element_class_set_static_metadata(element_class,
688         "VA-API decoder",
689         "Codec/Decoder/Video",
690         GST_PLUGIN_DESC,
691         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
692
693     /* sink pad */
694     pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
695     gst_element_class_add_pad_template(element_class, pad_template);
696
697     /* src pad */
698     pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
699     gst_element_class_add_pad_template(element_class, pad_template);
700 }
701
702 static gboolean
703 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
704 {
705     GstCaps *decode_caps;
706     guint i, n_decode_caps;
707
708     if (decode->allowed_caps)
709         return TRUE;
710
711     if (!gst_vaapidecode_ensure_display(decode))
712         goto error_no_display;
713
714     decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
715     if (!decode_caps)
716         goto error_no_decode_caps;
717     n_decode_caps = gst_caps_get_size(decode_caps);
718
719     decode->allowed_caps = gst_caps_new_empty();
720     if (!decode->allowed_caps)
721         goto error_no_memory;
722
723     for (i = 0; i < n_decode_caps; i++) {
724         GstStructure *structure;
725         structure = gst_caps_get_structure(decode_caps, i);
726         if (!structure)
727             continue;
728         structure = gst_structure_copy(structure);
729         if (!structure)
730             continue;
731         gst_structure_remove_field(structure, "profile");
732         gst_structure_set(
733             structure,
734             "width",  GST_TYPE_INT_RANGE, 1, G_MAXINT,
735             "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
736             NULL
737         );
738         decode->allowed_caps =
739             gst_caps_merge_structure(decode->allowed_caps, structure);
740     }
741
742     gst_caps_unref(decode_caps);
743     return TRUE;
744
745     /* ERRORS */
746 error_no_display:
747     {
748         GST_ERROR("failed to retrieve VA display");
749         return FALSE;
750     }
751 error_no_decode_caps:
752     {
753         GST_ERROR("failed to retrieve VA decode caps");
754         return FALSE;
755     }
756 error_no_memory:
757     {
758         GST_ERROR("failed to allocate allowed-caps set");
759         gst_caps_unref(decode_caps);
760         return FALSE;
761     }
762 }
763
764 static GstCaps *
765 gst_vaapidecode_get_caps(GstPad *pad)
766 {
767     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
768
769     if (!gst_vaapidecode_ensure_allowed_caps(decode))
770         return gst_caps_new_empty();
771
772     return gst_caps_ref(decode->allowed_caps);
773 }
774
775 static gboolean
776 gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
777 {
778     GstVaapiDecode * const decode =
779         GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
780     gboolean res;
781
782     GST_DEBUG("sharing display %p", decode->display);
783
784     if (gst_vaapi_reply_to_query(query, decode->display))
785         res = TRUE;
786     else if (GST_PAD_IS_SINK(pad)) {
787         switch (GST_QUERY_TYPE(query)) {
788 #if GST_CHECK_VERSION(1,0,0)
789         case GST_QUERY_CAPS: {
790             GstCaps * const caps = gst_vaapidecode_get_caps(pad);
791             gst_query_set_caps_result(query, caps);
792             gst_caps_unref(caps);
793             res = TRUE;
794             break;
795         }
796 #endif
797         default:
798             res = GST_PAD_QUERY_FUNCTION_CALL(decode->sinkpad_query,
799                 decode->sinkpad, parent, query);
800             break;
801         }
802     }
803     else
804         res = GST_PAD_QUERY_FUNCTION_CALL(decode->srcpad_query,
805             decode->srcpad, parent, query);
806
807     g_object_unref(decode);
808     return res;
809 }
810
811 static void
812 gst_vaapidecode_init(GstVaapiDecode *decode)
813 {
814     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
815
816     decode->display             = NULL;
817     decode->decoder             = NULL;
818     decode->decoder_caps        = NULL;
819     decode->allowed_caps        = NULL;
820     decode->render_time_base    = 0;
821     decode->last_buffer_time    = 0;
822
823     g_mutex_init(&decode->decoder_mutex);
824     g_cond_init(&decode->decoder_ready);
825
826     gst_video_decoder_set_packetized(vdec, FALSE);
827
828     /* Pad through which data comes in to the element */
829     decode->sinkpad = GST_VIDEO_DECODER_SINK_PAD(vdec);
830     decode->sinkpad_query = GST_PAD_QUERYFUNC(decode->sinkpad);
831     gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
832 #if !GST_CHECK_VERSION(1,0,0)
833     gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
834 #endif
835
836     /* Pad through which data goes out of the element */
837     decode->srcpad = GST_VIDEO_DECODER_SRC_PAD(vdec);
838     decode->srcpad_query = GST_PAD_QUERYFUNC(decode->srcpad);
839     gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);
840 }