static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
                                     int *got_frame, uint8_t *data_start,
                                     unsigned int data_size, int is_alpha_chunk)
{
    WebPContext *s = avctx->priv_data;
    int w, h, ret, i, used;

    if (!is_alpha_chunk) {
        s->lossless = 1;
        avctx->pix_fmt = AV_PIX_FMT_ARGB;
    }

    ret = init_get_bits8(&s->gb, data_start, data_size);
    if (ret < 0)
        return ret;

    if (!is_alpha_chunk) {
        if (get_bits(&s->gb, 8) != 0x2F) {
            av_log(avctx, AV_LOG_ERROR, "Invalid WebP Lossless signature\n");
            return AVERROR_INVALIDDATA;
        }

        w = get_bits(&s->gb, 14) + 1;
        h = get_bits(&s->gb, 14) + 1;

        update_canvas_size(avctx, w, h);

        ret = ff_set_dimensions(avctx, s->width, s->height);
        if (ret < 0)
            return ret;

        s->has_alpha = get_bits1(&s->gb);

        if (get_bits(&s->gb, 3) != 0x0) {
            av_log(avctx, AV_LOG_ERROR, "Invalid WebP Lossless version\n");
            return AVERROR_INVALIDDATA;
        }
    } else {
        if (!s->width || !s->height)
            return AVERROR_BUG;
        w = s->width;
        h = s->height;
    }

    /* parse transformations */
    s->nb_transforms = 0;
    s->reduced_width = 0;
    used = 0;
    while (get_bits1(&s->gb)) {
        enum TransformType transform = get_bits(&s->gb, 2);
        if (used & (1 << transform)) {
            av_log(avctx, AV_LOG_ERROR, "Transform %d used more than once\n",
                   transform);
            ret = AVERROR_INVALIDDATA;
            goto free_and_return;
        }
        used |= (1 << transform);
        s->transforms[s->nb_transforms++] = transform;
        switch (transform) {
        case PREDICTOR_TRANSFORM:
            ret = parse_transform_predictor(s);
            break;
        case COLOR_TRANSFORM:
            ret = parse_transform_color(s);
            break;
        case COLOR_INDEXING_TRANSFORM:
            ret = parse_transform_color_indexing(s);
            break;
        }
        if (ret < 0)
            goto free_and_return;
    }

    /* decode primary image */
    s->image[IMAGE_ROLE_ARGB].frame = p;
    if (is_alpha_chunk)
        s->image[IMAGE_ROLE_ARGB].is_alpha_primary = 1;
    ret = decode_entropy_coded_image(s, IMAGE_ROLE_ARGB, w, h);
    if (ret < 0)
        goto free_and_return;

    /* apply transformations */
    for (i = s->nb_transforms - 1; i >= 0; i--) {
        switch (s->transforms[i]) {
        case PREDICTOR_TRANSFORM:
            ret = apply_predictor_transform(s);
            break;
        case COLOR_TRANSFORM:
            ret = apply_color_transform(s);
            break;
        case SUBTRACT_GREEN:
            ret = apply_subtract_green_transform(s);
            break;
        case COLOR_INDEXING_TRANSFORM:
            ret = apply_color_indexing_transform(s);
            break;
        }
        if (ret < 0)
            goto free_and_return;
    }

    *got_frame   = 1;
    p->pict_type = AV_PICTURE_TYPE_I;
    p->key_frame = 1;
    ret          = data_size;

free_and_return:
    for (i = 0; i < IMAGE_ROLE_NB; i++)
        image_ctx_free(&s->image[i]);

    return ret;
}