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