2 * gstvaapidecoder.c - VA decoder abstraction
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:gstvaapidecoder
25 * @short_description: VA decoder abstraction
29 #include "gstvaapicompat.h"
30 #include "gstvaapidecoder.h"
31 #include "gstvaapidecoder_priv.h"
32 #include "gstvaapiutils.h"
33 #include "gstvaapi_priv.h"
36 #include "gstvaapidebug.h"
38 G_DEFINE_TYPE(GstVaapiDecoder, gst_vaapi_decoder, G_TYPE_OBJECT)
49 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
52 destroy_buffer(GstBuffer *buffer)
54 gst_buffer_unref(buffer);
58 push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
60 GstVaapiDecoderPrivate * const priv = decoder->priv;
63 buffer = gst_buffer_new();
66 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
69 GST_DEBUG("queue encoded data buffer %p (%d bytes)",
70 buffer, GST_BUFFER_SIZE(buffer));
72 g_queue_push_tail(priv->buffers, buffer);
77 pop_buffer(GstVaapiDecoder *decoder)
79 GstVaapiDecoderPrivate * const priv = decoder->priv;
82 buffer = g_queue_pop_head(priv->buffers);
86 GST_DEBUG("dequeue buffer %p for decoding (%d bytes)",
87 buffer, GST_BUFFER_SIZE(buffer));
92 static GstVaapiDecoderStatus
93 decode_step(GstVaapiDecoder *decoder, gboolean *try_again)
95 GstVaapiDecoderStatus status;
98 /* Decoding will fail if there is no surface left */
99 status = gst_vaapi_decoder_check_status(decoder);
100 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
105 buffer = gst_buffer_new();
107 gst_buffer_set_data(buffer, NULL, 0);
111 buffer = pop_buffer(decoder);
114 return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
116 status = GST_VAAPI_DECODER_GET_CLASS(decoder)->decode(decoder, buffer);
117 GST_DEBUG("decode frame (status = %d)", status);
118 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS && GST_BUFFER_IS_EOS(buffer))
119 status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
120 gst_buffer_unref(buffer);
121 } while (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA);
126 push_surface(GstVaapiDecoder *decoder, GstVaapiSurfaceProxy *proxy)
128 GstVaapiDecoderPrivate * const priv = decoder->priv;
129 GstClockTime duration;
131 GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
132 GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy)));
134 if (priv->fps_n && priv->fps_d) {
135 /* Actual field duration is computed in vaapipostproc */
136 duration = gst_util_uint64_scale(GST_SECOND, priv->fps_d, priv->fps_n);
137 gst_vaapi_surface_proxy_set_duration(proxy, duration);
139 g_queue_push_tail(priv->surfaces, proxy);
142 static inline GstVaapiSurfaceProxy *
143 pop_surface(GstVaapiDecoder *decoder)
145 GstVaapiDecoderPrivate * const priv = decoder->priv;
147 return g_queue_pop_head(priv->surfaces);
151 set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
153 GstVaapiDecoderPrivate * const priv = decoder->priv;
155 if (priv->codec_data) {
156 gst_buffer_unref(priv->codec_data);
157 priv->codec_data = NULL;
161 priv->codec_data = gst_buffer_ref(codec_data);
165 set_caps(GstVaapiDecoder *decoder, GstCaps *caps)
167 GstVaapiDecoderPrivate * const priv = decoder->priv;
168 GstStructure * const structure = gst_caps_get_structure(caps, 0);
169 GstVaapiProfile profile;
170 const GValue *v_codec_data;
174 profile = gst_vaapi_profile_from_caps(caps);
178 priv->caps = gst_caps_copy(caps);
180 priv->codec = gst_vaapi_profile_get_codec(profile);
184 if (gst_structure_get_int(structure, "width", &v1))
186 if (gst_structure_get_int(structure, "height", &v2))
189 if (gst_structure_get_fraction(structure, "framerate", &v1, &v2)) {
194 if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &v1, &v2)) {
199 if (gst_structure_get_boolean(structure, "interlaced", &b))
200 priv->is_interlaced = b;
202 v_codec_data = gst_structure_get_value(structure, "codec_data");
204 set_codec_data(decoder, gst_value_get_buffer(v_codec_data));
208 clear_queue(GQueue *q, GDestroyNotify destroy)
210 while (!g_queue_is_empty(q))
211 destroy(g_queue_pop_head(q));
215 gst_vaapi_decoder_finalize(GObject *object)
217 GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(object);
218 GstVaapiDecoderPrivate * const priv = decoder->priv;
220 set_codec_data(decoder, NULL);
223 gst_caps_unref(priv->caps);
228 g_object_unref(priv->context);
229 priv->context = NULL;
230 priv->va_context = VA_INVALID_ID;
234 clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
235 g_queue_free(priv->buffers);
236 priv->buffers = NULL;
239 if (priv->surfaces) {
240 clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref);
241 g_queue_free(priv->surfaces);
242 priv->surfaces = NULL;
246 g_object_unref(priv->display);
247 priv->display = NULL;
248 priv->va_display = NULL;
251 G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
255 gst_vaapi_decoder_set_property(
262 GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(object);
263 GstVaapiDecoderPrivate * const priv = decoder->priv;
267 priv->display = g_object_ref(g_value_get_object(value));
269 priv->va_display = gst_vaapi_display_get_display(priv->display);
271 priv->va_display = NULL;
274 set_caps(decoder, g_value_get_pointer(value));
277 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
283 gst_vaapi_decoder_get_property(
290 GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
294 g_value_set_object(value, priv->display);
297 gst_value_set_caps(value, priv->caps);
300 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
306 gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
308 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
310 g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate));
312 object_class->finalize = gst_vaapi_decoder_finalize;
313 object_class->set_property = gst_vaapi_decoder_set_property;
314 object_class->get_property = gst_vaapi_decoder_get_property;
317 * GstVaapiDecoder:display:
319 * The #GstVaapiDisplay this decoder is bound to.
321 g_properties[PROP_DISPLAY] =
322 g_param_spec_object("display",
324 "The GstVaapiDisplay this decoder is bound to",
325 GST_VAAPI_TYPE_DISPLAY,
326 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
328 g_properties[PROP_CAPS] =
329 g_param_spec_pointer("caps",
332 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
334 g_object_class_install_properties(object_class, N_PROPERTIES, g_properties);
338 gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
340 GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
342 decoder->priv = priv;
343 priv->display = NULL;
344 priv->va_display = NULL;
345 priv->context = NULL;
346 priv->va_context = VA_INVALID_ID;
349 priv->codec_data = NULL;
356 priv->buffers = g_queue_new();
357 priv->surfaces = g_queue_new();
358 priv->is_interlaced = FALSE;
362 * gst_vaapi_decoder_get_codec:
363 * @decoder: a #GstVaapiDecoder
365 * Retrieves the @decoder codec type.
367 * Return value: the #GstVaapiCodec type for @decoder
370 gst_vaapi_decoder_get_codec(GstVaapiDecoder *decoder)
372 g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), (GstVaapiCodec)0);
374 return decoder->priv->codec;
378 * gst_vaapi_decoder_get_caps:
379 * @decoder: a #GstVaapiDecoder
381 * Retrieves the @decoder caps. The deocder owns the returned caps, so
382 * use gst_caps_ref() whenever necessary.
384 * Return value: the @decoder caps
387 gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder)
389 return decoder->priv->caps;
393 * gst_vaapi_decoder_put_buffer:
394 * @decoder: a #GstVaapiDecoder
397 * Queues a #GstBuffer to the HW decoder. The decoder holds a
400 * Caller can notify an End-Of-Stream with @buf set to %NULL. However,
401 * if an empty buffer is passed, i.e. a buffer with %NULL data pointer
402 * or size equals to zero, then the function ignores this buffer and
405 * Return value: %TRUE on success
408 gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
410 g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
413 if (!GST_BUFFER_DATA(buf) || GST_BUFFER_SIZE(buf) <= 0)
415 buf = gst_buffer_ref(buf);
417 return push_buffer(decoder, buf);
421 * gst_vaapi_decoder_get_surface:
422 * @decoder: a #GstVaapiDecoder
423 * @pstatus: return location for the decoder status, or %NULL
424 * @try_again: a #gboolean
426 * Flushes encoded buffers to the decoder and returns a decoded
429 * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
430 * or %NULL if none is available (e.g. an error). Caller owns the
431 * returned object. g_object_unref() after usage.
433 GstVaapiSurfaceProxy *
434 gst_vaapi_decoder_get_surface(
435 GstVaapiDecoder *decoder,
436 GstVaapiDecoderStatus *pstatus,
440 GstVaapiSurfaceProxy *proxy;
441 GstVaapiDecoderStatus status;
444 *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
446 g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
448 proxy = pop_surface(decoder);
451 status = decode_step(decoder, &try_again);
452 } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
453 proxy = pop_surface(decoder);
457 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
465 gst_vaapi_decoder_clear_buffer(GstVaapiDecoder *decoder)
467 GstVaapiDecoderPrivate * const priv = decoder->priv;
468 GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
470 if (klass->clear_buffer)
471 klass->clear_buffer(decoder);
474 clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
477 clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref);
481 gst_vaapi_decoder_set_picture_size(
482 GstVaapiDecoder *decoder,
487 GstVaapiDecoderPrivate * const priv = decoder->priv;
488 gboolean size_changed = FALSE;
490 if (priv->width != width) {
491 GST_DEBUG("picture width changed to %d", width);
493 gst_caps_set_simple(priv->caps, "width", G_TYPE_INT, width, NULL);
497 if (priv->height != height) {
498 GST_DEBUG("picture height changed to %d", height);
499 priv->height = height;
500 gst_caps_set_simple(priv->caps, "height", G_TYPE_INT, height, NULL);
505 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
509 gst_vaapi_decoder_set_framerate(
510 GstVaapiDecoder *decoder,
515 GstVaapiDecoderPrivate * const priv = decoder->priv;
517 if (!fps_n || !fps_d)
520 if (priv->fps_n != fps_n || priv->fps_d != fps_d) {
521 GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d);
526 "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
529 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
534 gst_vaapi_decoder_set_pixel_aspect_ratio(
535 GstVaapiDecoder *decoder,
540 GstVaapiDecoderPrivate * const priv = decoder->priv;
542 if (!par_n || !par_d)
545 if (priv->par_n != par_n || priv->par_d != par_d) {
546 GST_DEBUG("pixel-aspect-ratio changed to %u/%u", par_n, par_d);
551 "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
554 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
559 gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced)
561 GstVaapiDecoderPrivate * const priv = decoder->priv;
563 if (priv->is_interlaced != interlaced) {
564 GST_DEBUG("interlaced changed to %s", interlaced ? "true" : "false");
565 priv->is_interlaced = interlaced;
568 "interlaced", G_TYPE_BOOLEAN, interlaced,
571 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
576 gst_vaapi_decoder_ensure_context(
577 GstVaapiDecoder *decoder,
578 GstVaapiContextInfo *cip
581 GstVaapiDecoderPrivate * const priv = decoder->priv;
583 cip->rate_control = GST_VAAPI_RATECONTROL_NONE;
584 gst_vaapi_decoder_set_picture_size(decoder, cip->width, cip->height);
587 if (!gst_vaapi_context_reset_full(priv->context, cip))
591 priv->context = gst_vaapi_context_new_full(priv->display, cip);
595 priv->va_context = gst_vaapi_context_get_id(priv->context);
600 gst_vaapi_decoder_push_surface_proxy(
601 GstVaapiDecoder *decoder,
602 GstVaapiSurfaceProxy *proxy
605 push_surface(decoder, proxy);
608 GstVaapiDecoderStatus
609 gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder)
611 GstVaapiDecoderPrivate * const priv = decoder->priv;
613 if (priv->context && gst_vaapi_context_get_surface_count(priv->context) < 1)
614 return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
615 return GST_VAAPI_DECODER_STATUS_SUCCESS;