vaapidecode: fix srcpad caps for GStreamer 1.2.
[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
34 #include "gstvaapidecode.h"
35 #include "gstvaapipluginutil.h"
36 #include "gstvaapivideocontext.h"
37 #include "gstvaapivideobuffer.h"
38 #if GST_CHECK_VERSION(1,1,0)
39 #include "gstvaapivideometa_texture.h"
40 #endif
41 #if GST_CHECK_VERSION(1,0,0)
42 #include "gstvaapivideobufferpool.h"
43 #include "gstvaapivideomemory.h"
44 #endif
45
46 #include <gst/vaapi/gstvaapidecoder_h264.h>
47 #include <gst/vaapi/gstvaapidecoder_jpeg.h>
48 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
49 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
50 #include <gst/vaapi/gstvaapidecoder_vc1.h>
51
52 #define GST_PLUGIN_NAME "vaapidecode"
53 #define GST_PLUGIN_DESC "A VA-API based video decoder"
54
55 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode);
56 #define GST_CAT_DEFAULT gst_debug_vaapidecode
57
58 /* Default templates */
59 #define GST_CAPS_CODEC(CODEC) CODEC "; "
60
61 static const char gst_vaapidecode_sink_caps_str[] =
62     GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
63     GST_CAPS_CODEC("video/mpeg, mpegversion=4")
64     GST_CAPS_CODEC("video/x-divx")
65     GST_CAPS_CODEC("video/x-xvid")
66     GST_CAPS_CODEC("video/x-h263")
67     GST_CAPS_CODEC("video/x-h264")
68     GST_CAPS_CODEC("video/x-wmv")
69     GST_CAPS_CODEC("image/jpeg")
70     ;
71
72 static const char gst_vaapidecode_src_caps_str[] =
73 #if GST_CHECK_VERSION(1,1,0)
74     GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
75         GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ";"
76     GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
77         GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA");
78 #else
79     GST_VAAPI_SURFACE_CAPS;
80 #endif
81
82 static GstStaticPadTemplate gst_vaapidecode_sink_factory =
83     GST_STATIC_PAD_TEMPLATE(
84         "sink",
85         GST_PAD_SINK,
86         GST_PAD_ALWAYS,
87         GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));
88
89 static GstStaticPadTemplate gst_vaapidecode_src_factory =
90     GST_STATIC_PAD_TEMPLATE(
91         "src",
92         GST_PAD_SRC,
93         GST_PAD_ALWAYS,
94         GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
95
96 /* GstImplementsInterface interface */
97 #if !GST_CHECK_VERSION(1,0,0)
98 static gboolean
99 gst_vaapidecode_implements_interface_supported(
100     GstImplementsInterface *iface,
101     GType                   type
102 )
103 {
104     return (type == GST_TYPE_VIDEO_CONTEXT);
105 }
106
107 static void
108 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface)
109 {
110     iface->supported = gst_vaapidecode_implements_interface_supported;
111 }
112 #endif
113
114 /* GstVideoContext interface */
115 #if !GST_CHECK_VERSION(1,1,0)
116 static void
117 gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
118     const GValue *value)
119 {
120     GstVaapiDecode *decode = GST_VAAPIDECODE (context);
121     gst_vaapi_set_display (type, value, &decode->display);
122 }
123
124 static void
125 gst_video_context_interface_init(GstVideoContextInterface *iface)
126 {
127     iface->set_context = gst_vaapidecode_set_video_context;
128 }
129
130 #define GstVideoContextClass GstVideoContextInterface
131 #endif
132
133 G_DEFINE_TYPE_WITH_CODE(
134     GstVaapiDecode,
135     gst_vaapidecode,
136     GST_TYPE_VIDEO_DECODER,
137 #if !GST_CHECK_VERSION(1,0,0)
138     G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
139                           gst_vaapidecode_implements_iface_init);
140 #endif
141 #if !GST_CHECK_VERSION(1,1,0)
142     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
143                           gst_video_context_interface_init)
144 #endif
145     )
146
147 static gboolean
148 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
149     const GstVideoCodecState *ref_state);
150
151 static void
152 gst_vaapi_decoder_state_changed(GstVaapiDecoder *decoder,
153     const GstVideoCodecState *codec_state, gpointer user_data)
154 {
155     GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
156
157     g_assert(decode->decoder == decoder);
158
159     gst_vaapidecode_update_src_caps(decode, codec_state);
160 }
161
162 static inline gboolean
163 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
164 {
165     gst_caps_replace(&decode->sinkpad_caps, caps);
166     return TRUE;
167 }
168
169 static gboolean
170 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
171     const GstVideoCodecState *ref_state)
172 {
173     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
174     GstVideoCodecState *state;
175     GstVideoInfo *vi, vis;
176
177     state = gst_video_decoder_set_output_state(vdec,
178         GST_VIDEO_INFO_FORMAT(&ref_state->info),
179         ref_state->info.width, ref_state->info.height,
180         (GstVideoCodecState *)ref_state);
181     if (!state)
182         return FALSE;
183
184     vi = &state->info;
185     if (GST_VIDEO_INFO_FORMAT(vi) == GST_VIDEO_FORMAT_ENCODED) {
186         gst_video_info_init(&vis);
187         gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12,
188             GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
189         vi->size = vis.size;
190     }
191     gst_video_codec_state_unref(state);
192
193 #if GST_CHECK_VERSION(1,1,0)
194     vis = *vi;
195     if (GST_VIDEO_INFO_FORMAT(vi) == GST_VIDEO_FORMAT_ENCODED) {
196         /* XXX: this is a workaround until auto-plugging is fixed when
197            format=ENCODED + memory:VASurface caps feature are provided.
198            Meanwhile, providing a random format here works but this is
199            a terribly wrong thing per se. */
200         gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12,
201             GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
202     }
203     state->caps = gst_video_info_to_caps(&vis);
204 #else
205     /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
206        reconstruct suitable caps for "encoded" video formats */
207     state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
208     if (!state->caps)
209         return FALSE;
210
211     gst_caps_set_simple(state->caps,
212         "type", G_TYPE_STRING, "vaapi",
213         "opengl", G_TYPE_BOOLEAN, USE_GLX,
214         "width", G_TYPE_INT, vi->width,
215         "height", G_TYPE_INT, vi->height,
216         "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
217         "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d,
218         NULL);
219
220     gst_caps_set_interlaced(state->caps, vi);
221 #endif
222     gst_caps_replace(&decode->srcpad_caps, state->caps);
223     return TRUE;
224 }
225
226 static void
227 gst_vaapidecode_release(GstVaapiDecode *decode)
228 {
229     g_mutex_lock(&decode->decoder_mutex);
230     g_cond_signal(&decode->decoder_ready);
231     g_mutex_unlock(&decode->decoder_mutex);
232 }
233
234 static GstFlowReturn
235 gst_vaapidecode_decode_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
236 {
237     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
238     GstVaapiDecoderStatus status;
239     GstFlowReturn ret;
240     gint64 end_time;
241
242     if (decode->render_time_base)
243         end_time = decode->render_time_base;
244     else
245         end_time = g_get_monotonic_time();
246     end_time += GST_TIME_AS_USECONDS(decode->last_buffer_time);
247     end_time += G_TIME_SPAN_SECOND;
248
249     /* Decode current frame */
250     for (;;) {
251         status = gst_vaapi_decoder_decode(decode->decoder, frame);
252         if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
253             gboolean was_signalled;
254             GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
255             g_mutex_lock(&decode->decoder_mutex);
256             was_signalled = g_cond_wait_until(
257                 &decode->decoder_ready,
258                 &decode->decoder_mutex,
259                 end_time
260             );
261             g_mutex_unlock(&decode->decoder_mutex);
262             GST_VIDEO_DECODER_STREAM_LOCK(vdec);
263             if (was_signalled)
264                 continue;
265             goto error_decode_timeout;
266         }
267         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
268             goto error_decode;
269         break;
270     }
271     return GST_FLOW_OK;
272
273     /* ERRORS */
274 error_decode_timeout:
275     {
276         GST_WARNING("decode timeout. Decoder required a VA surface but none "
277                     "got available within one second");
278         return GST_FLOW_EOS;
279     }
280 error_decode:
281     {
282         GST_ERROR("decode error %d", status);
283         switch (status) {
284         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
285         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
286         case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
287             ret = GST_FLOW_NOT_SUPPORTED;
288             break;
289         default:
290             ret = GST_FLOW_EOS;
291             break;
292         }
293         gst_video_decoder_drop_frame(vdec, frame);
294         return ret;
295     }
296 }
297
298 static GstFlowReturn
299 gst_vaapidecode_push_decoded_frame(GstVideoDecoder *vdec)
300 {
301     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
302     GstVaapiSurfaceProxy *proxy;
303     GstVaapiDecoderStatus status;
304     GstVideoCodecFrame *out_frame;
305     GstFlowReturn ret;
306 #if GST_CHECK_VERSION(1,0,0)
307     const GstVaapiRectangle *crop_rect;
308     GstVaapiVideoMeta *meta;
309     guint flags;
310 #endif
311
312     status = gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
313         &out_frame, 100000);
314     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
315         return GST_VIDEO_DECODER_FLOW_NEED_DATA;
316
317     if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
318         proxy = gst_video_codec_frame_get_user_data(out_frame);
319
320         gst_vaapi_surface_proxy_set_destroy_notify(proxy,
321             (GDestroyNotify)gst_vaapidecode_release, decode);
322
323 #if GST_CHECK_VERSION(1,0,0)
324         ret = gst_video_decoder_allocate_output_frame(vdec, out_frame);
325         if (ret != GST_FLOW_OK)
326             goto error_create_buffer;
327
328         meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer);
329         if (!meta)
330             goto error_get_meta;
331         gst_vaapi_video_meta_set_surface_proxy(meta, proxy);
332
333         flags = gst_vaapi_surface_proxy_get_flags(proxy);
334         if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
335             guint out_flags = GST_VIDEO_BUFFER_FLAG_INTERLACED;
336             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
337                 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
338             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
339                 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
340             if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
341                 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
342             GST_BUFFER_FLAG_SET(out_frame->output_buffer, out_flags);
343         }
344
345         crop_rect = gst_vaapi_surface_proxy_get_crop_rect(proxy);
346         if (crop_rect) {
347             GstVideoCropMeta * const crop_meta =
348                 gst_buffer_add_video_crop_meta(out_frame->output_buffer);
349             if (crop_meta) {
350                 crop_meta->x = crop_rect->x;
351                 crop_meta->y = crop_rect->y;
352                 crop_meta->width = crop_rect->width;
353                 crop_meta->height = crop_rect->height;
354             }
355         }
356
357 #if GST_CHECK_VERSION(1,1,0)
358         if (decode->has_texture_upload_meta)
359             gst_buffer_add_texture_upload_meta(out_frame->output_buffer);
360 #endif
361 #else
362         out_frame->output_buffer =
363             gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
364         if (!out_frame->output_buffer)
365             goto error_create_buffer;
366 #endif
367     }
368
369     ret = gst_video_decoder_finish_frame(vdec, out_frame);
370     if (ret != GST_FLOW_OK)
371         goto error_commit_buffer;
372
373     /* Estimate when this frame would no longer be needed for rendering */
374     if (GST_CLOCK_TIME_IS_VALID(out_frame->pts)) {
375         if (!decode->render_time_base)
376             decode->render_time_base = g_get_monotonic_time() -
377                 GST_TIME_AS_USECONDS(out_frame->pts);
378         decode->last_buffer_time = out_frame->pts;
379         if (GST_CLOCK_TIME_IS_VALID(out_frame->duration))
380             decode->last_buffer_time += out_frame->duration;
381         else
382             decode->last_buffer_time += GST_SECOND;
383     }
384     else {
385         decode->render_time_base = 0;
386         decode->last_buffer_time = 0;
387     }
388
389     gst_video_codec_frame_unref(out_frame);
390     return GST_FLOW_OK;
391
392     /* ERRORS */
393 error_create_buffer:
394     {
395         const GstVaapiID surface_id =
396             gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
397
398         GST_ERROR("video sink failed to create video buffer for proxy'ed "
399                   "surface %" GST_VAAPI_ID_FORMAT,
400                   GST_VAAPI_ID_ARGS(surface_id));
401         gst_video_decoder_drop_frame(vdec, out_frame);
402         gst_video_codec_frame_unref(out_frame);
403         return GST_FLOW_EOS;
404     }
405 #if GST_CHECK_VERSION(1,0,0)
406 error_get_meta:
407     {
408         GST_ERROR("failed to get vaapi video meta attached to video buffer");
409         gst_video_decoder_drop_frame(vdec, out_frame);
410         gst_video_codec_frame_unref(out_frame);
411         return GST_FLOW_EOS;
412     }
413 #endif
414 error_commit_buffer:
415     {
416         if (ret != GST_FLOW_FLUSHING)
417             GST_ERROR("video sink rejected the video buffer (error %d)", ret);
418         gst_video_codec_frame_unref(out_frame);
419         return GST_FLOW_EOS;
420     }
421 }
422
423 static GstFlowReturn
424 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
425 {
426     GstFlowReturn ret;
427
428     /* Make sure to release the base class stream lock so that decode
429        loop can call gst_video_decoder_finish_frame() without blocking */
430     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
431     ret = gst_vaapidecode_decode_frame(vdec, frame);
432     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
433     return ret;
434 }
435
436 static void
437 gst_vaapidecode_decode_loop(GstVaapiDecode *decode)
438 {
439     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
440     GstFlowReturn ret;
441
442     ret = gst_vaapidecode_push_decoded_frame(vdec);
443     if (ret == GST_FLOW_OK)
444         return;
445
446     /* If invoked from gst_vaapidecode_finish(), then return right
447        away no matter the errors, or the GstVaapiDecoder needs further
448        data to complete decoding (there no more data to feed in) */
449     if (decode->decoder_finish) {
450         g_mutex_lock(&decode->decoder_mutex);
451         g_cond_signal(&decode->decoder_finish_done);
452         g_mutex_unlock(&decode->decoder_mutex);
453         return;
454     }
455
456     /* Suspend the task if an error occurred */
457     if (ret != GST_VIDEO_DECODER_FLOW_NEED_DATA)
458         gst_pad_pause_task(decode->srcpad);
459 }
460
461 static GstFlowReturn
462 gst_vaapidecode_finish(GstVideoDecoder *vdec)
463 {
464     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
465     GstVaapiDecoderStatus status;
466
467     /* If there is something in GstVideoDecoder's output adapter, then
468        submit the frame for decoding */
469     if (decode->current_frame_size)
470         gst_video_decoder_have_frame(vdec);
471
472     status = gst_vaapi_decoder_flush(decode->decoder);
473     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
474         goto error_flush;
475
476     /* Make sure the decode loop function has a chance to return, thus
477        possibly unlocking gst_video_decoder_finish_frame() */
478     GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
479     g_mutex_lock(&decode->decoder_mutex);
480     decode->decoder_finish = TRUE;
481     g_cond_wait(&decode->decoder_finish_done, &decode->decoder_mutex);
482     g_mutex_unlock(&decode->decoder_mutex);
483     gst_pad_stop_task(decode->srcpad);
484     GST_VIDEO_DECODER_STREAM_LOCK(vdec);
485     return GST_FLOW_OK;
486
487     /* ERRORS */
488 error_flush:
489     {
490         GST_ERROR("failed to flush decoder (status %d)", status);
491         return GST_FLOW_EOS;
492     }
493 }
494
495 #if GST_CHECK_VERSION(1,0,0)
496 static gboolean
497 gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
498 {
499     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
500     GstCaps *caps = NULL;
501     GstBufferPool *pool;
502     GstStructure *config;
503     GstVideoInfo vi;
504     guint size, min, max;
505     gboolean need_pool, update_pool;
506
507     gst_query_parse_allocation(query, &caps, &need_pool);
508
509     if (!caps)
510         goto error_no_caps;
511
512     gst_video_info_init(&vi);
513     gst_video_info_from_caps(&vi, caps);
514     if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED)
515         gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
516             GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
517
518     g_return_val_if_fail(decode->display != NULL, FALSE);
519
520     if (gst_query_get_n_allocation_pools(query) > 0) {
521         gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
522         size = MAX(size, vi.size);
523         update_pool = TRUE;
524     }
525     else {
526         pool = NULL;
527         size = vi.size;
528         min = max = 0;
529         update_pool = FALSE;
530     }
531
532     if (!pool || !gst_buffer_pool_has_option(pool,
533             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
534         GST_INFO("no pool or doesn't support GstVaapiVideoMeta, "
535             "making new pool");
536         pool = gst_vaapi_video_buffer_pool_new(decode->display);
537         if (!pool)
538             goto error_create_pool;
539
540         config = gst_buffer_pool_get_config(pool);
541         gst_buffer_pool_config_set_params(config, caps, size, min, max);
542         gst_buffer_pool_config_add_option(config,
543             GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
544         gst_buffer_pool_set_config(pool, config);
545     }
546
547     decode->has_texture_upload_meta = FALSE;
548     if (gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL)) {
549         config = gst_buffer_pool_get_config(pool);
550         gst_buffer_pool_config_add_option(config,
551             GST_BUFFER_POOL_OPTION_VIDEO_META);
552         gst_buffer_pool_set_config(pool, config);
553 #if GST_CHECK_VERSION(1,1,0)
554         decode->has_texture_upload_meta = gst_query_find_allocation_meta(query,
555             GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
556 #endif
557     }
558
559     if (update_pool)
560         gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
561     else
562         gst_query_add_allocation_pool(query, pool, size, min, max);
563     if (pool)
564         gst_object_unref(pool);
565     return TRUE;
566
567     /* ERRORS */
568 error_no_caps:
569     {
570         GST_ERROR("no caps specified");
571         return FALSE;
572     }
573 error_create_pool:
574     {
575         GST_ERROR("failed to create buffer pool");
576         return FALSE;
577     }
578 }
579 #endif
580
581 #if GST_CHECK_VERSION(1,1,0)
582 static void
583 gst_vaapidecode_set_context(GstElement *element, GstContext *context)
584 {
585     GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
586     GstVaapiDisplay *display = NULL;
587
588     if (gst_vaapi_video_context_get_display(context, &display)) {
589         GST_INFO_OBJECT(element, "set display %p", display);
590         gst_vaapi_display_replace(&decode->display, display);
591     }
592 }
593 #endif
594
595 static inline gboolean
596 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
597 {
598     return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY,
599         &decode->display);
600 }
601
602 static inline guint
603 gst_vaapi_codec_from_caps(GstCaps *caps)
604 {
605     return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
606 }
607
608 static gboolean
609 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
610 {
611     GstVaapiDisplay *dpy;
612
613     if (!gst_vaapidecode_ensure_display(decode))
614         return FALSE;
615     dpy = decode->display;
616
617     switch (gst_vaapi_codec_from_caps(caps)) {
618     case GST_VAAPI_CODEC_MPEG2:
619         decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
620         break;
621     case GST_VAAPI_CODEC_MPEG4:
622     case GST_VAAPI_CODEC_H263:
623         decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
624         break;
625     case GST_VAAPI_CODEC_H264:
626         decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
627         break;
628     case GST_VAAPI_CODEC_WMV3:
629     case GST_VAAPI_CODEC_VC1:
630         decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
631         break;
632 #if USE_JPEG_DECODER
633     case GST_VAAPI_CODEC_JPEG:
634         decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
635         break;
636 #endif
637     default:
638         decode->decoder = NULL;
639         break;
640     }
641     if (!decode->decoder)
642         return FALSE;
643
644     gst_vaapi_decoder_set_codec_state_changed_func(decode->decoder,
645         gst_vaapi_decoder_state_changed, decode);
646
647     decode->decoder_caps = gst_caps_ref(caps);
648     return gst_pad_start_task(decode->srcpad,
649         (GstTaskFunction)gst_vaapidecode_decode_loop, decode, NULL);
650 }
651
652 static void
653 gst_vaapidecode_destroy(GstVaapiDecode *decode)
654 {
655     gst_pad_stop_task(decode->srcpad);
656     gst_vaapi_decoder_replace(&decode->decoder, NULL);
657     gst_caps_replace(&decode->decoder_caps, NULL);
658     gst_vaapidecode_release(decode);
659 }
660
661 static gboolean
662 gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
663 {
664     GstVaapiCodec codec;
665
666     decode->has_texture_upload_meta = FALSE;
667
668     /* Reset timers if hard reset was requested (e.g. seek) */
669     if (hard) {
670         decode->render_time_base = 0;
671         decode->last_buffer_time = 0;
672     }
673
674     /* Only reset decoder if codec type changed */
675     else if (decode->decoder && decode->decoder_caps) {
676         if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
677             return TRUE;
678         codec = gst_vaapi_codec_from_caps(caps);
679         if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
680             return TRUE;
681     }
682
683     /* Reset tracked frame size */
684     decode->current_frame_size = 0;
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     gst_vaapi_display_replace(&decode->display, NULL);
700
701     g_cond_clear(&decode->decoder_finish_done);
702     g_cond_clear(&decode->decoder_ready);
703     g_mutex_clear(&decode->decoder_mutex);
704
705     G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
706 }
707
708 static gboolean
709 gst_vaapidecode_open(GstVideoDecoder *vdec)
710 {
711     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
712     GstVaapiDisplay * const old_display = decode->display;
713     gboolean success;
714
715     /* Let GstVideoContext ask for a proper display to its neighbours */
716     /* Note: steal old display that may be allocated from get_caps()
717        so that to retain a reference to it, thus avoiding extra
718        initialization steps if we turn out to simply re-use the
719        existing (cached) VA display */
720     decode->display = NULL;
721     success = gst_vaapidecode_ensure_display(decode);
722     if (old_display)
723         gst_vaapi_display_unref(old_display);
724     return success;
725 }
726
727 static gboolean
728 gst_vaapidecode_close(GstVideoDecoder *vdec)
729 {
730     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
731
732     gst_vaapidecode_destroy(decode);
733     gst_vaapi_display_replace(&decode->display, NULL);
734     return TRUE;
735 }
736
737 static gboolean
738 gst_vaapidecode_reset(GstVideoDecoder *vdec, gboolean hard)
739 {
740     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
741
742     return gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, hard);
743 }
744
745 static gboolean
746 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
747 {
748     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
749
750     if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
751         return FALSE;
752     if (!gst_vaapidecode_update_src_caps(decode, state))
753         return FALSE;
754     if (!gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, FALSE))
755         return FALSE;
756     return TRUE;
757 }
758
759 static GstFlowReturn
760 gst_vaapidecode_parse(GstVideoDecoder *vdec,
761     GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
762 {
763     GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
764     GstVaapiDecoderStatus status;
765     GstFlowReturn ret;
766     guint got_unit_size;
767     gboolean got_frame;
768
769     status = gst_vaapi_decoder_parse(decode->decoder, frame,
770         adapter, at_eos, &got_unit_size, &got_frame);
771
772     switch (status) {
773     case GST_VAAPI_DECODER_STATUS_SUCCESS:
774         if (got_unit_size > 0) {
775             gst_video_decoder_add_to_frame(vdec, got_unit_size);
776             decode->current_frame_size += got_unit_size;
777         }
778         if (got_frame) {
779             ret = gst_video_decoder_have_frame(vdec);
780             decode->current_frame_size = 0;
781         }
782         else
783             ret = GST_FLOW_OK;
784         break;
785     case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
786         ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
787         break;
788     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
789     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
790     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
791         GST_WARNING("parse error %d", status);
792         ret = GST_FLOW_NOT_SUPPORTED;
793         decode->current_frame_size = 0;
794         break;
795     default:
796         GST_ERROR("parse error %d", status);
797         ret = GST_FLOW_EOS;
798         decode->current_frame_size = 0;
799         break;
800     }
801     return ret;
802 }
803
804 static void
805 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
806 {
807     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
808     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
809     GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
810     GstPadTemplate *pad_template;
811
812     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
813                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
814
815     object_class->finalize   = gst_vaapidecode_finalize;
816
817     vdec_class->open         = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
818     vdec_class->close        = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
819     vdec_class->set_format   = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
820     vdec_class->reset        = GST_DEBUG_FUNCPTR(gst_vaapidecode_reset);
821     vdec_class->parse        = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
822     vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
823     vdec_class->finish       = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish);
824
825 #if GST_CHECK_VERSION(1,0,0)
826     vdec_class->decide_allocation =
827         GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
828 #endif
829
830 #if GST_CHECK_VERSION(1,1,0)
831     element_class->set_context = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_context);
832 #endif
833
834     gst_element_class_set_static_metadata(element_class,
835         "VA-API decoder",
836         "Codec/Decoder/Video",
837         GST_PLUGIN_DESC,
838         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
839
840     /* sink pad */
841     pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
842     gst_element_class_add_pad_template(element_class, pad_template);
843
844     /* src pad */
845     pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
846     gst_element_class_add_pad_template(element_class, pad_template);
847 }
848
849 static gboolean
850 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
851 {
852     GstCaps *decode_caps;
853     guint i, n_decode_caps;
854
855     if (decode->allowed_caps)
856         return TRUE;
857
858     if (!gst_vaapidecode_ensure_display(decode))
859         goto error_no_display;
860
861     decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
862     if (!decode_caps)
863         goto error_no_decode_caps;
864     n_decode_caps = gst_caps_get_size(decode_caps);
865
866     decode->allowed_caps = gst_caps_new_empty();
867     if (!decode->allowed_caps)
868         goto error_no_memory;
869
870     for (i = 0; i < n_decode_caps; i++) {
871         GstStructure *structure;
872         structure = gst_caps_get_structure(decode_caps, i);
873         if (!structure)
874             continue;
875         structure = gst_structure_copy(structure);
876         if (!structure)
877             continue;
878         gst_structure_remove_field(structure, "profile");
879         decode->allowed_caps =
880             gst_caps_merge_structure(decode->allowed_caps, structure);
881     }
882
883     gst_caps_unref(decode_caps);
884     return TRUE;
885
886     /* ERRORS */
887 error_no_display:
888     {
889         GST_ERROR("failed to retrieve VA display");
890         return FALSE;
891     }
892 error_no_decode_caps:
893     {
894         GST_ERROR("failed to retrieve VA decode caps");
895         return FALSE;
896     }
897 error_no_memory:
898     {
899         GST_ERROR("failed to allocate allowed-caps set");
900         gst_caps_unref(decode_caps);
901         return FALSE;
902     }
903 }
904
905 static GstCaps *
906 gst_vaapidecode_get_caps(GstPad *pad)
907 {
908     GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
909
910     if (!gst_vaapidecode_ensure_allowed_caps(decode))
911         return gst_caps_new_empty();
912
913     return gst_caps_ref(decode->allowed_caps);
914 }
915
916 static gboolean
917 gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
918 {
919     GstVaapiDecode * const decode =
920         GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
921     gboolean res;
922
923     GST_INFO_OBJECT(decode, "query type %s", GST_QUERY_TYPE_NAME(query));
924
925     if (gst_vaapi_reply_to_query(query, decode->display)) {
926         GST_DEBUG("sharing display %p", decode->display);
927         res = TRUE;
928     }
929     else if (GST_PAD_IS_SINK(pad)) {
930         switch (GST_QUERY_TYPE(query)) {
931 #if GST_CHECK_VERSION(1,0,0)
932         case GST_QUERY_CAPS: {
933             GstCaps * const caps = gst_vaapidecode_get_caps(pad);
934             gst_query_set_caps_result(query, caps);
935             gst_caps_unref(caps);
936             res = TRUE;
937             break;
938         }
939 #endif
940         default:
941             res = GST_PAD_QUERY_FUNCTION_CALL(decode->sinkpad_query,
942                 decode->sinkpad, parent, query);
943             break;
944         }
945     }
946     else
947         res = GST_PAD_QUERY_FUNCTION_CALL(decode->srcpad_query,
948             decode->srcpad, parent, query);
949
950     gst_object_unref(decode);
951     return res;
952 }
953
954 static void
955 gst_vaapidecode_init(GstVaapiDecode *decode)
956 {
957     GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
958
959     decode->display             = NULL;
960     decode->decoder             = NULL;
961     decode->decoder_caps        = NULL;
962     decode->allowed_caps        = NULL;
963     decode->render_time_base    = 0;
964     decode->last_buffer_time    = 0;
965
966     g_mutex_init(&decode->decoder_mutex);
967     g_cond_init(&decode->decoder_ready);
968     g_cond_init(&decode->decoder_finish_done);
969
970     gst_video_decoder_set_packetized(vdec, FALSE);
971
972     /* Pad through which data comes in to the element */
973     decode->sinkpad = GST_VIDEO_DECODER_SINK_PAD(vdec);
974     decode->sinkpad_query = GST_PAD_QUERYFUNC(decode->sinkpad);
975     gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
976 #if !GST_CHECK_VERSION(1,0,0)
977     gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
978 #endif
979
980     /* Pad through which data goes out of the element */
981     decode->srcpad = GST_VIDEO_DECODER_SRC_PAD(vdec);
982     decode->srcpad_query = GST_PAD_QUERYFUNC(decode->srcpad);
983     gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);
984 }