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)
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)
104 buffer = pop_buffer(decoder);
106 return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
108 status = GST_VAAPI_DECODER_GET_CLASS(decoder)->decode(decoder, buffer);
109 GST_DEBUG("decode frame (status = %d)", status);
110 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS && GST_BUFFER_IS_EOS(buffer))
111 status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
112 gst_buffer_unref(buffer);
113 } while (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA);
118 push_surface(GstVaapiDecoder *decoder, GstVaapiSurfaceProxy *proxy)
120 GstVaapiDecoderPrivate * const priv = decoder->priv;
121 GstClockTime duration;
123 GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
124 GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy)));
126 if (priv->fps_n && priv->fps_d) {
127 /* Actual field duration is computed in vaapipostproc */
128 duration = gst_util_uint64_scale(GST_SECOND, priv->fps_d, priv->fps_n);
129 gst_vaapi_surface_proxy_set_duration(proxy, duration);
131 g_queue_push_tail(priv->surfaces, proxy);
134 static inline GstVaapiSurfaceProxy *
135 pop_surface(GstVaapiDecoder *decoder)
137 GstVaapiDecoderPrivate * const priv = decoder->priv;
139 return g_queue_pop_head(priv->surfaces);
143 set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
145 GstVaapiDecoderPrivate * const priv = decoder->priv;
147 if (priv->codec_data) {
148 gst_buffer_unref(priv->codec_data);
149 priv->codec_data = NULL;
153 priv->codec_data = gst_buffer_ref(codec_data);
157 set_caps(GstVaapiDecoder *decoder, GstCaps *caps)
159 GstVaapiDecoderPrivate * const priv = decoder->priv;
160 GstStructure * const structure = gst_caps_get_structure(caps, 0);
161 GstVaapiProfile profile;
162 const GValue *v_codec_data;
166 profile = gst_vaapi_profile_from_caps(caps);
170 priv->caps = gst_caps_copy(caps);
172 priv->codec = gst_vaapi_profile_get_codec(profile);
176 if (gst_structure_get_int(structure, "width", &v1))
178 if (gst_structure_get_int(structure, "height", &v2))
181 if (gst_structure_get_fraction(structure, "framerate", &v1, &v2)) {
186 if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &v1, &v2)) {
191 if (gst_structure_get_boolean(structure, "interlaced", &b))
192 priv->is_interlaced = b;
194 v_codec_data = gst_structure_get_value(structure, "codec_data");
196 set_codec_data(decoder, gst_value_get_buffer(v_codec_data));
200 clear_queue(GQueue *q, GDestroyNotify destroy)
202 while (!g_queue_is_empty(q))
203 destroy(g_queue_pop_head(q));
207 gst_vaapi_decoder_finalize(GObject *object)
209 GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(object);
210 GstVaapiDecoderPrivate * const priv = decoder->priv;
212 set_codec_data(decoder, NULL);
215 gst_caps_unref(priv->caps);
220 g_object_unref(priv->context);
221 priv->context = NULL;
222 priv->va_context = VA_INVALID_ID;
226 clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
227 g_queue_free(priv->buffers);
228 priv->buffers = NULL;
231 if (priv->surfaces) {
232 clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref);
233 g_queue_free(priv->surfaces);
234 priv->surfaces = NULL;
238 g_object_unref(priv->display);
239 priv->display = NULL;
240 priv->va_display = NULL;
243 G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
247 gst_vaapi_decoder_set_property(
254 GstVaapiDecoder * const decoder = GST_VAAPI_DECODER(object);
255 GstVaapiDecoderPrivate * const priv = decoder->priv;
259 priv->display = g_object_ref(g_value_get_object(value));
261 priv->va_display = gst_vaapi_display_get_display(priv->display);
263 priv->va_display = NULL;
266 set_caps(decoder, g_value_get_pointer(value));
269 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
275 gst_vaapi_decoder_get_property(
282 GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
286 g_value_set_object(value, priv->display);
289 gst_value_set_caps(value, priv->caps);
292 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
298 gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
300 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
302 g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate));
304 object_class->finalize = gst_vaapi_decoder_finalize;
305 object_class->set_property = gst_vaapi_decoder_set_property;
306 object_class->get_property = gst_vaapi_decoder_get_property;
309 * GstVaapiDecoder:display:
311 * The #GstVaapiDisplay this decoder is bound to.
313 g_properties[PROP_DISPLAY] =
314 g_param_spec_object("display",
316 "The GstVaapiDisplay this decoder is bound to",
317 GST_VAAPI_TYPE_DISPLAY,
318 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
320 g_properties[PROP_CAPS] =
321 g_param_spec_pointer("caps",
324 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
326 g_object_class_install_properties(object_class, N_PROPERTIES, g_properties);
330 gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
332 GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
334 decoder->priv = priv;
335 priv->display = NULL;
336 priv->va_display = NULL;
337 priv->context = NULL;
338 priv->va_context = VA_INVALID_ID;
341 priv->codec_data = NULL;
348 priv->buffers = g_queue_new();
349 priv->surfaces = g_queue_new();
350 priv->is_interlaced = FALSE;
354 * gst_vaapi_decoder_get_codec:
355 * @decoder: a #GstVaapiDecoder
357 * Retrieves the @decoder codec type.
359 * Return value: the #GstVaapiCodec type for @decoder
362 gst_vaapi_decoder_get_codec(GstVaapiDecoder *decoder)
364 g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), (GstVaapiCodec)0);
366 return decoder->priv->codec;
370 * gst_vaapi_decoder_get_caps:
371 * @decoder: a #GstVaapiDecoder
373 * Retrieves the @decoder caps. The deocder owns the returned caps, so
374 * use gst_caps_ref() whenever necessary.
376 * Return value: the @decoder caps
379 gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder)
381 return decoder->priv->caps;
385 * gst_vaapi_decoder_put_buffer:
386 * @decoder: a #GstVaapiDecoder
389 * Queues a #GstBuffer to the HW decoder. The decoder holds a
392 * Caller can notify an End-Of-Stream with @buf set to %NULL. However,
393 * if an empty buffer is passed, i.e. a buffer with %NULL data pointer
394 * or size equals to zero, then the function ignores this buffer and
397 * Return value: %TRUE on success
400 gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
402 g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
405 if (!GST_BUFFER_DATA(buf) || GST_BUFFER_SIZE(buf) <= 0)
407 buf = gst_buffer_ref(buf);
409 return push_buffer(decoder, buf);
413 * gst_vaapi_decoder_get_surface:
414 * @decoder: a #GstVaapiDecoder
415 * @pstatus: return location for the decoder status, or %NULL
417 * Flushes encoded buffers to the decoder and returns a decoded
420 * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
421 * or %NULL if none is available (e.g. an error). Caller owns the
422 * returned object. g_object_unref() after usage.
424 GstVaapiSurfaceProxy *
425 gst_vaapi_decoder_get_surface(
426 GstVaapiDecoder *decoder,
427 GstVaapiDecoderStatus *pstatus
430 GstVaapiSurfaceProxy *proxy;
431 GstVaapiDecoderStatus status;
434 *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
436 g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
438 proxy = pop_surface(decoder);
441 status = decode_step(decoder);
442 } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
443 proxy = pop_surface(decoder);
447 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
455 gst_vaapi_decoder_set_picture_size(
456 GstVaapiDecoder *decoder,
461 GstVaapiDecoderPrivate * const priv = decoder->priv;
462 gboolean size_changed = FALSE;
464 if (priv->width != width) {
465 GST_DEBUG("picture width changed to %d", width);
467 gst_caps_set_simple(priv->caps, "width", G_TYPE_INT, width, NULL);
471 if (priv->height != height) {
472 GST_DEBUG("picture height changed to %d", height);
473 priv->height = height;
474 gst_caps_set_simple(priv->caps, "height", G_TYPE_INT, height, NULL);
479 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
483 gst_vaapi_decoder_set_framerate(
484 GstVaapiDecoder *decoder,
489 GstVaapiDecoderPrivate * const priv = decoder->priv;
491 if (!fps_n || !fps_d)
494 if (priv->fps_n != fps_n || priv->fps_d != fps_d) {
495 GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d);
500 "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
503 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
508 gst_vaapi_decoder_set_pixel_aspect_ratio(
509 GstVaapiDecoder *decoder,
514 GstVaapiDecoderPrivate * const priv = decoder->priv;
516 if (!par_n || !par_d)
519 if (priv->par_n != par_n || priv->par_d != par_d) {
520 GST_DEBUG("pixel-aspect-ratio changed to %u/%u", par_n, par_d);
525 "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
528 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
533 gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced)
535 GstVaapiDecoderPrivate * const priv = decoder->priv;
537 if (priv->is_interlaced != interlaced) {
538 GST_DEBUG("interlaced changed to %s", interlaced ? "true" : "false");
539 priv->is_interlaced = interlaced;
542 "interlaced", G_TYPE_BOOLEAN, interlaced,
545 g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
550 gst_vaapi_decoder_ensure_context(
551 GstVaapiDecoder *decoder,
552 GstVaapiContextInfo *cip
555 GstVaapiDecoderPrivate * const priv = decoder->priv;
557 cip->rate_control = GST_VAAPI_RATECONTROL_NONE;
558 gst_vaapi_decoder_set_picture_size(decoder, cip->width, cip->height);
561 if (!gst_vaapi_context_reset_full(priv->context, cip))
565 priv->context = gst_vaapi_context_new_full(priv->display, cip);
569 priv->va_context = gst_vaapi_context_get_id(priv->context);
574 gst_vaapi_decoder_push_surface_proxy(
575 GstVaapiDecoder *decoder,
576 GstVaapiSurfaceProxy *proxy
579 push_surface(decoder, proxy);
582 GstVaapiDecoderStatus
583 gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder)
585 GstVaapiDecoderPrivate * const priv = decoder->priv;
587 if (priv->context && gst_vaapi_context_get_surface_count(priv->context) < 1)
588 return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
589 return GST_VAAPI_DECODER_STATUS_SUCCESS;