2 * gstvaapidecode.c - VA-API video decoder
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Copyright (C) 2011-2012 Intel Corporation
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1
10 * of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
24 * SECTION:gstvaapidecode
25 * @short_description: A VA-API based video decoder
27 * vaapidecode decodes from raw bitstreams to surfaces suitable for
28 * the vaapisink element.
31 #include "gst/vaapi/sysdeps.h"
32 #include <gst/vaapi/gstvaapidisplay.h>
33 #include <gst/vaapi/gstvaapivideobuffer.h>
34 #include <gst/video/videocontext.h>
36 #include "gstvaapidecode.h"
37 #include "gstvaapipluginutil.h"
38 #include "gstvaapipluginbuffer.h"
40 #include <gst/vaapi/gstvaapidecoder_h264.h>
41 #include <gst/vaapi/gstvaapidecoder_jpeg.h>
42 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
43 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
44 #include <gst/vaapi/gstvaapidecoder_vc1.h>
46 #define GST_PLUGIN_NAME "vaapidecode"
47 #define GST_PLUGIN_DESC "A VA-API based video decoder"
49 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode);
50 #define GST_CAT_DEFAULT gst_debug_vaapidecode
52 /* ElementFactory information */
53 static const GstElementDetails gst_vaapidecode_details =
56 "Codec/Decoder/Video",
58 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
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 GST_VAAPI_SURFACE_CAPS;
77 static GstStaticPadTemplate gst_vaapidecode_sink_factory =
78 GST_STATIC_PAD_TEMPLATE(
82 GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));
84 static GstStaticPadTemplate gst_vaapidecode_src_factory =
85 GST_STATIC_PAD_TEMPLATE(
89 GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
92 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface);
95 gst_video_context_interface_init(GstVideoContextInterface *iface);
97 #define GstVideoContextClass GstVideoContextInterface
98 G_DEFINE_TYPE_WITH_CODE(
101 GST_TYPE_VIDEO_DECODER,
102 G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
103 gst_vaapidecode_implements_iface_init);
104 G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
105 gst_video_context_interface_init))
108 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
109 GstVideoCodecState *ref_state);
112 gst_vaapi_decoder_notify_caps(GObject *obj, GParamSpec *pspec, void *user_data)
114 GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
115 GstVideoCodecState *codec_state;
117 g_assert(decode->decoder == GST_VAAPI_DECODER(obj));
119 codec_state = gst_vaapi_decoder_get_codec_state(decode->decoder);
120 gst_vaapidecode_update_src_caps(decode, codec_state);
121 gst_video_codec_state_unref(codec_state);
124 static inline gboolean
125 gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
127 gst_caps_replace(&decode->sinkpad_caps, caps);
132 gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
133 GstVideoCodecState *ref_state)
135 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
136 GstVideoCodecState *state;
139 state = gst_video_decoder_set_output_state(vdec,
140 GST_VIDEO_INFO_FORMAT(&ref_state->info),
141 ref_state->info.width, ref_state->info.height, ref_state);
146 gst_video_codec_state_unref(state);
148 /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
149 reconstruct suitable caps for "encoded" video formats */
150 state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
154 gst_caps_set_simple(state->caps,
155 "type", G_TYPE_STRING, "vaapi",
156 "opengl", G_TYPE_BOOLEAN, USE_GLX,
157 "width", G_TYPE_INT, vi->width,
158 "height", G_TYPE_INT, vi->height,
159 "framerate", GST_TYPE_FRACTION, vi->fps_n, vi->fps_d,
160 "pixel-aspect-ratio", GST_TYPE_FRACTION, vi->par_n, vi->par_d,
163 if (GST_VIDEO_INFO_IS_INTERLACED(vi))
164 gst_caps_set_simple(state->caps, "interlaced", G_TYPE_BOOLEAN,
167 gst_caps_replace(&decode->srcpad_caps, state->caps);
172 gst_vaapidecode_release(GstVaapiDecode *decode)
174 g_mutex_lock(&decode->decoder_mutex);
175 g_cond_signal(&decode->decoder_ready);
176 g_mutex_unlock(&decode->decoder_mutex);
180 gst_vaapidecode_handle_frame(GstVideoDecoder *vdec, GstVideoCodecFrame *frame)
182 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
183 GstVaapiSurfaceProxy *proxy;
184 GstVaapiDecoderStatus status;
185 GstVideoCodecFrame *out_frame;
189 /* Decode current frame */
191 end_time = decode->render_time_base;
193 end_time = g_get_monotonic_time();
194 end_time += GST_TIME_AS_USECONDS(decode->last_buffer_time);
195 end_time += G_TIME_SPAN_SECOND;
197 status = gst_vaapi_decoder_decode(decode->decoder, frame);
198 if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
199 gboolean was_signalled;
200 g_mutex_lock(&decode->decoder_mutex);
201 was_signalled = g_cond_wait_until(
202 &decode->decoder_ready,
203 &decode->decoder_mutex,
206 g_mutex_unlock(&decode->decoder_mutex);
209 goto error_decode_timeout;
211 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
216 /* Output all decoded frames */
218 status = gst_vaapi_decoder_get_frame(decode->decoder, &out_frame);
219 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
222 proxy = gst_video_codec_frame_get_user_data(out_frame);
224 gst_vaapi_surface_proxy_set_user_data(proxy,
225 decode, (GDestroyNotify)gst_vaapidecode_release);
227 out_frame->output_buffer = gst_vaapi_video_buffer_new(decode->display);
228 if (!out_frame->output_buffer)
229 goto error_create_buffer;
231 gst_vaapi_video_buffer_set_surface_proxy(
232 GST_VAAPI_VIDEO_BUFFER(out_frame->output_buffer), proxy);
234 ret = gst_video_decoder_finish_frame(vdec, out_frame);
235 if (ret != GST_FLOW_OK)
236 goto error_commit_buffer;
237 gst_video_codec_frame_unref(out_frame);
242 error_decode_timeout:
244 GST_WARNING("decode timeout. Decoder required a VA surface but none "
245 "got available within one second");
246 return GST_FLOW_UNEXPECTED;
250 GST_ERROR("decode error %d", status);
252 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
253 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
254 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
255 ret = GST_FLOW_NOT_SUPPORTED;
258 ret = GST_FLOW_UNEXPECTED;
261 gst_video_decoder_drop_frame(vdec, frame);
266 const GstVaapiID surface_id =
267 gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));
269 GST_ERROR("video sink failed to create video buffer for proxy'ed "
270 "surface %" GST_VAAPI_ID_FORMAT,
271 GST_VAAPI_ID_ARGS(surface_id));
272 gst_video_decoder_drop_frame(vdec, out_frame);
273 gst_video_codec_frame_unref(out_frame);
274 return GST_FLOW_UNEXPECTED;
278 GST_DEBUG("video sink rejected the video buffer (error %d)", ret);
279 gst_video_codec_frame_unref(out_frame);
280 return GST_FLOW_UNEXPECTED;
284 static inline gboolean
285 gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
287 return gst_vaapi_ensure_display(decode, GST_VAAPI_DISPLAY_TYPE_ANY,
292 gst_vaapi_codec_from_caps(GstCaps *caps)
294 return gst_vaapi_profile_get_codec(gst_vaapi_profile_from_caps(caps));
298 gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
300 GstVaapiDisplay *dpy;
302 if (!gst_vaapidecode_ensure_display(decode))
304 dpy = decode->display;
306 switch (gst_vaapi_codec_from_caps(caps)) {
307 case GST_VAAPI_CODEC_MPEG2:
308 decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
310 case GST_VAAPI_CODEC_MPEG4:
311 case GST_VAAPI_CODEC_H263:
312 decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
314 case GST_VAAPI_CODEC_H264:
315 decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
317 case GST_VAAPI_CODEC_WMV3:
318 case GST_VAAPI_CODEC_VC1:
319 decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
322 case GST_VAAPI_CODEC_JPEG:
323 decode->decoder = gst_vaapi_decoder_jpeg_new(dpy, caps);
327 decode->decoder = NULL;
330 if (!decode->decoder)
334 G_OBJECT(decode->decoder),
336 G_CALLBACK(gst_vaapi_decoder_notify_caps),
340 decode->decoder_caps = gst_caps_ref(caps);
345 gst_vaapidecode_destroy(GstVaapiDecode *decode)
347 g_clear_object(&decode->decoder);
348 gst_caps_replace(&decode->decoder_caps, NULL);
349 gst_vaapidecode_release(decode);
353 gst_vaapidecode_reset(GstVaapiDecode *decode, GstCaps *caps)
357 /* Only reset decoder if codec type changed */
358 if (decode->decoder && decode->decoder_caps) {
359 if (gst_caps_is_always_compatible(caps, decode->decoder_caps))
361 codec = gst_vaapi_codec_from_caps(caps);
362 if (codec == gst_vaapi_decoder_get_codec(decode->decoder))
366 gst_vaapidecode_destroy(decode);
367 return gst_vaapidecode_create(decode, caps);
370 /* GstImplementsInterface interface */
373 gst_vaapidecode_implements_interface_supported(
374 GstImplementsInterface *iface,
378 return (type == GST_TYPE_VIDEO_CONTEXT);
382 gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface)
384 iface->supported = gst_vaapidecode_implements_interface_supported;
387 /* GstVideoContext interface */
390 gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
393 GstVaapiDecode *decode = GST_VAAPIDECODE (context);
394 gst_vaapi_set_display (type, value, &decode->display);
398 gst_video_context_interface_init(GstVideoContextInterface *iface)
400 iface->set_context = gst_vaapidecode_set_video_context;
404 gst_vaapidecode_finalize(GObject *object)
406 GstVaapiDecode * const decode = GST_VAAPIDECODE(object);
408 gst_vaapidecode_destroy(decode);
410 gst_caps_replace(&decode->sinkpad_caps, NULL);
411 gst_caps_replace(&decode->srcpad_caps, NULL);
412 gst_caps_replace(&decode->allowed_caps, NULL);
414 g_clear_object(&decode->display);
416 g_cond_clear(&decode->decoder_ready);
417 g_mutex_clear(&decode->decoder_mutex);
419 G_OBJECT_CLASS(gst_vaapidecode_parent_class)->finalize(object);
423 gst_vaapidecode_open(GstVideoDecoder *vdec)
425 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
427 decode->is_ready = TRUE;
432 gst_vaapidecode_close(GstVideoDecoder *vdec)
434 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
436 gst_vaapidecode_destroy(decode);
437 g_clear_object(&decode->display);
438 decode->is_ready = FALSE;
443 gst_vaapidecode_set_format(GstVideoDecoder *vdec, GstVideoCodecState *state)
445 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
447 if (!gst_vaapidecode_update_sink_caps(decode, state->caps))
449 if (!gst_vaapidecode_update_src_caps(decode, state))
451 if (!gst_vaapidecode_reset(decode, decode->sinkpad_caps))
457 gst_vaapidecode_parse(GstVideoDecoder *vdec,
458 GstVideoCodecFrame *frame, GstAdapter *adapter, gboolean at_eos)
460 GstVaapiDecode * const decode = GST_VAAPIDECODE(vdec);
461 GstVaapiDecoderStatus status;
466 status = gst_vaapi_decoder_parse(decode->decoder, frame,
467 adapter, at_eos, &got_unit_size, &got_frame);
470 case GST_VAAPI_DECODER_STATUS_SUCCESS:
471 if (got_unit_size > 0)
472 gst_video_decoder_add_to_frame(vdec, got_unit_size);
474 ret = gst_video_decoder_have_frame(vdec);
478 case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
479 ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
481 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
482 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
483 case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
484 GST_WARNING("parse error %d", status);
485 ret = GST_FLOW_NOT_SUPPORTED;
488 GST_ERROR("parse error %d", status);
489 ret = GST_FLOW_UNEXPECTED;
496 gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
498 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
499 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
500 GstVideoDecoderClass * const vdec_class = GST_VIDEO_DECODER_CLASS(klass);
501 GstPadTemplate *pad_template;
503 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
504 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
506 object_class->finalize = gst_vaapidecode_finalize;
508 vdec_class->open = GST_DEBUG_FUNCPTR(gst_vaapidecode_open);
509 vdec_class->close = GST_DEBUG_FUNCPTR(gst_vaapidecode_close);
510 vdec_class->set_format = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_format);
511 vdec_class->parse = GST_DEBUG_FUNCPTR(gst_vaapidecode_parse);
512 vdec_class->handle_frame = GST_DEBUG_FUNCPTR(gst_vaapidecode_handle_frame);
514 gst_element_class_set_details_simple(
516 gst_vaapidecode_details.longname,
517 gst_vaapidecode_details.klass,
518 gst_vaapidecode_details.description,
519 gst_vaapidecode_details.author
523 pad_template = gst_static_pad_template_get(&gst_vaapidecode_sink_factory);
524 gst_element_class_add_pad_template(element_class, pad_template);
525 gst_object_unref(pad_template);
528 pad_template = gst_static_pad_template_get(&gst_vaapidecode_src_factory);
529 gst_element_class_add_pad_template(element_class, pad_template);
530 gst_object_unref(pad_template);
534 gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
536 GstCaps *decode_caps;
537 guint i, n_decode_caps;
539 if (decode->allowed_caps)
542 if (!gst_vaapidecode_ensure_display(decode))
543 goto error_no_display;
545 decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
547 goto error_no_decode_caps;
548 n_decode_caps = gst_caps_get_size(decode_caps);
550 decode->allowed_caps = gst_caps_new_empty();
551 if (!decode->allowed_caps)
552 goto error_no_memory;
554 for (i = 0; i < n_decode_caps; i++) {
555 GstStructure *structure;
556 structure = gst_caps_get_structure(decode_caps, i);
559 structure = gst_structure_copy(structure);
562 gst_structure_remove_field(structure, "profile");
565 "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
566 "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
569 gst_caps_merge_structure(decode->allowed_caps, structure);
572 gst_caps_unref(decode_caps);
578 GST_ERROR("failed to retrieve VA display");
581 error_no_decode_caps:
583 GST_ERROR("failed to retrieve VA decode caps");
588 GST_ERROR("failed to allocate allowed-caps set");
589 gst_caps_unref(decode_caps);
595 gst_vaapidecode_get_caps(GstPad *pad)
597 GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));
599 if (!decode->is_ready)
600 return gst_static_pad_template_get_caps(&gst_vaapidecode_sink_factory);
602 if (!gst_vaapidecode_ensure_allowed_caps(decode))
603 return gst_caps_new_empty();
605 return gst_caps_ref(decode->allowed_caps);
609 gst_vaapidecode_query (GstPad *pad, GstQuery *query) {
610 GstVaapiDecode *decode = GST_VAAPIDECODE (gst_pad_get_parent_element (pad));
613 GST_DEBUG ("sharing display %p", decode->display);
615 if (gst_vaapi_reply_to_query (query, decode->display))
617 else if (GST_PAD_IS_SINK(pad))
618 res = decode->sinkpad_query(decode->sinkpad, query);
620 res = decode->srcpad_query(decode->srcpad, query);
622 g_object_unref (decode);
627 gst_vaapidecode_init(GstVaapiDecode *decode)
629 GstVideoDecoder * const vdec = GST_VIDEO_DECODER(decode);
631 decode->display = NULL;
632 decode->decoder = NULL;
633 decode->decoder_caps = NULL;
634 decode->allowed_caps = NULL;
635 decode->render_time_base = 0;
636 decode->last_buffer_time = 0;
637 decode->is_ready = FALSE;
639 g_mutex_init(&decode->decoder_mutex);
640 g_cond_init(&decode->decoder_ready);
642 gst_video_decoder_set_packetized(vdec, FALSE);
644 /* Pad through which data comes in to the element */
645 decode->sinkpad = GST_VIDEO_DECODER_SINK_PAD(vdec);
646 decode->sinkpad_query = GST_PAD_QUERYFUNC(decode->sinkpad);
647 gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
648 gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
650 /* Pad through which data goes out of the element */
651 decode->srcpad = GST_VIDEO_DECODER_SRC_PAD(vdec);
652 decode->srcpad_query = GST_PAD_QUERYFUNC(decode->srcpad);
653 gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);