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 push_back_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
79 GstVaapiDecoderPrivate * const priv = decoder->priv;
81 GST_DEBUG("requeue encoded data buffer %p (%d bytes)",
82 buffer, GST_BUFFER_SIZE(buffer));
84 g_queue_push_head(priv->buffers, buffer);
88 pop_buffer(GstVaapiDecoder *decoder)
90 GstVaapiDecoderPrivate * const priv = decoder->priv;
93 buffer = g_queue_pop_head(priv->buffers);
97 GST_DEBUG("dequeue buffer %p for decoding (%d bytes)",
98 buffer, GST_BUFFER_SIZE(buffer));
103 static GstVaapiDecoderStatus
104 decode_step(GstVaapiDecoder *decoder)
106 GstVaapiDecoderStatus status;
109 /* Decoding will fail if there is no surface left */
110 status = gst_vaapi_decoder_check_status(decoder);
111 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
115 buffer = pop_buffer(decoder);
117 return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
119 status = GST_VAAPI_DECODER_GET_CLASS(decoder)->decode(decoder, buffer);
120 GST_DEBUG("decode frame (status = %d)", status);
121 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS && GST_BUFFER_IS_EOS(buffer))
122 status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
123 gst_buffer_unref(buffer);
124 } while (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA);
129 push_surface(GstVaapiDecoder *decoder, GstVaapiSurfaceProxy *proxy)
131 GstVaapiDecoderPrivate * const priv = decoder->priv;
133 GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
134 GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy)));
136 g_queue_push_tail(priv->surfaces, proxy);
139 static inline GstVaapiSurfaceProxy *
140 pop_surface(GstVaapiDecoder *decoder)
142 GstVaapiDecoderPrivate * const priv = decoder->priv;
144 return g_queue_pop_head(priv->surfaces);
148 set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
150 GstVaapiDecoderPrivate * const priv = decoder->priv;
152 if (priv->codec_data) {
153 gst_buffer_unref(priv->codec_data);
154 priv->codec_data = NULL;
158 priv->codec_data = gst_buffer_ref(codec_data);
162 set_caps(GstVaapiDecoder *decoder, GstCaps *caps)
164 GstVaapiDecoderPrivate * const priv = decoder->priv;
165 GstStructure * const structure = gst_caps_get_structure(caps, 0);
166 GstVaapiProfile profile;
167 const GValue *v_codec_data;
171 profile = gst_vaapi_profile_from_caps(caps);
175 priv->caps = gst_caps_copy(caps);
177 priv->codec = gst_vaapi_profile_get_codec(profile);
181 if (gst_structure_get_int(structure, "width", &v1))
183 if (gst_structure_get_int(structure, "height", &v2))
186 if (gst_structure_get_fraction(structure, "framerate", &v1, &v2)) {
191 if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &v1, &v2)) {
196 if (gst_structure_get_boolean(structure, "interlaced", &b))
197 priv->is_interlaced = b;
199 v_codec_data = gst_structure_get_value(structure, "codec_data");
201 set_codec_data(decoder, gst_value_get_buffer(v_codec_data));
205 clear_queue(GQueue *q, GDestroyNotify destroy)
207 while (!g_queue_is_empty(q))
208 destroy(g_queue_pop_head(q));
212 gst_vaapi_decoder_finalize(GObject *object)
214 GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(object);
215 GstVaapiDecoderPrivate * const priv = decoder->priv;
217 set_codec_data(decoder, NULL);
220 gst_caps_unref(priv->caps);
225 g_object_unref(priv->context);
226 priv->context = NULL;
227 priv->va_context = VA_INVALID_ID;
231 clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
232 g_queue_free(priv->buffers);
233 priv->buffers = NULL;
236 if (priv->surfaces) {
237 clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref);
238 g_queue_free(priv->surfaces);
239 priv->surfaces = NULL;
243 g_object_unref(priv->display);
244 priv->display = NULL;
245 priv->va_display = NULL;
248 G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
252 gst_vaapi_decoder_set_property(
259 GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(object);
260 GstVaapiDecoderPrivate * const priv = decoder->priv;
264 priv->display = g_object_ref(g_value_get_object(value));
266 priv->va_display = gst_vaapi_display_get_display(priv->display);
268 priv->va_display = NULL;
271 set_caps(decoder, g_value_get_pointer(value));
274 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
280 gst_vaapi_decoder_get_property(
287 GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
291 g_value_set_object(value, priv->display);
294 gst_value_set_caps(value, priv->caps);
297 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
303 gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
305 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
307 g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate));
309 object_class->finalize = gst_vaapi_decoder_finalize;
310 object_class->set_property = gst_vaapi_decoder_set_property;
311 object_class->get_property = gst_vaapi_decoder_get_property;
314 * GstVaapiDecoder:display:
316 * The #GstVaapiDisplay this decoder is bound to.
318 g_properties[PROP_DISPLAY] =
319 g_param_spec_object("display",
321 "The GstVaapiDisplay this decoder is bound to",
322 GST_VAAPI_TYPE_DISPLAY,
323 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
325 g_properties[PROP_CAPS] =
326 g_param_spec_pointer("caps",
329 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
331 g_object_class_install_properties(object_class, N_PROPERTIES, g_properties);
335 gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
337 GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
339 decoder->priv = priv;
340 priv->display = NULL;
341 priv->va_display = NULL;
342 priv->context = NULL;
343 priv->va_context = VA_INVALID_ID;
346 priv->codec_data = NULL;
353 priv->buffers = g_queue_new();
354 priv->surfaces = g_queue_new();
355 priv->is_interlaced = FALSE;
359 * gst_vaapi_decoder_get_caps:
360 * @decoder: a #GstVaapiDecoder
362 * Retrieves the @decoder caps. The deocder owns the returned caps, so
363 * use gst_caps_ref() whenever necessary.
365 * Return value: the @decoder caps
368 gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder)
370 return decoder->priv->caps;
374 * gst_vaapi_decoder_put_buffer:
375 * @decoder: a #GstVaapiDecoder
378 * Queues a #GstBuffer to the HW decoder. The decoder holds a
381 * Caller can notify an End-Of-Stream with @buf set to %NULL.
383 * Return value: %TRUE on success
386 gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
388 g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
390 return push_buffer(decoder, buf ? gst_buffer_ref(buf) : NULL);
394 * gst_vaapi_decoder_get_surface:
395 * @decoder: a #GstVaapiDecoder
396 * @pstatus: return location for the decoder status, or %NULL
398 * Flushes encoded buffers to the decoder and returns a decoded
401 * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
402 * or %NULL if none is available (e.g. an error). Caller owns the
403 * returned object. g_object_unref() after usage.
405 GstVaapiSurfaceProxy *
406 gst_vaapi_decoder_get_surface(
407 GstVaapiDecoder *decoder,
408 GstVaapiDecoderStatus *pstatus
411 GstVaapiSurfaceProxy *proxy;
412 GstVaapiDecoderStatus status;
415 *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
417 g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
419 proxy = pop_surface(decoder);
422 status = decode_step(decoder);
423 } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
424 proxy = pop_surface(decoder);
428 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
436 gst_vaapi_decoder_clear_buffer(GstVaapiDecoder *decoder)
438 GstVaapiDecoderPrivate * const priv = decoder->priv;
439 GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
441 if (klass->clear_buffer)
442 klass->clear_buffer(decoder);
445 clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
448 clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref);
452 gst_vaapi_decoder_set_picture_size(
453 GstVaapiDecoder *decoder,
458 GstVaapiDecoderPrivate * const priv = decoder->priv;
459 gboolean size_changed = FALSE;
461 if (priv->width != width) {
462 GST_DEBUG("picture width changed to %d", width);
464 gst_caps_set_simple(priv->caps, "width", G_TYPE_INT, width, NULL);
468 if (priv->height != height) {
469 GST_DEBUG("picture height changed to %d", height);
470 priv->height = height;
471 gst_caps_set_simple(priv->caps, "height", G_TYPE_INT, height, NULL);
476 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
480 gst_vaapi_decoder_set_framerate(
481 GstVaapiDecoder *decoder,
486 GstVaapiDecoderPrivate * const priv = decoder->priv;
488 if (!fps_n || !fps_d)
491 if (priv->fps_n != fps_n || priv->fps_d != fps_d) {
492 GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d);
497 "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
500 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
505 gst_vaapi_decoder_set_pixel_aspect_ratio(
506 GstVaapiDecoder *decoder,
511 GstVaapiDecoderPrivate * const priv = decoder->priv;
513 if (!par_n || !par_d)
516 if (priv->par_n != par_n || priv->par_d != par_d) {
517 GST_DEBUG("pixel-aspect-ratio changed to %u/%u", par_n, par_d);
522 "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
525 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
530 gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced)
532 GstVaapiDecoderPrivate * const priv = decoder->priv;
534 if (priv->is_interlaced != interlaced) {
535 GST_DEBUG("interlaced changed to %s", interlaced ? "true" : "false");
536 priv->is_interlaced = interlaced;
539 "interlaced", G_TYPE_BOOLEAN, interlaced,
542 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
547 gst_vaapi_decoder_ensure_context(
548 GstVaapiDecoder *decoder,
549 GstVaapiProfile profile,
550 GstVaapiEntrypoint entrypoint,
556 GstVaapiDecoderPrivate * const priv = decoder->priv;
559 gst_vaapi_decoder_set_picture_size(decoder, width, height);
562 ret = gst_vaapi_context_reset(priv->context,
569 priv->context = gst_vaapi_context_new(
573 GST_VAAPI_RATECONTROL_NONE,
581 priv->va_context = gst_vaapi_context_get_id(priv->context);
586 gst_vaapi_decoder_push_buffer_sub(
587 GstVaapiDecoder *decoder,
593 GstBuffer *subbuffer;
595 subbuffer = gst_buffer_create_sub(buffer, offset, size);
599 push_back_buffer(decoder, subbuffer);
604 gst_vaapi_decoder_push_surface_proxy(
605 GstVaapiDecoder *decoder,
606 GstVaapiSurfaceProxy *proxy
609 return push_surface(decoder, proxy);
613 gst_vaapi_decoder_context_increase_surfaces(
614 GstVaapiDecoder *decoder,
618 GstVaapiDecoderPrivate * const priv = decoder->priv;
619 guint profile, entrypoint;
627 if (!priv->context ||
628 (gst_vaapi_context_get_surface_left_capability(priv->context) < increment))
630 g_object_get(G_OBJECT(priv->context),
632 "entrypoint", &entrypoint,
635 "surface_num", &surface_num,
637 surface_num += increment;
638 ret = gst_vaapi_context_reset(priv->context,
639 (GstVaapiProfile)profile,
640 (GstVaapiEntrypoint)entrypoint,
644 priv->va_context = gst_vaapi_context_get_id(priv->context);
648 GstVaapiDecoderStatus
649 gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder)
651 GstVaapiDecoderPrivate * const priv = decoder->priv;
654 if (!priv->context || gst_vaapi_context_get_surface_count(priv->context) > 0)
655 return GST_VAAPI_DECODER_STATUS_SUCCESS;
657 increment = gst_vaapi_context_get_surface_left_capability(priv->context);
659 GST_DEBUG("decoder context surface pool is out of capability");
660 return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
665 if (!gst_vaapi_decoder_context_increase_surfaces(decoder, increment)) {
666 GST_ERROR("increase decoder surface failed");
667 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
669 return GST_VAAPI_DECODER_STATUS_SUCCESS;