2 * gstvaapidecode.c - VA-API video decoder
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>
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.
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.
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
26 * SECTION:gstvaapidecode
27 * @short_description: A VA-API based video decoder
29 * vaapidecode decodes from raw bitstreams to surfaces suitable for
30 * the vaapisink element.
33 #include "gst/vaapi/sysdeps.h"
34 #include <gst/vaapi/gstvaapidisplay.h>
36 #include "gstvaapidecode.h"
37 #include "gstvaapipluginutil.h"
38 #include "gstvaapivideobuffer.h"
39 #if GST_CHECK_VERSION(1,1,0) && (USE_GLX || USE_EGL)
40 #include "gstvaapivideometa_texture.h"
42 #if GST_CHECK_VERSION(1,0,0)
43 #include "gstvaapivideobufferpool.h"
44 #include "gstvaapivideomemory.h"
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 #include <gst/vaapi/gstvaapidecoder_vp8.h>
54 #define GST_PLUGIN_NAME "vaapidecode"
55 #define GST_PLUGIN_DESC "A VA-API based video decoder"
57 #define GST_VAAPI_DECODE_FLOW_PARSE_DATA GST_FLOW_CUSTOM_SUCCESS_2
59 GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapidecode);
60 #define GST_CAT_DEFAULT gst_debug_vaapidecode
62 /* Default templates */
63 #define GST_CAPS_CODEC(CODEC) CODEC "; "
66 static const char gst_vaapidecode_sink_caps_str[] =
67 GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
68 GST_CAPS_CODEC("video/mpeg, mpegversion=4")
69 GST_CAPS_CODEC("video/x-divx")
70 GST_CAPS_CODEC("video/x-xvid")
71 GST_CAPS_CODEC("video/x-h263")
72 GST_CAPS_CODEC("video/x-h264")
73 GST_CAPS_CODEC("video/x-wmv")
74 GST_CAPS_CODEC("video/x-vp8")
75 GST_CAPS_CODEC("image/jpeg")
78 static const char gst_vaapidecode_src_caps_str[] =
79 #if GST_CHECK_VERSION(1,1,0)
80 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
81 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, I420, YV12, NV12 }") ";"
82 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
83 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "{ RGBA, BGRA }") ";"
84 GST_VIDEO_CAPS_MAKE("{ I420, YV12, NV12 }");
86 GST_VAAPI_SURFACE_CAPS;
89 static GstStaticPadTemplate gst_vaapidecode_sink_factory =
90 GST_STATIC_PAD_TEMPLATE(
94 GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));
96 static GstStaticPadTemplate gst_vaapidecode_src_factory =
97 GST_STATIC_PAD_TEMPLATE(
101 GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
103 G_DEFINE_TYPE_WITH_CODE(
106 GST_TYPE_VIDEO_DECODER,
107 GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES)
110 static gboolean gst_vaapidecode_update_src_caps (GstVaapiDecode * decode);
113 gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode,
114 const GstVideoCodecState * new_state);
117 gst_vaapidecode_sink_query (GstVideoDecoder * vdec, GstQuery * query);
119 gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query);
122 gst_vaapi_decoder_state_changed (GstVaapiDecoder * decoder,
123 const GstVideoCodecState * codec_state, gpointer user_data)
125 GstVaapiDecode *const decode = GST_VAAPIDECODE (user_data);
126 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
127 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
129 g_assert (decode->decoder == decoder);
131 if (!gst_vaapi_decode_input_state_replace (decode, codec_state))
133 if (!gst_vaapidecode_update_src_caps (decode))
135 if (!gst_video_decoder_negotiate (vdec))
137 if (!gst_vaapi_plugin_base_set_caps (plugin, NULL, decode->srcpad_caps))
142 gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode,
143 const GstVideoCodecState * new_state)
145 if (decode->input_state) {
147 const GstCaps *curcaps = decode->input_state->caps;
148 if (gst_caps_is_always_compatible (curcaps, new_state->caps))
151 gst_video_codec_state_unref (decode->input_state);
155 decode->input_state = gst_video_codec_state_ref
156 ((GstVideoCodecState *) new_state);
158 decode->input_state = NULL;
163 static inline gboolean
164 gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode, GstCaps * caps)
166 gst_caps_replace (&decode->sinkpad_caps, caps);
171 gst_vaapidecode_update_src_caps (GstVaapiDecode * decode)
173 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
174 GstVideoCodecState *state, *ref_state;
176 GstVideoFormat format = GST_VIDEO_FORMAT_I420;
178 if (!decode->input_state)
181 ref_state = decode->input_state;
183 #if GST_CHECK_VERSION(1,1,0)
184 GstCapsFeatures *features = NULL;
185 GstVaapiCapsFeature feature;
188 gst_vaapi_find_preferred_caps_feature (GST_VIDEO_DECODER_SRC_PAD (vdec),
189 GST_VIDEO_INFO_FORMAT (&ref_state->info), &format);
191 if (feature == GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED)
195 #if (USE_GLX || USE_EGL)
196 case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
197 if (decode->has_texture_upload_meta)
199 gst_caps_features_new
200 (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL);
202 format = GST_VIDEO_FORMAT_I420;
205 #if GST_CHECK_VERSION(1,5,0)
206 case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:
208 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, NULL);
216 state = gst_video_decoder_set_output_state (vdec, format,
217 ref_state->info.width, ref_state->info.height,
218 (GstVideoCodecState *) ref_state);
219 if (!state || state->info.width == 0 || state->info.height == 0)
224 #if GST_CHECK_VERSION(1,1,0)
225 state->caps = gst_video_info_to_caps (vi);
227 gst_caps_set_features (state->caps, 0, features);
229 /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
230 reconstruct suitable caps for "encoded" video formats */
231 state->caps = gst_caps_from_string (GST_VAAPI_SURFACE_CAPS_NAME);
235 gst_caps_set_simple (state->caps,
236 "type", G_TYPE_STRING, "vaapi",
237 "opengl", G_TYPE_BOOLEAN, USE_GLX,
238 "width", G_TYPE_INT, vi->width,
239 "height", G_TYPE_INT, vi->height,
240 "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
241 "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d, NULL);
243 gst_caps_set_interlaced (state->caps, vi);
245 gst_caps_replace (&decode->srcpad_caps, state->caps);
246 gst_video_codec_state_unref (state);
251 gst_vaapidecode_release (GstVaapiDecode * decode)
253 g_mutex_lock (&decode->surface_ready_mutex);
254 g_cond_signal (&decode->surface_ready);
255 g_mutex_unlock (&decode->surface_ready_mutex);
256 gst_object_unref (decode);
260 gst_vaapidecode_push_decoded_frame (GstVideoDecoder * vdec,
261 GstVideoCodecFrame * out_frame)
263 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
264 GstVaapiSurfaceProxy *proxy;
266 #if GST_CHECK_VERSION(1,0,0)
267 const GstVaapiRectangle *crop_rect;
268 GstVaapiVideoMeta *meta;
272 if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY (out_frame)) {
273 proxy = gst_video_codec_frame_get_user_data (out_frame);
275 gst_vaapi_surface_proxy_set_destroy_notify (proxy,
276 (GDestroyNotify) gst_vaapidecode_release, gst_object_ref (decode));
278 #if GST_CHECK_VERSION(1,0,0)
279 ret = gst_video_decoder_allocate_output_frame (vdec, out_frame);
280 if (ret != GST_FLOW_OK)
281 goto error_create_buffer;
283 meta = gst_buffer_get_vaapi_video_meta (out_frame->output_buffer);
286 gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
288 flags = gst_vaapi_surface_proxy_get_flags (proxy);
289 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
290 guint out_flags = GST_VIDEO_BUFFER_FLAG_INTERLACED;
291 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
292 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
293 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
294 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
295 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
296 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
297 GST_BUFFER_FLAG_SET (out_frame->output_buffer, out_flags);
300 crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy);
302 GstVideoCropMeta *const crop_meta =
303 gst_buffer_add_video_crop_meta (out_frame->output_buffer);
305 crop_meta->x = crop_rect->x;
306 crop_meta->y = crop_rect->y;
307 crop_meta->width = crop_rect->width;
308 crop_meta->height = crop_rect->height;
311 #if GST_CHECK_VERSION(1,1,0) && (USE_GLX || USE_EGL)
312 if (decode->has_texture_upload_meta)
313 gst_buffer_ensure_texture_upload_meta (out_frame->output_buffer);
316 out_frame->output_buffer =
317 gst_vaapi_video_buffer_new_with_surface_proxy (proxy);
318 if (!out_frame->output_buffer)
319 goto error_create_buffer;
323 ret = gst_video_decoder_finish_frame (vdec, out_frame);
324 if (ret != GST_FLOW_OK)
325 goto error_commit_buffer;
327 gst_video_codec_frame_unref (out_frame);
333 const GstVaapiID surface_id =
334 gst_vaapi_surface_get_id (GST_VAAPI_SURFACE_PROXY_SURFACE (proxy));
336 GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
337 ("Failed to create sink buffer"),
338 ("video sink failed to create video buffer for proxy'ed "
339 "surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)));
340 gst_video_decoder_drop_frame (vdec, out_frame);
341 gst_video_codec_frame_unref (out_frame);
342 return GST_FLOW_ERROR;
344 #if GST_CHECK_VERSION(1,0,0)
347 GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
348 ("Failed to get vaapi video meta attached to video buffer"),
349 ("Failed to get vaapi video meta attached to video buffer"));
350 gst_video_decoder_drop_frame (vdec, out_frame);
351 gst_video_codec_frame_unref (out_frame);
352 return GST_FLOW_ERROR;
357 if (ret != GST_FLOW_FLUSHING)
358 GST_ERROR ("video sink rejected the video buffer (error: %s [%d])",
359 gst_flow_get_name (ret), ret);
360 gst_video_codec_frame_unref (out_frame);
366 gst_vaapidecode_push_all_decoded_frames (GstVaapiDecode * decode)
368 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
369 GstVaapiDecoderStatus status;
370 GstVideoCodecFrame *out_frame;
374 status = gst_vaapi_decoder_get_frame (decode->decoder, &out_frame);
377 case GST_VAAPI_DECODER_STATUS_SUCCESS:
378 ret = gst_vaapidecode_push_decoded_frame (vdec, out_frame);
379 if (ret != GST_FLOW_OK)
382 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
385 GST_ELEMENT_ERROR (vdec, STREAM, DECODE, ("Decoding failed"),
386 ("Unknown decoding error"));
387 return GST_FLOW_ERROR;
390 g_assert_not_reached ();
394 gst_vaapidecode_handle_frame (GstVideoDecoder * vdec,
395 GstVideoCodecFrame * frame)
397 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
398 GstVaapiDecoderStatus status;
401 if (!decode->input_state)
404 if (G_UNLIKELY (!decode->active) ||
405 gst_pad_needs_reconfigure (GST_VIDEO_DECODER_SRC_PAD (vdec))) {
406 GST_DEBUG_OBJECT (decode, "activating the decoder");
407 if (!gst_vaapidecode_update_src_caps (decode))
410 if (!gst_video_decoder_negotiate (vdec))
413 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
414 if (!gst_vaapi_plugin_base_set_caps (plugin, NULL, decode->srcpad_caps))
417 decode->active = TRUE;
420 /* Decode current frame */
422 status = gst_vaapi_decoder_decode (decode->decoder, frame);
423 if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
424 /* Make sure that there are no decoded frames waiting in the
426 ret = gst_vaapidecode_push_all_decoded_frames (decode);
427 if (ret != GST_FLOW_OK)
428 goto error_push_all_decoded_frames;
430 g_mutex_lock (&decode->surface_ready_mutex);
431 if (gst_vaapi_decoder_check_status (decode->decoder) ==
432 GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE)
433 g_cond_wait (&decode->surface_ready, &decode->surface_ready_mutex);
434 g_mutex_unlock (&decode->surface_ready_mutex);
437 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
442 /* Note that gst_vaapi_decoder_decode cannot return success without
443 completing the decode and pushing all decoded frames into the output
445 ret = gst_vaapidecode_push_all_decoded_frames (decode);
446 if (ret != GST_FLOW_OK && ret != GST_FLOW_FLUSHING)
447 GST_ERROR ("push loop error after decoding %d", ret);
451 error_push_all_decoded_frames:
453 GST_ERROR ("push loop error while decoding %d", ret);
454 gst_video_decoder_drop_frame (vdec, frame);
459 GST_ERROR ("decode error %d", status);
461 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
462 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
463 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
464 ret = GST_FLOW_NOT_SUPPORTED;
467 GST_ELEMENT_ERROR (vdec, STREAM, DECODE, ("Decoding error"),
468 ("Decode error %d", status));
469 ret = GST_FLOW_ERROR;
472 gst_video_decoder_drop_frame (vdec, frame);
477 GST_ERROR_OBJECT (decode, "not negotiated");
478 ret = GST_FLOW_NOT_NEGOTIATED;
479 gst_video_decoder_drop_frame (vdec, frame);
485 gst_vaapidecode_flush (GstVideoDecoder * vdec)
487 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
488 GstVaapiDecoderStatus status;
490 if (!decode->decoder)
493 /* If there is something in GstVideoDecoder's output adapter, then
494 submit the frame for decoding */
495 if (decode->current_frame_size) {
496 gst_video_decoder_have_frame (vdec);
497 decode->current_frame_size = 0;
500 status = gst_vaapi_decoder_flush (decode->decoder);
501 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
508 GST_ERROR ("failed to flush decoder (status %d)", status);
514 gst_vaapidecode_finish (GstVideoDecoder * vdec)
516 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
518 if (!decode->decoder)
521 if (!gst_vaapidecode_flush (vdec)) {
522 gst_vaapidecode_push_all_decoded_frames (decode);
523 return GST_FLOW_ERROR;
526 return gst_vaapidecode_push_all_decoded_frames (decode);
529 #if GST_CHECK_VERSION(1,0,0)
531 gst_vaapidecode_decide_allocation (GstVideoDecoder * vdec, GstQuery * query)
533 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
534 GstCaps *caps = NULL;
535 GstVideoCodecState *state;
536 GstVaapiCapsFeature feature;
537 GstVideoFormat out_format;
539 gst_query_parse_allocation (query, &caps, NULL);
542 gst_vaapi_find_preferred_caps_feature (GST_VIDEO_DECODER_SRC_PAD (vdec),
543 GST_VIDEO_FORMAT_ENCODED, &out_format);
544 decode->has_texture_upload_meta = FALSE;
545 #if GST_CHECK_VERSION(1,1,0) && (USE_GLX || USE_EGL)
546 decode->has_texture_upload_meta =
547 (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META) &&
548 gst_query_find_allocation_meta (query,
549 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
552 /* Update src caps if feature is not handled downstream */
553 state = gst_video_decoder_get_output_state (vdec);
554 if (!gst_caps_is_always_compatible (caps, state->caps))
555 gst_vaapidecode_update_src_caps (decode);
556 gst_video_codec_state_unref (state);
558 return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (vdec),
563 static inline gboolean
564 gst_vaapidecode_ensure_display (GstVaapiDecode * decode)
566 return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode));
570 gst_vaapi_codec_from_caps (GstCaps * caps)
572 return gst_vaapi_profile_get_codec (gst_vaapi_profile_from_caps (caps));
576 gst_vaapidecode_create (GstVaapiDecode * decode, GstCaps * caps)
578 GstVaapiDisplay *dpy;
580 if (!gst_vaapidecode_ensure_display (decode))
582 dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
584 switch (gst_vaapi_codec_from_caps (caps)) {
585 case GST_VAAPI_CODEC_MPEG2:
586 decode->decoder = gst_vaapi_decoder_mpeg2_new (dpy, caps);
588 case GST_VAAPI_CODEC_MPEG4:
589 case GST_VAAPI_CODEC_H263:
590 decode->decoder = gst_vaapi_decoder_mpeg4_new (dpy, caps);
592 case GST_VAAPI_CODEC_H264:
593 decode->decoder = gst_vaapi_decoder_h264_new (dpy, caps);
595 /* Set the stream buffer alignment for better optimizations */
596 if (decode->decoder && caps) {
597 GstStructure *const structure = gst_caps_get_structure (caps, 0);
598 const gchar *str = NULL;
600 if ((str = gst_structure_get_string (structure, "alignment"))) {
601 GstVaapiStreamAlignH264 alignment;
602 if (g_strcmp0 (str, "au") == 0)
603 alignment = GST_VAAPI_STREAM_ALIGN_H264_AU;
604 else if (g_strcmp0 (str, "nal") == 0)
605 alignment = GST_VAAPI_STREAM_ALIGN_H264_NALU;
607 alignment = GST_VAAPI_STREAM_ALIGN_H264_NONE;
608 gst_vaapi_decoder_h264_set_alignment (GST_VAAPI_DECODER_H264
609 (decode->decoder), alignment);
613 case GST_VAAPI_CODEC_WMV3:
614 case GST_VAAPI_CODEC_VC1:
615 decode->decoder = gst_vaapi_decoder_vc1_new (dpy, caps);
618 case GST_VAAPI_CODEC_JPEG:
619 decode->decoder = gst_vaapi_decoder_jpeg_new (dpy, caps);
623 case GST_VAAPI_CODEC_VP8:
624 decode->decoder = gst_vaapi_decoder_vp8_new (dpy, caps);
628 decode->decoder = NULL;
631 if (!decode->decoder)
634 gst_vaapi_decoder_set_codec_state_changed_func (decode->decoder,
635 gst_vaapi_decoder_state_changed, decode);
637 decode->decoder_caps = gst_caps_ref (caps);
642 gst_vaapidecode_destroy (GstVaapiDecode * decode)
644 gst_vaapi_decoder_replace (&decode->decoder, NULL);
645 gst_caps_replace (&decode->decoder_caps, NULL);
647 decode->active = FALSE;
649 gst_vaapidecode_release (gst_object_ref (decode));
653 gst_vaapidecode_reset_full (GstVaapiDecode * decode, GstCaps * caps,
658 decode->has_texture_upload_meta = FALSE;
660 /* Reset tracked frame size */
661 decode->current_frame_size = 0;
663 /* Reset timers if hard reset was requested (e.g. seek) */
665 GstVideoCodecFrame *out_frame = NULL;
667 gst_vaapi_decoder_flush (decode->decoder);
669 /* Purge all decoded frames as we don't need them (e.g. seek) */
670 while (gst_vaapi_decoder_get_frame_with_timeout (decode->decoder,
671 &out_frame, 0) == GST_VAAPI_DECODER_STATUS_SUCCESS) {
672 gst_video_codec_frame_unref (out_frame);
677 /* Only reset decoder if codec type changed */
678 else if (decode->decoder && decode->decoder_caps) {
679 if (gst_caps_is_always_compatible (caps, decode->decoder_caps))
681 codec = gst_vaapi_codec_from_caps (caps);
682 if (codec == gst_vaapi_decoder_get_codec (decode->decoder))
686 gst_vaapidecode_destroy (decode);
687 return gst_vaapidecode_create (decode, caps);
691 gst_vaapidecode_finalize (GObject * object)
693 GstVaapiDecode *const decode = GST_VAAPIDECODE (object);
695 gst_caps_replace (&decode->sinkpad_caps, NULL);
696 gst_caps_replace (&decode->srcpad_caps, NULL);
697 gst_caps_replace (&decode->allowed_caps, NULL);
699 g_cond_clear (&decode->surface_ready);
700 g_mutex_clear (&decode->surface_ready_mutex);
702 gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object));
703 G_OBJECT_CLASS (gst_vaapidecode_parent_class)->finalize (object);
707 gst_vaapidecode_open (GstVideoDecoder * vdec)
709 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
710 GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
713 if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (decode)))
716 /* Let GstVideoContext ask for a proper display to its neighbours */
717 /* Note: steal old display that may be allocated from get_caps()
718 so that to retain a reference to it, thus avoiding extra
719 initialization steps if we turn out to simply re-use the
720 existing (cached) VA display */
721 GST_VAAPI_PLUGIN_BASE_DISPLAY (decode) = NULL;
722 success = gst_vaapidecode_ensure_display (decode);
724 gst_vaapi_display_unref (old_display);
729 gst_vaapidecode_close (GstVideoDecoder * vdec)
731 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
733 gst_vaapi_decode_input_state_replace (decode, NULL);
734 gst_vaapidecode_destroy (decode);
735 gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode));
740 gst_vaapidecode_reset (GstVideoDecoder * vdec, gboolean hard)
742 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
744 /* In GStreamer 1.0 context, this means a flush */
745 if (decode->decoder && !hard && !gst_vaapidecode_flush (vdec))
747 return gst_vaapidecode_reset_full (decode, decode->sinkpad_caps, hard);
751 gst_vaapidecode_set_format (GstVideoDecoder * vdec, GstVideoCodecState * state)
753 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
754 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
756 if (!gst_vaapi_decode_input_state_replace (decode, state))
758 if (!gst_vaapidecode_update_sink_caps (decode, state->caps))
760 if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL))
762 if (!gst_vaapidecode_reset_full (decode, decode->sinkpad_caps, FALSE))
769 gst_vaapidecode_parse_frame (GstVideoDecoder * vdec,
770 GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
772 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
773 GstVaapiDecoderStatus status;
778 status = gst_vaapi_decoder_parse (decode->decoder, frame,
779 adapter, at_eos, &got_unit_size, &got_frame);
782 case GST_VAAPI_DECODER_STATUS_SUCCESS:
783 if (got_unit_size > 0) {
784 gst_video_decoder_add_to_frame (vdec, got_unit_size);
785 decode->current_frame_size += got_unit_size;
788 ret = gst_video_decoder_have_frame (vdec);
789 decode->current_frame_size = 0;
791 ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
793 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
794 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
796 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
797 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
798 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
799 GST_WARNING ("parse error %d", status);
800 ret = GST_FLOW_NOT_SUPPORTED;
801 decode->current_frame_size = 0;
804 GST_ERROR ("parse error %d", status);
806 decode->current_frame_size = 0;
813 gst_vaapidecode_parse (GstVideoDecoder * vdec,
814 GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
819 ret = gst_vaapidecode_parse_frame (vdec, frame, adapter, at_eos);
820 } while (ret == GST_VAAPI_DECODE_FLOW_PARSE_DATA);
825 gst_vaapidecode_class_init (GstVaapiDecodeClass * klass)
827 GObjectClass *const object_class = G_OBJECT_CLASS (klass);
828 GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
829 GstVideoDecoderClass *const vdec_class = GST_VIDEO_DECODER_CLASS (klass);
830 GstPadTemplate *pad_template;
832 GST_DEBUG_CATEGORY_INIT (gst_debug_vaapidecode,
833 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
835 gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass));
837 object_class->finalize = gst_vaapidecode_finalize;
839 vdec_class->open = GST_DEBUG_FUNCPTR (gst_vaapidecode_open);
840 vdec_class->close = GST_DEBUG_FUNCPTR (gst_vaapidecode_close);
841 vdec_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapidecode_set_format);
842 vdec_class->reset = GST_DEBUG_FUNCPTR (gst_vaapidecode_reset);
843 vdec_class->parse = GST_DEBUG_FUNCPTR (gst_vaapidecode_parse);
844 vdec_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapidecode_handle_frame);
845 vdec_class->finish = GST_DEBUG_FUNCPTR (gst_vaapidecode_finish);
847 #if GST_CHECK_VERSION(1,0,0)
848 vdec_class->decide_allocation =
849 GST_DEBUG_FUNCPTR (gst_vaapidecode_decide_allocation);
851 #if GST_CHECK_VERSION(1,4,0)
852 vdec_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_src_query);
853 vdec_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_query);
856 gst_element_class_set_static_metadata (element_class,
858 "Codec/Decoder/Video",
859 GST_PLUGIN_DESC, "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
862 pad_template = gst_static_pad_template_get (&gst_vaapidecode_sink_factory);
863 gst_element_class_add_pad_template (element_class, pad_template);
866 pad_template = gst_static_pad_template_get (&gst_vaapidecode_src_factory);
867 gst_element_class_add_pad_template (element_class, pad_template);
871 gst_vaapidecode_ensure_allowed_caps (GstVaapiDecode * decode)
873 GstCaps *caps, *allowed_caps;
877 if (decode->allowed_caps)
880 if (!gst_vaapidecode_ensure_display (decode))
881 goto error_no_display;
884 gst_vaapi_display_get_decode_profiles (GST_VAAPI_PLUGIN_BASE_DISPLAY
887 goto error_no_profiles;
889 allowed_caps = gst_caps_new_empty ();
891 goto error_no_memory;
893 for (i = 0; i < profiles->len; i++) {
894 const GstVaapiProfile profile =
895 g_array_index (profiles, GstVaapiProfile, i);
896 const gchar *media_type_name;
897 const gchar *profile_name;
898 GstStructure *structure;
900 media_type_name = gst_vaapi_profile_get_media_type_name (profile);
901 if (!media_type_name)
904 caps = gst_caps_from_string (media_type_name);
907 structure = gst_caps_get_structure (caps, 0);
909 profile_name = gst_vaapi_profile_get_name (profile);
911 gst_structure_set (structure, "profile", G_TYPE_STRING,
914 allowed_caps = gst_caps_merge (allowed_caps, caps);
916 decode->allowed_caps = gst_caps_simplify (allowed_caps);
918 g_array_unref (profiles);
924 GST_ERROR ("failed to retrieve VA display");
929 GST_ERROR ("failed to retrieve VA decode profiles");
934 GST_ERROR ("failed to allocate allowed-caps set");
935 g_array_unref (profiles);
941 gst_vaapidecode_get_caps (GstPad * pad)
943 GstVaapiDecode *const decode = GST_VAAPIDECODE (GST_OBJECT_PARENT (pad));
945 if (!gst_vaapidecode_ensure_allowed_caps (decode))
946 return gst_caps_new_empty ();
948 return gst_caps_ref (decode->allowed_caps);
951 #if !GST_CHECK_VERSION(1,4,0)
953 gst_vaapidecode_query (GST_PAD_QUERY_FUNCTION_ARGS)
955 GstVaapiDecode *const decode =
956 GST_VAAPIDECODE (gst_pad_get_parent_element (pad));
957 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
960 GST_INFO_OBJECT (decode, "query type %s on %s pad",
961 GST_QUERY_TYPE_NAME (query), GST_PAD_IS_SINK (pad) ? "sink" : "src");
963 if (GST_PAD_IS_SINK (pad))
964 res = gst_vaapidecode_sink_query (vdec, query);
966 res = gst_vaapidecode_src_query (vdec, query);
968 gst_object_unref (vdec);
974 gst_vaapidecode_sink_query (GstVideoDecoder * vdec, GstQuery * query)
977 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
978 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode);
980 if (gst_vaapi_reply_to_query (query, plugin->display)) {
981 GST_DEBUG_OBJECT (decode, "sharing display %p", plugin->display);
985 switch (GST_QUERY_TYPE (query)) {
986 #if GST_CHECK_VERSION(1,0,0)
987 case GST_QUERY_CAPS:{
988 GstCaps *caps, *filter = NULL;
989 GstPad *pad = GST_VIDEO_DECODER_SINK_PAD (vdec);
991 gst_query_parse_caps (query, &filter);
992 caps = gst_vaapidecode_get_caps (pad);
996 caps = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
997 gst_caps_unref (tmp);
1000 gst_query_set_caps_result (query, caps);
1001 gst_caps_unref (caps);
1006 #if GST_CHECK_VERSION(1,4,0)
1007 ret = GST_VIDEO_DECODER_CLASS (gst_vaapidecode_parent_class)->sink_query
1010 GstPad *pad = GST_VIDEO_DECODER_SINK_PAD (vdec);
1011 GstObject *parent = gst_pad_get_parent (pad);
1012 ret = GST_PAD_QUERY_FUNCTION_CALL (plugin->sinkpad_query, pad, parent,
1015 gst_object_unref (parent);
1025 gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query)
1027 gboolean ret = TRUE;
1028 GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1029 GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode);
1031 if (gst_vaapi_reply_to_query (query, plugin->display)) {
1032 GST_DEBUG_OBJECT (decode, "sharing display %p", plugin->display);
1036 switch (GST_QUERY_TYPE (query)) {
1037 #if GST_CHECK_VERSION(1,0,0)
1038 case GST_QUERY_CAPS:{
1039 GstCaps *caps, *filter = NULL;
1040 GstPad *pad = GST_VIDEO_DECODER_SRC_PAD (vdec);
1042 gst_query_parse_caps (query, &filter);
1043 caps = gst_pad_get_pad_template_caps (pad);
1046 GstCaps *tmp = caps;
1047 caps = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
1048 gst_caps_unref (tmp);
1051 gst_query_set_caps_result (query, caps);
1052 gst_caps_unref (caps);
1057 #if GST_CHECK_VERSION(1,4,0)
1058 ret = GST_VIDEO_DECODER_CLASS (gst_vaapidecode_parent_class)->src_query
1061 GstPad *pad = GST_VIDEO_DECODER_SRC_PAD (vdec);
1062 GstObject *parent = gst_pad_get_parent (pad);
1063 ret = GST_PAD_QUERY_FUNCTION_CALL (plugin->srcpad_query, pad, parent,
1066 gst_object_unref (parent);
1076 gst_vaapidecode_init (GstVaapiDecode * decode)
1078 GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
1080 gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (decode), GST_CAT_DEFAULT);
1082 decode->decoder = NULL;
1083 decode->decoder_caps = NULL;
1084 decode->allowed_caps = NULL;
1086 g_mutex_init (&decode->surface_ready_mutex);
1087 g_cond_init (&decode->surface_ready);
1089 gst_video_decoder_set_packetized (vdec, FALSE);
1091 #if !GST_CHECK_VERSION(1,4,0)
1092 /* Pad through which data comes in to the element */
1093 GstPad *pad = GST_VAAPI_PLUGIN_BASE_SINK_PAD (decode);
1094 gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_vaapidecode_query));
1095 #if !GST_CHECK_VERSION(1,0,0)
1096 gst_pad_set_getcaps_function (pad, gst_vaapidecode_get_caps);
1099 /* Pad through which data goes out of the element */
1100 pad = GST_VAAPI_PLUGIN_BASE_SRC_PAD (decode);
1101 gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_vaapidecode_query));