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>
53 #define GST_PLUGIN_NAME "vaapidecode"
54 #define GST_PLUGIN_DESC "A VA-API based video decoder"
56 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode);
57 #define GST_CAT_DEFAULT gst_debug_vaapidecode
59 /* Default templates */
60 #define GST_CAPS_CODEC(CODEC) CODEC "; "
62 static const char gst_vaapidecode_sink_caps_str[] =
63 GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
64 GST_CAPS_CODEC("video/mpeg, mpegversion=4")
65 GST_CAPS_CODEC("video/x-divx")
66 GST_CAPS_CODEC("video/x-xvid")
67 GST_CAPS_CODEC("video/x-h263")
68 GST_CAPS_CODEC("video/x-h264")
69 GST_CAPS_CODEC("video/x-wmv")
70 GST_CAPS_CODEC("image/jpeg")
73 static const char gst_vaapidecode_src_caps_str[] =
74 #if GST_CHECK_VERSION(1,1,0)
75 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
76 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ";"
77 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
78 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA") ";"
79 GST_VIDEO_CAPS_MAKE("{ NV12, I420, YV12 }");
81 GST_VAAPI_SURFACE_CAPS;
84 static GstStaticPadTemplate gst_vaapidecode_sink_factory =
85 GST_STATIC_PAD_TEMPLATE(
89 GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));
91 static GstStaticPadTemplate gst_vaapidecode_src_factory =
92 GST_STATIC_PAD_TEMPLATE(
96 GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
98 G_DEFINE_TYPE_WITH_CODE(
101 GST_TYPE_VIDEO_DECODER,
102 GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES)
105 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
106 const GstVideoCodecState *ref_state);
109 gst_vaapi_decoder_state_changed(GstVaapiDecoder *decoder,
110 const GstVideoCodecState *codec_state, gpointer user_data)
112 GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
113 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
115 g_assert(decode->decoder == decoder);
117 gst_vaapidecode_update_src_caps(decode, codec_state);
118 gst_video_decoder_negotiate(vdec);
121 static inline gboolean
122 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
124 gst_caps_replace(&decode->sinkpad_caps, caps);
129 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
130 const GstVideoCodecState *ref_state)
132 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
133 GstVideoCodecState *state;
134 GstVideoInfo *vi, vis;
135 #if GST_CHECK_VERSION(1,1,0)
136 GstCapsFeatures *features = NULL;
137 GstVaapiCapsFeature feature;
139 feature = gst_vaapi_find_preferred_caps_feature(
140 GST_VIDEO_DECODER_SRC_PAD(vdec),
141 GST_VIDEO_INFO_FORMAT(&ref_state->info));
144 state = gst_video_decoder_set_output_state(vdec,
145 GST_VIDEO_INFO_FORMAT(&ref_state->info),
146 ref_state->info.width, ref_state->info.height,
147 (GstVideoCodecState *)ref_state);
152 if (GST_VIDEO_INFO_FORMAT(vi) == GST_VIDEO_FORMAT_ENCODED) {
153 gst_video_info_init(&vis);
154 gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12,
155 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
158 gst_video_codec_state_unref(state);
160 #if GST_CHECK_VERSION(1,1,0)
163 case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
164 gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_RGBA,
165 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
166 features = gst_caps_features_new(
167 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL);
170 if (GST_VIDEO_INFO_FORMAT(vi) == GST_VIDEO_FORMAT_ENCODED) {
171 /* XXX: this is a workaround until auto-plugging is fixed when
172 format=ENCODED + memory:VASurface caps feature are provided.
173 Meanwhile, providing a random format here works but this is
174 a terribly wrong thing per se. */
175 gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12,
176 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
177 #if GST_CHECK_VERSION(1,3,0)
178 if (feature == GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
179 features = gst_caps_features_new(
180 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, NULL);
185 state->caps = gst_video_info_to_caps(&vis);
187 gst_caps_set_features(state->caps, 0, features);
189 /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
190 reconstruct suitable caps for "encoded" video formats */
191 state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
195 gst_caps_set_simple(state->caps,
196 "type", G_TYPE_STRING, "vaapi",
197 "opengl", G_TYPE_BOOLEAN, USE_GLX,
198 "width", G_TYPE_INT, vi->width,
199 "height", G_TYPE_INT, vi->height,
200 "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
201 "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d,
204 gst_caps_set_interlaced(state->caps, vi);
206 gst_caps_replace(&decode->srcpad_caps, state->caps);
211 gst_vaapidecode_release(GstVaapiDecode *decode)
213 g_mutex_lock(&decode->decoder_mutex);
214 g_cond_signal(&decode->decoder_ready);
215 g_mutex_unlock(&decode->decoder_mutex);
219 gst_vaapidecode_decode_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
221 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
222 GstVaapiDecoderStatus status;
225 /* Decode current frame */
227 status = gst_vaapi_decoder_decode(decode->decoder, frame);
228 if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
229 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
230 g_mutex_lock(&decode->decoder_mutex);
231 g_cond_wait(&decode->decoder_ready, &decode->decoder_mutex);
232 g_mutex_unlock(&decode->decoder_mutex);
233 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
234 if (decode->decoder_loop_status < 0)
235 goto error_decode_loop;
238 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
243 /* Try to report back early any error that occured in the decode task */
244 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
245 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
246 return decode->decoder_loop_status;
251 GST_ERROR("decode loop error %d", decode->decoder_loop_status);
252 gst_video_decoder_drop_frame(vdec, frame);
253 return decode->decoder_loop_status;
257 GST_ERROR("decode error %d", 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;
265 ret = GST_FLOW_ERROR;
268 gst_video_decoder_drop_frame(vdec, frame);
274 gst_vaapidecode_push_decoded_frame(GstVideoDecoder *vdec,
275 GstVideoCodecFrame *out_frame)
277 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
278 GstVaapiSurfaceProxy *proxy;
280 #if GST_CHECK_VERSION(1,0,0)
281 const GstVaapiRectangle *crop_rect;
282 GstVaapiVideoMeta *meta;
286 if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
287 proxy = gst_video_codec_frame_get_user_data(out_frame);
289 gst_vaapi_surface_proxy_set_destroy_notify(proxy,
290 (GDestroyNotify)gst_vaapidecode_release, decode);
292 #if GST_CHECK_VERSION(1,0,0)
293 ret = gst_video_decoder_allocate_output_frame(vdec, out_frame);
294 if (ret != GST_FLOW_OK)
295 goto error_create_buffer;
297 meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer);
300 gst_vaapi_video_meta_set_surface_proxy(meta, proxy);
302 flags = gst_vaapi_surface_proxy_get_flags(proxy);
303 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
304 guint out_flags = GST_VIDEO_BUFFER_FLAG_INTERLACED;
305 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
306 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
307 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
308 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
309 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
310 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
311 GST_BUFFER_FLAG_SET(out_frame->output_buffer, out_flags);
314 crop_rect = gst_vaapi_surface_proxy_get_crop_rect(proxy);
316 GstVideoCropMeta * const crop_meta =
317 gst_buffer_add_video_crop_meta(out_frame->output_buffer);
319 crop_meta->x = crop_rect->x;
320 crop_meta->y = crop_rect->y;
321 crop_meta->width = crop_rect->width;
322 crop_meta->height = crop_rect->height;
326 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
327 if (decode->has_texture_upload_meta)
328 gst_buffer_ensure_texture_upload_meta(out_frame->output_buffer);
331 out_frame->output_buffer =
332 gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
333 if (!out_frame->output_buffer)
334 goto error_create_buffer;
338 ret = gst_video_decoder_finish_frame(vdec, out_frame);
339 if (ret != GST_FLOW_OK)
340 goto error_commit_buffer;
342 gst_video_codec_frame_unref(out_frame);
348 const GstVaapiID surface_id =
349 gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
351 GST_ERROR("video sink failed to create video buffer for proxy'ed "
352 "surface %" GST_VAAPI_ID_FORMAT,
353 GST_VAAPI_ID_ARGS(surface_id));
354 gst_video_decoder_drop_frame(vdec, out_frame);
355 gst_video_codec_frame_unref(out_frame);
356 return GST_FLOW_ERROR;
358 #if GST_CHECK_VERSION(1,0,0)
361 GST_ERROR("failed to get vaapi video meta attached to video buffer");
362 gst_video_decoder_drop_frame(vdec, out_frame);
363 gst_video_codec_frame_unref(out_frame);
364 return GST_FLOW_ERROR;
369 if (ret != GST_FLOW_FLUSHING)
370 GST_ERROR("video sink rejected the video buffer (error %d)", ret);
371 gst_video_codec_frame_unref(out_frame);
377 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
381 /* Make sure to release the base class stream lock so that decode
382 loop can call gst_video_decoder_finish_frame() without blocking */
383 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
384 ret = gst_vaapidecode_decode_frame(vdec, frame);
385 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
390 gst_vaapidecode_decode_loop(GstVaapiDecode *decode)
392 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
393 GstVaapiDecoderStatus status;
394 GstVideoCodecFrame *out_frame;
397 status = gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
400 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
402 case GST_VAAPI_DECODER_STATUS_SUCCESS:
403 ret = gst_vaapidecode_push_decoded_frame(vdec, out_frame);
405 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
406 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
409 ret = GST_FLOW_ERROR;
412 decode->decoder_loop_status = ret;
413 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
415 if (ret == GST_FLOW_OK)
418 /* If invoked from gst_vaapidecode_finish(), then return right
419 away no matter the errors, or the GstVaapiDecoder needs further
420 data to complete decoding (there no more data to feed in) */
421 if (decode->decoder_finish) {
422 g_mutex_lock(&decode->decoder_mutex);
423 g_cond_signal(&decode->decoder_finish_done);
424 g_mutex_unlock(&decode->decoder_mutex);
428 /* Suspend the task if an error occurred */
429 if (ret != GST_VIDEO_DECODER_FLOW_NEED_DATA)
430 gst_pad_pause_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
434 gst_vaapidecode_flush(GstVideoDecoder *vdec)
436 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
437 GstVaapiDecoderStatus status;
439 /* If there is something in GstVideoDecoder's output adapter, then
440 submit the frame for decoding */
441 if (decode->current_frame_size) {
442 gst_video_decoder_have_frame(vdec);
443 decode->current_frame_size = 0;
446 status = gst_vaapi_decoder_flush(decode->decoder);
447 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
454 GST_ERROR("failed to flush decoder (status %d)", status);
460 gst_vaapidecode_finish(GstVideoDecoder *vdec)
462 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
463 GstFlowReturn ret = GST_FLOW_OK;
465 if (!gst_vaapidecode_flush(vdec))
468 /* Make sure the decode loop function has a chance to return, thus
469 possibly unlocking gst_video_decoder_finish_frame() */
470 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
471 g_mutex_lock(&decode->decoder_mutex);
472 decode->decoder_finish = TRUE;
473 g_cond_wait(&decode->decoder_finish_done, &decode->decoder_mutex);
474 g_mutex_unlock(&decode->decoder_mutex);
475 gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
476 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
480 #if GST_CHECK_VERSION(1,0,0)
482 gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
484 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
485 GstCaps *caps = NULL;
487 GstStructure *config;
489 guint size, min, max;
490 gboolean need_pool, update_pool;
491 gboolean has_video_meta = FALSE;
492 GstVideoCodecState *state;
493 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
494 GstCapsFeatures *features, *features2;
497 gst_query_parse_allocation(query, &caps, &need_pool);
502 state = gst_video_decoder_get_output_state(vdec);
504 decode->has_texture_upload_meta = FALSE;
505 has_video_meta = gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);
506 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
508 decode->has_texture_upload_meta = gst_query_find_allocation_meta(query,
509 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
511 features = gst_caps_get_features(state->caps, 0);
512 features2 = gst_caps_features_new(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL);
514 /* Update src caps if feature is not handled downstream */
515 if (!decode->has_texture_upload_meta &&
516 gst_caps_features_is_equal(features, features2))
517 gst_vaapidecode_update_src_caps (decode, state);
518 gst_caps_features_free(features2);
521 gst_video_codec_state_unref(state);
523 gst_video_info_init(&vi);
524 gst_video_info_from_caps(&vi, caps);
525 if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED)
526 gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
527 GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
529 g_return_val_if_fail(GST_VAAPI_PLUGIN_BASE_DISPLAY(decode) != NULL, FALSE);
531 if (gst_query_get_n_allocation_pools(query) > 0) {
532 gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
533 size = MAX(size, vi.size);
543 if (!pool || !gst_buffer_pool_has_option(pool,
544 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
545 GST_INFO("no pool or doesn't support GstVaapiVideoMeta, "
547 pool = gst_vaapi_video_buffer_pool_new(
548 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
550 goto error_create_pool;
552 config = gst_buffer_pool_get_config(pool);
553 gst_buffer_pool_config_set_params(config, caps, size, min, max);
554 gst_buffer_pool_config_add_option(config,
555 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
556 gst_buffer_pool_set_config(pool, config);
559 if (has_video_meta) {
560 config = gst_buffer_pool_get_config(pool);
561 gst_buffer_pool_config_add_option(config,
562 GST_BUFFER_POOL_OPTION_VIDEO_META);
563 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
564 if (decode->has_texture_upload_meta)
565 gst_buffer_pool_config_add_option(config,
566 GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
568 gst_buffer_pool_set_config(pool, config);
572 gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
574 gst_query_add_allocation_pool(query, pool, size, min, max);
576 gst_object_unref(pool);
582 GST_ERROR("no caps specified");
587 GST_ERROR("failed to create buffer pool");
593 static inline gboolean
594 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
596 return gst_vaapi_plugin_base_ensure_display(GST_VAAPI_PLUGIN_BASE(decode));
600 gst_vaapi_codec_from_caps(GstCaps *caps)
602 return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
606 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
608 GstVaapiDisplay *dpy;
610 if (!gst_vaapidecode_ensure_display(decode))
612 dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY(decode);
614 switch (gst_vaapi_codec_from_caps(caps)) {
615 case GST_VAAPI_CODEC_MPEG2:
616 decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
618 case GST_VAAPI_CODEC_MPEG4:
619 case GST_VAAPI_CODEC_H263:
620 decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
622 case GST_VAAPI_CODEC_H264:
623 decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
625 case GST_VAAPI_CODEC_WMV3:
626 case GST_VAAPI_CODEC_VC1:
627 decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
630 case GST_VAAPI_CODEC_JPEG:
631 decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
635 decode->decoder = NULL;
638 if (!decode->decoder)
641 gst_vaapi_decoder_set_codec_state_changed_func(decode->decoder,
642 gst_vaapi_decoder_state_changed, decode);
644 decode->decoder_caps = gst_caps_ref(caps);
645 return gst_pad_start_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode),
646 (GstTaskFunction)gst_vaapidecode_decode_loop, decode, NULL);
650 gst_vaapidecode_destroy(GstVaapiDecode *decode)
652 gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
653 gst_vaapi_decoder_replace(&decode->decoder, NULL);
654 gst_caps_replace(&decode->decoder_caps, NULL);
655 gst_vaapidecode_release(decode);
659 gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
663 decode->has_texture_upload_meta = FALSE;
665 /* Reset tracked frame size */
666 decode->current_frame_size = 0;
668 /* Reset timers if hard reset was requested (e.g. seek) */
670 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
671 GstVideoCodecFrame *out_frame = NULL;
673 gst_vaapi_decoder_flush(decode->decoder);
674 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
675 gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
676 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
677 decode->decoder_loop_status = GST_FLOW_OK;
679 /* Purge all decoded frames as we don't need them (e.g. seek) */
680 while (gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
681 &out_frame, 0) == GST_VAAPI_DECODER_STATUS_SUCCESS) {
682 gst_video_codec_frame_unref(out_frame);
687 /* Only reset decoder if codec type changed */
688 else if (decode->decoder && decode->decoder_caps) {
689 if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
691 codec = gst_vaapi_codec_from_caps(caps);
692 if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
696 gst_vaapidecode_destroy(decode);
697 return gst_vaapidecode_create(decode, caps);
701 gst_vaapidecode_finalize(GObject *object)
703 GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
705 gst_caps_replace(&decode->sinkpad_caps, NULL);
706 gst_caps_replace(&decode->srcpad_caps, NULL);
707 gst_caps_replace(&decode->allowed_caps, NULL);
709 g_cond_clear(&decode->decoder_finish_done);
710 g_cond_clear(&decode->decoder_ready);
711 g_mutex_clear(&decode->decoder_mutex);
713 gst_vaapi_plugin_base_finalize(GST_VAAPI_PLUGIN_BASE(object));
714 G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
718 gst_vaapidecode_open(GstVideoDecoder *vdec)
720 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
721 GstVaapiDisplay * const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY(decode);
724 if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(decode)))
727 /* Let GstVideoContext ask for a proper display to its neighbours */
728 /* Note: steal old display that may be allocated from get_caps()
729 so that to retain a reference to it, thus avoiding extra
730 initialization steps if we turn out to simply re-use the
731 existing (cached) VA display */
732 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode) = NULL;
733 success = gst_vaapidecode_ensure_display(decode);
735 gst_vaapi_display_unref(old_display);
740 gst_vaapidecode_close(GstVideoDecoder *vdec)
742 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
744 gst_vaapidecode_destroy(decode);
745 gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(decode));
750 gst_vaapidecode_reset(GstVideoDecoder *vdec, gboolean hard)
752 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
754 /* In GStreamer 1.0 context, this means a flush */
755 if (decode->decoder && !hard && !gst_vaapidecode_flush(vdec))
757 return gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, hard);
761 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
763 GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(vdec);
764 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
766 if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
768 if (!gst_vaapidecode_update_src_caps(decode, state))
770 if (!gst_video_decoder_negotiate(vdec))
772 if (!gst_vaapi_plugin_base_set_caps(plugin, decode->sinkpad_caps,
773 decode->srcpad_caps))
775 if (!gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, FALSE))
781 gst_vaapidecode_parse(GstVideoDecoder *vdec,
782 GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
784 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
785 GstVaapiDecoderStatus status;
790 status = gst_vaapi_decoder_parse(decode->decoder, frame,
791 adapter, at_eos, &got_unit_size, &got_frame);
794 case GST_VAAPI_DECODER_STATUS_SUCCESS:
795 if (got_unit_size > 0) {
796 gst_video_decoder_add_to_frame(vdec, got_unit_size);
797 decode->current_frame_size += got_unit_size;
800 ret = gst_video_decoder_have_frame(vdec);
801 decode->current_frame_size = 0;
806 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
807 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
809 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
810 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
811 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
812 GST_WARNING("parse error %d", status);
813 ret = GST_FLOW_NOT_SUPPORTED;
814 decode->current_frame_size = 0;
817 GST_ERROR("parse error %d", status);
819 decode->current_frame_size = 0;
825 static GstStateChangeReturn
826 gst_vaapidecode_change_state (GstElement * element, GstStateChange transition)
828 GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
830 switch (transition) {
831 case GST_STATE_CHANGE_PAUSED_TO_READY:
832 gst_pad_stop_task(GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode));
837 return GST_ELEMENT_CLASS(gst_vaapidecode_parent_class)->change_state(
838 element, transition);
842 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
844 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
845 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
846 GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
847 GstPadTemplate *pad_template;
849 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
850 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
852 gst_vaapi_plugin_base_class_init(GST_VAAPI_PLUGIN_BASE_CLASS(klass));
854 object_class->finalize = gst_vaapidecode_finalize;
856 element_class->change_state =
857 GST_DEBUG_FUNCPTR(gst_vaapidecode_change_state);
859 vdec_class->open = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
860 vdec_class->close = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
861 vdec_class->set_format = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
862 vdec_class->reset = GST_DEBUG_FUNCPTR(gst_vaapidecode_reset);
863 vdec_class->parse = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
864 vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
865 vdec_class->finish = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish);
867 #if GST_CHECK_VERSION(1,0,0)
868 vdec_class->decide_allocation =
869 GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
872 gst_element_class_set_static_metadata(element_class,
874 "Codec/Decoder/Video",
876 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
879 pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
880 gst_element_class_add_pad_template(element_class, pad_template);
883 pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
884 gst_element_class_add_pad_template(element_class, pad_template);
888 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
890 GstCaps *caps, *allowed_caps;
894 if (decode->allowed_caps)
897 if (!gst_vaapidecode_ensure_display(decode))
898 goto error_no_display;
900 profiles = gst_vaapi_display_get_decode_profiles(
901 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
903 goto error_no_profiles;
905 allowed_caps = gst_caps_new_empty();
907 goto error_no_memory;
909 for (i = 0; i < profiles->len; i++) {
910 const GstVaapiProfile profile =
911 g_array_index(profiles, GstVaapiProfile, i);
912 const gchar *media_type_name;
914 media_type_name = gst_vaapi_profile_get_media_type_name(profile);
915 if (!media_type_name)
918 caps = gst_caps_from_string(media_type_name);
921 allowed_caps = gst_caps_merge(allowed_caps, caps);
923 decode->allowed_caps = allowed_caps;
925 g_array_unref(profiles);
931 GST_ERROR("failed to retrieve VA display");
936 GST_ERROR("failed to retrieve VA decode profiles");
941 GST_ERROR("failed to allocate allowed-caps set");
942 g_array_unref(profiles);
948 gst_vaapidecode_get_caps(GstPad *pad)
950 GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
952 if (!gst_vaapidecode_ensure_allowed_caps(decode))
953 return gst_caps_new_empty();
955 return gst_caps_ref(decode->allowed_caps);
959 gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
961 GstVaapiDecode * const decode =
962 GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
963 GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(decode);
966 GST_INFO_OBJECT(decode, "query type %s", GST_QUERY_TYPE_NAME(query));
968 if (gst_vaapi_reply_to_query(query, plugin->display)) {
969 GST_DEBUG("sharing display %p", plugin->display);
972 else if (GST_PAD_IS_SINK(pad)) {
973 switch (GST_QUERY_TYPE(query)) {
974 #if GST_CHECK_VERSION(1,0,0)
975 case GST_QUERY_CAPS: {
976 GstCaps * const caps = gst_vaapidecode_get_caps(pad);
977 gst_query_set_caps_result(query, caps);
978 gst_caps_unref(caps);
984 res = GST_PAD_QUERY_FUNCTION_CALL(plugin->sinkpad_query, pad,
990 res = GST_PAD_QUERY_FUNCTION_CALL(plugin->srcpad_query, pad,
993 gst_object_unref(decode);
998 gst_vaapidecode_init(GstVaapiDecode *decode)
1000 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
1003 gst_vaapi_plugin_base_init(GST_VAAPI_PLUGIN_BASE(decode), GST_CAT_DEFAULT);
1005 decode->decoder = NULL;
1006 decode->decoder_caps = NULL;
1007 decode->allowed_caps = NULL;
1008 decode->decoder_loop_status = GST_FLOW_OK;
1010 g_mutex_init(&decode->decoder_mutex);
1011 g_cond_init(&decode->decoder_ready);
1012 g_cond_init(&decode->decoder_finish_done);
1014 gst_video_decoder_set_packetized(vdec, FALSE);
1016 /* Pad through which data comes in to the element */
1017 pad = GST_VAAPI_PLUGIN_BASE_SINK_PAD(decode);
1018 gst_pad_set_query_function(pad, gst_vaapidecode_query);
1019 #if !GST_CHECK_VERSION(1,0,0)
1020 gst_pad_set_getcaps_function(pad, gst_vaapidecode_get_caps);
1023 /* Pad through which data goes out of the element */
1024 pad = GST_VAAPI_PLUGIN_BASE_SRC_PAD(decode);
1025 gst_pad_set_query_function(pad, gst_vaapidecode_query);