gstvaapidecoder_vc1.c 50.9 KB
Newer Older
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1 2 3
/*
 *  gstvaapidecoder_vc1.c - VC-1 decoder
 *
4
 *  Copyright (C) 2011-2013 Intel Corporation
5
 *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 *  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.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  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
 */

/**
 * SECTION:gstvaapidecoder_vc1
 * @short_description: VC-1 decoder
 */

28
#include "sysdeps.h"
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
29 30 31
#include <string.h>
#include <gst/codecparsers/gstvc1parser.h>
#include "gstvaapidecoder_vc1.h"
32
#include "gstvaapidecoder_objects.h"
33
#include "gstvaapidecoder_dpb.h"
34
#include "gstvaapidecoder_unit.h"
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
35 36 37 38 39 40 41
#include "gstvaapidecoder_priv.h"
#include "gstvaapidisplay_priv.h"
#include "gstvaapiobject_priv.h"

#define DEBUG 1
#include "gstvaapidebug.h"

42 43 44
#define GST_VAAPI_DECODER_VC1_CAST(decoder) \
    ((GstVaapiDecoderVC1 *)(decoder))

45 46
typedef struct _GstVaapiDecoderVC1Private       GstVaapiDecoderVC1Private;
typedef struct _GstVaapiDecoderVC1Class         GstVaapiDecoderVC1Class;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
47

48 49 50 51 52
/**
 * GstVaapiDecoderVC1:
 *
 * A decoder based on VC1.
 */
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
53 54 55 56 57 58 59
struct _GstVaapiDecoderVC1Private {
    GstVaapiProfile             profile;
    guint                       width;
    guint                       height;
    GstVC1SeqHdr                seq_hdr;
    GstVC1EntryPointHdr         entrypoint_hdr;
    GstVC1FrameHdr              frame_hdr;
60
    GstVC1BitPlanes            *bitplanes;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
61
    GstVaapiPicture            *current_picture;
62 63 64
    GstVaapiPicture            *last_non_b_picture;
    GstVaapiDpb                *dpb;
    gint32                      next_poc;
65 66
    guint8                     *rbdu_buffer;
    guint                       rbdu_buffer_size;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
67 68
    guint                       is_opened               : 1;
    guint                       is_first_field          : 1;
69
    guint                       has_codec_data          : 1;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
70 71 72 73 74 75 76
    guint                       has_entrypoint          : 1;
    guint                       size_changed            : 1;
    guint                       profile_changed         : 1;
    guint                       closed_entry            : 1;
    guint                       broken_link             : 1;
};

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
/**
 * GstVaapiDecoderVC1:
 *
 * A decoder based on VC1.
 */
struct _GstVaapiDecoderVC1 {
    /*< private >*/
    GstVaapiDecoder             parent_instance;
    GstVaapiDecoderVC1Private   priv;
};

/**
 * GstVaapiDecoderVC1Class:
 *
 * A decoder class based on VC1.
 */
struct _GstVaapiDecoderVC1Class {
    /*< private >*/
    GstVaapiDecoderClass parent_class;
};

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
static GstVaapiDecoderStatus
get_status(GstVC1ParserResult result)
{
    GstVaapiDecoderStatus status;

    switch (result) {
    case GST_VC1_PARSER_OK:
        status = GST_VAAPI_DECODER_STATUS_SUCCESS;
        break;
    case GST_VC1_PARSER_NO_BDU_END:
        status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
        break;
    case GST_VC1_PARSER_ERROR:
        status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
        break;
    default:
        status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
        break;
    }
    return status;
}

static void
gst_vaapi_decoder_vc1_close(GstVaapiDecoderVC1 *decoder)
{
123
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
124

125
    gst_vaapi_picture_replace(&priv->last_non_b_picture, NULL);
126
    gst_vaapi_picture_replace(&priv->current_picture, NULL);
127
    gst_vaapi_dpb_replace(&priv->dpb, NULL);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
128

129 130 131 132
    if (priv->bitplanes) {
        gst_vc1_bitplanes_free(priv->bitplanes);
        priv->bitplanes = NULL;
    }
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
133 134 135
}

static gboolean
136
gst_vaapi_decoder_vc1_open(GstVaapiDecoderVC1 *decoder)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
137
{
138
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
139 140 141

    gst_vaapi_decoder_vc1_close(decoder);

142 143 144 145
    priv->dpb = gst_vaapi_dpb_new(2);
    if (!priv->dpb)
        return FALSE;

146 147 148
    priv->bitplanes = gst_vc1_bitplanes_new();
    if (!priv->bitplanes)
        return FALSE;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
149 150 151 152
    return TRUE;
}

static void
153
gst_vaapi_decoder_vc1_destroy(GstVaapiDecoder *base_decoder)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
154
{
155 156 157
    GstVaapiDecoderVC1 * const decoder =
        GST_VAAPI_DECODER_VC1_CAST(base_decoder);
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
158 159

    gst_vaapi_decoder_vc1_close(decoder);
160 161 162 163 164 165

    if (priv->rbdu_buffer) {
        g_free(priv->rbdu_buffer);
        priv->rbdu_buffer = NULL;
        priv->rbdu_buffer_size = 0;
    }
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
166 167 168
}

static gboolean
169
gst_vaapi_decoder_vc1_create(GstVaapiDecoder *base_decoder)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
170
{
171 172 173 174 175
    GstVaapiDecoderVC1 * const decoder =
        GST_VAAPI_DECODER_VC1_CAST(base_decoder);
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;

    priv->profile = (GstVaapiProfile)0;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
176 177 178 179 180 181
    return TRUE;
}

static GstVaapiDecoderStatus
ensure_context(GstVaapiDecoderVC1 *decoder)
{
182
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    GstVaapiProfile profiles[2];
    GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
    guint i, n_profiles = 0;
    gboolean reset_context = FALSE;

    if (priv->profile_changed) {
        GST_DEBUG("profile changed");
        priv->profile_changed = FALSE;
        reset_context         = TRUE;

        profiles[n_profiles++] = priv->profile;
        if (priv->profile == GST_VAAPI_PROFILE_VC1_SIMPLE)
            profiles[n_profiles++] = GST_VAAPI_PROFILE_VC1_MAIN;

        for (i = 0; i < n_profiles; i++) {
            if (gst_vaapi_display_has_decoder(GST_VAAPI_DECODER_DISPLAY(decoder),
                                              profiles[i], entrypoint))
                break;
        }
        if (i == n_profiles)
            return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
        priv->profile = profiles[i];
    }

    if (priv->size_changed) {
        GST_DEBUG("size changed");
        priv->size_changed = FALSE;
        reset_context      = TRUE;
    }

    if (reset_context) {
214 215 216 217 218 219 220 221
        GstVaapiContextInfo info;

        info.profile    = priv->profile;
        info.entrypoint = entrypoint;
        info.width      = priv->width;
        info.height     = priv->height;
        info.ref_frames = 2;
        reset_context   = gst_vaapi_decoder_ensure_context(
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
222
            GST_VAAPI_DECODER(decoder),
223
            &info
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
224 225 226 227 228 229 230 231 232 233
        );
        if (!reset_context)
            return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
    }
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static GstVaapiDecoderStatus
decode_current_picture(GstVaapiDecoderVC1 *decoder)
{
234
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
235
    GstVaapiPicture * const picture = priv->current_picture;
236 237 238 239 240 241 242 243 244

    if (!picture)
        return GST_VAAPI_DECODER_STATUS_SUCCESS;

    if (!gst_vaapi_picture_decode(picture))
        goto error;
    if (GST_VAAPI_PICTURE_IS_COMPLETE(picture)) {
        if (!gst_vaapi_dpb_add(priv->dpb, picture))
            goto error;
245
        gst_vaapi_picture_replace(&priv->current_picture, NULL);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
246
    }
247 248 249 250 251 252
    return GST_VAAPI_DECODER_STATUS_SUCCESS;

error:
    /* XXX: fix for cases where first field failed to be decoded */
    gst_vaapi_picture_replace(&priv->current_picture, NULL);
    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
253 254 255
}

static GstVaapiDecoderStatus
256
decode_sequence(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
257 258
{
    GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
259
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
260
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
261 262
    GstVC1AdvancedSeqHdr * const adv_hdr = &seq_hdr->advanced;
    GstVC1SeqStructC * const structc = &seq_hdr->struct_c;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
263 264
    GstVC1ParserResult result;
    GstVaapiProfile profile;
265
    guint width, height, fps_n, fps_d, par_n, par_d;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
266

267 268 269 270 271
    result = gst_vc1_parse_sequence_header(
        rbdu->data + rbdu->offset,
        rbdu->size,
        seq_hdr
    );
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
272
    if (result != GST_VC1_PARSER_OK) {
273
        GST_ERROR("failed to parse sequence layer");
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
274 275 276 277 278
        return get_status(result);
    }

    priv->has_entrypoint = FALSE;

279 280 281 282 283 284 285
    /* Reset POC */
    if (priv->last_non_b_picture) {
        if (priv->last_non_b_picture->poc == priv->next_poc)
            priv->next_poc++;
        gst_vaapi_picture_replace(&priv->last_non_b_picture, NULL);
    }

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
286 287 288 289 290 291 292
    /* Validate profile */
    switch (seq_hdr->profile) {
    case GST_VC1_PROFILE_SIMPLE:
    case GST_VC1_PROFILE_MAIN:
    case GST_VC1_PROFILE_ADVANCED:
        break;
    default:
293
        GST_ERROR("unsupported profile %d", seq_hdr->profile);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
294 295 296
        return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
    }

297 298
    fps_n = 0;
    fps_d = 0;
299 300
    par_n = 0;
    par_d = 0;
301 302 303 304 305 306 307 308 309
    switch (seq_hdr->profile) {
    case GST_VC1_PROFILE_SIMPLE:
    case GST_VC1_PROFILE_MAIN:
        if (structc->wmvp) {
            fps_n = structc->framerate;
            fps_d = 1;
        }
        break;
    case GST_VC1_PROFILE_ADVANCED:
310 311
        fps_n = adv_hdr->fps_n;
        fps_d = adv_hdr->fps_d;
312 313
        par_n = adv_hdr->par_n;
        par_d = adv_hdr->par_d;
314 315 316 317 318
        break;
    default:
        g_assert(0 && "XXX: we already validated the profile above");
        break;
    }
319 320 321

    if (fps_n && fps_d)
        gst_vaapi_decoder_set_framerate(base_decoder, fps_n, fps_d);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
322

323 324 325
    if (par_n > 0 && par_d > 0)
        gst_vaapi_decoder_set_pixel_aspect_ratio(base_decoder, par_n, par_d);

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
    switch (seq_hdr->profile) {
    case GST_VC1_PROFILE_SIMPLE:
    case GST_VC1_PROFILE_MAIN:
        width  = seq_hdr->struct_c.coded_width;
        height = seq_hdr->struct_c.coded_height;
        break;
    case GST_VC1_PROFILE_ADVANCED:
        width  = seq_hdr->advanced.max_coded_width;
        height = seq_hdr->advanced.max_coded_height;
        break;
    default:
        g_assert(0 && "XXX: we already validated the profile above");
        break;
    }

    if (priv->width != width) {
        priv->width = width;
        priv->size_changed = TRUE;
    }

    if (priv->height != height) {
        priv->height = height;
        priv->size_changed = TRUE;
    }

    switch (seq_hdr->profile) {
    case GST_VC1_PROFILE_SIMPLE:
        profile = GST_VAAPI_PROFILE_VC1_SIMPLE;
        break;
    case GST_VC1_PROFILE_MAIN:
        profile = GST_VAAPI_PROFILE_VC1_MAIN;
        break;
    case GST_VC1_PROFILE_ADVANCED:
        profile = GST_VAAPI_PROFILE_VC1_ADVANCED;
        break;
    default:
        g_assert(0 && "XXX: we already validated the profile above");
        break;
    }
    if (priv->profile != profile) {
        priv->profile = profile;
        priv->profile_changed = TRUE;
    }
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static GstVaapiDecoderStatus
decode_sequence_end(GstVaapiDecoderVC1 *decoder)
{
375
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
376 377
    GstVaapiDecoderStatus status;

378 379 380
    status = decode_current_picture(decoder);
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
        return status;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
381

382
    gst_vaapi_dpb_flush(priv->dpb);
383
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
384 385 386
}

static GstVaapiDecoderStatus
387
decode_entry_point(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
388
{
389
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
390 391 392 393 394
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
    GstVC1EntryPointHdr * const entrypoint_hdr = &priv->entrypoint_hdr;
    GstVC1ParserResult result;

    result = gst_vc1_parse_entry_point_header(
395 396
        rbdu->data + rbdu->offset,
        rbdu->size,
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
397 398 399 400
        entrypoint_hdr,
        seq_hdr
    );
    if (result != GST_VC1_PARSER_OK) {
401
        GST_ERROR("failed to parse entrypoint layer");
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
        return get_status(result);
    }

    if (entrypoint_hdr->coded_size_flag) {
        priv->width        = entrypoint_hdr->coded_width;
        priv->height       = entrypoint_hdr->coded_height;
        priv->size_changed = TRUE;
    }

    priv->has_entrypoint = TRUE;
    priv->closed_entry   = entrypoint_hdr->closed_entry;
    priv->broken_link    = entrypoint_hdr->broken_link;
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

417
/* Reconstruct bitstream PTYPE (7.1.1.4, index into Table-35) */
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
418
static guint
419
get_PTYPE(guint ptype)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
420
{
421
    switch (ptype) {
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
422 423 424 425 426 427 428 429
    case GST_VC1_PICTURE_TYPE_I:  return 0;
    case GST_VC1_PICTURE_TYPE_P:  return 1;
    case GST_VC1_PICTURE_TYPE_B:  return 2;
    case GST_VC1_PICTURE_TYPE_BI: return 3;
    }
    return 4; /* skipped P-frame */
}

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 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
/* Reconstruct bitstream BFRACTION (7.1.1.14, index into Table-40) */
static guint
get_BFRACTION(guint bfraction)
{
    guint i;

    static const struct {
        guint16 index;
        guint16 value;
    }
    bfraction_map[] = {
        {  0,  GST_VC1_BFRACTION_BASIS      / 2 },
        {  1,  GST_VC1_BFRACTION_BASIS      / 3 },
        {  2, (GST_VC1_BFRACTION_BASIS * 2) / 3 },
        {  3,  GST_VC1_BFRACTION_BASIS      / 4 },
        {  4, (GST_VC1_BFRACTION_BASIS * 3) / 4 },
        {  5,  GST_VC1_BFRACTION_BASIS      / 5 },
        {  6, (GST_VC1_BFRACTION_BASIS * 2) / 5 },
        {  7, (GST_VC1_BFRACTION_BASIS * 3) / 5 },
        {  8, (GST_VC1_BFRACTION_BASIS * 4) / 5 },
        {  9,  GST_VC1_BFRACTION_BASIS      / 6 },
        { 10, (GST_VC1_BFRACTION_BASIS * 5) / 6 },
        { 11,  GST_VC1_BFRACTION_BASIS      / 7 },
        { 12, (GST_VC1_BFRACTION_BASIS * 2) / 7 },
        { 13, (GST_VC1_BFRACTION_BASIS * 3) / 7 },
        { 14, (GST_VC1_BFRACTION_BASIS * 4) / 7 },
        { 15, (GST_VC1_BFRACTION_BASIS * 5) / 7 },
        { 16, (GST_VC1_BFRACTION_BASIS * 6) / 7 },
        { 17,  GST_VC1_BFRACTION_BASIS      / 8 },
        { 18, (GST_VC1_BFRACTION_BASIS * 3) / 8 },
        { 19, (GST_VC1_BFRACTION_BASIS * 5) / 8 },
        { 20, (GST_VC1_BFRACTION_BASIS * 7) / 8 },
        { 21,  GST_VC1_BFRACTION_RESERVED },
        { 22,  GST_VC1_BFRACTION_PTYPE_BI }
    };

    if (!bfraction)
        return 0;

    for (i = 0; i < G_N_ELEMENTS(bfraction_map); i++) {
        if (bfraction_map[i].value == bfraction)
            return bfraction_map[i].index;
    }
    return 21; /* RESERVED */
}

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
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 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
/* Translate GStreamer MV modes to VA-API */
static guint
get_VAMvModeVC1(guint mvmode)
{
    switch (mvmode) {
    case GST_VC1_MVMODE_1MV_HPEL_BILINEAR: return VAMvMode1MvHalfPelBilinear;
    case GST_VC1_MVMODE_1MV:               return VAMvMode1Mv;
    case GST_VC1_MVMODE_1MV_HPEL:          return VAMvMode1MvHalfPel;
    case GST_VC1_MVMODE_MIXED_MV:          return VAMvModeMixedMv;
    case GST_VC1_MVMODE_INTENSITY_COMP:    return VAMvModeIntensityCompensation;
    }
    return 0;
}

/* Reconstruct bitstream MVMODE (7.1.1.32) */
static guint
get_MVMODE(GstVC1FrameHdr *frame_hdr)
{
    guint mvmode;

    if (frame_hdr->profile == GST_VC1_PROFILE_ADVANCED)
        mvmode = frame_hdr->pic.advanced.mvmode;
    else
        mvmode = frame_hdr->pic.simple.mvmode;

    if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P ||
        frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B)
        return get_VAMvModeVC1(mvmode);
    return 0;
}

/* Reconstruct bitstream MVMODE2 (7.1.1.33) */
static guint
get_MVMODE2(GstVC1FrameHdr *frame_hdr)
{
    guint mvmode, mvmode2;

    if (frame_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
        mvmode  = frame_hdr->pic.advanced.mvmode;
        mvmode2 = frame_hdr->pic.advanced.mvmode2;
    }
    else {
        mvmode  = frame_hdr->pic.simple.mvmode;
        mvmode2 = frame_hdr->pic.simple.mvmode2;
    }

    if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P &&
        mvmode == GST_VC1_MVMODE_INTENSITY_COMP)
        return get_VAMvModeVC1(mvmode2);
    return 0;
}

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
528 529 530
static inline int
has_MVTYPEMB_bitplane(GstVaapiDecoderVC1 *decoder)
{
531
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;
    guint mvmode, mvmode2;

    if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
        GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced;
        if (pic->mvtypemb)
            return 0;
        mvmode  = pic->mvmode;
        mvmode2 = pic->mvmode2;
    }
    else {
        GstVC1PicSimpleMain * const pic = &frame_hdr->pic.simple;
        if (pic->mvtypemb)
            return 0;
        mvmode  = pic->mvmode;
        mvmode2 = pic->mvmode2;
    }
    return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P &&
            (mvmode == GST_VC1_MVMODE_MIXED_MV ||
             (mvmode == GST_VC1_MVMODE_INTENSITY_COMP &&
              mvmode2 == GST_VC1_MVMODE_MIXED_MV)));
}

static inline int
has_SKIPMB_bitplane(GstVaapiDecoderVC1 *decoder)
{
559
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;

    if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
        GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced;
        if (pic->skipmb)
            return 0;
    }
    else {
        GstVC1PicSimpleMain * const pic = &frame_hdr->pic.simple;
        if (pic->skipmb)
            return 0;
    }
    return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P ||
            frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B);
}

static inline int
has_DIRECTMB_bitplane(GstVaapiDecoderVC1 *decoder)
{
580
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;

    if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
        GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced;
        if (pic->directmb)
            return 0;
    }
    else {
        GstVC1PicSimpleMain * const pic = &frame_hdr->pic.simple;
        if (pic->directmb)
            return 0;
    }
    return frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B;
}

static inline int
has_ACPRED_bitplane(GstVaapiDecoderVC1 *decoder)
{
600
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;
    GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced;

    if (seq_hdr->profile != GST_VC1_PROFILE_ADVANCED)
        return 0;
    if (pic->acpred)
        return 0;
    return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I ||
            frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI);
}

static inline int
has_OVERFLAGS_bitplane(GstVaapiDecoderVC1 *decoder)
{
616
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
    GstVC1EntryPointHdr * const entrypoint_hdr = &priv->entrypoint_hdr;
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;
    GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced;

    if (seq_hdr->profile != GST_VC1_PROFILE_ADVANCED)
        return 0;
    if (pic->overflags)
        return 0;
    return ((frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I ||
             frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI) &&
            (entrypoint_hdr->overlap && frame_hdr->pquant <= 8) &&
            pic->condover == GST_VC1_CONDOVER_SELECT);
}

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
static inline void
pack_bitplanes(GstVaapiBitPlane *bitplane, guint n, const guint8 *bitplanes[3], guint x, guint y, guint stride)
{
    const guint dst_index = n / 2;
    const guint src_index = y * stride + x;
    guint8 v = 0;

    if (bitplanes[0])
        v |= bitplanes[0][src_index];
    if (bitplanes[1])
        v |= bitplanes[1][src_index] << 1;
    if (bitplanes[2])
        v |= bitplanes[2][src_index] << 2;
    bitplane->data[dst_index] = (bitplane->data[dst_index] << 4) | v;
}

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
648 649 650
static gboolean
fill_picture_structc(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture)
{
651
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
652 653 654 655 656 657 658 659 660 661 662 663 664 665
    VAPictureParameterBufferVC1 * const pic_param = picture->param;
    GstVC1SeqStructC * const structc = &priv->seq_hdr.struct_c;
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;
    GstVC1PicSimpleMain * const pic = &frame_hdr->pic.simple;

    /* Fill in VAPictureParameterBufferVC1 (simple/main profile bits) */
    pic_param->sequence_fields.bits.finterpflag                     = structc->finterpflag;
    pic_param->sequence_fields.bits.multires                        = structc->multires;
    pic_param->sequence_fields.bits.overlap                         = structc->overlap;
    pic_param->sequence_fields.bits.syncmarker                      = structc->syncmarker;
    pic_param->sequence_fields.bits.rangered                        = structc->rangered;
    pic_param->sequence_fields.bits.max_b_frames                    = structc->maxbframes;
    pic_param->conditional_overlap_flag                             = 0; /* advanced profile only */
    pic_param->fast_uvmc_flag                                       = structc->fastuvmc;
666
    pic_param->b_picture_fraction                                   = get_BFRACTION(pic->bfraction);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
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 693
    pic_param->cbp_table                                            = pic->cbptab;
    pic_param->mb_mode_table                                        = 0; /* XXX: interlaced frame */
    pic_param->range_reduction_frame                                = pic->rangeredfrm;
    pic_param->rounding_control                                     = 0; /* advanced profile only */
    pic_param->post_processing                                      = 0; /* advanced profile only */
    pic_param->picture_resolution_index                             = pic->respic;
    pic_param->luma_scale                                           = pic->lumscale;
    pic_param->luma_shift                                           = pic->lumshift;
    pic_param->raw_coding.flags.mv_type_mb                          = pic->mvtypemb;
    pic_param->raw_coding.flags.direct_mb                           = pic->directmb;
    pic_param->raw_coding.flags.skip_mb                             = pic->skipmb;
    pic_param->bitplane_present.flags.bp_mv_type_mb                 = has_MVTYPEMB_bitplane(decoder);
    pic_param->bitplane_present.flags.bp_direct_mb                  = has_DIRECTMB_bitplane(decoder);
    pic_param->bitplane_present.flags.bp_skip_mb                    = has_SKIPMB_bitplane(decoder);
    pic_param->mv_fields.bits.mv_table                              = pic->mvtab;
    pic_param->mv_fields.bits.extended_mv_flag                      = structc->extended_mv;
    pic_param->mv_fields.bits.extended_mv_range                     = pic->mvrange;
    pic_param->transform_fields.bits.variable_sized_transform_flag  = structc->vstransform;
    pic_param->transform_fields.bits.mb_level_transform_type_flag   = pic->ttmbf;
    pic_param->transform_fields.bits.frame_level_transform_type     = pic->ttfrm;
    pic_param->transform_fields.bits.transform_ac_codingset_idx2    = pic->transacfrm2;
    return TRUE;
}

static gboolean
fill_picture_advanced(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture)
{
694
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
    VAPictureParameterBufferVC1 * const pic_param = picture->param;
    GstVC1AdvancedSeqHdr * const adv_hdr = &priv->seq_hdr.advanced;
    GstVC1EntryPointHdr * const entrypoint_hdr = &priv->entrypoint_hdr;
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;
    GstVC1PicAdvanced * const pic = &frame_hdr->pic.advanced;

    if (!priv->has_entrypoint)
        return FALSE;

    /* Fill in VAPictureParameterBufferVC1 (advanced profile bits) */
    pic_param->sequence_fields.bits.pulldown                        = adv_hdr->pulldown;
    pic_param->sequence_fields.bits.interlace                       = adv_hdr->interlace;
    pic_param->sequence_fields.bits.tfcntrflag                      = adv_hdr->tfcntrflag;
    pic_param->sequence_fields.bits.finterpflag                     = adv_hdr->finterpflag;
    pic_param->sequence_fields.bits.psf                             = adv_hdr->psf;
    pic_param->sequence_fields.bits.overlap                         = entrypoint_hdr->overlap;
    pic_param->entrypoint_fields.bits.broken_link                   = entrypoint_hdr->broken_link;
    pic_param->entrypoint_fields.bits.closed_entry                  = entrypoint_hdr->closed_entry;
    pic_param->entrypoint_fields.bits.panscan_flag                  = entrypoint_hdr->panscan_flag;
    pic_param->entrypoint_fields.bits.loopfilter                    = entrypoint_hdr->loopfilter;
    pic_param->conditional_overlap_flag                             = pic->condover;
    pic_param->fast_uvmc_flag                                       = entrypoint_hdr->fastuvmc;
    pic_param->range_mapping_fields.bits.luma_flag                  = entrypoint_hdr->range_mapy_flag;
    pic_param->range_mapping_fields.bits.luma                       = entrypoint_hdr->range_mapy;
    pic_param->range_mapping_fields.bits.chroma_flag                = entrypoint_hdr->range_mapuv_flag;
    pic_param->range_mapping_fields.bits.chroma                     = entrypoint_hdr->range_mapuv;
721
    pic_param->b_picture_fraction                                   = get_BFRACTION(pic->bfraction);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
    pic_param->cbp_table                                            = pic->cbptab;
    pic_param->mb_mode_table                                        = 0; /* XXX: interlaced frame */
    pic_param->range_reduction_frame                                = 0; /* simple/main profile only */
    pic_param->rounding_control                                     = pic->rndctrl;
    pic_param->post_processing                                      = pic->postproc;
    pic_param->picture_resolution_index                             = 0; /* simple/main profile only */
    pic_param->luma_scale                                           = pic->lumscale;
    pic_param->luma_shift                                           = pic->lumshift;
    pic_param->picture_fields.bits.frame_coding_mode                = pic->fcm;
    pic_param->picture_fields.bits.top_field_first                  = pic->tff;
    pic_param->picture_fields.bits.is_first_field                   = pic->fcm == 0; /* XXX: interlaced frame */
    pic_param->picture_fields.bits.intensity_compensation           = pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP;
    pic_param->raw_coding.flags.mv_type_mb                          = pic->mvtypemb;
    pic_param->raw_coding.flags.direct_mb                           = pic->directmb;
    pic_param->raw_coding.flags.skip_mb                             = pic->skipmb;
    pic_param->raw_coding.flags.ac_pred                             = pic->acpred;
    pic_param->raw_coding.flags.overflags                           = pic->overflags;
    pic_param->bitplane_present.flags.bp_mv_type_mb                 = has_MVTYPEMB_bitplane(decoder);
    pic_param->bitplane_present.flags.bp_direct_mb                  = has_DIRECTMB_bitplane(decoder);
    pic_param->bitplane_present.flags.bp_skip_mb                    = has_SKIPMB_bitplane(decoder);
    pic_param->bitplane_present.flags.bp_ac_pred                    = has_ACPRED_bitplane(decoder);
    pic_param->bitplane_present.flags.bp_overflags                  = has_OVERFLAGS_bitplane(decoder);
    pic_param->reference_fields.bits.reference_distance_flag        = entrypoint_hdr->refdist_flag;
    pic_param->mv_fields.bits.mv_table                              = pic->mvtab;
    pic_param->mv_fields.bits.extended_mv_flag                      = entrypoint_hdr->extended_mv;
    pic_param->mv_fields.bits.extended_mv_range                     = pic->mvrange;
    pic_param->mv_fields.bits.extended_dmv_flag                     = entrypoint_hdr->extended_dmv;
    pic_param->pic_quantizer_fields.bits.dquant                     = entrypoint_hdr->dquant;
    pic_param->pic_quantizer_fields.bits.quantizer                  = entrypoint_hdr->quantizer;
    pic_param->transform_fields.bits.variable_sized_transform_flag  = entrypoint_hdr->vstransform;
    pic_param->transform_fields.bits.mb_level_transform_type_flag   = pic->ttmbf;
    pic_param->transform_fields.bits.frame_level_transform_type     = pic->ttfrm;
    pic_param->transform_fields.bits.transform_ac_codingset_idx2    = pic->transacfrm2;
    return TRUE;
}

static gboolean
fill_picture(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture)
{
761
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
762 763 764
    VAPictureParameterBufferVC1 * const pic_param = picture->param;
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;
765
    GstVC1VopDquant * const vopdquant = &frame_hdr->vopdquant;
766
    GstVaapiPicture *prev_picture, *next_picture;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
767 768 769 770 771 772 773 774 775 776 777 778 779 780

    /* Fill in VAPictureParameterBufferVC1 (common fields) */
    pic_param->forward_reference_picture                            = VA_INVALID_ID;
    pic_param->backward_reference_picture                           = VA_INVALID_ID;
    pic_param->inloop_decoded_picture                               = VA_INVALID_ID;
    pic_param->sequence_fields.value                                = 0;
#if VA_CHECK_VERSION(0,32,0)
    pic_param->sequence_fields.bits.profile                         = seq_hdr->profile;
#endif
    pic_param->coded_width                                          = priv->width;
    pic_param->coded_height                                         = priv->height;
    pic_param->entrypoint_fields.value                              = 0;
    pic_param->range_mapping_fields.value                           = 0;
    pic_param->picture_fields.value                                 = 0;
781
    pic_param->picture_fields.bits.picture_type                     = get_PTYPE(frame_hdr->ptype);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
782 783 784 785
    pic_param->raw_coding.value                                     = 0;
    pic_param->bitplane_present.value                               = 0;
    pic_param->reference_fields.value                               = 0;
    pic_param->mv_fields.value                                      = 0;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
786 787
    pic_param->mv_fields.bits.mv_mode                               = get_MVMODE(frame_hdr);
    pic_param->mv_fields.bits.mv_mode2                              = get_MVMODE2(frame_hdr);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
788 789 790 791
    pic_param->pic_quantizer_fields.value                           = 0;
    pic_param->pic_quantizer_fields.bits.half_qp                    = frame_hdr->halfqp;
    pic_param->pic_quantizer_fields.bits.pic_quantizer_scale        = frame_hdr->pquant;
    pic_param->pic_quantizer_fields.bits.pic_quantizer_type         = frame_hdr->pquantizer;
792 793 794 795 796 797
    pic_param->pic_quantizer_fields.bits.dq_frame                   = vopdquant->dquantfrm;
    pic_param->pic_quantizer_fields.bits.dq_profile                 = vopdquant->dqprofile;
    pic_param->pic_quantizer_fields.bits.dq_sb_edge                 = vopdquant->dqprofile == GST_VC1_DQPROFILE_SINGLE_EDGE ? vopdquant->dqbedge : 0;
    pic_param->pic_quantizer_fields.bits.dq_db_edge                 = vopdquant->dqprofile == GST_VC1_DQPROFILE_DOUBLE_EDGES ? vopdquant->dqbedge : 0;
    pic_param->pic_quantizer_fields.bits.dq_binary_level            = vopdquant->dqbilevel;
    pic_param->pic_quantizer_fields.bits.alt_pic_quantizer          = vopdquant->altpquant;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
798 799 800 801 802 803 804 805 806 807 808 809 810
    pic_param->transform_fields.value                               = 0;
    pic_param->transform_fields.bits.transform_ac_codingset_idx1    = frame_hdr->transacfrm;
    pic_param->transform_fields.bits.intra_transform_dc_table       = frame_hdr->transdctab;

    if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
        if (!fill_picture_advanced(decoder, picture))
            return FALSE;
    }
    else {
        if (!fill_picture_structc(decoder, picture))
            return FALSE;
    }

811 812 813
    gst_vaapi_dpb_get_neighbours(priv->dpb, picture,
        &prev_picture, &next_picture);

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
814 815
    switch (picture->type) {
    case GST_VAAPI_PICTURE_TYPE_B:
816 817
        if (next_picture)
            pic_param->backward_reference_picture = next_picture->surface_id;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
818 819 820 821 822
        if (prev_picture)
            pic_param->forward_reference_picture = prev_picture->surface_id;
        else if (!priv->closed_entry)
            GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
        break;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
823
    case GST_VAAPI_PICTURE_TYPE_P:
824 825
        if (prev_picture)
            pic_param->forward_reference_picture = prev_picture->surface_id;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
826 827 828 829
        break;
    default:
        break;
    }
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858

    if (pic_param->bitplane_present.value) {
        const guint8 *bitplanes[3];
        guint x, y, n;

        switch (picture->type) {
        case GST_VAAPI_PICTURE_TYPE_P:
            bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb  ? priv->bitplanes->directmb  : NULL;
            bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb    ? priv->bitplanes->skipmb    : NULL;
            bitplanes[2] = pic_param->bitplane_present.flags.bp_mv_type_mb ? priv->bitplanes->mvtypemb  : NULL;
            break;
        case GST_VAAPI_PICTURE_TYPE_B:
            bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb  ? priv->bitplanes->directmb  : NULL;
            bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb    ? priv->bitplanes->skipmb    : NULL;
            bitplanes[2] = NULL; /* XXX: interlaced frame (FORWARD plane) */
            break;
        case GST_VAAPI_PICTURE_TYPE_BI:
        case GST_VAAPI_PICTURE_TYPE_I:
            bitplanes[0] = NULL; /* XXX: interlaced frame (FIELDTX plane) */
            bitplanes[1] = pic_param->bitplane_present.flags.bp_ac_pred    ? priv->bitplanes->acpred    : NULL;
            bitplanes[2] = pic_param->bitplane_present.flags.bp_overflags  ? priv->bitplanes->overflags : NULL;
            break;
        default:
            bitplanes[0] = NULL;
            bitplanes[1] = NULL;
            bitplanes[2] = NULL;
            break;
        }

859 860
        picture->bitplane = GST_VAAPI_BITPLANE_NEW(
            decoder,
861 862 863 864 865 866 867 868 869 870 871 872
            (seq_hdr->mb_width * seq_hdr->mb_height + 1) / 2
        );
        if (!picture->bitplane)
            return FALSE;

        n = 0;
        for (y = 0; y < seq_hdr->mb_height; y++)
            for (x = 0; x < seq_hdr->mb_width; x++, n++)
                pack_bitplanes(picture->bitplane, n, bitplanes, x, y, seq_hdr->mb_stride);
        if (n & 1) /* move last nibble to the high order */
            picture->bitplane->data[n/2] <<= 4;
    }
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
873 874 875
    return TRUE;
}

876 877 878 879
static GstVaapiDecoderStatus
decode_slice_chunk(GstVaapiDecoderVC1 *decoder, GstVC1BDU *ebdu,
    guint slice_addr, guint header_size)
{
880
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
    GstVaapiPicture * const picture = priv->current_picture;
    GstVaapiSlice *slice;
    VASliceParameterBufferVC1 *slice_param;

    slice = GST_VAAPI_SLICE_NEW(VC1, decoder,
        ebdu->data + ebdu->sc_offset,
        ebdu->size + ebdu->offset - ebdu->sc_offset);
    if (!slice) {
        GST_ERROR("failed to allocate slice");
        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
    }
    gst_vaapi_picture_add_slice(picture, slice);

    /* Fill in VASliceParameterBufferVC1 */
    slice_param = slice->param;
    slice_param->macroblock_offset = 8 * (ebdu->offset - ebdu->sc_offset) +
        header_size;
    slice_param->slice_vertical_position = slice_addr;
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
902
static GstVaapiDecoderStatus
903
decode_frame(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
904
{
905
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
906 907
    GstVC1FrameHdr * const frame_hdr = &priv->frame_hdr;
    GstVC1ParserResult result;
908
    GstVaapiPicture * const picture = priv->current_picture;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
909 910

    memset(frame_hdr, 0, sizeof(*frame_hdr));
911
    result = gst_vc1_parse_frame_header(
912 913
        rbdu->data + rbdu->offset,
        rbdu->size,
914
        frame_hdr,
915
        &priv->seq_hdr,
916 917
        priv->bitplanes
    );
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
918
    if (result != GST_VC1_PARSER_OK) {
919
        GST_ERROR("failed to parse frame layer");
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
920 921 922 923 924 925
        return get_status(result);
    }

    switch (frame_hdr->ptype) {
    case GST_VC1_PICTURE_TYPE_I:
        picture->type   = GST_VAAPI_PICTURE_TYPE_I;
926
        GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
927 928 929 930
        break;
    case GST_VC1_PICTURE_TYPE_SKIPPED:
    case GST_VC1_PICTURE_TYPE_P:
        picture->type   = GST_VAAPI_PICTURE_TYPE_P;
931
        GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
932 933 934 935 936 937 938 939
        break;
    case GST_VC1_PICTURE_TYPE_B:
        picture->type   = GST_VAAPI_PICTURE_TYPE_B;
        break;
    case GST_VC1_PICTURE_TYPE_BI:
        picture->type   = GST_VAAPI_PICTURE_TYPE_BI;
        break;
    default:
940
        GST_ERROR("unsupported picture type %d", frame_hdr->ptype);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
941 942 943
        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
    }

944
    /* Update presentation time */
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
945
    if (GST_VAAPI_PICTURE_IS_REFERENCE(picture)) {
946 947 948 949 950 951 952 953 954 955
        picture->poc = priv->last_non_b_picture ?
            (priv->last_non_b_picture->poc + 1) : priv->next_poc;
        priv->next_poc = picture->poc + 1;
        gst_vaapi_picture_replace(&priv->last_non_b_picture, picture);
    }
    else if (!priv->last_non_b_picture)
        picture->poc = priv->next_poc++;
    else {                                              /* B or BI */
        picture->poc = priv->last_non_b_picture->poc++;
        priv->next_poc = priv->last_non_b_picture->poc + 1;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
956
    }
957
    picture->pts = GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
958 959 960

    if (!fill_picture(decoder, picture))
        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
961 962
    return decode_slice_chunk(decoder, ebdu, 0, frame_hdr->header_size);
}
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
963

964 965 966
static GstVaapiDecoderStatus
decode_slice(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu)
{
967
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
968 969 970 971 972 973 974 975 976
    GstVC1SliceHdr slice_hdr;
    GstVC1ParserResult result;

    memset(&slice_hdr, 0, sizeof(slice_hdr));
    result = gst_vc1_parse_slice_header(
        rbdu->data + rbdu->offset,
        rbdu->size,
        &slice_hdr,
        &priv->seq_hdr
977
    );
978 979 980
    if (result != GST_VC1_PARSER_OK) {
        GST_ERROR("failed to parse slice layer");
        return get_status(result);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
981
    }
982 983
    return decode_slice_chunk(decoder, ebdu, slice_hdr.slice_addr,
        slice_hdr.header_size);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
984 985
}

986 987 988
static gboolean
decode_rbdu(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu)
{
989
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
    guint8 *rbdu_buffer;
    guint i, j, rbdu_buffer_size;

    /* BDU are encapsulated in advanced profile mode only */
    if (priv->profile != GST_VAAPI_PROFILE_VC1_ADVANCED) {
        memcpy(rbdu, ebdu, sizeof(*rbdu));
        return TRUE;
    }

    /* Reallocate unescaped bitstream buffer */
    rbdu_buffer = priv->rbdu_buffer;
    if (!rbdu_buffer || ebdu->size > priv->rbdu_buffer_size) {
        rbdu_buffer = g_realloc(priv->rbdu_buffer, ebdu->size);
        if (!rbdu_buffer)
            return FALSE;
        priv->rbdu_buffer = rbdu_buffer;
        priv->rbdu_buffer_size = ebdu->size;
    }

    /* Unescape bitstream buffer */
    if (ebdu->size < 4) {
        memcpy(rbdu_buffer, ebdu->data + ebdu->offset, ebdu->size);
        rbdu_buffer_size = ebdu->size;
    }
    else {
        guint8 * const bdu_buffer = ebdu->data + ebdu->offset;
        for (i = 0, j = 0; i < ebdu->size; i++) {
            if (i >= 2 && i < ebdu->size - 1 &&
                bdu_buffer[i - 1] == 0x00   &&
                bdu_buffer[i - 2] == 0x00   &&
                bdu_buffer[i    ] == 0x03   &&
                bdu_buffer[i + 1] <= 0x03)
                i++;
            rbdu_buffer[j++] = bdu_buffer[i];
        }
        rbdu_buffer_size = j;
    }

    /* Reconstruct RBDU */
    rbdu->type      = ebdu->type;
    rbdu->size      = rbdu_buffer_size;
    rbdu->sc_offset = 0;
    rbdu->offset    = 0;
    rbdu->data      = rbdu_buffer;
    return TRUE;
}

static GstVaapiDecoderStatus
decode_ebdu(GstVaapiDecoderVC1 *decoder, GstVC1BDU *ebdu)
{
    GstVaapiDecoderStatus status;
    GstVC1BDU rbdu;

    if (!decode_rbdu(decoder, &rbdu, ebdu))
        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;

    switch (ebdu->type) {
    case GST_VC1_SEQUENCE:
        status = decode_sequence(decoder, &rbdu, ebdu);
        break;
    case GST_VC1_ENTRYPOINT:
        status = decode_entry_point(decoder, &rbdu, ebdu);
        break;
    case GST_VC1_FRAME:
        status = decode_frame(decoder, &rbdu, ebdu);
        break;
    case GST_VC1_SLICE:
1057
        status = decode_slice(decoder, &rbdu, ebdu);
1058 1059 1060 1061 1062
        break;
    case GST_VC1_END_OF_SEQ:
        status = decode_sequence_end(decoder);
        break;
    default:
1063
        GST_WARNING("unsupported BDU type %d", ebdu->type);
1064 1065 1066 1067 1068 1069
        status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
        break;
    }
    return status;
}

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1070
static GstVaapiDecoderStatus
1071
decode_buffer(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1072
{
1073
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
1074
    GstVC1BDU ebdu;
1075

1076
    if (priv->has_codec_data) {
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1077 1078 1079 1080
        ebdu.type      = GST_VC1_FRAME;
        ebdu.sc_offset = 0;
        ebdu.offset    = 0;
    }
1081 1082 1083 1084
    else {
        ebdu.type      = buf[3];
        ebdu.sc_offset = 0;
        ebdu.offset    = 4;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1085
    }
1086
    ebdu.data = buf;
1087
    ebdu.size = buf_size - ebdu.offset;
1088
    return decode_ebdu(decoder, &ebdu);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1089 1090
}

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1091
static GstVaapiDecoderStatus
1092 1093
gst_vaapi_decoder_vc1_decode_codec_data(GstVaapiDecoder *base_decoder,
    const guchar *buf, guint buf_size)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1094
{
1095 1096
    GstVaapiDecoderVC1 * const decoder =
        GST_VAAPI_DECODER_VC1_CAST(base_decoder);
1097
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
1098
    GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1099 1100 1101
    GstVaapiDecoderStatus status;
    GstVC1ParserResult result;
    GstVC1BDU ebdu;
1102 1103
    GstCaps *caps;
    GstStructure *structure;
1104
    guint ofs;
1105 1106
    gint width, height;
    guint32 format;
1107
    gint version;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1108

1109
    priv->has_codec_data = TRUE;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1110

1111 1112 1113
    width = GST_VAAPI_DECODER_WIDTH(decoder);
    height = GST_VAAPI_DECODER_HEIGHT(decoder);
    if (!width || !height) {
1114
        GST_ERROR("failed to parse size from codec-data");
1115 1116 1117
        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
    }

1118 1119
    caps = GST_VAAPI_DECODER_CODEC_STATE(decoder)->caps;
    structure = gst_caps_get_structure(caps, 0);
1120
    if (!gst_structure_get_fourcc(structure, "format", &format)) {
1121 1122 1123 1124
        /* Try to determine format from "wmvversion" property */
        if (gst_structure_get_int(structure, "wmvversion", &version))
            format = (version >= 1 && version <= 3) ?
                GST_MAKE_FOURCC('W','M','V',('0'+version)) : 0;
1125 1126
        else
            format = 0;
1127 1128
    }
    if (!format) {
1129
        GST_ERROR("failed to parse profile from codec-data");
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
        return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
    }

    /* WMV3 -- expecting sequence header */
    if (format == GST_MAKE_FOURCC('W','M','V','3')) {
        seq_hdr->struct_c.coded_width  = width;
        seq_hdr->struct_c.coded_height = height;
        ebdu.type      = GST_VC1_SEQUENCE;
        ebdu.size      = buf_size;
        ebdu.sc_offset = 0;
        ebdu.offset    = 0;
1141
        ebdu.data      = (guint8 *)buf;
1142 1143 1144 1145 1146 1147 1148 1149 1150
        return decode_ebdu(decoder, &ebdu);
    }

    /* WVC1 -- expecting bitstream data units */
    if (format != GST_MAKE_FOURCC('W','V','C','1'))
        return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
    seq_hdr->advanced.max_coded_width  = width;
    seq_hdr->advanced.max_coded_height = height;

Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
    ofs = 0;
    do {
        result = gst_vc1_identify_next_bdu(
            buf + ofs,
            buf_size - ofs,
            &ebdu
        );

        switch (result) {
        case GST_VC1_PARSER_NO_BDU_END:
            /* Assume the EBDU is complete within codec-data bounds */
1162
            ebdu.size = buf_size - ofs - ebdu.offset;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
            // fall-through
        case GST_VC1_PARSER_OK:
            status = decode_ebdu(decoder, &ebdu);
            ofs += ebdu.offset + ebdu.size;
            break;
        default:
            status = get_status(result);
            break;
        }
    } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS && ofs < buf_size);
    return status;
}

1176 1177
static GstVaapiDecoderStatus
ensure_decoder(GstVaapiDecoderVC1 *decoder)
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1178
{
1179
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1180
    GstVaapiDecoderStatus status;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1181 1182

    if (!priv->is_opened) {
1183
        priv->is_opened = gst_vaapi_decoder_vc1_open(decoder);
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1184 1185
        if (!priv->is_opened)
            return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1186

1187 1188 1189 1190
        status = gst_vaapi_decoder_decode_codec_data(
            GST_VAAPI_DECODER_CAST(decoder));
        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
            return status;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1191
    }
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static inline gint
scan_for_start_code(GstAdapter *adapter, guint ofs, guint size, guint32 *scp)
{
    return (gint)gst_adapter_masked_scan_uint32_peek(adapter,
        0xffffff00, 0x00000100, ofs, size, scp);
}

static GstVaapiDecoderStatus
gst_vaapi_decoder_vc1_parse(GstVaapiDecoder *base_decoder,
1204
    GstAdapter *adapter, gboolean at_eos, GstVaapiDecoderUnit *unit)
1205
{
1206 1207 1208
    GstVaapiDecoderVC1 * const decoder =
        GST_VAAPI_DECODER_VC1_CAST(base_decoder);
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
    GstVaapiDecoderStatus status;
    guint8 bdu_type;
    guint size, buf_size, flags = 0;
    gint ofs;

    status = ensure_decoder(decoder);
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
        return status;

    size = gst_adapter_available(adapter);

    if (priv->has_codec_data) {
        // Assume demuxer sends out plain frames
        if (size < 1)
            return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
        buf_size = size;
        bdu_type = GST_VC1_FRAME;
    }
    else {
        if (size < 4)
            return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;

        ofs = scan_for_start_code(adapter, 0, size, NULL);
        if (ofs < 0)
            return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
        gst_adapter_flush(adapter, ofs);
        size -= ofs;

        ofs = G_UNLIKELY(size < 8) ? -1 :
            scan_for_start_code(adapter, 4, size - 4, NULL);
        if (ofs < 0) {
            // Assume the whole packet is present if end-of-stream
            if (!at_eos)
                return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
            ofs = size;
        }
        buf_size = ofs;
        gst_adapter_copy(adapter, &bdu_type, 3, 1);
    }

1249
    unit->size = buf_size;
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276

    /* Check for new picture layer */
    switch (bdu_type) {
    case GST_VC1_END_OF_SEQ:
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
        break;
    case GST_VC1_SEQUENCE:
    case GST_VC1_ENTRYPOINT:
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
        break;
    case GST_VC1_FRAME:
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
        break;
    case GST_VC1_SLICE:
        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
        break;
    }
    GST_VAAPI_DECODER_UNIT_FLAG_SET(unit, flags);
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
}

static GstVaapiDecoderStatus
gst_vaapi_decoder_vc1_decode(GstVaapiDecoder *base_decoder,
    GstVaapiDecoderUnit *unit)
{
1277 1278
    GstVaapiDecoderVC1 * const decoder =
        GST_VAAPI_DECODER_VC1_CAST(base_decoder);
1279
    GstVaapiDecoderStatus status;
1280 1281
    GstBuffer * const buffer =
        GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer;
1282
    GstMapInfo map_info;
1283 1284 1285 1286 1287

    status = ensure_decoder(decoder);
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
        return status;

1288 1289 1290 1291 1292 1293
    if (!gst_buffer_map(buffer, &map_info, GST_MAP_READ)) {
        GST_ERROR("failed to map buffer");
        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
    }

    status = decode_buffer(decoder, map_info.data + unit->offset, unit->size);
1294
    gst_buffer_unmap(buffer, &map_info);
1295 1296 1297
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
        return status;
    return GST_VAAPI_DECODER_STATUS_SUCCESS;
Gwenole Beauchesne's avatar
Gwenole Beauchesne committed
1298 1299
}

1300 1301 1302 1303
static GstVaapiDecoderStatus
gst_vaapi_decoder_vc1_start_frame(GstVaapiDecoder *base_decoder,
    GstVaapiDecoderUnit *unit)
{
1304 1305 1306
    GstVaapiDecoderVC1 * const decoder =
        GST_VAAPI_DECODER_VC1_CAST(base_decoder);
    GstVaapiDecoderVC1Private * const priv = &decoder->priv;
1307 1308 1309 1310 1311
    GstVaapiDecoderStatus status;
    GstVaapiPicture *picture;

    status = ensure_context(decoder);
    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
1312
        GST_ERROR("failed to reset context");
1313 1314 1315 1316 1317
        return status;
    }

    picture = GST_VAAPI_PICTURE_NEW(VC1, decoder);
    if (!picture) {
1318
        GST_ERROR("failed to allocate picture");