gstvaapidecoder.c 31 KB
Newer Older
1 2 3
/*
 *  gstvaapidecoder.c - VA decoder abstraction
 *
4
 *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5
 *  Copyright (C) 2011-2013 Intel Corporation
6
 *
gb's avatar
gb committed
7 8 9 10
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1
 *  of the License, or (at your option) any later version.
11
 *
gb's avatar
gb committed
12
 *  This library is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
gb's avatar
gb committed
14 15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
16
 *
gb's avatar
gb committed
17 18 19 20
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301 USA
21 22 23 24 25 26 27
 */

/**
 * SECTION:gstvaapidecoder
 * @short_description: VA decoder abstraction
 */

28
#include "sysdeps.h"
29 30 31
#include "gstvaapicompat.h"
#include "gstvaapidecoder.h"
#include "gstvaapidecoder_priv.h"
32
#include "gstvaapiparser_frame.h"
33
#include "gstvaapisurfaceproxy_priv.h"
34 35 36 37 38
#include "gstvaapiutils.h"

#define DEBUG 1
#include "gstvaapidebug.h"

39 40 41
static void
drop_frame(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame);

42 43 44 45 46 47 48 49 50 51 52 53 54 55
static void
parser_state_finalize(GstVaapiParserState *ps)
{
    if (ps->input_adapter) {
        gst_adapter_clear(ps->input_adapter);
        g_object_unref(ps->input_adapter);
        ps->input_adapter = NULL;
    }

    if (ps->output_adapter) {
        gst_adapter_clear(ps->output_adapter);
        g_object_unref(ps->output_adapter);
        ps->output_adapter = NULL;
    }
56 57 58 59 60

    if (ps->next_unit_pending) {
        gst_vaapi_decoder_unit_clear(&ps->next_unit);
        ps->next_unit_pending = FALSE;
    }
61 62 63 64 65
}

static gboolean
parser_state_init(GstVaapiParserState *ps)
{
66 67
    memset(ps, 0, sizeof(*ps));

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
    ps->input_adapter = gst_adapter_new();
    if (!ps->input_adapter)
        return FALSE;

    ps->output_adapter = gst_adapter_new();
    if (!ps->output_adapter)
        return FALSE;
    return TRUE;
}

static void
parser_state_prepare(GstVaapiParserState *ps, GstAdapter *adapter)
{
    /* XXX: check we really have a continuity from the previous call */
    if (ps->current_adapter != adapter)
        goto reset;
    return;

reset:
    ps->current_adapter = adapter;
    ps->input_offset2 = -1;
}

91 92 93
static gboolean
push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
{
94
    if (!buffer) {
gb's avatar
gb committed
95
        buffer = gst_buffer_new();
gb's avatar
gb committed
96 97
        if (!buffer)
            return FALSE;
gb's avatar
gb committed
98
        GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
99
    }
100 101

    GST_DEBUG("queue encoded data buffer %p (%d bytes)",
102
              buffer, gst_buffer_get_size(buffer));
103

104
    g_async_queue_push(decoder->buffers, buffer);
105 106 107
    return TRUE;
}

gb's avatar
gb committed
108 109 110 111 112
static GstBuffer *
pop_buffer(GstVaapiDecoder *decoder)
{
    GstBuffer *buffer;

113
    buffer = g_async_queue_try_pop(decoder->buffers);
114 115
    if (!buffer)
        return NULL;
gb's avatar
gb committed
116

117
    GST_DEBUG("dequeue buffer %p for decoding (%d bytes)",
118
              buffer, gst_buffer_get_size(buffer));
119

gb's avatar
gb committed
120 121 122
    return buffer;
}

123 124 125 126 127
static GstVaapiDecoderStatus
do_parse(GstVaapiDecoder *decoder,
    GstVideoCodecFrame *base_frame, GstAdapter *adapter, gboolean at_eos,
    guint *got_unit_size_ptr, gboolean *got_frame_ptr)
{
128
    GstVaapiParserState * const ps = &decoder->parser_state;
129
    GstVaapiParserFrame *frame;
130 131 132 133 134 135 136 137
    GstVaapiDecoderUnit *unit;
    GstVaapiDecoderStatus status;

    *got_unit_size_ptr = 0;
    *got_frame_ptr = FALSE;

    frame = gst_video_codec_frame_get_user_data(base_frame);
    if (!frame) {
138
        GstVideoCodecState * const codec_state = decoder->codec_state;
139
        frame = gst_vaapi_parser_frame_new(codec_state->info.width,
140
            codec_state->info.height);
141 142 143 144 145 146 147 148
        if (!frame)
            return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
        gst_video_codec_frame_set_user_data(base_frame,
            frame, (GDestroyNotify)gst_vaapi_mini_object_unref);
    }

    parser_state_prepare(ps, adapter);

149 150 151
    unit = &ps->next_unit;
    if (ps->next_unit_pending) {
        ps->next_unit_pending = FALSE;
152
        goto got_unit;
153 154
    }
    gst_vaapi_decoder_unit_init(unit);
155

156 157
    ps->current_frame = base_frame;
    status = GST_VAAPI_DECODER_GET_CLASS(decoder)->parse(decoder,
158
        adapter, at_eos, unit);
159 160 161 162 163 164 165
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
        if (at_eos && frame->units->len > 0 &&
            status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) {
            /* XXX: assume the frame is complete at <EOS> */
            *got_frame_ptr = TRUE;
            return GST_VAAPI_DECODER_STATUS_SUCCESS;
        }
166
        return status;
167
    }
168

169 170 171 172
    if (GST_VAAPI_DECODER_UNIT_IS_FRAME_START(unit) && frame->units->len > 0) {
        ps->next_unit_pending = TRUE;
        *got_frame_ptr = TRUE;
        return GST_VAAPI_DECODER_STATUS_SUCCESS;
173 174 175
    }

got_unit:
176
    gst_vaapi_parser_frame_append_unit(frame, unit);
177
    *got_unit_size_ptr = unit->size;
178
    *got_frame_ptr = GST_VAAPI_DECODER_UNIT_IS_FRAME_END(unit);
179 180 181 182
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static GstVaapiDecoderStatus
183
do_decode_units(GstVaapiDecoder *decoder, GArray *units)
184 185 186
{
    GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
    GstVaapiDecoderStatus status;
187
    guint i;
188

189 190 191
    for (i = 0; i < units->len; i++) {
        GstVaapiDecoderUnit * const unit =
            &g_array_index(units, GstVaapiDecoderUnit, i);
192 193 194 195 196
        if (GST_VAAPI_DECODER_UNIT_IS_SKIPPED(unit))
            continue;
        status = klass->decode(decoder, unit);
        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
            return status;
197 198 199 200 201
    }
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static GstVaapiDecoderStatus
202
do_decode_1(GstVaapiDecoder *decoder, GstVaapiParserFrame *frame)
203 204 205 206
{
    GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
    GstVaapiDecoderStatus status;

207 208
    if (frame->pre_units->len > 0) {
        status = do_decode_units(decoder, frame->pre_units);
209 210
        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
            return status;
211 212
    }

213
    if (frame->units->len > 0) {
214
        if (klass->start_frame) {
215 216 217
            GstVaapiDecoderUnit * const unit =
                &g_array_index(frame->units, GstVaapiDecoderUnit, 0);
            status = klass->start_frame(decoder, unit);
218 219 220 221
            if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
                return status;
        }

222
        status = do_decode_units(decoder, frame->units);
223 224
        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
            return status;
225 226 227 228 229 230

        if (klass->end_frame) {
            status = klass->end_frame(decoder);
            if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
                return status;
        }
231
    }
232

233 234
    if (frame->post_units->len > 0) {
        status = do_decode_units(decoder, frame->post_units);
235 236 237
        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
            return status;
    }
238 239 240 241

    /* Drop frame if there is no slice data unit in there */
    if (G_UNLIKELY(frame->units->len == 0))
        return GST_VAAPI_DECODER_STATUS_DROP_FRAME;
242 243 244
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

245 246 247
static inline GstVaapiDecoderStatus
do_decode(GstVaapiDecoder *decoder, GstVideoCodecFrame *base_frame)
{
248
    GstVaapiParserState * const ps = &decoder->parser_state;
249
    GstVaapiParserFrame * const frame = base_frame->user_data;
250 251 252 253
    GstVaapiDecoderStatus status;

    ps->current_frame = base_frame;

254
    gst_vaapi_parser_frame_ref(frame);
255
    status = do_decode_1(decoder, frame);
256
    gst_vaapi_parser_frame_unref(frame);
257 258 259 260 261 262 263

    switch ((guint)status) {
    case GST_VAAPI_DECODER_STATUS_DROP_FRAME:
        drop_frame(decoder, base_frame);
        status = GST_VAAPI_DECODER_STATUS_SUCCESS;
        break;
    }
264 265 266
    return status;
}

267 268 269 270 271 272 273 274 275 276
static inline GstVaapiDecoderStatus
do_flush(GstVaapiDecoder *decoder)
{
    GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);

    if (klass->flush)
        return klass->flush(decoder);
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

277 278 279
static GstVaapiDecoderStatus
decode_step(GstVaapiDecoder *decoder)
{
280
    GstVaapiParserState * const ps = &decoder->parser_state;
281 282
    GstVaapiDecoderStatus status;
    GstBuffer *buffer;
283
    gboolean got_frame;
284
    guint got_unit_size, input_size;
285

286 287 288
    status = gst_vaapi_decoder_check_status(decoder);
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
        return status;
gb's avatar
gb committed
289

290 291
    /* Fill adapter with all buffers we have in the queue */
    for (;;) {
292 293
        buffer = pop_buffer(decoder);
        if (!buffer)
294
            break;
295

296 297
        ps->at_eos = GST_BUFFER_IS_EOS(buffer);
        if (!ps->at_eos)
298
            gst_adapter_push(ps->input_adapter, buffer);
299
    }
300

301 302 303 304 305 306 307
    /* Parse and decode all decode units */
    input_size = gst_adapter_available(ps->input_adapter);
    if (input_size == 0) {
        if (ps->at_eos)
            return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
    }
308

309 310 311 312 313 314 315
    do {
        if (!ps->current_frame) {
            ps->current_frame = g_slice_new0(GstVideoCodecFrame);
            if (!ps->current_frame)
                return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
            ps->current_frame->ref_count = 1;
        }
316

317 318 319 320 321 322 323 324
        status = do_parse(decoder, ps->current_frame, ps->input_adapter,
            ps->at_eos, &got_unit_size, &got_frame);
        GST_DEBUG("parse frame (status = %d)", status);
        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
            if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA && ps->at_eos)
                status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
            break;
        }
325

326 327 328
        if (got_unit_size > 0) {
            buffer = gst_adapter_take_buffer(ps->input_adapter, got_unit_size);
            input_size -= got_unit_size;
329

330 331 332
            if (gst_adapter_available(ps->output_adapter) == 0) {
                ps->current_frame->pts =
                    gst_adapter_prev_timestamp(ps->input_adapter, NULL);
333
            }
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
            gst_adapter_push(ps->output_adapter, buffer);
        }

        if (got_frame) {
            ps->current_frame->input_buffer = gst_adapter_take_buffer(
                ps->output_adapter,
                gst_adapter_available(ps->output_adapter));

            status = do_decode(decoder, ps->current_frame);
            GST_DEBUG("decode frame (status = %d)", status);

            gst_video_codec_frame_unref(ps->current_frame);
            ps->current_frame = NULL;
            break;
        }
    } while (input_size > 0);
350 351 352
    return status;
}

353 354 355 356 357 358 359 360 361 362 363 364
static void
drop_frame(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame)
{
    GST_DEBUG("drop frame %d", frame->system_frame_number);

    /* no surface proxy */
    gst_video_codec_frame_set_user_data(frame, NULL, NULL);

    frame->pts = GST_CLOCK_TIME_NONE;
    GST_VIDEO_CODEC_FRAME_FLAG_SET(frame,
        GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);

365
    g_async_queue_push(decoder->frames, gst_video_codec_frame_ref(frame));
366 367
}

368
static inline void
369
push_frame(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame)
370
{
371
    GstVaapiSurfaceProxy * const proxy = frame->user_data;
372

373
    GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
374
              GST_VAAPI_ID_ARGS(GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy)));
gb's avatar
gb committed
375

376
    g_async_queue_push(decoder->frames, gst_video_codec_frame_ref(frame));
377 378
}

379
static inline GstVideoCodecFrame *
380
pop_frame(GstVaapiDecoder *decoder, guint64 timeout)
381
{
382
    GstVideoCodecFrame *frame;
383
    GstVaapiSurfaceProxy *proxy;
384

385
    if (G_LIKELY(timeout > 0))
386
        frame = g_async_queue_timeout_pop(decoder->frames, timeout);
387
    else
388
        frame = g_async_queue_try_pop(decoder->frames);
389 390 391
    if (!frame)
        return NULL;

392
    proxy = frame->user_data;
393
    GST_DEBUG("dequeue decoded surface %" GST_VAAPI_ID_FORMAT,
394
              GST_VAAPI_ID_ARGS(GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy)));
395

396
    return frame;
397 398
}

399
static gboolean
400
set_caps(GstVaapiDecoder *decoder, const GstCaps *caps)
gb's avatar
gb committed
401
{
402
    GstVideoCodecState * const codec_state = decoder->codec_state;
gb's avatar
gb committed
403
    GstStructure * const structure = gst_caps_get_structure(caps, 0);
gb's avatar
gb committed
404 405 406
    GstVaapiProfile profile;
    const GValue *v_codec_data;

gb's avatar
gb committed
407 408
    profile = gst_vaapi_profile_from_caps(caps);
    if (!profile)
409
        return FALSE;
gb's avatar
gb committed
410

411 412 413
    decoder->codec = gst_vaapi_profile_get_codec(profile);
    if (!decoder->codec)
        return FALSE;
gb's avatar
gb committed
414

415
    if (!gst_video_info_from_caps(&codec_state->info, caps))
416
        return FALSE;
gb's avatar
gb committed
417

418
    codec_state->caps = gst_caps_copy(caps);
419

gb's avatar
gb committed
420 421
    v_codec_data = gst_structure_get_value(structure, "codec_data");
    if (v_codec_data)
422
        gst_buffer_replace(&codec_state->codec_data,
423
            gst_value_get_buffer(v_codec_data));
424
    return TRUE;
gb's avatar
gb committed
425 426
}

427 428 429 430 431 432
static inline GstCaps *
get_caps(GstVaapiDecoder *decoder)
{
    return GST_VAAPI_DECODER_CODEC_STATE(decoder)->caps;
}

433
static void
434
notify_codec_state_changed(GstVaapiDecoder *decoder)
435
{
436 437 438 439
    if (decoder->codec_state_changed_func)
        decoder->codec_state_changed_func(decoder, decoder->codec_state,
            decoder->codec_state_changed_data);
}
440

441 442 443 444 445
void
gst_vaapi_decoder_finalize(GstVaapiDecoder *decoder)
{
    const GstVaapiDecoderClass * const klass =
        GST_VAAPI_DECODER_GET_CLASS(decoder);
446

447 448 449 450 451 452 453
    if (klass->destroy)
        klass->destroy(decoder);

    gst_video_codec_state_unref(decoder->codec_state);
    decoder->codec_state = NULL;

    parser_state_finalize(&decoder->parser_state);
gb's avatar
gb committed
454
 
455 456 457
    if (decoder->buffers) {
        g_async_queue_unref(decoder->buffers);
        decoder->buffers = NULL;
458 459
    }

460 461 462
    if (decoder->frames) {
        g_async_queue_unref(decoder->frames);
        decoder->frames = NULL;
463 464
    }

465 466
    gst_vaapi_object_replace(&decoder->context, NULL);
    decoder->va_context = VA_INVALID_ID;
467

468
    gst_vaapi_display_replace(&decoder->display, NULL);
469
    decoder->va_display = NULL;
470 471
}

472 473 474
static gboolean
gst_vaapi_decoder_init(GstVaapiDecoder *decoder, GstVaapiDisplay *display,
    GstCaps *caps)
475
{
476 477 478 479
    const GstVaapiDecoderClass * const klass =
        GST_VAAPI_DECODER_GET_CLASS(decoder);
    GstVideoCodecState *codec_state;
    guint sub_size;
480

481
    parser_state_init(&decoder->parser_state);
482

483 484 485
    codec_state = g_slice_new0(GstVideoCodecState);
    codec_state->ref_count = 1;
    gst_video_info_init(&codec_state->info);
486

487
    decoder->user_data   = NULL;
488
    decoder->display     = gst_vaapi_display_ref(display);
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    decoder->va_display  = GST_VAAPI_DISPLAY_VADISPLAY(display);
    decoder->context     = NULL;
    decoder->va_context  = VA_INVALID_ID;
    decoder->codec       = 0;
    decoder->codec_state = codec_state;
    decoder->codec_state_changed_func = NULL;
    decoder->codec_state_changed_data = NULL;

    decoder->buffers = g_async_queue_new_full((GDestroyNotify)gst_buffer_unref);
    decoder->frames  = g_async_queue_new_full((GDestroyNotify)
        gst_video_codec_frame_unref);

    if (!set_caps(decoder, caps))
        return FALSE;

    sub_size = GST_VAAPI_MINI_OBJECT_CLASS(klass)->size - sizeof(*decoder);
    if (sub_size > 0)
        memset(((guchar *)decoder) + sizeof(*decoder), 0, sub_size);

    if (klass->create && !klass->create(decoder))
        return FALSE;
    return TRUE;
511 512
}

513 514 515
GstVaapiDecoder *
gst_vaapi_decoder_new(const GstVaapiDecoderClass *klass,
    GstVaapiDisplay *display, GstCaps *caps)
516
{
517 518
    GstVaapiDecoder *decoder;

519
    g_return_val_if_fail(display != NULL, NULL);
520
    g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
521

522 523 524 525
    decoder = (GstVaapiDecoder *)
        gst_vaapi_mini_object_new(GST_VAAPI_MINI_OBJECT_CLASS(klass));
    if (!decoder)
        return NULL;
526

527 528 529
    if (!gst_vaapi_decoder_init(decoder, display, caps))
        goto error;
    return decoder;
530

531 532 533 534
error:
    gst_vaapi_decoder_unref(decoder);
    return NULL;
}
535

536 537 538 539 540 541 542 543 544 545 546 547 548
/**
 * gst_vaapi_decoder_ref:
 * @decoder: a #GstVaapiDecoder
 *
 * Atomically increases the reference count of the given @decoder by one.
 *
 * Returns: The same @decoder argument
 */
GstVaapiDecoder *
gst_vaapi_decoder_ref(GstVaapiDecoder *decoder)
{
    return gst_vaapi_object_ref(decoder);
}
549

550 551 552 553 554 555 556 557 558 559 560
/**
 * gst_vaapi_decoder_unref:
 * @decoder: a #GstVaapiDecoder
 *
 * Atomically decreases the reference count of the @decoder by one. If
 * the reference count reaches zero, the decoder will be free'd.
 */
void
gst_vaapi_decoder_unref(GstVaapiDecoder *decoder)
{
    gst_vaapi_object_unref(decoder);
561 562
}

563 564 565 566 567 568 569 570 571 572 573 574
/**
 * gst_vaapi_decoder_replace:
 * @old_decoder_ptr: a pointer to a #GstVaapiDecoder
 * @new_decoder: a #GstVaapiDecoder
 *
 * Atomically replaces the decoder decoder held in @old_decoder_ptr
 * with @new_decoder. This means that @old_decoder_ptr shall reference
 * a valid decoder. However, @new_decoder can be NULL.
 */
void
gst_vaapi_decoder_replace(GstVaapiDecoder **old_decoder_ptr,
    GstVaapiDecoder *new_decoder)
575
{
576 577
    gst_vaapi_object_replace(old_decoder_ptr, new_decoder);
}
578

579 580 581 582 583 584 585 586 587 588 589
/**
 * gst_vaapi_decoder_get_user_data:
 * @decoder: a #GstVaapiDecoder
 *
 * Retrieves the user-defined data associated with the @decoder, if any.
 *
 * Return value: the user-defined data associated with the @decoder
 */
gpointer
gst_vaapi_decoder_get_user_data(GstVaapiDecoder *decoder)
{
590
    g_return_val_if_fail(decoder != NULL, NULL);
591

592 593
    return decoder->user_data;
}
594

595 596 597 598 599 600 601 602 603 604 605
/**
 * gst_vaapi_decoder_set_user_data:
 * @decoder: a #GstVaapiDecoder
 * @user_data: the pointer to user-defined data
 *
 * Associates user-defined @user_data to the @decoder. Retrieve the
 * attached value with gst_vaapi_decoder_get_user_data() function.
 */
void
gst_vaapi_decoder_set_user_data(GstVaapiDecoder *decoder, gpointer user_data)
{
606
    g_return_if_fail(decoder != NULL);
607

608
    decoder->user_data = user_data;
609 610
}

611 612 613 614 615 616 617 618 619 620 621
/**
 * gst_vaapi_decoder_get_codec:
 * @decoder: a #GstVaapiDecoder
 *
 * Retrieves the @decoder codec type.
 *
 * Return value: the #GstVaapiCodec type for @decoder
 */
GstVaapiCodec
gst_vaapi_decoder_get_codec(GstVaapiDecoder *decoder)
{
622
    g_return_val_if_fail(decoder != NULL, (GstVaapiCodec)0);
623

624
    return decoder->codec;
625 626
}

627 628 629 630
/**
 * gst_vaapi_decoder_get_codec_state:
 * @decoder: a #GstVaapiDecoder
 *
631 632 633
 * Retrieves the @decoder codec state. The decoder owns the returned
 * #GstVideoCodecState structure, so use gst_video_codec_state_ref()
 * whenever necessary.
634 635 636 637 638 639
 *
 * Return value: the #GstVideoCodecState object for @decoder
 */
GstVideoCodecState *
gst_vaapi_decoder_get_codec_state(GstVaapiDecoder *decoder)
{
640
    g_return_val_if_fail(decoder != NULL, NULL);
641

642
    return GST_VAAPI_DECODER_CODEC_STATE(decoder);
643 644
}

645 646 647 648 649 650 651 652 653 654 655 656 657
/**
 * gst_vaapi_decoder_set_codec_state_changed_func:
 * @decoder: a #GstVaapiDecoder
 * @func: the function to call when codec state changed
 * @user_data: a pointer to user-defined data
 *
 * Sets @func as the function to call whenever the @decoder codec
 * state changes.
 */
void
gst_vaapi_decoder_set_codec_state_changed_func(GstVaapiDecoder *decoder,
    GstVaapiDecoderStateChangedFunc func, gpointer user_data)
{
658
    g_return_if_fail(decoder != NULL);
659 660 661 662 663

    decoder->codec_state_changed_func = func;
    decoder->codec_state_changed_data = user_data;
}

gb's avatar
gb committed
664 665 666 667
/**
 * gst_vaapi_decoder_get_caps:
 * @decoder: a #GstVaapiDecoder
 *
668
 * Retrieves the @decoder caps. The decoder owns the returned caps, so
gb's avatar
gb committed
669 670 671 672 673 674 675
 * use gst_caps_ref() whenever necessary.
 *
 * Return value: the @decoder caps
 */
GstCaps *
gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder)
{
676
    return get_caps(decoder);
gb's avatar
gb committed
677 678
}

679 680 681 682 683 684 685 686
/**
 * gst_vaapi_decoder_put_buffer:
 * @decoder: a #GstVaapiDecoder
 * @buf: a #GstBuffer
 *
 * Queues a #GstBuffer to the HW decoder. The decoder holds a
 * reference to @buf.
 *
687 688 689 690
 * Caller can notify an End-Of-Stream with @buf set to %NULL. However,
 * if an empty buffer is passed, i.e. a buffer with %NULL data pointer
 * or size equals to zero, then the function ignores this buffer and
 * returns %TRUE.
691 692 693 694 695 696
 *
 * Return value: %TRUE on success
 */
gboolean
gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
{
697
    g_return_val_if_fail(decoder != NULL, FALSE);
698

699
    if (buf) {
700
        if (gst_buffer_get_size(buf) == 0)
701 702 703 704
            return TRUE;
        buf = gst_buffer_ref(buf);
    }
    return push_buffer(decoder, buf);
705 706 707 708 709
}

/**
 * gst_vaapi_decoder_get_surface:
 * @decoder: a #GstVaapiDecoder
710
 * @out_proxy_ptr: the next decoded surface as a #GstVaapiSurfaceProxy
711
 *
712 713
 * Flushes encoded buffers to the decoder and returns a decoded
 * surface, if any.
714
 *
715 716 717 718 719
 * On successful return, *@out_proxy_ptr contains the decoded surface
 * as a #GstVaapiSurfaceProxy. The caller owns this object, so
 * gst_vaapi_surface_proxy_unref() shall be called after usage.
 *
 * Return value: a #GstVaapiDecoderStatus
720
 */
721 722 723
GstVaapiDecoderStatus
gst_vaapi_decoder_get_surface(GstVaapiDecoder *decoder,
    GstVaapiSurfaceProxy **out_proxy_ptr)
724
{
725
    GstVideoCodecFrame *frame;
gb's avatar
gb committed
726 727
    GstVaapiDecoderStatus status;

728
    g_return_val_if_fail(decoder != NULL,
729 730 731
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
    g_return_val_if_fail(out_proxy_ptr != NULL,
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
732

733
    do {
734
        frame = pop_frame(decoder, 0);
735 736
        while (frame) {
            if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(frame)) {
737 738 739
                GstVaapiSurfaceProxy * const proxy = frame->user_data;
                proxy->timestamp = frame->pts;
                proxy->duration = frame->duration;
740
                *out_proxy_ptr = gst_vaapi_surface_proxy_ref(proxy);
741 742 743
                gst_video_codec_frame_unref(frame);
                return GST_VAAPI_DECODER_STATUS_SUCCESS;
            }
744
            gst_video_codec_frame_unref(frame);
745
            frame = pop_frame(decoder, 0);
746
        }
747 748
        status = decode_step(decoder);
    } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
749

750
    *out_proxy_ptr = NULL;
751
    return status;
752 753
}

754 755 756 757 758
/**
 * gst_vaapi_decoder_get_frame:
 * @decoder: a #GstVaapiDecoder
 * @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame
 *
759 760 761 762 763
 * On successful return, *@out_frame_ptr contains the next decoded
 * frame available as a #GstVideoCodecFrame. The caller owns this
 * object, so gst_video_codec_frame_unref() shall be called after
 * usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is
 * returned if no decoded frame is available.
764 765 766 767 768
 *
 * The actual surface is available as a #GstVaapiSurfaceProxy attached
 * to the user-data anchor of the output frame. Ownership of the proxy
 * is transferred to the frame.
 *
769 770 771
 * This is equivalent to gst_vaapi_decoder_get_frame_with_timeout()
 * with a timeout value of zero.
 *
772 773 774 775 776
 * Return value: a #GstVaapiDecoderStatus
 */
GstVaapiDecoderStatus
gst_vaapi_decoder_get_frame(GstVaapiDecoder *decoder,
    GstVideoCodecFrame **out_frame_ptr)
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
{
    return gst_vaapi_decoder_get_frame_with_timeout(decoder, out_frame_ptr, 0);
}

/**
 * gst_vaapi_decoder_get_frame_with_timeout:
 * @decoder: a #GstVaapiDecoder
 * @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame
 * @timeout: the number of microseconds to wait for the frame, at most
 *
 * On successful return, *@out_frame_ptr contains the next decoded
 * frame available as a #GstVideoCodecFrame. The caller owns this
 * object, so gst_video_codec_frame_unref() shall be called after
 * usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is
 * returned if no decoded frame is available.
 *
 * The actual surface is available as a #GstVaapiSurfaceProxy attached
 * to the user-data anchor of the output frame. Ownership of the proxy
 * is transferred to the frame.
 *
 * Return value: a #GstVaapiDecoderStatus
 */
GstVaapiDecoderStatus
gst_vaapi_decoder_get_frame_with_timeout(GstVaapiDecoder *decoder,
    GstVideoCodecFrame **out_frame_ptr, guint64 timeout)
802 803 804
{
    GstVideoCodecFrame *out_frame;

805
    g_return_val_if_fail(decoder != NULL,
806 807 808 809
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
    g_return_val_if_fail(out_frame_ptr != NULL,
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);

810
    out_frame = pop_frame(decoder, timeout);
811
    if (!out_frame)
812 813
        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;

814 815 816 817 818 819 820 821 822 823 824
#if !GST_CHECK_VERSION(1,0,0)
    if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
        const guint flags = GST_VAAPI_SURFACE_PROXY_FLAGS(out_frame->user_data);
        guint out_flags = 0;

        if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
            out_flags |= GST_VIDEO_CODEC_FRAME_FLAG_TFF;
        if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
            out_flags |= GST_VIDEO_CODEC_FRAME_FLAG_RFF;
        if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
            out_flags |= GST_VIDEO_CODEC_FRAME_FLAG_ONEFIELD;
825
        GST_VIDEO_CODEC_FRAME_FLAG_SET(out_frame, out_flags);
826 827 828
    }
#endif

829 830 831 832
    *out_frame_ptr = out_frame;
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

gb's avatar
gb committed
833 834 835 836 837 838 839
void
gst_vaapi_decoder_set_picture_size(
    GstVaapiDecoder    *decoder,
    guint               width,
    guint               height
)
{
840
    GstVideoCodecState * const codec_state = decoder->codec_state;
841
    gboolean size_changed = FALSE;
gb's avatar
gb committed
842

843
    if (codec_state->info.width != width) {
gb's avatar
gb committed
844
        GST_DEBUG("picture width changed to %d", width);
845 846 847
        codec_state->info.width = width;
        gst_caps_set_simple(codec_state->caps,
            "width", G_TYPE_INT, width, NULL);
848
        size_changed = TRUE;
gb's avatar
gb committed
849 850
    }

851
    if (codec_state->info.height != height) {
gb's avatar
gb committed
852
        GST_DEBUG("picture height changed to %d", height);
853 854 855
        codec_state->info.height = height;
        gst_caps_set_simple(codec_state->caps,
            "height", G_TYPE_INT, height, NULL);
856
        size_changed = TRUE;
gb's avatar
gb committed
857 858
    }

859
    if (size_changed)
860
        notify_codec_state_changed(decoder);
gb's avatar
gb committed
861 862 863 864 865 866 867 868 869
}

void
gst_vaapi_decoder_set_framerate(
    GstVaapiDecoder    *decoder,
    guint               fps_n,
    guint               fps_d
)
{
870
    GstVideoCodecState * const codec_state = decoder->codec_state;
gb's avatar
gb committed
871 872 873 874

    if (!fps_n || !fps_d)
        return;

875
    if (codec_state->info.fps_n != fps_n || codec_state->info.fps_d != fps_d) {
gb's avatar
gb committed
876
        GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d);
877 878 879 880
        codec_state->info.fps_n = fps_n;
        codec_state->info.fps_d = fps_d;
        gst_caps_set_simple(codec_state->caps,
            "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
881
        notify_codec_state_changed(decoder);
gb's avatar
gb committed
882 883 884 885 886 887 888 889 890 891
    }
}

void
gst_vaapi_decoder_set_pixel_aspect_ratio(
    GstVaapiDecoder    *decoder,
    guint               par_n,
    guint               par_d
)
{
892
    GstVideoCodecState * const codec_state = decoder->codec_state;
gb's avatar
gb committed
893 894 895 896

    if (!par_n || !par_d)
        return;

897
    if (codec_state->info.par_n != par_n || codec_state->info.par_d != par_d) {
gb's avatar
gb committed
898
        GST_DEBUG("pixel-aspect-ratio changed to %u/%u", par_n, par_d);
899 900 901 902
        codec_state->info.par_n = par_n;
        codec_state->info.par_d = par_d;
        gst_caps_set_simple(codec_state->caps,
            "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL);
903
        notify_codec_state_changed(decoder);
gb's avatar
gb committed
904 905 906
    }
}

907 908
static const gchar *
gst_interlace_mode_to_string(GstVideoInterlaceMode mode)
909
{
910 911 912 913 914 915 916
    switch (mode) {
    case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:  return "progressive";
    case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:  return "interleaved";
    case GST_VIDEO_INTERLACE_MODE_MIXED:        return "mixed";
    }
    return "<unknown>";
}
917

918 919 920 921
void
gst_vaapi_decoder_set_interlace_mode(GstVaapiDecoder *decoder,
    GstVideoInterlaceMode mode)
{
922
    GstVideoCodecState * const codec_state = decoder->codec_state;
923 924 925 926 927 928 929

    if (codec_state->info.interlace_mode != mode) {
        GST_DEBUG("interlace mode changed to %s",
                  gst_interlace_mode_to_string(mode));
        codec_state->info.interlace_mode = mode;
        gst_caps_set_simple(codec_state->caps, "interlaced",
            G_TYPE_BOOLEAN, mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, NULL);
930
        notify_codec_state_changed(decoder);
931 932 933
    }
}

934 935 936 937 938 939 940 941 942
void
gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced)
{
    gst_vaapi_decoder_set_interlace_mode(decoder,
        (interlaced ?
         GST_VIDEO_INTERLACE_MODE_INTERLEAVED :
         GST_VIDEO_INTERLACE_MODE_PROGRESSIVE));
}

943 944
gboolean
gst_vaapi_decoder_ensure_context(
945 946
    GstVaapiDecoder     *decoder,
    GstVaapiContextInfo *cip
947 948
)
{
949 950
    gst_vaapi_decoder_set_picture_size(decoder, cip->width, cip->height);

951 952
    if (decoder->context) {
        if (!gst_vaapi_context_reset_full(decoder->context, cip))
953 954 955
            return FALSE;
    }
    else {
956 957
        decoder->context = gst_vaapi_context_new_full(decoder->display, cip);
        if (!decoder->context)
958 959
            return FALSE;
    }
960
    decoder->va_context = gst_vaapi_context_get_id(decoder->context);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
961
    return TRUE;
962 963
}

964
void
965 966
gst_vaapi_decoder_push_frame(GstVaapiDecoder *decoder,
    GstVideoCodecFrame *frame)
967
{
968
    push_frame(decoder, frame);
969
}
970 971 972 973

GstVaapiDecoderStatus
gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder)
{
974 975
    if (decoder->context &&
        gst_vaapi_context_get_surface_count(decoder->context) < 1)
976 977 978
        return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
979 980 981 982 983 984

GstVaapiDecoderStatus
gst_vaapi_decoder_parse(GstVaapiDecoder *decoder,
    GstVideoCodecFrame *base_frame, GstAdapter *adapter, gboolean at_eos,
    guint *got_unit_size_ptr, gboolean *got_frame_ptr)
{
985
    g_return_val_if_fail(decoder != NULL,
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
    g_return_val_if_fail(base_frame != NULL,
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
    g_return_val_if_fail(adapter != NULL,
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
    g_return_val_if_fail(got_unit_size_ptr != NULL,
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
    g_return_val_if_fail(got_frame_ptr != NULL,
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);

    return do_parse(decoder, base_frame, adapter, at_eos,
        got_unit_size_ptr, got_frame_ptr);
}

GstVaapiDecoderStatus
1001
gst_vaapi_decoder_decode(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame)
1002 1003 1004
{
    GstVaapiDecoderStatus status;

1005
    g_return_val_if_fail(decoder != NULL,
1006
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
1007
    g_return_val_if_fail(frame != NULL,
1008
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
1009
    g_return_val_if_fail(frame->user_data != NULL,
1010 1011 1012 1013 1014
        GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);

    status = gst_vaapi_decoder_check_status(decoder);
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
        return status;
1015
    return do_decode(decoder, frame);
1016
}
1017 1018 1019 1020

GstVaapiDecoderStatus
gst_vaapi_decoder_flush(GstVaapiDecoder *decoder)
{