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