gstvaapidecode.c 21.3 KB
Newer Older
1 2 3
/*
 *  gstvaapidecode.c - VA-API video decoder
 *
4
 *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5
 *  Copyright (C) 2011 Intel Corporation
6
 *
warly's avatar
warly 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
 *
warly's avatar
warly 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
warly's avatar
warly committed
14 15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
16
 *
warly's avatar
warly committed
17 18 19 20 21
 *  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
*/
22 23 24 25 26 27 28 29 30 31

/**
 * SECTION:gstvaapidecode
 * @short_description: A VA-API based video decoder
 *
 * vaapidecode decodes from raw bitstreams to surfaces suitable for
 * the vaapisink element.
 */

#include "config.h"
32 33

#include <gst/vaapi/gstvaapidisplay.h>
34
#include <gst/vaapi/gstvaapidecoder_mpeg2.h>
35 36 37
#include <gst/vaapi/gstvaapivideosink.h>
#include <gst/vaapi/gstvaapivideobuffer.h>
#include <gst/vaapi/gstvaapidecoder_ffmpeg.h>
38 39
#include <gst/video/videocontext.h>

40 41 42 43 44 45
#if USE_VAAPI_GLX
#include <gst/vaapi/gstvaapivideobuffer_glx.h>
#define gst_vaapi_video_buffer_new(display) \
    gst_vaapi_video_buffer_glx_new(GST_VAAPI_DISPLAY_GLX(display))
#endif

46 47
#include "gstvaapidecode.h"
#include "gstvaapipluginutil.h"
48

49 50 51 52
#if USE_FFMPEG
# include <gst/vaapi/gstvaapidecoder_ffmpeg.h>
#endif
#if USE_CODEC_PARSERS
53
# include <gst/vaapi/gstvaapidecoder_mpeg2.h>
54
# include <gst/vaapi/gstvaapidecoder_mpeg4.h>
55
# include <gst/vaapi/gstvaapidecoder_vc1.h>
56 57 58 59 60 61
#endif

/* Favor codecparsers-based decoders for 0.3.x series */
#define USE_FFMPEG_DEFAULT \
    (USE_FFMPEG && !USE_CODEC_PARSERS)

62 63 64 65 66 67 68 69 70
#define GST_PLUGIN_NAME "vaapidecode"
#define GST_PLUGIN_DESC "A VA-API based video decoder"

GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidecode);
#define GST_CAT_DEFAULT gst_debug_vaapidecode

/* ElementFactory information */
static const GstElementDetails gst_vaapidecode_details =
    GST_ELEMENT_DETAILS(
gb's avatar
gb committed
71
        "VA-API decoder",
72 73
        "Codec/Decoder/Video",
        GST_PLUGIN_DESC,
74
        "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
75 76

/* Default templates */
77
#define GST_CAPS_CODEC(CODEC) CODEC "; "
78 79

static const char gst_vaapidecode_sink_caps_str[] =
80
    GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
81
    GST_CAPS_CODEC("video/mpeg, mpegversion=4")
82 83
    GST_CAPS_CODEC("video/x-divx")
    GST_CAPS_CODEC("video/x-xvid")
84 85
    GST_CAPS_CODEC("video/x-h263")
    GST_CAPS_CODEC("video/x-h264")
gb's avatar
gb committed
86
    GST_CAPS_CODEC("video/x-wmv")
87 88 89
    ;

static const char gst_vaapidecode_src_caps_str[] =
gb's avatar
gb committed
90
    GST_VAAPI_SURFACE_CAPS;
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

static GstStaticPadTemplate gst_vaapidecode_sink_factory =
    GST_STATIC_PAD_TEMPLATE(
        "sink",
        GST_PAD_SINK,
        GST_PAD_ALWAYS,
        GST_STATIC_CAPS(gst_vaapidecode_sink_caps_str));

static GstStaticPadTemplate gst_vaapidecode_src_factory =
    GST_STATIC_PAD_TEMPLATE(
        "src",
        GST_PAD_SRC,
        GST_PAD_ALWAYS,
        GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));

106 107
#define GstVideoContextClass GstVideoContextInterface
GST_BOILERPLATE_WITH_INTERFACE(
108 109 110
    GstVaapiDecode,
    gst_vaapidecode,
    GstElement,
111 112 113 114
    GST_TYPE_ELEMENT,
    GstVideoContext,
    GST_TYPE_VIDEO_CONTEXT,
    gst_video_context);
115 116 117 118 119 120 121

enum {
    PROP_0,

    PROP_USE_FFMPEG,
};

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
static gboolean
gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, GstCaps *caps);

static void
gst_vaapi_decoder_notify_caps(GObject *obj, GParamSpec *pspec, void *user_data)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(user_data);
    GstCaps *caps;

    g_assert(decode->decoder == GST_VAAPI_DECODER(obj));

    caps = gst_vaapi_decoder_get_caps(decode->decoder);
    gst_vaapidecode_update_src_caps(decode, caps);
}

static inline gboolean
gst_vaapidecode_update_sink_caps(GstVaapiDecode *decode, GstCaps *caps)
{
    if (decode->sinkpad_caps)
        gst_caps_unref(decode->sinkpad_caps);
    decode->sinkpad_caps = gst_caps_ref(caps);
    return TRUE;
}

static gboolean
gst_vaapidecode_update_src_caps(GstVaapiDecode *decode, GstCaps *caps)
{
    GstCaps *other_caps;
    GstStructure *structure;
    const GValue *v_width, *v_height, *v_framerate, *v_par;
    gboolean success;

    if (!decode->srcpad_caps) {
        decode->srcpad_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
        if (!decode->srcpad_caps)
            return FALSE;
    }

    structure    = gst_caps_get_structure(caps, 0);
    v_width      = gst_structure_get_value(structure, "width");
    v_height     = gst_structure_get_value(structure, "height");
    v_framerate  = gst_structure_get_value(structure, "framerate");
    v_par        = gst_structure_get_value(structure, "pixel-aspect-ratio");

    structure = gst_caps_get_structure(decode->srcpad_caps, 0);
    if (v_width && v_height) {
        gst_structure_set_value(structure, "width", v_width);
        gst_structure_set_value(structure, "height", v_height);
    }
    if (v_framerate)
        gst_structure_set_value(structure, "framerate", v_framerate);
    if (v_par)
        gst_structure_set_value(structure, "pixel-aspect-ratio", v_par);

176
    gst_structure_set(structure, "type", G_TYPE_STRING, "vaapi", NULL);
177 178
    gst_structure_set(structure, "opengl", G_TYPE_BOOLEAN, USE_VAAPI_GLX, NULL);

179 180 181 182 183 184
    other_caps = gst_caps_copy(decode->srcpad_caps);
    success = gst_pad_set_caps(decode->srcpad, other_caps);
    gst_caps_unref(other_caps);
    return success;
}

185 186 187 188 189 190 191 192
static void
gst_vaapidecode_release(GstVaapiDecode *decode, GObject *dead_object)
{
    g_mutex_lock(decode->decoder_mutex);
    g_cond_signal(decode->decoder_ready);
    g_mutex_unlock(decode->decoder_mutex);
}

193 194
static GstFlowReturn
gst_vaapidecode_step(GstVaapiDecode *decode)
195 196
{
    GstVaapiSurfaceProxy *proxy;
197
    GstVaapiDecoderStatus status;
198 199
    GstBuffer *buffer;
    GstFlowReturn ret;
200
    guint tries;
201

202
    for (;;) {
203 204
        tries = 0;
    again:
205 206
        proxy = gst_vaapi_decoder_get_surface(decode->decoder, &status);
        if (!proxy) {
207 208
            if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) {
                /* Wait for a VA surface to be displayed and free'd */
209 210
                if (++tries > 100)
                    goto error_decode_timeout;
211 212
                GTimeVal timeout;
                g_get_current_time(&timeout);
213
                g_time_val_add(&timeout, 10000); /* 10 ms each step */
214 215 216 217 218 219 220
                g_mutex_lock(decode->decoder_mutex);
                g_cond_timed_wait(
                    decode->decoder_ready,
                    decode->decoder_mutex,
                    &timeout
                );
                g_mutex_unlock(decode->decoder_mutex);
221
                goto again;
222
            }
223 224 225 226 227 228
            if (status != GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA)
                goto error_decode;
            /* More data is needed */
            break;
        }

229 230 231 232 233 234
        g_object_weak_ref(
            G_OBJECT(proxy),
            (GWeakNotify)gst_vaapidecode_release,
            decode
        );

235 236
        buffer = gst_vaapi_video_buffer_new(decode->display);
        if (!buffer)
237 238 239
            goto error_create_buffer;

        GST_BUFFER_TIMESTAMP(buffer) = GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy);
240
        gst_buffer_set_caps(buffer, GST_PAD_CAPS(decode->srcpad));
241 242 243 244 245 246 247 248
        gst_vaapi_video_buffer_set_surface_proxy(
            GST_VAAPI_VIDEO_BUFFER(buffer),
            proxy
        );

        ret = gst_pad_push(decode->srcpad, buffer);
        if (ret != GST_FLOW_OK)
            goto error_commit_buffer;
249

250 251
        g_object_unref(proxy);
    }
252
    return GST_FLOW_OK;
253 254

    /* ERRORS */
255 256 257 258 259 260
error_decode_timeout:
    {
        GST_DEBUG("decode timeout. Decoder required a VA surface but none "
                  "got available within one second");
        return GST_FLOW_UNEXPECTED;
    }
261 262 263 264 265
error_decode:
    {
        GST_DEBUG("decode error %d", status);
        return GST_FLOW_UNEXPECTED;
    }
266 267 268 269 270 271 272 273 274
error_create_buffer:
    {
        const GstVaapiID surface_id =
            gst_vaapi_surface_get_id(GST_VAAPI_SURFACE_PROXY_SURFACE(proxy));

        GST_DEBUG("video sink failed to create video buffer for proxy'ed "
                  "surface %" GST_VAAPI_ID_FORMAT " (error %d)",
                  GST_VAAPI_ID_ARGS(surface_id), ret);
        g_object_unref(proxy);
275
        return GST_FLOW_UNEXPECTED;
276 277 278 279 280
    }
error_commit_buffer:
    {
        GST_DEBUG("video sink rejected the video buffer (error %d)", ret);
        g_object_unref(proxy);
281
        return GST_FLOW_UNEXPECTED;
282 283 284
    }
}

285
static gboolean
gb's avatar
gb committed
286
gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
287
{
288 289
    VADisplay dpy;
    GstStructure *structure;
290
    int version;
291

292
    if (!gst_vaapi_ensure_display(decode, &decode->display))
293
        return FALSE;
294

295 296 297 298 299 300 301 302
    decode->decoder_mutex = g_mutex_new();
    if (!decode->decoder_mutex)
        return FALSE;

    decode->decoder_ready = g_cond_new();
    if (!decode->decoder_ready)
        return FALSE;

303 304 305 306 307 308 309 310 311 312 313
    dpy = decode->display;
    if (decode->use_ffmpeg) {
#if USE_FFMPEG
        decode->decoder = gst_vaapi_decoder_ffmpeg_new(dpy, caps);
#endif
    }
    else {
#if USE_CODEC_PARSERS
        structure = gst_caps_get_structure(caps, 0);
        if (!structure)
            return FALSE;
314 315 316 317 318
        if (gst_structure_has_name(structure, "video/mpeg")) {
            if (!gst_structure_get_int(structure, "mpegversion", &version))
                return FALSE;
            if (version == 2)
                decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
319 320
            else if (version == 4)
                decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
321
        }
322 323
        else if (gst_structure_has_name(structure, "video/x-wmv"))
            decode->decoder = gst_vaapi_decoder_vc1_new(dpy, caps);
324 325 326 327
        else if (gst_structure_has_name(structure, "video/x-h263") ||
                 gst_structure_has_name(structure, "video/x-divx") ||
                 gst_structure_has_name(structure, "video/x-xvid"))
            decode->decoder = gst_vaapi_decoder_mpeg4_new(dpy, caps);
328 329
#endif
    }
gb's avatar
gb committed
330 331 332
    if (!decode->decoder)
        return FALSE;

333 334 335 336 337 338 339
    g_signal_connect(
        G_OBJECT(decode->decoder),
        "notify::caps",
        G_CALLBACK(gst_vaapi_decoder_notify_caps),
        decode
    );

gb's avatar
gb committed
340 341
    decode->decoder_caps = gst_caps_ref(caps);
    return TRUE;
342 343 344 345 346 347 348 349 350 351 352
}

static void
gst_vaapidecode_destroy(GstVaapiDecode *decode)
{
    if (decode->decoder) {
        gst_vaapi_decoder_put_buffer(decode->decoder, NULL);
        g_object_unref(decode->decoder);
        decode->decoder = NULL;
    }

gb's avatar
gb committed
353 354 355
    if (decode->decoder_caps) {
        gst_caps_unref(decode->decoder_caps);
        decode->decoder_caps = NULL;
356
    }
357 358 359 360 361 362 363 364 365 366 367

    if (decode->decoder_ready) {
        gst_vaapidecode_release(decode, NULL);
        g_cond_free(decode->decoder_ready);
        decode->decoder_ready = NULL;
    }

    if (decode->decoder_mutex) {
        g_mutex_free(decode->decoder_mutex);
        decode->decoder_mutex = NULL;
    }
368 369
}

gb's avatar
gb committed
370 371 372 373 374 375 376 377 378 379 380 381
static gboolean
gst_vaapidecode_reset(GstVaapiDecode *decode, GstCaps *caps)
{
    if (decode->decoder &&
        decode->decoder_caps &&
        gst_caps_is_always_compatible(caps, decode->decoder_caps))
        return TRUE;

    gst_vaapidecode_destroy(decode);
    return gst_vaapidecode_create(decode, caps);
}

382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
/* GstVideoContext interface */

static void
gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
    const GValue *value)
{
    GstVaapiDecode *decode = GST_VAAPIDECODE (context);
    gst_vaapi_set_display (type, value, &decode->display);
}

static gboolean
gst_video_context_supported (GstVaapiDecode *decode, GType iface_type)
{
  return (iface_type == GST_TYPE_VIDEO_CONTEXT);
}

static void
gst_video_context_interface_init(GstVideoContextInterface *iface)
{
    iface->set_context = gst_vaapidecode_set_video_context;
}

gb's avatar
gb committed
404 405
static void
gst_vaapidecode_base_init(gpointer klass)
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
{
    GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);

    gst_element_class_set_details(element_class, &gst_vaapidecode_details);

    /* sink pad */
    gst_element_class_add_pad_template(
        element_class,
        gst_static_pad_template_get(&gst_vaapidecode_sink_factory)
    );

    /* src pad */
    gst_element_class_add_pad_template(
        element_class,
        gst_static_pad_template_get(&gst_vaapidecode_src_factory)
    );
}

static void
gst_vaapidecode_finalize(GObject *object)
{
gb's avatar
gb committed
427 428 429 430
    GstVaapiDecode * const decode = GST_VAAPIDECODE(object);

    gst_vaapidecode_destroy(decode);

431 432 433 434 435 436 437 438 439 440
    if (decode->sinkpad_caps) {
        gst_caps_unref(decode->sinkpad_caps);
        decode->sinkpad_caps = NULL;
    }

    if (decode->srcpad_caps) {
        gst_caps_unref(decode->srcpad_caps);
        decode->srcpad_caps = NULL;
    }

gb's avatar
gb committed
441 442 443 444
    if (decode->display) {
        g_object_unref(decode->display);
        decode->display = NULL;
    }
445

446 447 448 449 450
    if (decode->allowed_caps) {
        gst_caps_unref(decode->allowed_caps);
        decode->allowed_caps = NULL;
    }

451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
    G_OBJECT_CLASS(parent_class)->finalize(object);
}

static void
gst_vaapidecode_set_property(
    GObject      *object,
    guint         prop_id,
    const GValue *value,
    GParamSpec   *pspec
)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(object);

    switch (prop_id) {
    case PROP_USE_FFMPEG:
        decode->use_ffmpeg = g_value_get_boolean(value);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
}

static void
gst_vaapidecode_get_property(
    GObject    *object,
    guint       prop_id,
    GValue     *value,
    GParamSpec *pspec
)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(object);

    switch (prop_id) {
    case PROP_USE_FFMPEG:
        g_value_set_boolean(value, decode->use_ffmpeg);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
}

static GstStateChangeReturn
gst_vaapidecode_change_state(GstElement *element, GstStateChange transition)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
    GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;

    switch (transition) {
501 502 503
    case GST_STATE_CHANGE_NULL_TO_READY:
        decode->is_ready = TRUE;
        break;
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
    case GST_STATE_CHANGE_READY_TO_PAUSED:
        break;
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
        break;
    default:
        break;
    }

    ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
    if (ret != GST_STATE_CHANGE_SUCCESS)
        return ret;

    switch (transition) {
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
        break;
    case GST_STATE_CHANGE_PAUSED_TO_READY:
        break;
521 522 523 524 525 526 527 528
    case GST_STATE_CHANGE_READY_TO_NULL:
        gst_vaapidecode_destroy(decode);
        if (decode->display) {
            g_object_unref(decode->display);
            decode->display = NULL;
        }
        decode->is_ready = FALSE;
        break;
529 530 531 532 533 534 535 536 537 538 539 540
    default:
        break;
    }
    return GST_STATE_CHANGE_SUCCESS;
}

static void
gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
{
    GObjectClass * const object_class = G_OBJECT_CLASS(klass);
    GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);

541 542 543
    GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidecode,
                            GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);

544 545 546 547 548 549
    object_class->finalize      = gst_vaapidecode_finalize;
    object_class->set_property  = gst_vaapidecode_set_property;
    object_class->get_property  = gst_vaapidecode_get_property;

    element_class->change_state = gst_vaapidecode_change_state;

550
#if USE_FFMPEG
551 552 553 554 555 556
    g_object_class_install_property
        (object_class,
         PROP_USE_FFMPEG,
         g_param_spec_boolean("use-ffmpeg",
                              "Use FFmpeg/VAAPI for decoding",
                              "Uses FFmpeg/VAAPI for decoding",
557
                              USE_FFMPEG_DEFAULT,
558
                              G_PARAM_READWRITE));
559
#endif
560 561
}

562 563 564 565 566 567 568 569 570
static gboolean
gst_vaapidecode_ensure_allowed_caps(GstVaapiDecode *decode)
{
    GstCaps *decode_caps;
    guint i, n_decode_caps;

    if (decode->allowed_caps)
        return TRUE;

571 572
    if (!gst_vaapi_ensure_display(decode, &decode->display))
        goto error_no_display;
573

574
    decode_caps = gst_vaapi_display_get_decode_caps(decode->display);
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
    if (!decode_caps)
        goto error_no_decode_caps;
    n_decode_caps = gst_caps_get_size(decode_caps);

    decode->allowed_caps = gst_caps_new_empty();
    if (!decode->allowed_caps)
        goto error_no_memory;

    for (i = 0; i < n_decode_caps; i++) {
        GstStructure *structure;
        structure = gst_caps_get_structure(decode_caps, i);
        if (!structure)
            continue;
        structure = gst_structure_copy(structure);
        if (!structure)
            continue;
        gst_structure_remove_field(structure, "profile");
        gst_structure_set(
            structure,
            "width",  GST_TYPE_INT_RANGE, 1, G_MAXINT,
            "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
            NULL
        );
        gst_caps_merge_structure(decode->allowed_caps, structure);
    }

    gst_caps_unref(decode_caps);
    return TRUE;

    /* ERRORS */
error_no_display:
    {
        GST_DEBUG("failed to retrieve VA display");
        return FALSE;
    }
error_no_decode_caps:
    {
        GST_DEBUG("failed to retrieve VA decode caps");
        return FALSE;
    }
error_no_memory:
    {
        GST_DEBUG("failed to allocate allowed-caps set");
        gst_caps_unref(decode_caps);
        return FALSE;
    }
}

static GstCaps *
gst_vaapidecode_get_caps(GstPad *pad)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

628 629 630
    if (!decode->is_ready)
        return gst_static_pad_template_get_caps(&gst_vaapidecode_sink_factory);

631 632 633 634 635 636
    if (!gst_vaapidecode_ensure_allowed_caps(decode))
        return gst_caps_new_empty();

    return gst_caps_ref(decode->allowed_caps);
}

637 638 639 640 641
static gboolean
gst_vaapidecode_set_caps(GstPad *pad, GstCaps *caps)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

642 643
    g_return_val_if_fail(pad == decode->sinkpad, FALSE);

644
    if (!gst_vaapidecode_update_sink_caps(decode, caps))
645
        return FALSE;
646
    if (!gst_vaapidecode_update_src_caps(decode, caps))
gb's avatar
gb committed
647
        return FALSE;
648
    return gst_vaapidecode_reset(decode, decode->sinkpad_caps);
649 650 651 652 653 654 655 656 657 658 659
}

static GstFlowReturn
gst_vaapidecode_chain(GstPad *pad, GstBuffer *buf)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

    if (!gst_vaapi_decoder_put_buffer(decode->decoder, buf))
        goto error_push_buffer;

    gst_buffer_unref(buf);
660
    return gst_vaapidecode_step(decode);
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692

    /* ERRORS */
error_push_buffer:
    {
        GST_DEBUG("failed to push input buffer to decoder");
        gst_buffer_unref(buf);
        return GST_FLOW_UNEXPECTED;
    }
}

static gboolean
gst_vaapidecode_sink_event(GstPad *pad, GstEvent *event)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

    GST_DEBUG("handle sink event '%s'", GST_EVENT_TYPE_NAME(event));

    /* Propagate event downstream */
    return gst_pad_push_event(decode->srcpad, event);
}

static gboolean
gst_vaapidecode_src_event(GstPad *pad, GstEvent *event)
{
    GstVaapiDecode * const decode = GST_VAAPIDECODE(GST_OBJECT_PARENT(pad));

    GST_DEBUG("handle src event '%s'", GST_EVENT_TYPE_NAME(event));

    /* Propagate event upstream */
    return gst_pad_push_event(decode->sinkpad, event);
}

693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
static gboolean
gst_vaapidecode_query (GstPad *pad, GstQuery *query) {
    GstVaapiDecode *decode = GST_VAAPIDECODE (gst_pad_get_parent_element (pad));
    gboolean res;

    GST_DEBUG ("sharing display %p", decode->display);

    if (gst_vaapi_reply_to_query (query, decode->display))
      res = TRUE;
    else
      res = gst_pad_query_default (pad, query);

    g_object_unref (decode);
    return res;
}

709 710 711 712 713
static void
gst_vaapidecode_init(GstVaapiDecode *decode, GstVaapiDecodeClass *klass)
{
    GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);

714 715 716 717 718 719
    decode->display             = NULL;
    decode->decoder             = NULL;
    decode->decoder_mutex       = NULL;
    decode->decoder_ready       = NULL;
    decode->decoder_caps        = NULL;
    decode->allowed_caps        = NULL;
720
    decode->use_ffmpeg          = USE_FFMPEG_DEFAULT;
721
    decode->is_ready            = FALSE;
722 723 724 725 726 727

    /* Pad through which data comes in to the element */
    decode->sinkpad = gst_pad_new_from_template(
        gst_element_class_get_pad_template(element_class, "sink"),
        "sink"
    );
728
    decode->sinkpad_caps = NULL;
729

730
    gst_pad_set_getcaps_function(decode->sinkpad, gst_vaapidecode_get_caps);
731 732 733
    gst_pad_set_setcaps_function(decode->sinkpad, gst_vaapidecode_set_caps);
    gst_pad_set_chain_function(decode->sinkpad, gst_vaapidecode_chain);
    gst_pad_set_event_function(decode->sinkpad, gst_vaapidecode_sink_event);
734
    gst_pad_set_query_function(decode->sinkpad, gst_vaapidecode_query);
735 736 737 738 739 740 741
    gst_element_add_pad(GST_ELEMENT(decode), decode->sinkpad);

    /* Pad through which data goes out of the element */
    decode->srcpad = gst_pad_new_from_template(
        gst_element_class_get_pad_template(element_class, "src"),
        "src"
    );
742
    decode->srcpad_caps = NULL;
743

744
    gst_pad_use_fixed_caps(decode->srcpad);
745
    gst_pad_set_event_function(decode->srcpad, gst_vaapidecode_src_event);
746
    gst_pad_set_query_function(decode->srcpad, gst_vaapidecode_query);
747 748
    gst_element_add_pad(GST_ELEMENT(decode), decode->srcpad);
}