loco.c 8.71 KB
Newer Older
1 2 3 4
/*
 * LOCO codec
 * Copyright (c) 2005 Konstantin Shishkov
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13 14 15 16 17
 * 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
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

22 23 24 25
/**
 * @file loco.c
 * LOCO codec.
 */
26

27 28 29 30
#include "avcodec.h"
#include "bitstream.h"
#include "golomb.h"

31
enum LOCO_MODE {LOCO_UNKN=0, LOCO_CYUY2=-1, LOCO_CRGB=-2, LOCO_CRGBA=-3, LOCO_CYV12=-4,
32 33 34 35 36 37 38 39 40 41 42 43 44
 LOCO_YUY2=1, LOCO_UYVY=2, LOCO_RGB=3, LOCO_RGBA=4, LOCO_YV12=5};

typedef struct LOCOContext{
    AVCodecContext *avctx;
    AVFrame pic;
    int lossy;
    int mode;
} LOCOContext;

typedef struct RICEContext{
    GetBitContext gb;
    int save, run, run2; /* internal rice decoder state */
    int sum, count; /* sum and count for getting rice parameter */
45
    int lossy;
46 47 48 49 50 51
}RICEContext;

static int loco_get_rice_param(RICEContext *r)
{
    int cnt = 0;
    int val = r->count;
52

53 54 55 56
    while(r->sum > val && cnt < 9) {
        val <<= 1;
        cnt++;
    }
57

58 59 60 61 62 63 64
    return cnt;
}

static inline void loco_update_rice_param(RICEContext *r, int val)
{
    r->sum += val;
    r->count++;
65

66 67 68 69 70 71 72 73 74 75 76
    if(r->count == 16) {
        r->sum >>= 1;
        r->count >>= 1;
    }
}

static inline int loco_get_rice(RICEContext *r)
{
    int v;
    if (r->run > 0) { /* we have zero run */
        r->run--;
77
        loco_update_rice_param(r, 0);
78 79
        return 0;
    }
80 81
    v = get_ur_golomb_jpegls(&r->gb, loco_get_rice_param(r), INT_MAX, 0);
    loco_update_rice_param(r, (v+1)>>1);
82 83
    if (!v) {
        if (r->save >= 0) {
84
            r->run = get_ur_golomb_jpegls(&r->gb, 2, INT_MAX, 0);
85 86 87 88 89 90 91
            if(r->run > 1)
                r->save += r->run + 1;
            else
                r->save -= 3;
        }
        else
            r->run2++;
92 93 94 95 96 97 98 99 100
    } else {
        v = ((v>>1) + r->lossy) ^ -(v&1);
        if (r->run2 > 0) {
            if (r->run2 > 2)
                r->save += r->run2;
            else
                r->save -= 3;
            r->run2 = 0;
        }
101
    }
102

103 104 105 106 107 108 109
    return v;
}

/* LOCO main predictor - LOCO-I/JPEG-LS predictor */
static inline int loco_predict(uint8_t* data, int stride, int step)
{
    int a, b, c;
110

111 112 113
    a = data[-stride];
    b = data[-step];
    c = data[-stride - step];
114

115
    return mid_pred(a, a + b - c, b);
116 117 118
}

static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int height,
Michael Niedermayer's avatar
Michael Niedermayer committed
119
                             int stride, const uint8_t *buf, int buf_size, int step)
120 121 122 123
{
    RICEContext rc;
    int val;
    int i, j;
124

125 126 127 128
    init_get_bits(&rc.gb, buf, buf_size*8);
    rc.save = 0;
    rc.run = 0;
    rc.run2 = 0;
129 130
    rc.lossy = l->lossy;

131 132
    rc.sum = 8;
    rc.count = 1;
133

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    /* restore top left pixel */
    val = loco_get_rice(&rc);
    data[0] = 128 + val;
    /* restore top line */
    for (i = 1; i < width; i++) {
        val = loco_get_rice(&rc);
        data[i * step] = data[i * step - step] + val;
    }
    data += stride;
    for (j = 1; j < height; j++) {
        /* restore left column */
        val = loco_get_rice(&rc);
        data[0] = data[-stride] + val;
        /* restore all other pixels */
        for (i = 1; i < width; i++) {
            val = loco_get_rice(&rc);
            data[i * step] = loco_predict(&data[i * step], stride, step) + val;
        }
        data += stride;
    }
154

155
    return (get_bits_count(&rc.gb) + 7) >> 3;
156 157
}

158
static int decode_frame(AVCodecContext *avctx,
159
                        void *data, int *data_size,
Michael Niedermayer's avatar
Michael Niedermayer committed
160
                        const uint8_t *buf, int buf_size)
161 162 163 164 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
{
    LOCOContext * const l = avctx->priv_data;
    AVFrame * const p= (AVFrame*)&l->pic;
    int decoded;

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

    p->reference = 0;
    if(avctx->get_buffer(avctx, p) < 0){
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
        return -1;
    }
    p->key_frame = 1;

    switch(l->mode) {
    case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY:
        decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
                                    p->linesize[0], buf, buf_size, 1);
        buf += decoded; buf_size -= decoded;
        decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height,
                                    p->linesize[1], buf, buf_size, 1);
        buf += decoded; buf_size -= decoded;
        decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height,
                                    p->linesize[2], buf, buf_size, 1);
        break;
    case LOCO_CYV12: case LOCO_YV12:
        decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
                                    p->linesize[0], buf, buf_size, 1);
        buf += decoded; buf_size -= decoded;
        decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height / 2,
                                    p->linesize[2], buf, buf_size, 1);
193 194 195
        buf += decoded; buf_size -= decoded;
        decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height / 2,
                                    p->linesize[1], buf, buf_size, 1);
196 197
        break;
    case LOCO_CRGB: case LOCO_RGB:
198 199
        decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height,
                                    -p->linesize[0], buf, buf_size, 3);
200
        buf += decoded; buf_size -= decoded;
201 202
        decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height,
                                    -p->linesize[0], buf, buf_size, 3);
203
        buf += decoded; buf_size -= decoded;
204 205
        decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height,
                                    -p->linesize[0], buf, buf_size, 3);
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
        break;
    case LOCO_RGBA:
        decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
                                    p->linesize[0], buf, buf_size, 4);
        buf += decoded; buf_size -= decoded;
        decoded = loco_decode_plane(l, p->data[0] + 1, avctx->width, avctx->height,
                                    p->linesize[0], buf, buf_size, 4);
        buf += decoded; buf_size -= decoded;
        decoded = loco_decode_plane(l, p->data[0] + 2, avctx->width, avctx->height,
                                    p->linesize[0], buf, buf_size, 4);
        buf += decoded; buf_size -= decoded;
        decoded = loco_decode_plane(l, p->data[0] + 3, avctx->width, avctx->height,
                                    p->linesize[0], buf, buf_size, 4);
        break;
    }

    *data_size = sizeof(AVFrame);
    *(AVFrame*)data = l->pic;
224

225 226 227
    return buf_size;
}

228
static av_cold int decode_init(AVCodecContext *avctx){
229 230 231 232 233 234 235 236 237
    LOCOContext * const l = avctx->priv_data;
    int version;

    l->avctx = avctx;
    if (avctx->extradata_size < 12) {
        av_log(avctx, AV_LOG_ERROR, "Extradata size must be >= 12 instead of %i\n",
               avctx->extradata_size);
        return -1;
    }
238
    version = AV_RL32(avctx->extradata);
239 240 241 242 243
    switch(version) {
    case 1:
        l->lossy = 0;
        break;
    case 2:
244
        l->lossy = AV_RL32(avctx->extradata + 8);
245 246
        break;
    default:
247
        l->lossy = AV_RL32(avctx->extradata + 8);
248 249
        av_log(avctx, AV_LOG_INFO, "This is LOCO codec version %i, please upload file for study\n", version);
    }
250

251
    l->mode = AV_RL32(avctx->extradata + 4);
252 253 254 255 256 257 258 259 260 261
    switch(l->mode) {
    case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY:
        avctx->pix_fmt = PIX_FMT_YUV422P;
        break;
    case LOCO_CRGB: case LOCO_RGB:
        avctx->pix_fmt = PIX_FMT_BGR24;
        break;
    case LOCO_CYV12: case LOCO_YV12:
        avctx->pix_fmt = PIX_FMT_YUV420P;
        break;
262
    case LOCO_CRGBA: case LOCO_RGBA:
263
        avctx->pix_fmt = PIX_FMT_RGB32;
264 265 266 267 268
        break;
    default:
        av_log(avctx, AV_LOG_INFO, "Unknown colorspace, index = %i\n", l->mode);
        return -1;
    }
269 270
    if(avctx->debug & FF_DEBUG_PICT_INFO)
        av_log(avctx, AV_LOG_INFO, "lossy:%i, version:%i, mode: %i\n", l->lossy, version, l->mode);
271 272 273 274 275 276 277 278 279 280 281 282 283 284

    return 0;
}

AVCodec loco_decoder = {
    "loco",
    CODEC_TYPE_VIDEO,
    CODEC_ID_LOCO,
    sizeof(LOCOContext),
    decode_init,
    NULL,
    NULL,
    decode_frame,
    CODEC_CAP_DR1,
285
    .long_name = NULL_IF_CONFIG_SMALL("LOCO"),
286
};