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-2013 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 "gstvaapivideocontext.h"
39 #include "gstvaapivideobuffer.h"
40 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
41 #include "gstvaapivideometa_texture.h"
43 #if GST_CHECK_VERSION(1,0,0)
44 #include "gstvaapivideobufferpool.h"
45 #include "gstvaapivideomemory.h"
48 #include <gst/vaapi/gstvaapidecoder_h264.h>
49 #include <gst/vaapi/gstvaapidecoder_jpeg.h>
50 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
51 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
52 #include <gst/vaapi/gstvaapidecoder_vc1.h>
54 #define GST_PLUGIN_NAME "vaapidecode"
55 #define GST_PLUGIN_DESC "A VA-API based video decoder"
57 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode);
58 #define GST_CAT_DEFAULT gst_debug_vaapidecode
60 /* Default templates */
61 #define GST_CAPS_CODEC(CODEC) CODEC "; "
63 static const char gst_vaapidecode_sink_caps_str[] =
64 GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
65 GST_CAPS_CODEC("video/mpeg, mpegversion=4")
66 GST_CAPS_CODEC("video/x-divx")
67 GST_CAPS_CODEC("video/x-xvid")
68 GST_CAPS_CODEC("video/x-h263")
69 GST_CAPS_CODEC("video/x-h264")
70 GST_CAPS_CODEC("video/x-wmv")
71 GST_CAPS_CODEC("image/jpeg")
74 static const char gst_vaapidecode_src_caps_str[] =
75 #if GST_CHECK_VERSION(1,1,0)
76 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
77 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ";"
78 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
79 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA");
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 /* GstImplementsInterface interface */
99 #if !GST_CHECK_VERSION(1,0,0)
101 gst_vaapidecode_implements_interface_supported(
102 GstImplementsInterface *iface,
106 return (type == GST_TYPE_VIDEO_CONTEXT);
110 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface)
112 iface->supported = gst_vaapidecode_implements_interface_supported;
116 /* GstVideoContext interface */
117 #if !GST_CHECK_VERSION(1,1,0)
119 gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
122 GstVaapiDecode *decode = GST_VAAPIDECODE (context);
123 gst_vaapi_set_display (type, value, &GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
127 gst_video_context_interface_init(GstVideoContextInterface *iface)
129 iface->set_context = gst_vaapidecode_set_video_context;
132 #define GstVideoContextClass GstVideoContextInterface
135 G_DEFINE_TYPE_WITH_CODE(
138 GST_TYPE_VIDEO_DECODER,
139 #if !GST_CHECK_VERSION(1,0,0)
140 G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
141 gst_vaapidecode_implements_iface_init);
143 #if !GST_CHECK_VERSION(1,1,0)
144 G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
145 gst_video_context_interface_init)
150 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
151 const GstVideoCodecState *ref_state);
154 gst_vaapi_decoder_state_changed(GstVaapiDecoder *decoder,
155 const GstVideoCodecState *codec_state, gpointer user_data)
157 GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
159 g_assert(decode->decoder == decoder);
161 gst_vaapidecode_update_src_caps(decode, codec_state);
164 static inline gboolean
165 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
167 gst_caps_replace(&decode->sinkpad_caps, caps);
172 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
173 const GstVideoCodecState *ref_state)
175 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
176 GstVideoCodecState *state;
177 GstVideoInfo *vi, vis;
179 state = gst_video_decoder_set_output_state(vdec,
180 GST_VIDEO_INFO_FORMAT(&ref_state->info),
181 ref_state->info.width, ref_state->info.height,
182 (GstVideoCodecState *)ref_state);
187 if (GST_VIDEO_INFO_FORMAT(vi) == GST_VIDEO_FORMAT_ENCODED) {
188 gst_video_info_init(&vis);
189 gst_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12,
190 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
193 gst_video_codec_state_unref(state);
195 #if GST_CHECK_VERSION(1,1,0)
197 if (GST_VIDEO_INFO_FORMAT(vi) == 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_video_info_set_format(&vis, GST_VIDEO_FORMAT_NV12,
203 GST_VIDEO_INFO_WIDTH(vi), GST_VIDEO_INFO_HEIGHT(vi));
205 state->caps = gst_video_info_to_caps(&vis);
207 /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
208 reconstruct suitable caps for "encoded" video formats */
209 state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
213 gst_caps_set_simple(state->caps,
214 "type", G_TYPE_STRING, "vaapi",
215 "opengl", G_TYPE_BOOLEAN, USE_GLX,
216 "width", G_TYPE_INT, vi->width,
217 "height", G_TYPE_INT, vi->height,
218 "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
219 "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d,
222 gst_caps_set_interlaced(state->caps, vi);
224 gst_caps_replace(&decode->srcpad_caps, state->caps);
229 gst_vaapidecode_release(GstVaapiDecode *decode)
231 g_mutex_lock(&decode->decoder_mutex);
232 g_cond_signal(&decode->decoder_ready);
233 g_mutex_unlock(&decode->decoder_mutex);
237 gst_vaapidecode_decode_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
239 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
240 GstVaapiDecoderStatus status;
243 /* Decode current frame */
245 status = gst_vaapi_decoder_decode(decode->decoder, frame);
246 if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
247 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
248 g_mutex_lock(&decode->decoder_mutex);
249 g_cond_wait(&decode->decoder_ready, &decode->decoder_mutex);
250 g_mutex_unlock(&decode->decoder_mutex);
251 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
252 if (decode->decoder_loop_status < 0)
253 goto error_decode_loop;
256 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
261 /* Try to report back early any error that occured in the decode task */
262 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
263 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
264 return decode->decoder_loop_status;
269 GST_ERROR("decode loop error %d", decode->decoder_loop_status);
270 gst_video_decoder_drop_frame(vdec, frame);
271 return decode->decoder_loop_status;
275 GST_ERROR("decode error %d", status);
277 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
278 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
279 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
280 ret = GST_FLOW_NOT_SUPPORTED;
283 ret = GST_FLOW_ERROR;
286 gst_video_decoder_drop_frame(vdec, frame);
292 gst_vaapidecode_push_decoded_frame(GstVideoDecoder *vdec,
293 GstVideoCodecFrame *out_frame)
295 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
296 GstVaapiSurfaceProxy *proxy;
298 #if GST_CHECK_VERSION(1,0,0)
299 const GstVaapiRectangle *crop_rect;
300 GstVaapiVideoMeta *meta;
304 if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
305 proxy = gst_video_codec_frame_get_user_data(out_frame);
307 gst_vaapi_surface_proxy_set_destroy_notify(proxy,
308 (GDestroyNotify)gst_vaapidecode_release, decode);
310 #if GST_CHECK_VERSION(1,0,0)
311 ret = gst_video_decoder_allocate_output_frame(vdec, out_frame);
312 if (ret != GST_FLOW_OK)
313 goto error_create_buffer;
315 meta = gst_buffer_get_vaapi_video_meta(out_frame->output_buffer);
318 gst_vaapi_video_meta_set_surface_proxy(meta, proxy);
320 flags = gst_vaapi_surface_proxy_get_flags(proxy);
321 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
322 guint out_flags = GST_VIDEO_BUFFER_FLAG_INTERLACED;
323 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
324 out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
325 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
326 out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
327 if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
328 out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
329 GST_BUFFER_FLAG_SET(out_frame->output_buffer, out_flags);
332 crop_rect = gst_vaapi_surface_proxy_get_crop_rect(proxy);
334 GstVideoCropMeta * const crop_meta =
335 gst_buffer_add_video_crop_meta(out_frame->output_buffer);
337 crop_meta->x = crop_rect->x;
338 crop_meta->y = crop_rect->y;
339 crop_meta->width = crop_rect->width;
340 crop_meta->height = crop_rect->height;
344 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
345 if (decode->has_texture_upload_meta)
346 gst_buffer_ensure_texture_upload_meta(out_frame->output_buffer);
349 out_frame->output_buffer =
350 gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
351 if (!out_frame->output_buffer)
352 goto error_create_buffer;
356 ret = gst_video_decoder_finish_frame(vdec, out_frame);
357 if (ret != GST_FLOW_OK)
358 goto error_commit_buffer;
360 gst_video_codec_frame_unref(out_frame);
366 const GstVaapiID surface_id =
367 gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
369 GST_ERROR("video sink failed to create video buffer for proxy'ed "
370 "surface %" GST_VAAPI_ID_FORMAT,
371 GST_VAAPI_ID_ARGS(surface_id));
372 gst_video_decoder_drop_frame(vdec, out_frame);
373 gst_video_codec_frame_unref(out_frame);
374 return GST_FLOW_ERROR;
376 #if GST_CHECK_VERSION(1,0,0)
379 GST_ERROR("failed to get vaapi video meta attached to video buffer");
380 gst_video_decoder_drop_frame(vdec, out_frame);
381 gst_video_codec_frame_unref(out_frame);
382 return GST_FLOW_ERROR;
387 if (ret != GST_FLOW_FLUSHING)
388 GST_ERROR("video sink rejected the video buffer (error %d)", ret);
389 gst_video_codec_frame_unref(out_frame);
395 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
399 /* Make sure to release the base class stream lock so that decode
400 loop can call gst_video_decoder_finish_frame() without blocking */
401 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
402 ret = gst_vaapidecode_decode_frame(vdec, frame);
403 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
408 gst_vaapidecode_decode_loop(GstVaapiDecode *decode)
410 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
411 GstVaapiDecoderStatus status;
412 GstVideoCodecFrame *out_frame;
415 status = gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
418 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
420 case GST_VAAPI_DECODER_STATUS_SUCCESS:
421 ret = gst_vaapidecode_push_decoded_frame(vdec, out_frame);
423 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
424 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
427 ret = GST_FLOW_ERROR;
430 decode->decoder_loop_status = ret;
431 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
433 if (ret == GST_FLOW_OK)
436 /* If invoked from gst_vaapidecode_finish(), then return right
437 away no matter the errors, or the GstVaapiDecoder needs further
438 data to complete decoding (there no more data to feed in) */
439 if (decode->decoder_finish) {
440 g_mutex_lock(&decode->decoder_mutex);
441 g_cond_signal(&decode->decoder_finish_done);
442 g_mutex_unlock(&decode->decoder_mutex);
446 /* Suspend the task if an error occurred */
447 if (ret != GST_VIDEO_DECODER_FLOW_NEED_DATA)
448 gst_pad_pause_task(decode->srcpad);
452 gst_vaapidecode_flush(GstVideoDecoder *vdec)
454 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
455 GstVaapiDecoderStatus status;
457 /* If there is something in GstVideoDecoder's output adapter, then
458 submit the frame for decoding */
459 if (decode->current_frame_size) {
460 gst_video_decoder_have_frame(vdec);
461 decode->current_frame_size = 0;
464 status = gst_vaapi_decoder_flush(decode->decoder);
465 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
472 GST_ERROR("failed to flush decoder (status %d)", status);
478 gst_vaapidecode_finish(GstVideoDecoder *vdec)
480 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
481 GstFlowReturn ret = GST_FLOW_OK;
483 if (!gst_vaapidecode_flush(vdec))
486 /* Make sure the decode loop function has a chance to return, thus
487 possibly unlocking gst_video_decoder_finish_frame() */
488 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
489 g_mutex_lock(&decode->decoder_mutex);
490 decode->decoder_finish = TRUE;
491 g_cond_wait(&decode->decoder_finish_done, &decode->decoder_mutex);
492 g_mutex_unlock(&decode->decoder_mutex);
493 gst_pad_stop_task(decode->srcpad);
494 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
498 #if GST_CHECK_VERSION(1,0,0)
500 gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
502 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
503 GstCaps *caps = NULL;
505 GstStructure *config;
507 guint size, min, max;
508 gboolean need_pool, update_pool;
510 gst_query_parse_allocation(query, &caps, &need_pool);
515 gst_video_info_init(&vi);
516 gst_video_info_from_caps(&vi, caps);
517 if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED)
518 gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
519 GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
521 g_return_val_if_fail(GST_VAAPI_PLUGIN_BASE_DISPLAY(decode) != NULL, FALSE);
523 if (gst_query_get_n_allocation_pools(query) > 0) {
524 gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
525 size = MAX(size, vi.size);
535 if (!pool || !gst_buffer_pool_has_option(pool,
536 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
537 GST_INFO("no pool or doesn't support GstVaapiVideoMeta, "
539 pool = gst_vaapi_video_buffer_pool_new(
540 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
542 goto error_create_pool;
544 config = gst_buffer_pool_get_config(pool);
545 gst_buffer_pool_config_set_params(config, caps, size, min, max);
546 gst_buffer_pool_config_add_option(config,
547 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
548 gst_buffer_pool_set_config(pool, config);
551 decode->has_texture_upload_meta = FALSE;
552 if (gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL)) {
553 config = gst_buffer_pool_get_config(pool);
554 gst_buffer_pool_config_add_option(config,
555 GST_BUFFER_POOL_OPTION_VIDEO_META);
556 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
557 decode->has_texture_upload_meta = gst_query_find_allocation_meta(query,
558 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
559 if (decode->has_texture_upload_meta)
560 gst_buffer_pool_config_add_option(config,
561 GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
563 gst_buffer_pool_set_config(pool, config);
567 gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
569 gst_query_add_allocation_pool(query, pool, size, min, max);
571 gst_object_unref(pool);
577 GST_ERROR("no caps specified");
582 GST_ERROR("failed to create buffer pool");
588 #if GST_CHECK_VERSION(1,1,0)
590 gst_vaapidecode_set_context(GstElement *element, GstContext *context)
592 GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
593 GstVaapiDisplay *display = NULL;
595 if (gst_vaapi_video_context_get_display(context, &display)) {
596 GST_INFO_OBJECT(element, "set display %p", display);
597 GST_VAAPI_PLUGIN_BASE_DISPLAY_REPLACE(decode, display);
598 gst_vaapi_display_unref(display);
603 static inline gboolean
604 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
606 return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY,
607 &GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
611 gst_vaapi_codec_from_caps(GstCaps *caps)
613 return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
617 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
619 GstVaapiDisplay *dpy;
621 if (!gst_vaapidecode_ensure_display(decode))
623 dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY(decode);
625 switch (gst_vaapi_codec_from_caps(caps)) {
626 case GST_VAAPI_CODEC_MPEG2:
627 decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
629 case GST_VAAPI_CODEC_MPEG4:
630 case GST_VAAPI_CODEC_H263:
631 decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
633 case GST_VAAPI_CODEC_H264:
634 decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
636 case GST_VAAPI_CODEC_WMV3:
637 case GST_VAAPI_CODEC_VC1:
638 decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
641 case GST_VAAPI_CODEC_JPEG:
642 decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
646 decode->decoder = NULL;
649 if (!decode->decoder)
652 gst_vaapi_decoder_set_codec_state_changed_func(decode->decoder,
653 gst_vaapi_decoder_state_changed, decode);
655 decode->decoder_caps = gst_caps_ref(caps);
656 return gst_pad_start_task(decode->srcpad,
657 (GstTaskFunction)gst_vaapidecode_decode_loop, decode, NULL);
661 gst_vaapidecode_destroy(GstVaapiDecode *decode)
663 gst_pad_stop_task(decode->srcpad);
664 gst_vaapi_decoder_replace(&decode->decoder, NULL);
665 gst_caps_replace(&decode->decoder_caps, NULL);
666 gst_vaapidecode_release(decode);
670 gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
674 decode->has_texture_upload_meta = FALSE;
676 /* Reset tracked frame size */
677 decode->current_frame_size = 0;
679 /* Reset timers if hard reset was requested (e.g. seek) */
681 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
682 GstVideoCodecFrame *out_frame = NULL;
684 gst_vaapi_decoder_flush(decode->decoder);
685 GST_VIDEO_DECODER_STREAM_UNLOCK(vdec);
686 gst_pad_stop_task(decode->srcpad);
687 GST_VIDEO_DECODER_STREAM_LOCK(vdec);
688 decode->decoder_loop_status = GST_FLOW_OK;
690 /* Purge all decoded frames as we don't need them (e.g. seek) */
691 while (gst_vaapi_decoder_get_frame_with_timeout(decode->decoder,
692 &out_frame, 0) == GST_VAAPI_DECODER_STATUS_SUCCESS) {
693 gst_video_codec_frame_unref(out_frame);
698 /* Only reset decoder if codec type changed */
699 else if (decode->decoder && decode->decoder_caps) {
700 if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
702 codec = gst_vaapi_codec_from_caps(caps);
703 if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
707 gst_vaapidecode_destroy(decode);
708 return gst_vaapidecode_create(decode, caps);
712 gst_vaapidecode_finalize(GObject *object)
714 GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
716 gst_caps_replace(&decode->sinkpad_caps, NULL);
717 gst_caps_replace(&decode->srcpad_caps, NULL);
718 gst_caps_replace(&decode->allowed_caps, NULL);
720 g_cond_clear(&decode->decoder_finish_done);
721 g_cond_clear(&decode->decoder_ready);
722 g_mutex_clear(&decode->decoder_mutex);
724 gst_vaapi_plugin_base_finalize(GST_VAAPI_PLUGIN_BASE(object));
725 G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
729 gst_vaapidecode_open(GstVideoDecoder *vdec)
731 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
732 GstVaapiDisplay * const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY(decode);
735 if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(decode)))
738 /* Let GstVideoContext ask for a proper display to its neighbours */
739 /* Note: steal old display that may be allocated from get_caps()
740 so that to retain a reference to it, thus avoiding extra
741 initialization steps if we turn out to simply re-use the
742 existing (cached) VA display */
743 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode) = NULL;
744 success = gst_vaapidecode_ensure_display(decode);
746 gst_vaapi_display_unref(old_display);
751 gst_vaapidecode_close(GstVideoDecoder *vdec)
753 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
755 gst_vaapidecode_destroy(decode);
756 gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(decode));
761 gst_vaapidecode_reset(GstVideoDecoder *vdec, gboolean hard)
763 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
765 /* In GStreamer 1.0 context, this means a flush */
766 if (decode->decoder && !hard && !gst_vaapidecode_flush(vdec))
768 return gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, hard);
772 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
774 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
776 if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
778 if (!gst_vaapidecode_update_src_caps(decode, state))
780 if (!gst_vaapidecode_reset_full(decode, decode->sinkpad_caps, FALSE))
786 gst_vaapidecode_parse(GstVideoDecoder *vdec,
787 GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
789 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
790 GstVaapiDecoderStatus status;
795 status = gst_vaapi_decoder_parse(decode->decoder, frame,
796 adapter, at_eos, &got_unit_size, &got_frame);
799 case GST_VAAPI_DECODER_STATUS_SUCCESS:
800 if (got_unit_size > 0) {
801 gst_video_decoder_add_to_frame(vdec, got_unit_size);
802 decode->current_frame_size += got_unit_size;
805 ret = gst_video_decoder_have_frame(vdec);
806 decode->current_frame_size = 0;
811 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
812 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
814 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
815 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
816 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
817 GST_WARNING("parse error %d", status);
818 ret = GST_FLOW_NOT_SUPPORTED;
819 decode->current_frame_size = 0;
822 GST_ERROR("parse error %d", status);
824 decode->current_frame_size = 0;
831 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
833 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
834 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
835 GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
836 GstPadTemplate *pad_template;
838 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
839 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
841 gst_vaapi_plugin_base_class_init(GST_VAAPI_PLUGIN_BASE_CLASS(klass));
843 object_class->finalize = gst_vaapidecode_finalize;
845 vdec_class->open = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
846 vdec_class->close = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
847 vdec_class->set_format = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
848 vdec_class->reset = GST_DEBUG_FUNCPTR(gst_vaapidecode_reset);
849 vdec_class->parse = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
850 vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
851 vdec_class->finish = GST_DEBUG_FUNCPTR(gst_vaapidecode_finish);
853 #if GST_CHECK_VERSION(1,0,0)
854 vdec_class->decide_allocation =
855 GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
858 #if GST_CHECK_VERSION(1,1,0)
859 element_class->set_context = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_context);
862 gst_element_class_set_static_metadata(element_class,
864 "Codec/Decoder/Video",
866 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
869 pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
870 gst_element_class_add_pad_template(element_class, pad_template);
873 pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
874 gst_element_class_add_pad_template(element_class, pad_template);
878 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
880 GstCaps *decode_caps;
881 guint i, n_decode_caps;
883 if (decode->allowed_caps)
886 if (!gst_vaapidecode_ensure_display(decode))
887 goto error_no_display;
889 decode_caps = gst_vaapi_display_get_decode_caps(
890 GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
892 goto error_no_decode_caps;
893 n_decode_caps = gst_caps_get_size(decode_caps);
895 decode->allowed_caps = gst_caps_new_empty();
896 if (!decode->allowed_caps)
897 goto error_no_memory;
899 for (i = 0; i < n_decode_caps; i++) {
900 GstStructure *structure;
901 structure = gst_caps_get_structure(decode_caps, i);
904 structure = gst_structure_copy(structure);
907 gst_structure_remove_field(structure, "profile");
908 decode->allowed_caps =
909 gst_caps_merge_structure(decode->allowed_caps, structure);
912 gst_caps_unref(decode_caps);
918 GST_ERROR("failed to retrieve VA display");
921 error_no_decode_caps:
923 GST_ERROR("failed to retrieve VA decode caps");
928 GST_ERROR("failed to allocate allowed-caps set");
929 gst_caps_unref(decode_caps);
935 gst_vaapidecode_get_caps(GstPad *pad)
937 GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
939 if (!gst_vaapidecode_ensure_allowed_caps(decode))
940 return gst_caps_new_empty();
942 return gst_caps_ref(decode->allowed_caps);
946 gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
948 GstVaapiDecode * const decode =
949 GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
952 GST_INFO_OBJECT(decode, "query type %s", GST_QUERY_TYPE_NAME(query));
954 if (gst_vaapi_reply_to_query(query, GST_VAAPI_PLUGIN_BASE_DISPLAY(decode))) {
955 GST_DEBUG("sharing display %p", GST_VAAPI_PLUGIN_BASE_DISPLAY(decode));
958 else if (GST_PAD_IS_SINK(pad)) {
959 switch (GST_QUERY_TYPE(query)) {
960 #if GST_CHECK_VERSION(1,0,0)
961 case GST_QUERY_CAPS: {
962 GstCaps * const caps = gst_vaapidecode_get_caps(pad);
963 gst_query_set_caps_result(query, caps);
964 gst_caps_unref(caps);
970 res = GST_PAD_QUERY_FUNCTION_CALL(decode->sinkpad_query,
971 decode->sinkpad, parent, query);
976 res = GST_PAD_QUERY_FUNCTION_CALL(decode->srcpad_query,
977 decode->srcpad, parent, query);
979 gst_object_unref(decode);
984 gst_vaapidecode_init(GstVaapiDecode *decode)
986 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
988 gst_vaapi_plugin_base_init(GST_VAAPI_PLUGIN_BASE(decode), GST_CAT_DEFAULT);
990 decode->decoder = NULL;
991 decode->decoder_caps = NULL;
992 decode->allowed_caps = NULL;
993 decode->decoder_loop_status = GST_FLOW_OK;
995 g_mutex_init(&decode->decoder_mutex);
996 g_cond_init(&decode->decoder_ready);
997 g_cond_init(&decode->decoder_finish_done);
999 gst_video_decoder_set_packetized(vdec, FALSE);
1001 /* Pad through which data comes in to the element */
1002 decode->sinkpad = GST_VIDEO_DECODER_SINK_PAD(vdec);
1003 decode->sinkpad_query = GST_PAD_QUERYFUNC(decode->sinkpad);
1004 gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
1005 #if !GST_CHECK_VERSION(1,0,0)
1006 gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
1009 /* Pad through which data goes out of the element */
1010 decode->srcpad = GST_VIDEO_DECODER_SRC_PAD(vdec);
1011 decode->srcpad_query = GST_PAD_QUERYFUNC(decode->srcpad);
1012 gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);