vaapidecode: fix auto-plugging of vaapisink element.
[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  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23 */
24
25 /**
26  * SECTION:gstvaapidecode
27  * @short_description: A VA-API based video decoder
28  *
29  * vaapidecode decodes from raw bitstreams to surfaces suitable for
30  * the vaapisink element.
31  */
32
33 #include "gst/vaapi/sysdeps.h"
34 #include <gst/vaapi/gstvaapidisplay.h>
35
36 #include "gstvaapidecode.h"
37 #include "gstvaapipluginutil.h"
38 #include "gstvaapivideobuffer.h"
39 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
40 #include "gstvaapivideometa_texture.h"
41 #endif
42 #if GST_CHECK_VERSION(1,0,0)
43 #include "gstvaapivideobufferpool.h"
44 #include "gstvaapivideomemory.h"
45 #endif
46
47 #include <gst/vaapi/gstvaapidecoder_h264.h>
48 #include <gst/vaapi/gstvaapidecoder_jpeg.h>
49 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
50 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
51 #include <gst/vaapi/gstvaapidecoder_vc1.h>
52 #include <gst/vaapi/gstvaapidecoder_vp8.h>
53
54 #define GST_PLUGIN_NAME "vaapidecode"
55 #define GST_PLUGIN_DESC "A VA-API based video decoder"
56
57 #define GST_VAAPI_DECODE_FLOW_PARSE_DATA        GST_FLOW_CUSTOM_SUCCESS_2
58
59 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode);
60 #define GST_CAT_DEFAULT gst_debug_vaapidecode
61
62 /* Default templates */
63 #define GST_CAPS_CODEC(CODEC) CODEC "; "
64
65 static const char gst_vaapidecode_sink_caps_str[] =
66     GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
67     GST_CAPS_CODEC("video/mpeg, mpegversion=4")
68     GST_CAPS_CODEC("video/x-divx")
69     GST_CAPS_CODEC("video/x-xvid")
70     GST_CAPS_CODEC("video/x-h263")
71     GST_CAPS_CODEC("video/x-h264")
72     GST_CAPS_CODEC("video/x-wmv")
73     GST_CAPS_CODEC("video/x-vp8")
74     GST_CAPS_CODEC("image/jpeg")
75     ;
76
77 static const char gst_vaapidecode_src_caps_str[] =
78 #if GST_CHECK_VERSION(1,1,0)
79     GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
80         GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, I420, YV12, NV12 }") ";"
81     GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
82         GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA") ";"
83     GST_VIDEO_CAPS_MAKE("{ I420, YV12, NV12 }");
84 #else
85     GST_VAAPI_SURFACE_CAPS;
86 #endif
87
88 static GstStaticPadTemplate gst_vaapidecode_sink_factory =
89     GST_STATIC_PAD_TEMPLATE(
90         "sink",
91         GST_PAD_SINK,
92         GST_PAD_ALWAYS,
93         GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));
94
95 static GstStaticPadTemplate gst_vaapidecode_src_factory =
96     GST_STATIC_PAD_TEMPLATE(
97         "src",
98         GST_PAD_SRC,
99         GST_PAD_ALWAYS,
100         GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
101
102 G_DEFINE_TYPE_WITH_CODE(
103     GstVaapiDecode,
104     gst_vaapidecode,
105     GST_TYPE_VIDEO_DECODER,
106     GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES)
107
108 static gboolean
109 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
110     const GstVideoCodecState *ref_state);
111
112 static void
113 gst_vaapi_decoder_state_changed(GstVaapiDecoder *decoder,
114     const GstVideoCodecState *codec_state, gpointer user_data)
115 {
116     GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
117     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
118
119     g_assert(decode->decoder == decoder);
120
121     gst_vaapidecode_update_src_caps(decode, codec_state);
122     gst_video_decoder_negotiate(vdec);
123 }
124
125 static inline gboolean
126 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
127 {
128     gst_caps_replace(&decode->sinkpad_caps, caps);
129     return TRUE;
130 }
131
132 #if GST_CHECK_VERSION(1,1,0)
133 static void
134 gst_vaapidecode_video_info_change_format(GstVideoInfo *info,
135     GstVideoFormat format, guint width, guint height)
136 {
137     GstVideoInfo vi = *info;
138
139     gst_video_info_set_format (info, format, width, height);
140
141     info->interlace_mode = vi.interlace_mode;
142     info->flags = vi.flags;
143     info->views = vi.views;
144     info->par_n = vi.par_n;
145     info->par_d = vi.par_d;
146     info->fps_n = vi.fps_n;
147     info->fps_d = vi.fps_d;
148 }
149 #endif
150
151 static gboolean
152 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
153     const GstVideoCodecState *ref_state)
154 {
155     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
156     GstVideoCodecState *state;
157     GstVideoInfo *vi, vis;
158     GstVideoFormat format, out_format;
159 #if GST_CHECK_VERSION(1,1,0)
160     GstCapsFeatures *features = NULL;
161     GstVaapiCapsFeature feature;
162
163     feature = gst_vaapi_find_preferred_caps_feature(
164         GST_VIDEO_DECODER_SRC_PAD(vdec),
165         GST_VIDEO_INFO_FORMAT(&ref_state->info));
166 #endif
167
168     format = GST_VIDEO_INFO_FORMAT(&ref_state->info);
169
170     state = gst_video_decoder_set_output_state(vdec, format,
171         ref_state->info.width, ref_state->info.height,
172         (GstVideoCodecState *)ref_state);
173     if (!state)
174         return FALSE;
175
176     vi = &state->info;
177     out_format = format;
178     if (format == GST_VIDEO_FORMAT_ENCODED) {
179         out_format = GST_VIDEO_FORMAT_I420;
180         gst_video_info_init(&vis);
181         gst_video_info_set_format(&vis, out_format,
182             GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
183         vi->size = vis.size;
184     }
185     gst_video_codec_state_unref(state);
186
187 #if GST_CHECK_VERSION(1,1,0)
188     vis = *vi;
189     switch (feature) {
190     case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
191         gst_vaapidecode_video_info_change_format(&vis, GST_VIDEO_FORMAT_RGBA,
192             GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
193         features = gst_caps_features_new(
194             GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL);
195         break;
196     default:
197         if (format == GST_VIDEO_FORMAT_ENCODED) {
198             /* XXX: this is a workaround until auto-plugging is fixed when
199                format=ENCODED + memory:VASurface caps feature are provided.
200                Meanwhile, providing a random format here works but this is
201                a terribly wrong thing per se. */
202             gst_vaapidecode_video_info_change_format(&vis, out_format,
203                 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
204 #if GST_CHECK_VERSION(1,5,0)
205             if (feature == GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
206                 features = gst_caps_features_new(
207                     GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, NULL);
208 #endif
209         }
210         break;
211     }
212     state->caps = gst_video_info_to_caps(&vis);
213     if (features)
214         gst_caps_set_features(state->caps, 0, features);
215 #else
216     /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
217        reconstruct suitable caps for "encoded" video formats */
218     state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
219     if (!state->caps)
220         return FALSE;
221
222     gst_caps_set_simple(state->caps,
223         "type", G_TYPE_STRING, "vaapi",
224         "opengl", G_TYPE_BOOLEAN, USE_GLX,
225         "width", G_TYPE_INT, vi->width,
226         "height", G_TYPE_INT, vi->height,
227         "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
228         "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d,
229         NULL);
230
231     gst_caps_set_interlaced(state->caps, vi);
232 #endif
233     gst_caps_replace(&decode->srcpad_caps, state->caps);
234     return TRUE;
235 }
236
237 static void
238 gst_vaapidecode_release(GstVaapiDecode *decode)
239 {
240     g_mutex_lock(&decode->decoder_mutex);
241     g_cond_signal(&decode->decoder_ready);
242     g_mutex_unlock(&decode->decoder_mutex);
243 }
244
245 static GstFlowReturn
246 gst_vaapidecode_decode_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
247 {
248     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
249     GstVaapiDecoderStatus status;
250     GstFlowReturn ret;
251
252     /* Decode current frame */
253     for (;;) {
254         status = gst_vaapi_decoder_decode(decode->decoder, frame);
255         if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
256             GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
257             g_mutex_lock(&decode->decoder_mutex);
258             g_cond_wait(&decode->decoder_ready, &decode->decoder_mutex);
259             g_mutex_unlock(&decode->decoder_mutex);
260             GST_VIDEO_DECODER_STREAM_LOCK(vdec);
261             if (decode->decoder_loop_status < 0)
262                 goto error_decode_loop;
263             continue;
264         }
265         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
266             goto error_decode;
267         break;
268     }
269
270     /* Try to report back early any error that occured in the decode task */
271     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
272     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
273     return decode->decoder_loop_status;
274
275     /* ERRORS */
276 error_decode_loop:
277     {
278         GST_ERROR("decode loop error %d", decode->decoder_loop_status);
279         gst_video_decoder_drop_frame(vdec, frame);
280         return decode->decoder_loop_status;
281     }
282 error_decode:
283     {
284         GST_ERROR("decode error %d", status);
285         switch (status) {
286         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
287         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
288         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
289             ret = GST_FLOW_NOT_SUPPORTED;
290             break;
291         default:
292             ret = GST_FLOW_ERROR;
293             break;
294         }
295         gst_video_decoder_drop_frame(vdec, frame);
296         return ret;
297     }
298 }
299
300 static GstFlowReturn
301 gst_vaapidecode_push_decoded_frame(GstVideoDecoder *vdec,
302     GstVideoCodecFrame *out_frame)
303 {
304     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
305     GstVaapiSurfaceProxy *proxy;
306     GstFlowReturn ret;
307 #if GST_CHECK_VERSION(1,0,0)
308     const GstVaapiRectangle *crop_rect;
309     GstVaapiVideoMeta *meta;
310     guint flags;
311 #endif
312
313     if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
314         proxy = gst_video_codec_frame_get_user_data(out_frame);
315
316         gst_vaapi_surface_proxy_set_destroy_notify(proxy,
317             (GDestroyNotify)gst_vaapidecode_release, decode);
318
319 #if GST_CHECK_VERSION(1,0,0)
320         ret = gst_video_decoder_allocate_output_frame(vdec, out_frame);
321         if (ret != GST_FLOW_OK)
322             goto error_create_buffer;
323
324         meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer);
325         if (!meta)
326             goto error_get_meta;
327         gst_vaapi_video_meta_set_surface_proxy(meta, proxy);
328
329         flags = gst_vaapi_surface_proxy_get_flags(proxy);
330         if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
331             guint out_flags = GST_VIDEO_BUFFER_FLAG_INTERLACED;
332             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
333                 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
334             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
335                 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
336             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
337                 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
338             GST_BUFFER_FLAG_SET(out_frame->output_buffer, out_flags);
339         }
340
341         crop_rect = gst_vaapi_surface_proxy_get_crop_rect(proxy);
342         if (crop_rect) {
343             GstVideoCropMeta * const crop_meta =
344                 gst_buffer_add_video_crop_meta(out_frame->output_buffer);
345             if (crop_meta) {
346                 crop_meta->x = crop_rect->x;
347                 crop_meta->y = crop_rect->y;
348                 crop_meta->width = crop_rect->width;
349                 crop_meta->height = crop_rect->height;
350             }
351         }
352
353 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
354         if (decode->has_texture_upload_meta)
355             gst_buffer_ensure_texture_upload_meta(out_frame->output_buffer);
356 #endif
357 #else
358         out_frame->output_buffer =
359             gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
360         if (!out_frame->output_buffer)
361             goto error_create_buffer;
362 #endif
363     }
364
365     ret = gst_video_decoder_finish_frame(vdec, out_frame);
366     if (ret != GST_FLOW_OK)
367         goto error_commit_buffer;
368
369     gst_video_codec_frame_unref(out_frame);
370     return GST_FLOW_OK;
371
372     /* ERRORS */
373 error_create_buffer:
374     {
375         const GstVaapiID surface_id =
376             gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
377
378         GST_ERROR("video sink failed to create video buffer for proxy'ed "
379                   "surface %" GST_VAAPI_ID_FORMAT,
380                   GST_VAAPI_ID_ARGS(surface_id));
381         gst_video_decoder_drop_frame(vdec, out_frame);
382         gst_video_codec_frame_unref(out_frame);
383         return GST_FLOW_ERROR;
384     }
385 #if GST_CHECK_VERSION(1,0,0)
386 error_get_meta:
387     {
388         GST_ERROR("failed to get vaapi video meta attached to video buffer");
389         gst_video_decoder_drop_frame(vdec, out_frame);
390         gst_video_codec_frame_unref(out_frame);
391         return GST_FLOW_ERROR;
392     }
393 #endif
394 error_commit_buffer:
395     {
396         if (ret != GST_FLOW_FLUSHING)
397             GST_ERROR("video sink rejected the video buffer (error %d)", ret);
398         gst_video_codec_frame_unref(out_frame);
399         return ret;
400     }
401 }
402
403 static GstFlowReturn
404 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
405 {
406     GstFlowReturn ret;
407
408     /* Make sure to release the base class stream lock so that decode
409        loop can call gst_video_decoder_finish_frame() without blocking */
410     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
411     ret = gst_vaapidecode_decode_frame(vdec, frame);
412     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
413     return ret;
414 }
415
416 static void
417 gst_vaapidecode_decode_loop(GstVaapiDecode *decode)
418 {
419     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
420     GstVaapiDecoderStatus status;
421     GstVideoCodecFrame *out_frame;
422     GstFlowReturn ret;
423
424     status = gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
425         &out_frame, 100000);
426
427     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
428     switch (status) {
429     case GST_VAAPI_DECODER_STATUS_SUCCESS:
430         ret = gst_vaapidecode_push_decoded_frame(vdec, out_frame);
431         break;
432     case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
433         ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
434         break;
435     default:
436         ret = GST_FLOW_ERROR;
437         break;
438     }
439     decode->decoder_loop_status = ret;
440     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
441
442     if (ret == GST_FLOW_OK)
443         return;
444
445     /* If invoked from gst_vaapidecode_finish(), then return right
446        away no matter the errors, or the GstVaapiDecoder needs further
447        data to complete decoding (there no more data to feed in) */
448     if (decode->decoder_finish) {
449         g_mutex_lock(&decode->decoder_mutex);
450         g_cond_signal(&decode->decoder_finish_done);
451         g_mutex_unlock(&decode->decoder_mutex);
452         return;
453     }
454
455     /* Suspend the task if an error occurred */
456     if (ret != GST_VIDEO_DECODER_FLOW_NEED_DATA)
457         gst_pad_pause_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
458 }
459
460 static gboolean
461 gst_vaapidecode_flush(GstVideoDecoder *vdec)
462 {
463     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
464     GstVaapiDecoderStatus status;
465
466     /* If there is something in GstVideoDecoder's output adapter, then
467        submit the frame for decoding */
468     if (decode->current_frame_size) {
469         gst_video_decoder_have_frame(vdec);
470         decode->current_frame_size = 0;
471     }
472
473     status = gst_vaapi_decoder_flush(decode->decoder);
474     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
475         goto error_flush;
476     return TRUE;
477
478     /* ERRORS */
479 error_flush:
480     {
481         GST_ERROR("failed to flush decoder (status %d)", status);
482         return FALSE;
483     }
484 }
485
486 static GstFlowReturn
487 gst_vaapidecode_finish(GstVideoDecoder *vdec)
488 {
489     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
490     GstFlowReturn ret = GST_FLOW_OK;
491
492     if (!gst_vaapidecode_flush(vdec))
493         ret = GST_FLOW_OK;
494
495     /* Make sure the decode loop function has a chance to return, thus
496        possibly unlocking gst_video_decoder_finish_frame() */
497     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
498     g_mutex_lock(&decode->decoder_mutex);
499     decode->decoder_finish = TRUE;
500     g_cond_wait(&decode->decoder_finish_done, &decode->decoder_mutex);
501     g_mutex_unlock(&decode->decoder_mutex);
502     gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
503     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
504     return ret;
505 }
506
507 #if GST_CHECK_VERSION(1,0,0)
508 static gboolean
509 gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
510 {
511     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
512     GstCaps *caps = NULL;
513     GstBufferPool *pool;
514     GstStructure *config;
515     GstVideoInfo vi;
516     guint size, min, max;
517     gboolean need_pool, update_pool;
518     gboolean has_video_meta = FALSE;
519     gboolean has_video_alignment = FALSE;
520     GstVideoCodecState *state;
521 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
522     gboolean has_texture_upload_meta = FALSE;
523     GstCapsFeatures *features, *features2;
524 #endif
525
526     gst_query_parse_allocation(query, &caps, &need_pool);
527
528     if (!caps)
529         goto error_no_caps;
530
531     state = gst_video_decoder_get_output_state(vdec);
532
533     decode->has_texture_upload_meta = FALSE;
534     has_video_meta = gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
535 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
536     if (has_video_meta)
537         decode->has_texture_upload_meta = gst_query_find_allocation_meta(query,
538             GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
539
540     features = gst_caps_get_features(state->caps, 0);
541     features2 = gst_caps_features_new(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL);
542
543     has_texture_upload_meta =
544         gst_vaapi_find_preferred_caps_feature(GST_VIDEO_DECODER_SRC_PAD(vdec),
545             GST_VIDEO_FORMAT_ENCODED) ==
546         GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META;
547
548     /* Update src caps if feature is not handled downstream */
549     if (!decode->has_texture_upload_meta &&
550         gst_caps_features_is_equal(features, features2))
551         gst_vaapidecode_update_src_caps (decode, state);
552     else if (has_texture_upload_meta &&
553              !gst_caps_features_is_equal(features, features2)) {
554         gst_video_info_set_format(&state->info, GST_VIDEO_FORMAT_RGBA,
555                                   state->info.width,
556                                   state->info.height);
557         gst_vaapidecode_update_src_caps(decode, state);
558     }
559     gst_caps_features_free(features2);
560 #endif
561
562     gst_video_codec_state_unref(state);
563
564     gst_video_info_init(&vi);
565     gst_video_info_from_caps(&vi, caps);
566     if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED)
567         gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_I420,
568             GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
569
570     g_return_val_if_fail(GST_VAAPI_PLUGIN_BASE_DISPLAY(decode) != NULL, FALSE);
571
572     if (gst_query_get_n_allocation_pools(query) > 0) {
573         gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
574         size = MAX(size, vi.size);
575         update_pool = TRUE;
576
577         /* Check whether downstream element proposed a bufferpool but did
578            not provide a correct propose_allocation() implementation */
579         has_video_alignment = gst_buffer_pool_has_option(pool,
580             GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
581     }
582     else {
583         pool = NULL;
584         size = vi.size;
585         min = max = 0;
586         update_pool = FALSE;
587     }
588
589     if (!pool || !gst_buffer_pool_has_option(pool,
590             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
591         GST_INFO("no pool or doesn't support GstVaapiVideoMeta, "
592             "making new pool");
593         if (pool)
594             gst_object_unref(pool);
595         pool = gst_vaapi_video_buffer_pool_new(
596             GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
597         if (!pool)
598             goto error_create_pool;
599
600         config = gst_buffer_pool_get_config(pool);
601         gst_buffer_pool_config_set_params(config, caps, size, min, max);
602         gst_buffer_pool_config_add_option(config,
603             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
604         gst_buffer_pool_set_config(pool, config);
605     }
606
607     if (has_video_meta) {
608         config = gst_buffer_pool_get_config(pool);
609         gst_buffer_pool_config_add_option(config,
610             GST_BUFFER_POOL_OPTION_VIDEO_META);
611 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
612         if (decode->has_texture_upload_meta)
613             gst_buffer_pool_config_add_option(config,
614                 GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
615 #endif
616         gst_buffer_pool_set_config(pool, config);
617     }
618     else if (has_video_alignment) {
619         config = gst_buffer_pool_get_config(pool);
620         gst_buffer_pool_config_add_option(config,
621             GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
622         gst_buffer_pool_set_config(pool, config);
623     }
624
625     if (update_pool)
626         gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
627     else
628         gst_query_add_allocation_pool(query, pool, size, min, max);
629     if (pool)
630         gst_object_unref(pool);
631     return TRUE;
632
633     /* ERRORS */
634 error_no_caps:
635     {
636         GST_ERROR("no caps specified");
637         return FALSE;
638     }
639 error_create_pool:
640     {
641         GST_ERROR("failed to create buffer pool");
642         return FALSE;
643     }
644 }
645 #endif
646
647 static inline gboolean
648 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
649 {
650     return gst_vaapi_plugin_base_ensure_display(GST_VAAPI_PLUGIN_BASE(decode));
651 }
652
653 static inline guint
654 gst_vaapi_codec_from_caps(GstCaps *caps)
655 {
656     return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
657 }
658
659 static gboolean
660 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
661 {
662     GstVaapiDisplay *dpy;
663
664     if (!gst_vaapidecode_ensure_display(decode))
665         return FALSE;
666     dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY(decode);
667
668     switch (gst_vaapi_codec_from_caps(caps)) {
669     case GST_VAAPI_CODEC_MPEG2:
670         decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
671         break;
672     case GST_VAAPI_CODEC_MPEG4:
673     case GST_VAAPI_CODEC_H263:
674         decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
675         break;
676     case GST_VAAPI_CODEC_H264:
677         decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
678
679         /* Set the stream buffer alignment for better optimizations */
680         if (decode->decoder && caps) {
681             GstStructure * const structure = gst_caps_get_structure(caps, 0);
682             const gchar *str = NULL;
683
684             if ((str = gst_structure_get_string(structure, "alignment"))) {
685                 GstVaapiStreamAlignH264 alignment;
686                 if (g_strcmp0(str, "au") == 0)
687                     alignment = GST_VAAPI_STREAM_ALIGN_H264_AU;
688                 else if (g_strcmp0(str, "nal") == 0)
689                     alignment = GST_VAAPI_STREAM_ALIGN_H264_NALU;
690                 else
691                     alignment = GST_VAAPI_STREAM_ALIGN_H264_NONE;
692                 gst_vaapi_decoder_h264_set_alignment(
693                     GST_VAAPI_DECODER_H264(decode->decoder), alignment);
694             }
695         }
696         break;
697     case GST_VAAPI_CODEC_WMV3:
698     case GST_VAAPI_CODEC_VC1:
699         decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
700         break;
701 #if USE_JPEG_DECODER
702     case GST_VAAPI_CODEC_JPEG:
703         decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
704         break;
705 #endif
706 #if USE_VP8_DECODER
707     case GST_VAAPI_CODEC_VP8:
708         decode->decoder = gst_vaapi_decoder_vp8_new(dpy, caps);
709         break;
710 #endif
711     default:
712         decode->decoder = NULL;
713         break;
714     }
715     if (!decode->decoder)
716         return FALSE;
717
718     gst_vaapi_decoder_set_codec_state_changed_func(decode->decoder,
719         gst_vaapi_decoder_state_changed, decode);
720
721     decode->decoder_caps = gst_caps_ref(caps);
722     return gst_pad_start_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode),
723         (GstTaskFunction)gst_vaapidecode_decode_loop, decode, NULL);
724 }
725
726 static void
727 gst_vaapidecode_destroy(GstVaapiDecode *decode)
728 {
729     gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
730     gst_vaapi_decoder_replace(&decode->decoder, NULL);
731     gst_caps_replace(&decode->decoder_caps, NULL);
732     gst_vaapidecode_release(decode);
733 }
734
735 static gboolean
736 gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
737 {
738     GstVaapiCodec codec;
739
740     decode->has_texture_upload_meta = FALSE;
741
742     /* Reset tracked frame size */
743     decode->current_frame_size = 0;
744
745     /* Reset timers if hard reset was requested (e.g. seek) */
746     if (hard) {
747         GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
748         GstVideoCodecFrame *out_frame = NULL;
749
750         gst_vaapi_decoder_flush(decode->decoder);
751         GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
752         gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
753         GST_VIDEO_DECODER_STREAM_LOCK(vdec);
754         decode->decoder_loop_status = GST_FLOW_OK;
755
756         /* Purge all decoded frames as we don't need them (e.g. seek) */
757         while (gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
758                    &out_frame, 0) == GST_VAAPI_DECODER_STATUS_SUCCESS) {
759             gst_video_codec_frame_unref(out_frame);
760             out_frame = NULL;
761         }
762     }
763
764     /* Only reset decoder if codec type changed */
765     else if (decode->decoder && decode->decoder_caps) {
766         if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
767             return TRUE;
768         codec = gst_vaapi_codec_from_caps(caps);
769         if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
770             return TRUE;
771     }
772
773     gst_vaapidecode_destroy(decode);
774     return gst_vaapidecode_create(decode, caps);
775 }
776
777 static void
778 gst_vaapidecode_finalize(GObject *object)
779 {
780     GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
781
782     gst_caps_replace(&decode->sinkpad_caps, NULL);
783     gst_caps_replace(&decode->srcpad_caps,  NULL);
784     gst_caps_replace(&decode->allowed_caps, NULL);
785
786     g_cond_clear(&decode->decoder_finish_done);
787     g_cond_clear(&decode->decoder_ready);
788     g_mutex_clear(&decode->decoder_mutex);
789
790     gst_vaapi_plugin_base_finalize(GST_VAAPI_PLUGIN_BASE(object));
791     G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
792 }
793
794 static gboolean
795 gst_vaapidecode_open(GstVideoDecoder *vdec)
796 {
797     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
798     GstVaapiDisplay * const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY(decode);
799     gboolean success;
800
801     if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(decode)))
802         return FALSE;
803
804     /* Let GstVideoContext ask for a proper display to its neighbours */
805     /* Note: steal old display that may be allocated from get_caps()
806        so that to retain a reference to it, thus avoiding extra
807        initialization steps if we turn out to simply re-use the
808        existing (cached) VA display */
809     GST_VAAPI_PLUGIN_BASE_DISPLAY(decode) = NULL;
810     success = gst_vaapidecode_ensure_display(decode);
811     if (old_display)
812         gst_vaapi_display_unref(old_display);
813     return success;
814 }
815
816 static gboolean
817 gst_vaapidecode_close(GstVideoDecoder *vdec)
818 {
819     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
820
821     gst_vaapidecode_destroy(decode);
822     gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(decode));
823     return TRUE;
824 }
825
826 static gboolean
827 gst_vaapidecode_reset(GstVideoDecoder *vdec, gboolean hard)
828 {
829     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
830
831     /* In GStreamer 1.0 context, this means a flush */
832     if (decode->decoder && !hard && !gst_vaapidecode_flush(vdec))
833         return FALSE;
834     return gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, hard);
835 }
836
837 static gboolean
838 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
839 {
840     GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(vdec);
841     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
842
843     if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
844         return FALSE;
845     if (!gst_vaapidecode_update_src_caps(decode, state))
846         return FALSE;
847     if (!gst_video_decoder_negotiate(vdec))
848         return FALSE;
849     if (!gst_vaapi_plugin_base_set_caps(plugin, decode->sinkpad_caps,
850             decode->srcpad_caps))
851         return FALSE;
852     if (!gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, FALSE))
853         return FALSE;
854     return TRUE;
855 }
856
857 static GstFlowReturn
858 gst_vaapidecode_parse_frame(GstVideoDecoder *vdec,
859     GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
860 {
861     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
862     GstVaapiDecoderStatus status;
863     GstFlowReturn ret;
864     guint got_unit_size;
865     gboolean got_frame;
866
867     status = gst_vaapi_decoder_parse(decode->decoder, frame,
868         adapter, at_eos, &got_unit_size, &got_frame);
869
870     switch (status) {
871     case GST_VAAPI_DECODER_STATUS_SUCCESS:
872         if (got_unit_size > 0) {
873             gst_video_decoder_add_to_frame(vdec, got_unit_size);
874             decode->current_frame_size += got_unit_size;
875         }
876         if (got_frame) {
877             ret = gst_video_decoder_have_frame(vdec);
878             decode->current_frame_size = 0;
879         }
880         else
881             ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
882         break;
883     case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
884         ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
885         break;
886     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
887     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
888     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
889         GST_WARNING("parse error %d", status);
890         ret = GST_FLOW_NOT_SUPPORTED;
891         decode->current_frame_size = 0;
892         break;
893     default:
894         GST_ERROR("parse error %d", status);
895         ret = GST_FLOW_EOS;
896         decode->current_frame_size = 0;
897         break;
898     }
899     return ret;
900 }
901
902 static GstFlowReturn
903 gst_vaapidecode_parse(GstVideoDecoder *vdec,
904     GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
905 {
906     GstFlowReturn ret;
907
908     do {
909         ret = gst_vaapidecode_parse_frame(vdec, frame, adapter, at_eos);
910     } while (ret == GST_VAAPI_DECODE_FLOW_PARSE_DATA);
911     return ret;
912 }
913
914 static GstStateChangeReturn
915 gst_vaapidecode_change_state (GstElement * element, GstStateChange transition)
916 {
917     GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
918
919     switch (transition) {
920     case GST_STATE_CHANGE_PAUSED_TO_READY:
921         gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
922         break;
923     default:
924         break;
925     }
926     return GST_ELEMENT_CLASS(gst_vaapidecode_parent_class)->change_state(
927         element, transition);
928 }
929
930 static void
931 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
932 {
933     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
934     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
935     GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
936     GstPadTemplate *pad_template;
937
938     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
939                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
940
941     gst_vaapi_plugin_base_class_init(GST_VAAPI_PLUGIN_BASE_CLASS(klass));
942
943     object_class->finalize   = gst_vaapidecode_finalize;
944
945     element_class->change_state =
946         GST_DEBUG_FUNCPTR(gst_vaapidecode_change_state);
947
948     vdec_class->open         = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
949     vdec_class->close        = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
950     vdec_class->set_format   = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
951     vdec_class->reset        = GST_DEBUG_FUNCPTR(gst_vaapidecode_reset);
952     vdec_class->parse        = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
953     vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
954     vdec_class->finish       = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish);
955
956 #if GST_CHECK_VERSION(1,0,0)
957     vdec_class->decide_allocation =
958         GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
959 #endif
960
961     gst_element_class_set_static_metadata(element_class,
962         "VA-API decoder",
963         "Codec/Decoder/Video",
964         GST_PLUGIN_DESC,
965         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
966
967     /* sink pad */
968     pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
969     gst_element_class_add_pad_template(element_class, pad_template);
970
971     /* src pad */
972     pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
973     gst_element_class_add_pad_template(element_class, pad_template);
974 }
975
976 static gboolean
977 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
978 {
979     GstCaps *caps, *allowed_caps;
980     GArray *profiles;
981     guint i;
982
983     if (decode->allowed_caps)
984         return TRUE;
985
986     if (!gst_vaapidecode_ensure_display(decode))
987         goto error_no_display;
988
989     profiles = gst_vaapi_display_get_decode_profiles(
990         GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
991     if (!profiles)
992         goto error_no_profiles;
993
994     allowed_caps = gst_caps_new_empty();
995     if (!allowed_caps)
996         goto error_no_memory;
997
998     for (i = 0; i < profiles->len; i++) {
999         const GstVaapiProfile profile =
1000             g_array_index(profiles, GstVaapiProfile, i);
1001         const gchar *media_type_name;
1002
1003         media_type_name = gst_vaapi_profile_get_media_type_name(profile);
1004         if (!media_type_name)
1005             continue;
1006
1007         caps = gst_caps_from_string(media_type_name);
1008         if (!caps)
1009             continue;
1010         allowed_caps = gst_caps_merge(allowed_caps, caps);
1011     }
1012     decode->allowed_caps = allowed_caps;
1013
1014     g_array_unref(profiles);
1015     return TRUE;
1016
1017     /* ERRORS */
1018 error_no_display:
1019     {
1020         GST_ERROR("failed to retrieve VA display");
1021         return FALSE;
1022     }
1023 error_no_profiles:
1024     {
1025         GST_ERROR("failed to retrieve VA decode profiles");
1026         return FALSE;
1027     }
1028 error_no_memory:
1029     {
1030         GST_ERROR("failed to allocate allowed-caps set");
1031         g_array_unref(profiles);
1032         return FALSE;
1033     }
1034 }
1035
1036 static GstCaps *
1037 gst_vaapidecode_get_caps(GstPad *pad)
1038 {
1039     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
1040
1041     if (!gst_vaapidecode_ensure_allowed_caps(decode))
1042         return gst_caps_new_empty();
1043
1044     return gst_caps_ref(decode->allowed_caps);
1045 }
1046
1047 static gboolean
1048 gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
1049 {
1050     GstVaapiDecode * const decode =
1051         GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
1052     GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(decode);
1053     gboolean res;
1054
1055     GST_INFO_OBJECT(decode, "query type %s", GST_QUERY_TYPE_NAME(query));
1056
1057     if (gst_vaapi_reply_to_query(query, plugin->display)) {
1058         GST_DEBUG("sharing display %p", plugin->display);
1059         res = TRUE;
1060     }
1061     else if (GST_PAD_IS_SINK(pad)) {
1062         switch (GST_QUERY_TYPE(query)) {
1063 #if GST_CHECK_VERSION(1,0,0)
1064         case GST_QUERY_CAPS: {
1065             GstCaps * const caps = gst_vaapidecode_get_caps(pad);
1066             gst_query_set_caps_result(query, caps);
1067             gst_caps_unref(caps);
1068             res = TRUE;
1069             break;
1070         }
1071 #endif
1072         default:
1073             res = GST_PAD_QUERY_FUNCTION_CALL(plugin->sinkpad_query, pad,
1074                 parent, query);
1075             break;
1076         }
1077     }
1078     else
1079         res = GST_PAD_QUERY_FUNCTION_CALL(plugin->srcpad_query, pad,
1080             parent, query);
1081
1082     gst_object_unref(decode);
1083     return res;
1084 }
1085
1086 static void
1087 gst_vaapidecode_init(GstVaapiDecode *decode)
1088 {
1089     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
1090     GstPad *pad;
1091
1092     gst_vaapi_plugin_base_init(GST_VAAPI_PLUGIN_BASE(decode), GST_CAT_DEFAULT);
1093
1094     decode->decoder             = NULL;
1095     decode->decoder_caps        = NULL;
1096     decode->allowed_caps        = NULL;
1097     decode->decoder_loop_status = GST_FLOW_OK;
1098
1099     g_mutex_init(&decode->decoder_mutex);
1100     g_cond_init(&decode->decoder_ready);
1101     g_cond_init(&decode->decoder_finish_done);
1102
1103     gst_video_decoder_set_packetized(vdec, FALSE);
1104
1105     /* Pad through which data comes in to the element */
1106     pad = GST_VAAPI_PLUGIN_BASE_SINK_PAD(decode);
1107     gst_pad_set_query_function(pad, gst_vaapidecode_query);
1108 #if !GST_CHECK_VERSION(1,0,0)
1109     gst_pad_set_getcaps_function(pad, gst_vaapidecode_get_caps);
1110 #endif
1111
1112     /* Pad through which data goes out of the element */
1113     pad = GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode);
1114     gst_pad_set_query_function(pad, gst_vaapidecode_query);
1115 }