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