Fix build with older gstreamer libs where gst_buffer_unref() is not a plain function.
[vaapi:gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder.c
1 /*
2  *  gstvaapidecoder.c - VA decoder abstraction
3  *
4  *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * SECTION:gstvaapidecoder
24  * @short_description: VA decoder abstraction
25  */
26
27 #include "config.h"
28 #include <assert.h>
29 #include <string.h>
30 #include "gstvaapicompat.h"
31 #include "gstvaapidecoder.h"
32 #include "gstvaapidecoder_priv.h"
33 #include "gstvaapiutils.h"
34 #include "gstvaapi_priv.h"
35
36 #define DEBUG 1
37 #include "gstvaapidebug.h"
38
39 G_DEFINE_TYPE(GstVaapiDecoder, gst_vaapi_decoder, G_TYPE_OBJECT);
40
41 /* XXX: Make it a GstVaapiDecodedSurface + propagate PTS */
42 typedef struct _DecodedSurface DecodedSurface;
43 struct _DecodedSurface {
44     GstVaapiSurfaceProxy *proxy;
45     GstVaapiDecoderStatus status;
46 };
47
48 enum {
49     PROP_0,
50
51     PROP_DISPLAY,
52     PROP_CODEC,
53     PROP_CODEC_DATA
54 };
55
56 static inline void
57 init_buffer(GstBuffer *buffer, const guchar *buf, guint buf_size)
58 {
59     GST_BUFFER_DATA(buffer)      = (guint8 *)buf;
60     GST_BUFFER_SIZE(buffer)      = buf_size;
61     GST_BUFFER_TIMESTAMP(buffer) = GST_CLOCK_TIME_NONE;
62     GST_BUFFER_DURATION(buffer)  = GST_CLOCK_TIME_NONE;
63 }
64
65 static inline GstBuffer *
66 create_eos_buffer(void)
67 {
68     GstBuffer *buffer;
69
70     buffer = gst_buffer_new();
71     if (!buffer)
72         return NULL;
73
74     init_buffer(buffer, NULL, 0);
75     GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
76     return buffer;
77 }
78
79 static GstBuffer *
80 create_buffer(const guchar *buf, guint buf_size, gboolean copy)
81 {
82     GstBuffer *buffer;
83
84     if (!buf || !buf_size)
85         return NULL;
86
87     buffer = gst_buffer_new();
88     if (!buffer)
89         return NULL;
90
91     if (copy) {
92         buffer->malloc_data = g_malloc(buf_size);
93         if (!buffer->malloc_data) {
94             gst_buffer_unref(buffer);
95             return NULL;
96         }
97         memcpy(buffer->malloc_data, buf, buf_size);
98         buf = buffer->malloc_data;
99     }
100     init_buffer(buffer, buf, buf_size);
101     return buffer;
102 }
103
104 static void
105 destroy_buffer(GstBuffer *buffer)
106 {
107     gst_buffer_unref(buffer);
108 }
109
110 static gboolean
111 push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
112 {
113     GstVaapiDecoderPrivate * const priv = decoder->priv;
114
115     if (!buffer) {
116         buffer = create_eos_buffer();
117         if (!buffer)
118             return FALSE;
119     }
120
121     GST_DEBUG("queue encoded data buffer %p (%d bytes)",
122               buffer, GST_BUFFER_SIZE(buffer));
123
124     g_queue_push_tail(priv->buffers, buffer);
125     return TRUE;
126 }
127
128 static GstBuffer *
129 pop_buffer(GstVaapiDecoder *decoder)
130 {
131     GstVaapiDecoderPrivate * const priv = decoder->priv;
132     GstBuffer *buffer;
133
134     buffer = g_queue_pop_head(priv->buffers);
135     if (!buffer)
136         return NULL;
137
138     GST_DEBUG("dequeue buffer %p for decoding (%d bytes)",
139               buffer, GST_BUFFER_SIZE(buffer));
140
141     return buffer;
142 }
143
144 static GstVaapiDecoderStatus
145 decode_step(GstVaapiDecoder *decoder)
146 {
147     GstVaapiDecoderStatus status;
148     GstBuffer *buffer;
149
150     do {
151         buffer = pop_buffer(decoder);
152         if (!buffer)
153             return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
154
155         status = GST_VAAPI_DECODER_GET_CLASS(decoder)->decode(decoder, buffer);
156         GST_DEBUG("decode frame (status = %d)", status);
157         if (status == GST_VAAPI_DECODER_STATUS_SUCCESS)
158             return status;
159
160         if (GST_BUFFER_IS_EOS(buffer))
161             return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
162     } while (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA);
163     return status;
164 }
165
166 static inline DecodedSurface *
167 create_surface(void)
168 {
169     return g_slice_new0(DecodedSurface);
170 }
171
172 static inline void
173 destroy_surface(DecodedSurface *ds)
174 {
175     g_slice_free(DecodedSurface, ds);
176 }
177
178 static gboolean
179 push_surface(
180     GstVaapiDecoder *decoder,
181     GstVaapiSurface *surface,
182     GstClockTime     timestamp
183 )
184 {
185     GstVaapiDecoderPrivate * const priv = decoder->priv;
186     DecodedSurface *ds;
187
188     ds = create_surface();
189     if (!ds)
190         return FALSE;
191
192     GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
193               GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
194     ds->proxy = gst_vaapi_surface_proxy_new(priv->context, surface);
195     if (ds->proxy) {
196         ds->status = GST_VAAPI_DECODER_STATUS_SUCCESS;
197         gst_vaapi_surface_proxy_set_timestamp(ds->proxy, timestamp);
198     }
199     else
200         ds->status = GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
201
202     g_queue_push_tail(priv->surfaces, ds);
203     return TRUE;
204 }
205
206 static inline DecodedSurface *
207 pop_surface(GstVaapiDecoder *decoder)
208 {
209     GstVaapiDecoderPrivate * const priv = decoder->priv;
210
211     return g_queue_pop_head(priv->surfaces);
212 }
213
214 static inline void
215 set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
216 {
217     GstVaapiDecoderPrivate * const priv = decoder->priv;
218
219     if (priv->codec_data) {
220         gst_buffer_unref(priv->codec_data);
221         priv->codec_data = NULL;
222     }
223
224     if (codec_data)
225         priv->codec_data = gst_buffer_ref(codec_data);
226 }
227
228 static void
229 clear_queue(GQueue *q, GDestroyNotify destroy)
230 {
231     while (!g_queue_is_empty(q))
232         destroy(g_queue_pop_head(q));
233 }
234
235 static void
236 gst_vaapi_decoder_finalize(GObject *object)
237 {
238     GstVaapiDecoder * const        decoder = GST_VAAPI_DECODER(object);
239     GstVaapiDecoderPrivate * const priv    = decoder->priv;
240
241     set_codec_data(decoder, NULL);
242
243     if (priv->context) {
244         g_object_unref(priv->context);
245         priv->context = NULL;
246     }
247
248     if (priv->buffers) {
249         clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
250         g_queue_free(priv->buffers);
251         priv->buffers = NULL;
252     }
253
254     if (priv->surfaces) {
255         clear_queue(priv->surfaces, (GDestroyNotify)destroy_surface);
256         g_queue_free(priv->surfaces);
257         priv->surfaces = NULL;
258     }
259
260     if (priv->display) {
261         g_object_unref(priv->display);
262         priv->display = NULL;
263     }
264
265     G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
266 }
267
268 static void
269 gst_vaapi_decoder_set_property(
270     GObject      *object,
271     guint         prop_id,
272     const GValue *value,
273     GParamSpec   *pspec
274 )
275 {
276     GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
277
278     switch (prop_id) {
279     case PROP_DISPLAY:
280         priv->display = g_object_ref(g_value_get_object(value));
281         break;
282     case PROP_CODEC:
283         priv->codec = g_value_get_uint(value);
284         break;
285     case PROP_CODEC_DATA:
286         set_codec_data(GST_VAAPI_DECODER(object), gst_value_get_buffer(value));
287         break;
288     default:
289         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
290         break;
291     }
292 }
293
294 static void
295 gst_vaapi_decoder_get_property(
296     GObject    *object,
297     guint       prop_id,
298     GValue     *value,
299     GParamSpec *pspec
300 )
301 {
302     GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
303
304     switch (prop_id) {
305     case PROP_DISPLAY:
306         g_value_set_object(value, priv->display);
307         break;
308     case PROP_CODEC:
309         g_value_set_uint(value, priv->codec);
310         break;
311     case PROP_CODEC_DATA:
312         gst_value_set_buffer(value, priv->codec_data);
313         break;
314     default:
315         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
316         break;
317     }
318 }
319
320 static void
321 gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
322 {
323     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
324
325     g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate));
326
327     object_class->finalize     = gst_vaapi_decoder_finalize;
328     object_class->set_property = gst_vaapi_decoder_set_property;
329     object_class->get_property = gst_vaapi_decoder_get_property;
330
331     /**
332      * GstVaapiDecoder:display:
333      *
334      * The #GstVaapiDisplay this decoder is bound to.
335      */
336     g_object_class_install_property
337         (object_class,
338          PROP_DISPLAY,
339          g_param_spec_object("display",
340                              "Display",
341                              "The GstVaapiDisplay this decoder is bound to",
342                              GST_VAAPI_TYPE_DISPLAY,
343                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
344
345     g_object_class_install_property
346         (object_class,
347          PROP_CODEC,
348          g_param_spec_uint("codec",
349                            "Codec",
350                            "The codec handled by the decoder",
351                            0, G_MAXINT32, 0,
352                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
353
354     g_object_class_install_property
355         (object_class,
356          PROP_CODEC_DATA,
357          gst_param_spec_mini_object("codec-data",
358                                     "Codec data",
359                                     "Extra codec data",
360                                     GST_TYPE_BUFFER,
361                                     G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
362 }
363
364 static void
365 gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
366 {
367     GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
368
369     decoder->priv               = priv;
370     priv->context               = NULL;
371     priv->codec                 = 0;
372     priv->codec_data            = NULL;
373     priv->fps_n                 = 1000;
374     priv->fps_d                 = 30;
375     priv->buffers               = g_queue_new();
376     priv->surfaces              = g_queue_new();
377 }
378
379 /**
380  * gst_vaapi_decoder_get_frame_rate:
381  * @decoder: a #GstVaapiDecoder
382  * @num: return location for the numerator of the frame rate
383  * @den: return location for the denominator of the frame rate
384  *
385  * Retrieves the current frame rate as the fraction @num / @den. The
386  * default frame rate is 30 fps.
387  */
388 void
389 gst_vaapi_decoder_get_frame_rate(
390     GstVaapiDecoder *decoder,
391     guint           *num,
392     guint           *den
393 )
394 {
395     g_return_if_fail(GST_VAAPI_IS_DECODER(decoder));
396
397     if (num)
398         *num = decoder->priv->fps_n;
399
400     if (den)
401         *den = decoder->priv->fps_d;
402 }
403
404 /**
405  * gst_vaapi_decoder_set_frame_rate:
406  * @decoder: a #GstVaapiDecoder
407  * @num: the numerator of the frame rate
408  * @den: the denominator of the frame rate
409  *
410  * Sets the frame rate for the stream to @num / @den. By default, the
411  * decoder will use the frame rate encoded in the elementary stream.
412  * If none is available, the decoder will default to 30 fps.
413  */
414 void
415 gst_vaapi_decoder_set_frame_rate(
416     GstVaapiDecoder *decoder,
417     guint            num,
418     guint            den
419 )
420 {
421     g_return_if_fail(GST_VAAPI_IS_DECODER(decoder));
422
423     decoder->priv->fps_n = num;
424     decoder->priv->fps_d = den;
425 }
426
427 /**
428  * gst_vaapi_decoder_put_buffer_data:
429  * @decoder: a #GstVaapiDecoder
430  * @buf: pointer to buffer data
431  * @buf_size: size of buffer data in bytes
432  *
433  * Queues @buf_size bytes from the data @buf to the HW decoder. The
434  * caller is responsible for making sure @buf is live beyond this
435  * function. So, this function is mostly useful with static data
436  * buffers. gst_vaapi_decoder_put_buffer_data_copy() does the same but
437  * copies the data.
438  *
439  * Caller can notify an End-Of-Stream with @buf set to %NULL and
440  * @buf_size set to zero.
441  *
442  * Return value: %TRUE on success
443  */
444 gboolean
445 gst_vaapi_decoder_put_buffer_data(
446     GstVaapiDecoder *decoder,
447     const guchar    *buf,
448     guint            buf_size
449 )
450 {
451     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
452
453     return push_buffer(decoder, create_buffer(buf, buf_size, FALSE));
454 }
455
456 /**
457  * gst_vaapi_decoder_put_buffer_data_copy:
458  * @decoder: a #GstVaapiDecoder
459  * @buf: pointer to buffer data
460  * @buf_size: size of buffer data in bytes
461  *
462  * Queues a copy of @buf to the HW decoder.
463  *
464  * Caller can notify an End-Of-Stream with @buf set to %NULL and
465  * @buf_size set to zero.
466  *
467  * Return value: %TRUE on success
468  */
469 gboolean
470 gst_vaapi_decoder_put_buffer_data_copy(
471     GstVaapiDecoder *decoder,
472     const guchar    *buf,
473     guint            buf_size
474 )
475 {
476     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
477
478     return push_buffer(decoder, create_buffer(buf, buf_size, TRUE));
479 }
480
481 /**
482  * gst_vaapi_decoder_put_buffer:
483  * @decoder: a #GstVaapiDecoder
484  * @buf: a #GstBuffer
485  *
486  * Queues a #GstBuffer to the HW decoder. The decoder holds a
487  * reference to @buf.
488  *
489  * Caller can notify an End-Of-Stream with @buf set to %NULL.
490  *
491  * Return value: %TRUE on success
492  */
493 gboolean
494 gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
495 {
496     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
497
498     return push_buffer(decoder, buf ? gst_buffer_ref(buf) : NULL);
499 }
500
501 /**
502  * gst_vaapi_decoder_get_surface:
503  * @decoder: a #GstVaapiDecoder
504  * @pstatus: return location for the decoder status, or %NULL
505  *
506  * Flushes encoded buffers to the decoder and returns a decoded
507  * surface, if any.
508  *
509  * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
510  *   or %NULL if none is available (e.g. an error). Caller owns the
511  *   returned object. g_object_unref() after usage.
512  */
513 GstVaapiSurfaceProxy *
514 gst_vaapi_decoder_get_surface(
515     GstVaapiDecoder       *decoder,
516     GstVaapiDecoderStatus *pstatus
517 )
518 {
519     GstVaapiSurfaceProxy *proxy  = NULL;
520     GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
521     DecodedSurface *ds;
522
523     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
524
525     ds = pop_surface(decoder);
526     if (!ds) {
527         do {
528             status = decode_step(decoder);
529         } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
530         ds = pop_surface(decoder);
531     }
532
533     if (ds) {
534         proxy  = ds->proxy;
535         status = ds->status;
536         destroy_surface(ds);
537     }
538
539     if (pstatus)
540         *pstatus = status;
541     return proxy;
542 }
543
544 gboolean
545 gst_vaapi_decoder_ensure_context(
546     GstVaapiDecoder    *decoder,
547     GstVaapiProfile     profile,
548     GstVaapiEntrypoint  entrypoint,
549     guint               width,
550     guint               height
551 )
552 {
553     GstVaapiDecoderPrivate * const priv = decoder->priv;
554
555     if (priv->context)
556         return gst_vaapi_context_reset(priv->context,
557                                        profile, entrypoint, width, height);
558
559     priv->context = gst_vaapi_context_new(
560         priv->display,
561         profile,
562         entrypoint,
563         width,
564         height
565     );
566     return priv->context != NULL;
567 }
568
569 gboolean
570 gst_vaapi_decoder_push_surface(
571     GstVaapiDecoder *decoder,
572     GstVaapiSurface *surface,
573     GstClockTime     timestamp
574 )
575 {
576     return push_surface(decoder, surface, timestamp);
577 }