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