decoder context: rate_control unset to GST_VAAPI_RATECONTROL_NONE
[profile/ivi/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder.c
1 /*
2  *  gstvaapidecoder.c - VA decoder abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *  Copyright (C) 2011-2012 Intel Corporation
6  *
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.
11  *
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.
16  *
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
21  */
22
23 /**
24  * SECTION:gstvaapidecoder
25  * @short_description: VA decoder abstraction
26  */
27
28 #include "sysdeps.h"
29 #include "gstvaapicompat.h"
30 #include "gstvaapidecoder.h"
31 #include "gstvaapidecoder_priv.h"
32 #include "gstvaapiutils.h"
33 #include "gstvaapi_priv.h"
34
35 #define DEBUG 1
36 #include "gstvaapidebug.h"
37
38 G_DEFINE_TYPE(GstVaapiDecoder, gst_vaapi_decoder, G_TYPE_OBJECT)
39
40 enum {
41     PROP_0,
42
43     PROP_DISPLAY,
44     PROP_CAPS,
45
46     N_PROPERTIES
47 };
48
49 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
50
51 static void
52 destroy_buffer(GstBuffer *buffer)
53 {
54     gst_buffer_unref(buffer);
55 }
56
57 static gboolean
58 push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
59 {
60     GstVaapiDecoderPrivate * const priv = decoder->priv;
61
62     if (!buffer) {
63         buffer = gst_buffer_new();
64         if (!buffer)
65             return FALSE;
66         GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
67     }
68
69     GST_DEBUG("queue encoded data buffer %p (%d bytes)",
70               buffer, GST_BUFFER_SIZE(buffer));
71
72     g_queue_push_tail(priv->buffers, buffer);
73     return TRUE;
74 }
75
76 static GstBuffer *
77 pop_buffer(GstVaapiDecoder *decoder)
78 {
79     GstVaapiDecoderPrivate * const priv = decoder->priv;
80     GstBuffer *buffer;
81
82     buffer = g_queue_pop_head(priv->buffers);
83     if (!buffer)
84         return NULL;
85
86     GST_DEBUG("dequeue buffer %p for decoding (%d bytes)",
87               buffer, GST_BUFFER_SIZE(buffer));
88
89     return buffer;
90 }
91
92 static GstVaapiDecoderStatus
93 decode_step(GstVaapiDecoder *decoder)
94 {
95     GstVaapiDecoderStatus status;
96     GstBuffer *buffer;
97
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)
101         return status;
102
103     do {
104         buffer = pop_buffer(decoder);
105         if (!buffer)
106             return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
107
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);
114     return status;
115 }
116
117 static inline void
118 push_surface(GstVaapiDecoder *decoder, GstVaapiSurfaceProxy *proxy)
119 {
120     GstVaapiDecoderPrivate * const priv = decoder->priv;
121     GstClockTime duration;
122
123     GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
124               GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy)));
125
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);
130     }
131     g_queue_push_tail(priv->surfaces, proxy);
132 }
133
134 static inline GstVaapiSurfaceProxy *
135 pop_surface(GstVaapiDecoder *decoder)
136 {
137     GstVaapiDecoderPrivate * const priv = decoder->priv;
138
139     return g_queue_pop_head(priv->surfaces);
140 }
141
142 static inline void
143 set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
144 {
145     GstVaapiDecoderPrivate * const priv = decoder->priv;
146
147     if (priv->codec_data) {
148         gst_buffer_unref(priv->codec_data);
149         priv->codec_data = NULL;
150     }
151
152     if (codec_data)
153         priv->codec_data = gst_buffer_ref(codec_data);
154 }
155
156 static void
157 set_caps(GstVaapiDecoder *decoder, GstCaps *caps)
158 {
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;
163     gint v1, v2;
164     gboolean b;
165
166     profile = gst_vaapi_profile_from_caps(caps);
167     if (!profile)
168         return;
169
170     priv->caps = gst_caps_copy(caps);
171
172     priv->codec = gst_vaapi_profile_get_codec(profile);
173     if (!priv->codec)
174         return;
175
176     if (gst_structure_get_int(structure, "width", &v1))
177         priv->width = v1;
178     if (gst_structure_get_int(structure, "height", &v2))
179         priv->height = v2;
180
181     if (gst_structure_get_fraction(structure, "framerate", &v1, &v2)) {
182         priv->fps_n = v1;
183         priv->fps_d = v2;
184     }
185
186     if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &v1, &v2)) {
187         priv->par_n = v1;
188         priv->par_d = v2;
189     }
190
191     if (gst_structure_get_boolean(structure, "interlaced", &b))
192         priv->is_interlaced = b;
193
194     v_codec_data = gst_structure_get_value(structure, "codec_data");
195     if (v_codec_data)
196         set_codec_data(decoder, gst_value_get_buffer(v_codec_data));
197 }
198
199 static void
200 clear_queue(GQueue *q, GDestroyNotify destroy)
201 {
202     while (!g_queue_is_empty(q))
203         destroy(g_queue_pop_head(q));
204 }
205
206 static void
207 gst_vaapi_decoder_finalize(GObject *object)
208 {
209     GstVaapiDecoder * const        decoder = GST_VAAPI_DECODER(object);
210     GstVaapiDecoderPrivate * const priv    = decoder->priv;
211
212     set_codec_data(decoder, NULL);
213
214     if (priv->caps) {
215         gst_caps_unref(priv->caps);
216         priv->caps = NULL;
217     }
218
219     if (priv->context) {
220         g_object_unref(priv->context);
221         priv->context = NULL;
222         priv->va_context = VA_INVALID_ID;
223     }
224  
225     if (priv->buffers) {
226         clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
227         g_queue_free(priv->buffers);
228         priv->buffers = NULL;
229     }
230
231     if (priv->surfaces) {
232         clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref);
233         g_queue_free(priv->surfaces);
234         priv->surfaces = NULL;
235     }
236
237     if (priv->display) {
238         g_object_unref(priv->display);
239         priv->display = NULL;
240         priv->va_display = NULL;
241     }
242
243     G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
244 }
245
246 static void
247 gst_vaapi_decoder_set_property(
248     GObject      *object,
249     guint         prop_id,
250     const GValue *value,
251     GParamSpec   *pspec
252 )
253 {
254     GstVaapiDecoder * const        decoder = GST_VAAPI_DECODER(object);
255     GstVaapiDecoderPrivate * const priv    = decoder->priv;
256
257     switch (prop_id) {
258     case PROP_DISPLAY:
259         priv->display = g_object_ref(g_value_get_object(value));
260         if (priv->display)
261             priv->va_display = gst_vaapi_display_get_display(priv->display);
262         else
263             priv->va_display = NULL;
264         break;
265     case PROP_CAPS:
266         set_caps(decoder, g_value_get_pointer(value));
267         break;
268     default:
269         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
270         break;
271     }
272 }
273
274 static void
275 gst_vaapi_decoder_get_property(
276     GObject    *object,
277     guint       prop_id,
278     GValue     *value,
279     GParamSpec *pspec
280 )
281 {
282     GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
283
284     switch (prop_id) {
285     case PROP_DISPLAY:
286         g_value_set_object(value, priv->display);
287         break;
288     case PROP_CAPS:
289         gst_value_set_caps(value, priv->caps);
290         break;
291     default:
292         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
293         break;
294     }
295 }
296
297 static void
298 gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
299 {
300     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
301
302     g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate));
303
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;
307
308     /**
309      * GstVaapiDecoder:display:
310      *
311      * The #GstVaapiDisplay this decoder is bound to.
312      */
313     g_properties[PROP_DISPLAY] =
314          g_param_spec_object("display",
315                              "Display",
316                              "The GstVaapiDisplay this decoder is bound to",
317                              GST_VAAPI_TYPE_DISPLAY,
318                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
319
320     g_properties[PROP_CAPS] =
321          g_param_spec_pointer("caps",
322                               "Decoder caps",
323                               "The decoder caps",
324                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
325
326     g_object_class_install_properties(object_class, N_PROPERTIES, g_properties);
327 }
328
329 static void
330 gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
331 {
332     GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
333
334     decoder->priv               = priv;
335     priv->display               = NULL;
336     priv->va_display            = NULL;
337     priv->context               = NULL;
338     priv->va_context            = VA_INVALID_ID;
339     priv->caps                  = NULL;
340     priv->codec                 = 0;
341     priv->codec_data            = NULL;
342     priv->width                 = 0;
343     priv->height                = 0;
344     priv->fps_n                 = 0;
345     priv->fps_d                 = 0;
346     priv->par_n                 = 0;
347     priv->par_d                 = 0;
348     priv->buffers               = g_queue_new();
349     priv->surfaces              = g_queue_new();
350     priv->is_interlaced         = FALSE;
351 }
352
353 /**
354  * gst_vaapi_decoder_get_codec:
355  * @decoder: a #GstVaapiDecoder
356  *
357  * Retrieves the @decoder codec type.
358  *
359  * Return value: the #GstVaapiCodec type for @decoder
360  */
361 GstVaapiCodec
362 gst_vaapi_decoder_get_codec(GstVaapiDecoder *decoder)
363 {
364     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), (GstVaapiCodec)0);
365
366     return decoder->priv->codec;
367 }
368
369 /**
370  * gst_vaapi_decoder_get_caps:
371  * @decoder: a #GstVaapiDecoder
372  *
373  * Retrieves the @decoder caps. The deocder owns the returned caps, so
374  * use gst_caps_ref() whenever necessary.
375  *
376  * Return value: the @decoder caps
377  */
378 GstCaps *
379 gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder)
380 {
381     return decoder->priv->caps;
382 }
383
384 /**
385  * gst_vaapi_decoder_put_buffer:
386  * @decoder: a #GstVaapiDecoder
387  * @buf: a #GstBuffer
388  *
389  * Queues a #GstBuffer to the HW decoder. The decoder holds a
390  * reference to @buf.
391  *
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
395  * returns %TRUE.
396  *
397  * Return value: %TRUE on success
398  */
399 gboolean
400 gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
401 {
402     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
403
404     if (buf) {
405         if (!GST_BUFFER_DATA(buf) || GST_BUFFER_SIZE(buf) <= 0)
406             return TRUE;
407         buf = gst_buffer_ref(buf);
408     }
409     return push_buffer(decoder, buf);
410 }
411
412 /**
413  * gst_vaapi_decoder_get_surface:
414  * @decoder: a #GstVaapiDecoder
415  * @pstatus: return location for the decoder status, or %NULL
416  *
417  * Flushes encoded buffers to the decoder and returns a decoded
418  * surface, if any.
419  *
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.
423  */
424 GstVaapiSurfaceProxy *
425 gst_vaapi_decoder_get_surface(
426     GstVaapiDecoder       *decoder,
427     GstVaapiDecoderStatus *pstatus
428 )
429 {
430     GstVaapiSurfaceProxy *proxy;
431     GstVaapiDecoderStatus status;
432
433     if (pstatus)
434         *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
435
436     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
437
438     proxy = pop_surface(decoder);
439     if (!proxy) {
440         do {
441             status = decode_step(decoder);
442         } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
443         proxy = pop_surface(decoder);
444     }
445
446     if (proxy)
447         status = GST_VAAPI_DECODER_STATUS_SUCCESS;
448
449     if (pstatus)
450         *pstatus = status;
451     return proxy;
452 }
453
454 void
455 gst_vaapi_decoder_set_picture_size(
456     GstVaapiDecoder    *decoder,
457     guint               width,
458     guint               height
459 )
460 {
461     GstVaapiDecoderPrivate * const priv = decoder->priv;
462     gboolean size_changed = FALSE;
463
464     if (priv->width != width) {
465         GST_DEBUG("picture width changed to %d", width);
466         priv->width = width;
467         gst_caps_set_simple(priv->caps, "width", G_TYPE_INT, width, NULL);
468         size_changed = TRUE;
469     }
470
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);
475         size_changed = TRUE;
476     }
477
478     if (size_changed)
479         g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
480 }
481
482 void
483 gst_vaapi_decoder_set_framerate(
484     GstVaapiDecoder    *decoder,
485     guint               fps_n,
486     guint               fps_d
487 )
488 {
489     GstVaapiDecoderPrivate * const priv = decoder->priv;
490
491     if (!fps_n || !fps_d)
492         return;
493
494     if (priv->fps_n != fps_n || priv->fps_d != fps_d) {
495         GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d);
496         priv->fps_n = fps_n;
497         priv->fps_d = fps_d;
498         gst_caps_set_simple(
499             priv->caps,
500             "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
501             NULL
502         );
503         g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
504     }
505 }
506
507 void
508 gst_vaapi_decoder_set_pixel_aspect_ratio(
509     GstVaapiDecoder    *decoder,
510     guint               par_n,
511     guint               par_d
512 )
513 {
514     GstVaapiDecoderPrivate * const priv = decoder->priv;
515
516     if (!par_n || !par_d)
517         return;
518
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);
521         priv->par_n = par_n;
522         priv->par_d = par_d;
523         gst_caps_set_simple(
524             priv->caps,
525             "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
526             NULL
527         );
528         g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
529     }
530 }
531
532 void
533 gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced)
534 {
535     GstVaapiDecoderPrivate * const priv = decoder->priv;
536
537     if (priv->is_interlaced != interlaced) {
538         GST_DEBUG("interlaced changed to %s", interlaced ? "true" : "false");
539         priv->is_interlaced = interlaced;
540         gst_caps_set_simple(
541             priv->caps,
542             "interlaced", G_TYPE_BOOLEAN, interlaced,
543             NULL
544         );
545         g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
546     }
547 }
548
549 gboolean
550 gst_vaapi_decoder_ensure_context(
551     GstVaapiDecoder     *decoder,
552     GstVaapiContextInfo *cip
553 )
554 {
555     GstVaapiDecoderPrivate * const priv = decoder->priv;
556
557     cip->rate_control = GST_VAAPI_RATECONTROL_NONE;
558     gst_vaapi_decoder_set_picture_size(decoder, cip->width, cip->height);
559
560     if (priv->context) {
561         if (!gst_vaapi_context_reset_full(priv->context, cip))
562             return FALSE;
563     }
564     else {
565         priv->context = gst_vaapi_context_new_full(priv->display, cip);
566         if (!priv->context)
567             return FALSE;
568     }
569     priv->va_context = gst_vaapi_context_get_id(priv->context);
570     return TRUE;
571 }
572
573 void
574 gst_vaapi_decoder_push_surface_proxy(
575     GstVaapiDecoder      *decoder,
576     GstVaapiSurfaceProxy *proxy
577 )
578 {
579     push_surface(decoder, proxy);
580 }
581
582 GstVaapiDecoderStatus
583 gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder)
584 {
585     GstVaapiDecoderPrivate * const priv = decoder->priv;
586
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;
590 }