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