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