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
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 "; "
65 static const char gst_vaapidecode_sink_caps_str[] =
66 GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
67 GST_CAPS_CODEC("video/mpeg, mpegversion=4")
68 GST_CAPS_CODEC("video/x-divx")
69 GST_CAPS_CODEC("video/x-xvid")
70 GST_CAPS_CODEC("video/x-h263")
71 GST_CAPS_CODEC("video/x-h264")
72 GST_CAPS_CODEC("video/x-wmv")
73 GST_CAPS_CODEC("video/x-vp8")
74 GST_CAPS_CODEC("image/jpeg")
77 static const char gst_vaapidecode_src_caps_str[] =
78 #if GST_CHECK_VERSION(1,1,0)
79 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
80 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, I420, YV12, NV12 }") ";"
81 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
82 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA") ";"
83 GST_VIDEO_CAPS_MAKE("{ I420, YV12, NV12 }");
85 GST_VAAPI_SURFACE_CAPS;
88 static GstStaticPadTemplate gst_vaapidecode_sink_factory =
89 GST_STATIC_PAD_TEMPLATE(
93 GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));
95 static GstStaticPadTemplate gst_vaapidecode_src_factory =
96 GST_STATIC_PAD_TEMPLATE(
100 GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
102 G_DEFINE_TYPE_WITH_CODE(
105 GST_TYPE_VIDEO_DECODER,
106 GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES)
109 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
110 const GstVideoCodecState *ref_state);
113 gst_vaapi_decoder_state_changed(GstVaapiDecoder *decoder,
114 const GstVideoCodecState *codec_state, gpointer user_data)
116 GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
117 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
119 g_assert(decode->decoder == decoder);
121 gst_vaapidecode_update_src_caps(decode, codec_state);
122 gst_video_decoder_negotiate(vdec);
125 static inline gboolean
126 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
128 gst_caps_replace(&decode->sinkpad_caps, caps);
132 #if GST_CHECK_VERSION(1,1,0)
134 gst_vaapidecode_video_info_change_format(GstVideoInfo *info,
135 GstVideoFormat format, guint width, guint height)
137 GstVideoInfo vi = *info;
139 gst_video_info_set_format (info, format, width, height);
141 info->interlace_mode = vi.interlace_mode;
142 info->flags = vi.flags;
143 info->views = vi.views;
144 info->par_n = vi.par_n;
145 info->par_d = vi.par_d;
146 info->fps_n = vi.fps_n;
147 info->fps_d = vi.fps_d;
152 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
153 const GstVideoCodecState *ref_state)
155 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
156 GstVideoCodecState *state;
157 GstVideoInfo *vi, vis;
158 GstVideoFormat format, out_format;
159 #if GST_CHECK_VERSION(1,1,0)
160 GstCapsFeatures *features = NULL;
161 GstVaapiCapsFeature feature;
163 feature = gst_vaapi_find_preferred_caps_feature(
164 GST_VIDEO_DECODER_SRC_PAD(vdec),
165 GST_VIDEO_INFO_FORMAT(&ref_state->info));
168 format = GST_VIDEO_INFO_FORMAT(&ref_state->info);
170 state = gst_video_decoder_set_output_state(vdec, format,
171 ref_state->info.width, ref_state->info.height,
172 (GstVideoCodecState *)ref_state);
178 if (format == GST_VIDEO_FORMAT_ENCODED) {
179 out_format = GST_VIDEO_FORMAT_I420;
180 gst_video_info_init(&vis);
181 gst_video_info_set_format(&vis, out_format,
182 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
185 gst_video_codec_state_unref(state);
187 #if GST_CHECK_VERSION(1,1,0)
190 case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
191 gst_vaapidecode_video_info_change_format(&vis, GST_VIDEO_FORMAT_RGBA,
192 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
193 features = gst_caps_features_new(
194 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL);
197 if (format == GST_VIDEO_FORMAT_ENCODED) {
198 /* XXX: this is a workaround until auto-plugging is fixed when
199 format=ENCODED + memory:VASurface caps feature are provided.
200 Meanwhile, providing a random format here works but this is
201 a terribly wrong thing per se. */
202 gst_vaapidecode_video_info_change_format(&vis, out_format,
203 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
204 #if GST_CHECK_VERSION(1,5,0)
205 if (feature == GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
206 features = gst_caps_features_new(
207 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, NULL);
212 state->caps = gst_video_info_to_caps(&vis);
214 gst_caps_set_features(state->caps, 0, features);
216 /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
217 reconstruct suitable caps for "encoded" video formats */
218 state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
222 gst_caps_set_simple(state->caps,
223 "type", G_TYPE_STRING, "vaapi",
224 "opengl", G_TYPE_BOOLEAN, USE_GLX,
225 "width", G_TYPE_INT, vi->width,
226 "height", G_TYPE_INT, vi->height,
227 "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
228 "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d,
231 gst_caps_set_interlaced(state->caps, vi);
233 gst_caps_replace(&decode->srcpad_caps, state->caps);
238 gst_vaapidecode_release(GstVaapiDecode *decode)
240 g_mutex_lock(&decode->decoder_mutex);
241 g_cond_signal(&decode->decoder_ready);
242 g_mutex_unlock(&decode->decoder_mutex);
246 gst_vaapidecode_decode_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
248 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
249 GstVaapiDecoderStatus status;
252 /* Decode current frame */
254 status = gst_vaapi_decoder_decode(decode->decoder, frame);
255 if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
256 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
257 g_mutex_lock(&decode->decoder_mutex);
258 g_cond_wait(&decode->decoder_ready, &decode->decoder_mutex);
259 g_mutex_unlock(&decode->decoder_mutex);
260 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
261 if (decode->decoder_loop_status < 0)
262 goto error_decode_loop;
265 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
270 /* Try to report back early any error that occured in the decode task */
271 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
272 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
273 return decode->decoder_loop_status;
278 GST_ERROR("decode loop error %d", decode->decoder_loop_status);
279 gst_video_decoder_drop_frame(vdec, frame);
280 return decode->decoder_loop_status;
284 GST_ERROR("decode error %d", status);
286 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
287 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
288 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
289 ret = GST_FLOW_NOT_SUPPORTED;
292 ret = GST_FLOW_ERROR;
295 gst_video_decoder_drop_frame(vdec, frame);
301 gst_vaapidecode_push_decoded_frame(GstVideoDecoder *vdec,
302 GstVideoCodecFrame *out_frame)
304 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
305 GstVaapiSurfaceProxy *proxy;
307 #if GST_CHECK_VERSION(1,0,0)
308 const GstVaapiRectangle *crop_rect;
309 GstVaapiVideoMeta *meta;
313 if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
314 proxy = gst_video_codec_frame_get_user_data(out_frame);
316 gst_vaapi_surface_proxy_set_destroy_notify(proxy,
317 (GDestroyNotify)gst_vaapidecode_release, decode);
319 #if GST_CHECK_VERSION(1,0,0)
320 ret = gst_video_decoder_allocate_output_frame(vdec, out_frame);
321 if (ret != GST_FLOW_OK)
322 goto error_create_buffer;
324 meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer);
327 gst_vaapi_video_meta_set_surface_proxy(meta, proxy);
329 flags = gst_vaapi_surface_proxy_get_flags(proxy);
330 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
331 guint out_flags = GST_VIDEO_BUFFER_FLAG_INTERLACED;
332 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
333 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
334 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
335 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
336 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
337 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
338 GST_BUFFER_FLAG_SET(out_frame->output_buffer, out_flags);
341 crop_rect = gst_vaapi_surface_proxy_get_crop_rect(proxy);
343 GstVideoCropMeta * const crop_meta =
344 gst_buffer_add_video_crop_meta(out_frame->output_buffer);
346 crop_meta->x = crop_rect->x;
347 crop_meta->y = crop_rect->y;
348 crop_meta->width = crop_rect->width;
349 crop_meta->height = crop_rect->height;
353 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
354 if (decode->has_texture_upload_meta)
355 gst_buffer_ensure_texture_upload_meta(out_frame->output_buffer);
358 out_frame->output_buffer =
359 gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
360 if (!out_frame->output_buffer)
361 goto error_create_buffer;
365 ret = gst_video_decoder_finish_frame(vdec, out_frame);
366 if (ret != GST_FLOW_OK)
367 goto error_commit_buffer;
369 gst_video_codec_frame_unref(out_frame);
375 const GstVaapiID surface_id =
376 gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
378 GST_ERROR("video sink failed to create video buffer for proxy'ed "
379 "surface %" GST_VAAPI_ID_FORMAT,
380 GST_VAAPI_ID_ARGS(surface_id));
381 gst_video_decoder_drop_frame(vdec, out_frame);
382 gst_video_codec_frame_unref(out_frame);
383 return GST_FLOW_ERROR;
385 #if GST_CHECK_VERSION(1,0,0)
388 GST_ERROR("failed to get vaapi video meta attached to video buffer");
389 gst_video_decoder_drop_frame(vdec, out_frame);
390 gst_video_codec_frame_unref(out_frame);
391 return GST_FLOW_ERROR;
396 if (ret != GST_FLOW_FLUSHING)
397 GST_ERROR("video sink rejected the video buffer (error %d)", ret);
398 gst_video_codec_frame_unref(out_frame);
404 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
408 /* Make sure to release the base class stream lock so that decode
409 loop can call gst_video_decoder_finish_frame() without blocking */
410 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
411 ret = gst_vaapidecode_decode_frame(vdec, frame);
412 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
417 gst_vaapidecode_decode_loop(GstVaapiDecode *decode)
419 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
420 GstVaapiDecoderStatus status;
421 GstVideoCodecFrame *out_frame;
424 status = gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
427 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
429 case GST_VAAPI_DECODER_STATUS_SUCCESS:
430 ret = gst_vaapidecode_push_decoded_frame(vdec, out_frame);
432 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
433 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
436 ret = GST_FLOW_ERROR;
439 decode->decoder_loop_status = ret;
440 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
442 if (ret == GST_FLOW_OK)
445 /* If invoked from gst_vaapidecode_finish(), then return right
446 away no matter the errors, or the GstVaapiDecoder needs further
447 data to complete decoding (there no more data to feed in) */
448 if (decode->decoder_finish) {
449 g_mutex_lock(&decode->decoder_mutex);
450 g_cond_signal(&decode->decoder_finish_done);
451 g_mutex_unlock(&decode->decoder_mutex);
455 /* Suspend the task if an error occurred */
456 if (ret != GST_VIDEO_DECODER_FLOW_NEED_DATA)
457 gst_pad_pause_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
461 gst_vaapidecode_flush(GstVideoDecoder *vdec)
463 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
464 GstVaapiDecoderStatus status;
466 /* If there is something in GstVideoDecoder's output adapter, then
467 submit the frame for decoding */
468 if (decode->current_frame_size) {
469 gst_video_decoder_have_frame(vdec);
470 decode->current_frame_size = 0;
473 status = gst_vaapi_decoder_flush(decode->decoder);
474 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
481 GST_ERROR("failed to flush decoder (status %d)", status);
487 gst_vaapidecode_finish(GstVideoDecoder *vdec)
489 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
490 GstFlowReturn ret = GST_FLOW_OK;
492 if (!gst_vaapidecode_flush(vdec))
495 /* Make sure the decode loop function has a chance to return, thus
496 possibly unlocking gst_video_decoder_finish_frame() */
497 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
498 g_mutex_lock(&decode->decoder_mutex);
499 decode->decoder_finish = TRUE;
500 g_cond_wait(&decode->decoder_finish_done, &decode->decoder_mutex);
501 g_mutex_unlock(&decode->decoder_mutex);
502 gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
503 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
507 #if GST_CHECK_VERSION(1,0,0)
509 gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
511 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
512 GstCaps *caps = NULL;
514 GstStructure *config;
516 guint size, min, max;
517 gboolean need_pool, update_pool;
518 gboolean has_video_meta = FALSE;
519 gboolean has_video_alignment = FALSE;
520 GstVideoCodecState *state;
521 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
522 gboolean has_texture_upload_meta = FALSE;
523 GstCapsFeatures *features, *features2;
526 gst_query_parse_allocation(query, &caps, &need_pool);
531 state = gst_video_decoder_get_output_state(vdec);
533 decode->has_texture_upload_meta = FALSE;
534 has_video_meta = gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
535 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
537 decode->has_texture_upload_meta = gst_query_find_allocation_meta(query,
538 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
540 features = gst_caps_get_features(state->caps, 0);
541 features2 = gst_caps_features_new(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL);
543 has_texture_upload_meta =
544 gst_vaapi_find_preferred_caps_feature(GST_VIDEO_DECODER_SRC_PAD(vdec),
545 GST_VIDEO_FORMAT_ENCODED) ==
546 GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META;
548 /* Update src caps if feature is not handled downstream */
549 if (!decode->has_texture_upload_meta &&
550 gst_caps_features_is_equal(features, features2))
551 gst_vaapidecode_update_src_caps (decode, state);
552 else if (has_texture_upload_meta &&
553 !gst_caps_features_is_equal(features, features2)) {
554 gst_video_info_set_format(&state->info, GST_VIDEO_FORMAT_RGBA,
557 gst_vaapidecode_update_src_caps(decode, state);
559 gst_caps_features_free(features2);
562 gst_video_codec_state_unref(state);
564 gst_video_info_init(&vi);
565 gst_video_info_from_caps(&vi, caps);
566 if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED)
567 gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_I420,
568 GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
570 g_return_val_if_fail(GST_VAAPI_PLUGIN_BASE_DISPLAY(decode) != NULL, FALSE);
572 if (gst_query_get_n_allocation_pools(query) > 0) {
573 gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
574 size = MAX(size, vi.size);
577 /* Check whether downstream element proposed a bufferpool but did
578 not provide a correct propose_allocation() implementation */
579 has_video_alignment = gst_buffer_pool_has_option(pool,
580 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
589 if (!pool || !gst_buffer_pool_has_option(pool,
590 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
591 GST_INFO("no pool or doesn't support GstVaapiVideoMeta, "
594 gst_object_unref(pool);
595 pool = gst_vaapi_video_buffer_pool_new(
596 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
598 goto error_create_pool;
600 config = gst_buffer_pool_get_config(pool);
601 gst_buffer_pool_config_set_params(config, caps, size, min, max);
602 gst_buffer_pool_config_add_option(config,
603 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
604 gst_buffer_pool_set_config(pool, config);
607 if (has_video_meta) {
608 config = gst_buffer_pool_get_config(pool);
609 gst_buffer_pool_config_add_option(config,
610 GST_BUFFER_POOL_OPTION_VIDEO_META);
611 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
612 if (decode->has_texture_upload_meta)
613 gst_buffer_pool_config_add_option(config,
614 GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
616 gst_buffer_pool_set_config(pool, config);
618 else if (has_video_alignment) {
619 config = gst_buffer_pool_get_config(pool);
620 gst_buffer_pool_config_add_option(config,
621 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
622 gst_buffer_pool_set_config(pool, config);
626 gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
628 gst_query_add_allocation_pool(query, pool, size, min, max);
630 gst_object_unref(pool);
636 GST_ERROR("no caps specified");
641 GST_ERROR("failed to create buffer pool");
647 static inline gboolean
648 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
650 return gst_vaapi_plugin_base_ensure_display(GST_VAAPI_PLUGIN_BASE(decode));
654 gst_vaapi_codec_from_caps(GstCaps *caps)
656 return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
660 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
662 GstVaapiDisplay *dpy;
664 if (!gst_vaapidecode_ensure_display(decode))
666 dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY(decode);
668 switch (gst_vaapi_codec_from_caps(caps)) {
669 case GST_VAAPI_CODEC_MPEG2:
670 decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
672 case GST_VAAPI_CODEC_MPEG4:
673 case GST_VAAPI_CODEC_H263:
674 decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
676 case GST_VAAPI_CODEC_H264:
677 decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
679 /* Set the stream buffer alignment for better optimizations */
680 if (decode->decoder && caps) {
681 GstStructure * const structure = gst_caps_get_structure(caps, 0);
682 const gchar *str = NULL;
684 if ((str = gst_structure_get_string(structure, "alignment"))) {
685 GstVaapiStreamAlignH264 alignment;
686 if (g_strcmp0(str, "au") == 0)
687 alignment = GST_VAAPI_STREAM_ALIGN_H264_AU;
688 else if (g_strcmp0(str, "nal") == 0)
689 alignment = GST_VAAPI_STREAM_ALIGN_H264_NALU;
691 alignment = GST_VAAPI_STREAM_ALIGN_H264_NONE;
692 gst_vaapi_decoder_h264_set_alignment(
693 GST_VAAPI_DECODER_H264(decode->decoder), alignment);
697 case GST_VAAPI_CODEC_WMV3:
698 case GST_VAAPI_CODEC_VC1:
699 decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
702 case GST_VAAPI_CODEC_JPEG:
703 decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
707 case GST_VAAPI_CODEC_VP8:
708 decode->decoder = gst_vaapi_decoder_vp8_new(dpy, caps);
712 decode->decoder = NULL;
715 if (!decode->decoder)
718 gst_vaapi_decoder_set_codec_state_changed_func(decode->decoder,
719 gst_vaapi_decoder_state_changed, decode);
721 decode->decoder_caps = gst_caps_ref(caps);
722 return gst_pad_start_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode),
723 (GstTaskFunction)gst_vaapidecode_decode_loop, decode, NULL);
727 gst_vaapidecode_destroy(GstVaapiDecode *decode)
729 gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
730 gst_vaapi_decoder_replace(&decode->decoder, NULL);
731 gst_caps_replace(&decode->decoder_caps, NULL);
732 gst_vaapidecode_release(decode);
736 gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
740 decode->has_texture_upload_meta = FALSE;
742 /* Reset tracked frame size */
743 decode->current_frame_size = 0;
745 /* Reset timers if hard reset was requested (e.g. seek) */
747 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
748 GstVideoCodecFrame *out_frame = NULL;
750 gst_vaapi_decoder_flush(decode->decoder);
751 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
752 gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
753 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
754 decode->decoder_loop_status = GST_FLOW_OK;
756 /* Purge all decoded frames as we don't need them (e.g. seek) */
757 while (gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
758 &out_frame, 0) == GST_VAAPI_DECODER_STATUS_SUCCESS) {
759 gst_video_codec_frame_unref(out_frame);
764 /* Only reset decoder if codec type changed */
765 else if (decode->decoder && decode->decoder_caps) {
766 if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
768 codec = gst_vaapi_codec_from_caps(caps);
769 if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
773 gst_vaapidecode_destroy(decode);
774 return gst_vaapidecode_create(decode, caps);
778 gst_vaapidecode_finalize(GObject *object)
780 GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
782 gst_caps_replace(&decode->sinkpad_caps, NULL);
783 gst_caps_replace(&decode->srcpad_caps, NULL);
784 gst_caps_replace(&decode->allowed_caps, NULL);
786 g_cond_clear(&decode->decoder_finish_done);
787 g_cond_clear(&decode->decoder_ready);
788 g_mutex_clear(&decode->decoder_mutex);
790 gst_vaapi_plugin_base_finalize(GST_VAAPI_PLUGIN_BASE(object));
791 G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
795 gst_vaapidecode_open(GstVideoDecoder *vdec)
797 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
798 GstVaapiDisplay * const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY(decode);
801 if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(decode)))
804 /* Let GstVideoContext ask for a proper display to its neighbours */
805 /* Note: steal old display that may be allocated from get_caps()
806 so that to retain a reference to it, thus avoiding extra
807 initialization steps if we turn out to simply re-use the
808 existing (cached) VA display */
809 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode) = NULL;
810 success = gst_vaapidecode_ensure_display(decode);
812 gst_vaapi_display_unref(old_display);
817 gst_vaapidecode_close(GstVideoDecoder *vdec)
819 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
821 gst_vaapidecode_destroy(decode);
822 gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(decode));
827 gst_vaapidecode_reset(GstVideoDecoder *vdec, gboolean hard)
829 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
831 /* In GStreamer 1.0 context, this means a flush */
832 if (decode->decoder && !hard && !gst_vaapidecode_flush(vdec))
834 return gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, hard);
838 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
840 GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(vdec);
841 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
843 if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
845 if (!gst_vaapidecode_update_src_caps(decode, state))
847 if (!gst_video_decoder_negotiate(vdec))
849 if (!gst_vaapi_plugin_base_set_caps(plugin, decode->sinkpad_caps,
850 decode->srcpad_caps))
852 if (!gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, FALSE))
858 gst_vaapidecode_parse_frame(GstVideoDecoder *vdec,
859 GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
861 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
862 GstVaapiDecoderStatus status;
867 status = gst_vaapi_decoder_parse(decode->decoder, frame,
868 adapter, at_eos, &got_unit_size, &got_frame);
871 case GST_VAAPI_DECODER_STATUS_SUCCESS:
872 if (got_unit_size > 0) {
873 gst_video_decoder_add_to_frame(vdec, got_unit_size);
874 decode->current_frame_size += got_unit_size;
877 ret = gst_video_decoder_have_frame(vdec);
878 decode->current_frame_size = 0;
881 ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
883 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
884 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
886 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
887 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
888 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
889 GST_WARNING("parse error %d", status);
890 ret = GST_FLOW_NOT_SUPPORTED;
891 decode->current_frame_size = 0;
894 GST_ERROR("parse error %d", status);
896 decode->current_frame_size = 0;
903 gst_vaapidecode_parse(GstVideoDecoder *vdec,
904 GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
909 ret = gst_vaapidecode_parse_frame(vdec, frame, adapter, at_eos);
910 } while (ret == GST_VAAPI_DECODE_FLOW_PARSE_DATA);
914 static GstStateChangeReturn
915 gst_vaapidecode_change_state (GstElement * element, GstStateChange transition)
917 GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
919 switch (transition) {
920 case GST_STATE_CHANGE_PAUSED_TO_READY:
921 gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
926 return GST_ELEMENT_CLASS(gst_vaapidecode_parent_class)->change_state(
927 element, transition);
931 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
933 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
934 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
935 GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
936 GstPadTemplate *pad_template;
938 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
939 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
941 gst_vaapi_plugin_base_class_init(GST_VAAPI_PLUGIN_BASE_CLASS(klass));
943 object_class->finalize = gst_vaapidecode_finalize;
945 element_class->change_state =
946 GST_DEBUG_FUNCPTR(gst_vaapidecode_change_state);
948 vdec_class->open = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
949 vdec_class->close = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
950 vdec_class->set_format = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
951 vdec_class->reset = GST_DEBUG_FUNCPTR(gst_vaapidecode_reset);
952 vdec_class->parse = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
953 vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
954 vdec_class->finish = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish);
956 #if GST_CHECK_VERSION(1,0,0)
957 vdec_class->decide_allocation =
958 GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
961 gst_element_class_set_static_metadata(element_class,
963 "Codec/Decoder/Video",
965 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
968 pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
969 gst_element_class_add_pad_template(element_class, pad_template);
972 pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
973 gst_element_class_add_pad_template(element_class, pad_template);
977 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
979 GstCaps *caps, *allowed_caps;
983 if (decode->allowed_caps)
986 if (!gst_vaapidecode_ensure_display(decode))
987 goto error_no_display;
989 profiles = gst_vaapi_display_get_decode_profiles(
990 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
992 goto error_no_profiles;
994 allowed_caps = gst_caps_new_empty();
996 goto error_no_memory;
998 for (i = 0; i < profiles->len; i++) {
999 const GstVaapiProfile profile =
1000 g_array_index(profiles, GstVaapiProfile, i);
1001 const gchar *media_type_name;
1003 media_type_name = gst_vaapi_profile_get_media_type_name(profile);
1004 if (!media_type_name)
1007 caps = gst_caps_from_string(media_type_name);
1010 allowed_caps = gst_caps_merge(allowed_caps, caps);
1012 decode->allowed_caps = allowed_caps;
1014 g_array_unref(profiles);
1020 GST_ERROR("failed to retrieve VA display");
1025 GST_ERROR("failed to retrieve VA decode profiles");
1030 GST_ERROR("failed to allocate allowed-caps set");
1031 g_array_unref(profiles);
1037 gst_vaapidecode_get_caps(GstPad *pad)
1039 GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
1041 if (!gst_vaapidecode_ensure_allowed_caps(decode))
1042 return gst_caps_new_empty();
1044 return gst_caps_ref(decode->allowed_caps);
1048 gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
1050 GstVaapiDecode * const decode =
1051 GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
1052 GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(decode);
1055 GST_INFO_OBJECT(decode, "query type %s", GST_QUERY_TYPE_NAME(query));
1057 if (gst_vaapi_reply_to_query(query, plugin->display)) {
1058 GST_DEBUG("sharing display %p", plugin->display);
1061 else if (GST_PAD_IS_SINK(pad)) {
1062 switch (GST_QUERY_TYPE(query)) {
1063 #if GST_CHECK_VERSION(1,0,0)
1064 case GST_QUERY_CAPS: {
1065 GstCaps * const caps = gst_vaapidecode_get_caps(pad);
1066 gst_query_set_caps_result(query, caps);
1067 gst_caps_unref(caps);
1073 res = GST_PAD_QUERY_FUNCTION_CALL(plugin->sinkpad_query, pad,
1079 res = GST_PAD_QUERY_FUNCTION_CALL(plugin->srcpad_query, pad,
1082 gst_object_unref(decode);
1087 gst_vaapidecode_init(GstVaapiDecode *decode)
1089 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
1092 gst_vaapi_plugin_base_init(GST_VAAPI_PLUGIN_BASE(decode), GST_CAT_DEFAULT);
1094 decode->decoder = NULL;
1095 decode->decoder_caps = NULL;
1096 decode->allowed_caps = NULL;
1097 decode->decoder_loop_status = GST_FLOW_OK;
1099 g_mutex_init(&decode->decoder_mutex);
1100 g_cond_init(&decode->decoder_ready);
1101 g_cond_init(&decode->decoder_finish_done);
1103 gst_video_decoder_set_packetized(vdec, FALSE);
1105 /* Pad through which data comes in to the element */
1106 pad = GST_VAAPI_PLUGIN_BASE_SINK_PAD(decode);
1107 gst_pad_set_query_function(pad, gst_vaapidecode_query);
1108 #if !GST_CHECK_VERSION(1,0,0)
1109 gst_pad_set_getcaps_function(pad, gst_vaapidecode_get_caps);
1112 /* Pad through which data goes out of the element */
1113 pad = GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode);
1114 gst_pad_set_query_function(pad, gst_vaapidecode_query);