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