vble.c 6.58 KB
Newer Older
Derek Buitenhuis's avatar
Derek Buitenhuis committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * VBLE Decoder
 * Copyright (c) 2011 Derek Buitenhuis
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg 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.
 *
 * FFmpeg 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 FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * VBLE Decoder
 */

27
#define BITSTREAM_READER_LE
Derek Buitenhuis's avatar
Derek Buitenhuis committed
28 29

#include "avcodec.h"
30
#include "dsputil.h"
Derek Buitenhuis's avatar
Derek Buitenhuis committed
31 32 33 34
#include "get_bits.h"

typedef struct {
    AVCodecContext *avctx;
35
    DSPContext dsp;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
36 37

    int            size;
38
    uint8_t        *val; ///< This array first holds the lengths of vlc symbols and then their value.
Derek Buitenhuis's avatar
Derek Buitenhuis committed
39 40
} VBLEContext;

41
static int vble_unpack(VBLEContext *ctx, GetBitContext *gb)
Derek Buitenhuis's avatar
Derek Buitenhuis committed
42
{
43
    int i;
44
    int allbits = 0;
45 46 47 48 49 50 51 52 53 54
    static const uint8_t LUT[256] = {
        8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
        5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
        6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
        5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
        7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
        5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
        6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
        5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
    };
Derek Buitenhuis's avatar
Derek Buitenhuis committed
55 56 57

    /* Read all the lengths in first */
    for (i = 0; i < ctx->size; i++) {
58 59 60 61 62 63 64
        /* At most we need to read 9 bits total to get indices up to 8 */
        int val = show_bits(gb, 8);

        // read reverse unary
        if (val) {
            val = LUT[val];
            skip_bits(gb, val + 1);
65
            ctx->val[i] = val;
66 67 68 69
        } else {
            skip_bits(gb, 8);
            if (!get_bits1(gb))
                return -1;
70
            ctx->val[i] = 8;
71
        }
72
        allbits += ctx->val[i];
Derek Buitenhuis's avatar
Derek Buitenhuis committed
73 74
    }

75 76 77
    /* Check we have enough bits left */
    if (get_bits_left(gb) < allbits)
        return -1;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
78 79 80
    return 0;
}

81 82
static void vble_restore_plane(VBLEContext *ctx, GetBitContext *gb, int plane,
                               int offset, int width, int height)
Derek Buitenhuis's avatar
Derek Buitenhuis committed
83 84 85 86 87
{
    AVFrame *pic = ctx->avctx->coded_frame;
    uint8_t *dst = pic->data[plane];
    uint8_t *val = ctx->val + offset;
    int stride = pic->linesize[plane];
88
    int i, j, left, left_top;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
89 90 91

    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
92 93 94 95 96
            /* get_bits can't take a length of 0 */
            if (val[j]) {
                int v = (1 << val[j]) + get_bits(gb, val[j]) - 1;
                val[j] = (v >> 1) ^ -(v & 1);
            }
97 98 99 100 101 102 103 104 105
        }
        if (i) {
            left = 0;
            left_top = dst[-stride];
            ctx->dsp.add_hfyu_median_prediction(dst, dst-stride, val, width, &left, &left_top);
        } else {
            dst[0] = val[0];
            for (j = 1; j < width; j++)
                dst[j] = val[j] + dst[j - 1];
Derek Buitenhuis's avatar
Derek Buitenhuis committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
        }
        dst += stride;
        val += width;
    }
}

static int vble_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
                             AVPacket *avpkt)
{
    VBLEContext *ctx = avctx->priv_data;
    AVFrame *pic = avctx->coded_frame;
    GetBitContext gb;
    const uint8_t *src = avpkt->data;
    int version;
    int offset = 0;
    int width_uv = avctx->width / 2, height_uv = avctx->height / 2;

    pic->reference = 0;

    /* Clear buffer if need be */
    if (pic->data[0])
        avctx->release_buffer(avctx, pic);

    /* Allocate buffer */
    if (avctx->get_buffer(avctx, pic) < 0) {
        av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
        return AVERROR(ENOMEM);
    }

    /* Set flags */
    pic->key_frame = 1;
137
    pic->pict_type = AV_PICTURE_TYPE_I;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155

    /* Version should always be 1 */
    version = AV_RL32(src);

    if (version != 1) {
        av_log(avctx, AV_LOG_ERROR, "Unsupported VBLE Version: %d\n", version);
        return AVERROR_INVALIDDATA;
    }

    init_get_bits(&gb, src + 4, (avpkt->size - 4) * 8);

    /* Unpack */
    if (vble_unpack(ctx, &gb) < 0) {
        av_log(avctx, AV_LOG_ERROR, "Invalid Code\n");
        return AVERROR_INVALIDDATA;
    }

    /* Restore planes. Should be almost identical to Huffyuv's. */
156
    vble_restore_plane(ctx, &gb, 0, offset, avctx->width, avctx->height);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
157 158

    /* Chroma */
159
    if (!(ctx->avctx->flags & CODEC_FLAG_GRAY)) {
Derek Buitenhuis's avatar
Derek Buitenhuis committed
160
        offset += avctx->width * avctx->height;
161
        vble_restore_plane(ctx, &gb, 1, offset, width_uv, height_uv);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
162 163

        offset += width_uv * height_uv;
164
        vble_restore_plane(ctx, &gb, 2, offset, width_uv, height_uv);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
    }

    *data_size = sizeof(AVFrame);
    *(AVFrame *)data = *pic;

    return avpkt->size;
}

static av_cold int vble_decode_close(AVCodecContext *avctx)
{
    VBLEContext *ctx = avctx->priv_data;
    AVFrame *pic = avctx->coded_frame;

    if (pic->data[0])
        avctx->release_buffer(avctx, pic);

    av_freep(&avctx->coded_frame);
    av_freep(&ctx->val);

    return 0;
}

static av_cold int vble_decode_init(AVCodecContext *avctx)
{
    VBLEContext *ctx = avctx->priv_data;

    /* Stash for later use */
    ctx->avctx = avctx;
193
    ff_dsputil_init(&ctx->dsp, avctx);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
194 195 196 197 198

    avctx->pix_fmt = PIX_FMT_YUV420P;
    avctx->bits_per_raw_sample = 8;
    avctx->coded_frame = avcodec_alloc_frame();

199 200 201 202
    if (!avctx->coded_frame) {
        av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
        return AVERROR(ENOMEM);
    }
Derek Buitenhuis's avatar
Derek Buitenhuis committed
203 204 205 206 207 208

    ctx->size = avpicture_get_size(avctx->pix_fmt,
                                   avctx->width, avctx->height);

    ctx->val = av_malloc(ctx->size * sizeof(*ctx->val));

209 210 211 212 213
    if (!ctx->val) {
        av_log(avctx, AV_LOG_ERROR, "Could not allocate values buffer.\n");
        vble_decode_close(avctx);
        return AVERROR(ENOMEM);
    }
Derek Buitenhuis's avatar
Derek Buitenhuis committed
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228

    return 0;
}

AVCodec ff_vble_decoder = {
    .name           = "vble",
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = CODEC_ID_VBLE,
    .priv_data_size = sizeof(VBLEContext),
    .init           = vble_decode_init,
    .close          = vble_decode_close,
    .decode         = vble_decode_frame,
    .capabilities   = CODEC_CAP_DR1,
    .long_name      = NULL_IF_CONFIG_SMALL("VBLE Lossless Codec"),
};