~ubuntu-branches/ubuntu/quantal/gstreamer-vaapi/quantal

« back to all changes in this revision

Viewing changes to gst-libs/gst/vaapi/gstvaapidecoder.c

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2012-02-10 14:35:09 UTC
  • Revision ID: package-import@ubuntu.com-20120210143509-wq9j8uqb5leu1iik
Tags: upstream-0.3.4
ImportĀ upstreamĀ versionĀ 0.3.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
47
static void
 
48
destroy_buffer(GstBuffer *buffer)
 
49
{
 
50
    gst_buffer_unref(buffer);
 
51
}
 
52
 
 
53
static gboolean
 
54
push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
 
55
{
 
56
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
57
 
 
58
    if (!buffer) {
 
59
        buffer = gst_buffer_new();
 
60
        if (!buffer)
 
61
            return FALSE;
 
62
        GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
 
63
    }
 
64
 
 
65
    GST_DEBUG("queue encoded data buffer %p (%d bytes)",
 
66
              buffer, GST_BUFFER_SIZE(buffer));
 
67
 
 
68
    g_queue_push_tail(priv->buffers, buffer);
 
69
    return TRUE;
 
70
}
 
71
 
 
72
static void
 
73
push_back_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
 
74
{
 
75
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
76
 
 
77
    GST_DEBUG("requeue encoded data buffer %p (%d bytes)",
 
78
              buffer, GST_BUFFER_SIZE(buffer));
 
79
 
 
80
    g_queue_push_head(priv->buffers, buffer);
 
81
}
 
82
 
 
83
static GstBuffer *
 
84
pop_buffer(GstVaapiDecoder *decoder)
 
85
{
 
86
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
87
    GstBuffer *buffer;
 
88
 
 
89
    buffer = g_queue_pop_head(priv->buffers);
 
90
    if (!buffer)
 
91
        return NULL;
 
92
 
 
93
    GST_DEBUG("dequeue buffer %p for decoding (%d bytes)",
 
94
              buffer, GST_BUFFER_SIZE(buffer));
 
95
 
 
96
    return buffer;
 
97
}
 
98
 
 
99
static GstVaapiDecoderStatus
 
100
decode_step(GstVaapiDecoder *decoder)
 
101
{
 
102
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
103
    GstVaapiDecoderStatus status;
 
104
    GstBuffer *buffer;
 
105
 
 
106
    /* Decoding will fail if there is no surface left */
 
107
    if (priv->context &&
 
108
        gst_vaapi_context_get_surface_count(priv->context) == 0)
 
109
        return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
 
110
 
 
111
    do {
 
112
        buffer = pop_buffer(decoder);
 
113
        if (!buffer)
 
114
            return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
 
115
 
 
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);
 
122
    return status;
 
123
}
 
124
 
 
125
static inline void
 
126
push_surface(GstVaapiDecoder *decoder, GstVaapiSurfaceProxy *proxy)
 
127
{
 
128
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
129
 
 
130
    GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
 
131
              GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy)));
 
132
 
 
133
    g_queue_push_tail(priv->surfaces, proxy);
 
134
}
 
135
 
 
136
static inline GstVaapiSurfaceProxy *
 
137
pop_surface(GstVaapiDecoder *decoder)
 
138
{
 
139
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
140
 
 
141
    return g_queue_pop_head(priv->surfaces);
 
142
}
 
143
 
 
144
static inline void
 
145
set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
 
146
{
 
147
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
148
 
 
149
    if (priv->codec_data) {
 
150
        gst_buffer_unref(priv->codec_data);
 
151
        priv->codec_data = NULL;
 
152
    }
 
153
 
 
154
    if (codec_data)
 
155
        priv->codec_data = gst_buffer_ref(codec_data);
 
156
}
 
157
 
 
158
static void
 
159
set_caps(GstVaapiDecoder *decoder, GstCaps *caps)
 
160
{
 
161
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
162
    GstStructure * const structure = gst_caps_get_structure(caps, 0);
 
163
    GstVaapiProfile profile;
 
164
    const GValue *v_codec_data;
 
165
    gint v1, v2;
 
166
 
 
167
    profile = gst_vaapi_profile_from_caps(caps);
 
168
    if (!profile)
 
169
        return;
 
170
 
 
171
    priv->caps = gst_caps_copy(caps);
 
172
 
 
173
    priv->codec = gst_vaapi_profile_get_codec(profile);
 
174
    if (!priv->codec)
 
175
        return;
 
176
 
 
177
    if (gst_structure_get_int(structure, "width", &v1))
 
178
        priv->width = v1;
 
179
    if (gst_structure_get_int(structure, "height", &v2))
 
180
        priv->height = v2;
 
181
 
 
182
    if (gst_structure_get_fraction(structure, "framerate", &v1, &v2)) {
 
183
        priv->fps_n = v1;
 
184
        priv->fps_d = v2;
 
185
    }
 
186
 
 
187
    if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &v1, &v2)) {
 
188
        priv->par_n = v1;
 
189
        priv->par_d = v2;
 
190
    }
 
191
 
 
192
    v_codec_data = gst_structure_get_value(structure, "codec_data");
 
193
    if (v_codec_data)
 
194
        set_codec_data(decoder, gst_value_get_buffer(v_codec_data));
 
195
}
 
196
 
 
197
static void
 
198
clear_queue(GQueue *q, GDestroyNotify destroy)
 
199
{
 
200
    while (!g_queue_is_empty(q))
 
201
        destroy(g_queue_pop_head(q));
 
202
}
 
203
 
 
204
static void
 
205
gst_vaapi_decoder_finalize(GObject *object)
 
206
{
 
207
    GstVaapiDecoder * const        decoder = GST_VAAPI_DECODER(object);
 
208
    GstVaapiDecoderPrivate * const priv    = decoder->priv;
 
209
 
 
210
    set_codec_data(decoder, NULL);
 
211
 
 
212
    if (priv->caps) {
 
213
        gst_caps_unref(priv->caps);
 
214
        priv->caps = NULL;
 
215
    }
 
216
 
 
217
    if (priv->context) {
 
218
        g_object_unref(priv->context);
 
219
        priv->context = NULL;
 
220
        priv->va_context = VA_INVALID_ID;
 
221
    }
 
222
 
 
223
    if (priv->buffers) {
 
224
        clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
 
225
        g_queue_free(priv->buffers);
 
226
        priv->buffers = NULL;
 
227
    }
 
228
 
 
229
    if (priv->surfaces) {
 
230
        clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref);
 
231
        g_queue_free(priv->surfaces);
 
232
        priv->surfaces = NULL;
 
233
    }
 
234
 
 
235
    if (priv->display) {
 
236
        g_object_unref(priv->display);
 
237
        priv->display = NULL;
 
238
        priv->va_display = NULL;
 
239
    }
 
240
 
 
241
    G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
 
242
}
 
243
 
 
244
static void
 
245
gst_vaapi_decoder_set_property(
 
246
    GObject      *object,
 
247
    guint         prop_id,
 
248
    const GValue *value,
 
249
    GParamSpec   *pspec
 
250
)
 
251
{
 
252
    GstVaapiDecoder * const        decoder = GST_VAAPI_DECODER(object);
 
253
    GstVaapiDecoderPrivate * const priv    = decoder->priv;
 
254
 
 
255
    switch (prop_id) {
 
256
    case PROP_DISPLAY:
 
257
        priv->display = g_object_ref(g_value_get_object(value));
 
258
        if (priv->display)
 
259
            priv->va_display = gst_vaapi_display_get_display(priv->display);
 
260
        else
 
261
            priv->va_display = NULL;
 
262
        break;
 
263
    case PROP_CAPS:
 
264
        set_caps(decoder, g_value_get_pointer(value));
 
265
        break;
 
266
    default:
 
267
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
 
268
        break;
 
269
    }
 
270
}
 
271
 
 
272
static void
 
273
gst_vaapi_decoder_get_property(
 
274
    GObject    *object,
 
275
    guint       prop_id,
 
276
    GValue     *value,
 
277
    GParamSpec *pspec
 
278
)
 
279
{
 
280
    GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
 
281
 
 
282
    switch (prop_id) {
 
283
    case PROP_DISPLAY:
 
284
        g_value_set_object(value, priv->display);
 
285
        break;
 
286
    case PROP_CAPS:
 
287
        gst_value_set_caps(value, priv->caps);
 
288
        break;
 
289
    default:
 
290
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
 
291
        break;
 
292
    }
 
293
}
 
294
 
 
295
static void
 
296
gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
 
297
{
 
298
    GObjectClass * const object_class = G_OBJECT_CLASS(klass);
 
299
 
 
300
    g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate));
 
301
 
 
302
    object_class->finalize     = gst_vaapi_decoder_finalize;
 
303
    object_class->set_property = gst_vaapi_decoder_set_property;
 
304
    object_class->get_property = gst_vaapi_decoder_get_property;
 
305
 
 
306
    /**
 
307
     * GstVaapiDecoder:display:
 
308
     *
 
309
     * The #GstVaapiDisplay this decoder is bound to.
 
310
     */
 
311
    g_object_class_install_property
 
312
        (object_class,
 
313
         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_object_class_install_property
 
321
        (object_class,
 
322
         PROP_CAPS,
 
323
         g_param_spec_pointer("caps",
 
324
                              "Decoder caps",
 
325
                              "The decoder caps",
 
326
                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
 
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
}
 
351
 
 
352
/**
 
353
 * gst_vaapi_decoder_get_caps:
 
354
 * @decoder: a #GstVaapiDecoder
 
355
 *
 
356
 * Retrieves the @decoder caps. The deocder owns the returned caps, so
 
357
 * use gst_caps_ref() whenever necessary.
 
358
 *
 
359
 * Return value: the @decoder caps
 
360
 */
 
361
GstCaps *
 
362
gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder)
 
363
{
 
364
    return decoder->priv->caps;
 
365
}
 
366
 
 
367
/**
 
368
 * gst_vaapi_decoder_put_buffer:
 
369
 * @decoder: a #GstVaapiDecoder
 
370
 * @buf: a #GstBuffer
 
371
 *
 
372
 * Queues a #GstBuffer to the HW decoder. The decoder holds a
 
373
 * reference to @buf.
 
374
 *
 
375
 * Caller can notify an End-Of-Stream with @buf set to %NULL.
 
376
 *
 
377
 * Return value: %TRUE on success
 
378
 */
 
379
gboolean
 
380
gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
 
381
{
 
382
    g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
 
383
 
 
384
    return push_buffer(decoder, buf ? gst_buffer_ref(buf) : NULL);
 
385
}
 
386
 
 
387
/**
 
388
 * gst_vaapi_decoder_get_surface:
 
389
 * @decoder: a #GstVaapiDecoder
 
390
 * @pstatus: return location for the decoder status, or %NULL
 
391
 *
 
392
 * Flushes encoded buffers to the decoder and returns a decoded
 
393
 * surface, if any.
 
394
 *
 
395
 * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
 
396
 *   or %NULL if none is available (e.g. an error). Caller owns the
 
397
 *   returned object. g_object_unref() after usage.
 
398
 */
 
399
GstVaapiSurfaceProxy *
 
400
gst_vaapi_decoder_get_surface(
 
401
    GstVaapiDecoder       *decoder,
 
402
    GstVaapiDecoderStatus *pstatus
 
403
)
 
404
{
 
405
    GstVaapiSurfaceProxy *proxy;
 
406
    GstVaapiDecoderStatus status;
 
407
 
 
408
    if (pstatus)
 
409
        *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
 
410
 
 
411
    g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
 
412
 
 
413
    proxy = pop_surface(decoder);
 
414
    if (!proxy) {
 
415
        do {
 
416
            status = decode_step(decoder);
 
417
        } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
 
418
        proxy = pop_surface(decoder);
 
419
    }
 
420
 
 
421
    if (proxy)
 
422
        status = GST_VAAPI_DECODER_STATUS_SUCCESS;
 
423
 
 
424
    if (pstatus)
 
425
        *pstatus = status;
 
426
    return proxy;
 
427
}
 
428
 
 
429
void
 
430
gst_vaapi_decoder_set_picture_size(
 
431
    GstVaapiDecoder    *decoder,
 
432
    guint               width,
 
433
    guint               height
 
434
)
 
435
{
 
436
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
437
    gboolean size_changed = FALSE;
 
438
 
 
439
    if (priv->width != width) {
 
440
        GST_DEBUG("picture width changed to %d", width);
 
441
        priv->width = width;
 
442
        gst_caps_set_simple(priv->caps, "width", G_TYPE_INT, width, NULL);
 
443
        size_changed = TRUE;
 
444
    }
 
445
 
 
446
    if (priv->height != height) {
 
447
        GST_DEBUG("picture height changed to %d", height);
 
448
        priv->height = height;
 
449
        gst_caps_set_simple(priv->caps, "height", G_TYPE_INT, height, NULL);
 
450
        size_changed = TRUE;
 
451
    }
 
452
 
 
453
    if (size_changed)
 
454
        g_object_notify(G_OBJECT(decoder), "caps");
 
455
}
 
456
 
 
457
void
 
458
gst_vaapi_decoder_set_framerate(
 
459
    GstVaapiDecoder    *decoder,
 
460
    guint               fps_n,
 
461
    guint               fps_d
 
462
)
 
463
{
 
464
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
465
 
 
466
    if (!fps_n || !fps_d)
 
467
        return;
 
468
 
 
469
    if (priv->fps_n != fps_n || priv->fps_d != fps_d) {
 
470
        GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d);
 
471
        priv->fps_n = fps_n;
 
472
        priv->fps_d = fps_d;
 
473
        gst_caps_set_simple(
 
474
            priv->caps,
 
475
            "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
 
476
            NULL
 
477
        );
 
478
        g_object_notify(G_OBJECT(decoder), "caps");
 
479
    }
 
480
}
 
481
 
 
482
void
 
483
gst_vaapi_decoder_set_pixel_aspect_ratio(
 
484
    GstVaapiDecoder    *decoder,
 
485
    guint               par_n,
 
486
    guint               par_d
 
487
)
 
488
{
 
489
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
490
 
 
491
    if (!par_n || !par_d)
 
492
        return;
 
493
 
 
494
    if (priv->par_n != par_n || priv->par_d != par_d) {
 
495
        GST_DEBUG("pixel-aspect-ratio changed to %u/%u", par_n, par_d);
 
496
        priv->par_n = par_n;
 
497
        priv->par_d = par_d;
 
498
        gst_caps_set_simple(
 
499
            priv->caps,
 
500
            "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
 
501
            NULL
 
502
        );
 
503
        g_object_notify(G_OBJECT(decoder), "caps");
 
504
    }
 
505
}
 
506
 
 
507
gboolean
 
508
gst_vaapi_decoder_ensure_context(
 
509
    GstVaapiDecoder    *decoder,
 
510
    GstVaapiProfile     profile,
 
511
    GstVaapiEntrypoint  entrypoint,
 
512
    guint               width,
 
513
    guint               height
 
514
)
 
515
{
 
516
    GstVaapiDecoderPrivate * const priv = decoder->priv;
 
517
 
 
518
    gst_vaapi_decoder_set_picture_size(decoder, width, height);
 
519
 
 
520
    if (priv->context)
 
521
        return gst_vaapi_context_reset(priv->context,
 
522
                                       profile, entrypoint, width, height);
 
523
 
 
524
    priv->context = gst_vaapi_context_new(
 
525
        priv->display,
 
526
        profile,
 
527
        entrypoint,
 
528
        width,
 
529
        height
 
530
    );
 
531
    if (!priv->context)
 
532
        return FALSE;
 
533
 
 
534
    priv->va_context = gst_vaapi_context_get_id(priv->context);
 
535
    return TRUE;
 
536
}
 
537
 
 
538
gboolean
 
539
gst_vaapi_decoder_push_buffer_sub(
 
540
    GstVaapiDecoder *decoder,
 
541
    GstBuffer       *buffer,
 
542
    guint            offset,
 
543
    guint            size
 
544
)
 
545
{
 
546
    GstBuffer *subbuffer;
 
547
 
 
548
    subbuffer = gst_buffer_create_sub(buffer, offset, size);
 
549
    if (!subbuffer)
 
550
        return FALSE;
 
551
 
 
552
    push_back_buffer(decoder, subbuffer);
 
553
    return TRUE;
 
554
}
 
555
 
 
556
void
 
557
gst_vaapi_decoder_push_surface_proxy(
 
558
    GstVaapiDecoder      *decoder,
 
559
    GstVaapiSurfaceProxy *proxy
 
560
)
 
561
{
 
562
    return push_surface(decoder, proxy);
 
563
}