dfa.c 12.2 KB
Newer Older
1 2 3 4 5
/*
 * Chronomaster DFA Video Decoder
 * Copyright (c) 2011 Konstantin Shishkov
 * based on work by Vladimir "VAG" Gneushev
 *
6
 * This file is part of FFmpeg.
7
 *
8
 * FFmpeg is free software; you can redistribute it and/or
9 10 11 12
 * 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.
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
14 15 16 17 18
 * 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
19
 * License along with FFmpeg; if not, write to the Free Software
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "avcodec.h"
#include "bytestream.h"
#include "libavutil/lzo.h" // for av_memcpy_backptr

typedef struct DfaContext {
    AVFrame pic;

    uint32_t pal[256];
    uint8_t *frame_buf;
} DfaContext;

static av_cold int dfa_decode_init(AVCodecContext *avctx)
{
    DfaContext *s = avctx->priv_data;

    avctx->pix_fmt = PIX_FMT_PAL8;

    s->frame_buf = av_mallocz(avctx->width * avctx->height + AV_LZO_OUTPUT_PADDING);
    if (!s->frame_buf)
        return AVERROR(ENOMEM);

    return 0;
}

47
static int decode_copy(GetByteContext *gb, uint8_t *frame, int width, int height)
48 49 50
{
    const int size = width * height;

51
    if (bytestream2_get_buffer(gb, frame, size) != size)
52
        return AVERROR_INVALIDDATA;
53 54 55
    return 0;
}

56
static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height)
57 58 59 60
{
    const uint8_t *frame_start = frame;
    const uint8_t *frame_end   = frame + width * height;
    int mask = 0x10000, bitbuf = 0;
61 62
    int v, count, segments;
    unsigned offset;
63

64 65
    segments = bytestream2_get_le32(gb);
    offset   = bytestream2_get_le32(gb);
66 67
    if (segments == 0 && offset == frame_end - frame)
        return 0; // skip frame
68
    if (frame_end - frame <= offset)
69
        return AVERROR_INVALIDDATA;
70
    frame += offset;
71
    while (segments--) {
72
        if (bytestream2_get_bytes_left(gb) < 2)
73
            return AVERROR_INVALIDDATA;
74
        if (mask == 0x10000) {
75
            bitbuf = bytestream2_get_le16u(gb);
76 77
            mask = 1;
        }
78
        if (frame_end - frame < 2)
79
            return AVERROR_INVALIDDATA;
80
        if (bitbuf & mask) {
81
            v = bytestream2_get_le16(gb);
82 83
            offset = (v & 0x1FFF) << 1;
            count = ((v >> 13) + 2) << 1;
84
            if (frame - frame_start < offset || frame_end - frame < count)
85
                return AVERROR_INVALIDDATA;
86 87 88
            av_memcpy_backptr(frame, offset, count);
            frame += count;
        } else {
89 90
            *frame++ = bytestream2_get_byte(gb);
            *frame++ = bytestream2_get_byte(gb);
91 92 93 94 95 96 97
        }
        mask <<= 1;
    }

    return 0;
}

98
static int decode_dsw1(GetByteContext *gb, uint8_t *frame, int width, int height)
99 100 101 102 103 104
{
    const uint8_t *frame_start = frame;
    const uint8_t *frame_end   = frame + width * height;
    int mask = 0x10000, bitbuf = 0;
    int v, offset, count, segments;

105
    segments = bytestream2_get_le16(gb);
106
    while (segments--) {
107
        if (bytestream2_get_bytes_left(gb) < 2)
108
            return AVERROR_INVALIDDATA;
109
        if (mask == 0x10000) {
110
            bitbuf = bytestream2_get_le16u(gb);
111 112
            mask = 1;
        }
113
        if (frame_end - frame < 2)
114
            return AVERROR_INVALIDDATA;
115
        if (bitbuf & mask) {
116
            v = bytestream2_get_le16(gb);
117 118
            offset = (v & 0x1FFF) << 1;
            count = ((v >> 13) + 2) << 1;
119
            if (frame - frame_start < offset || frame_end - frame < count)
120
                return AVERROR_INVALIDDATA;
121 122 123 124 125
            // can't use av_memcpy_backptr() since it can overwrite following pixels
            for (v = 0; v < count; v++)
                frame[v] = frame[v - offset];
            frame += count;
        } else if (bitbuf & (mask << 1)) {
126
            frame += bytestream2_get_le16(gb);
127
        } else {
128 129
            *frame++ = bytestream2_get_byte(gb);
            *frame++ = bytestream2_get_byte(gb);
130 131 132 133 134 135 136
        }
        mask <<= 2;
    }

    return 0;
}

137
static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height)
138 139 140 141 142 143
{
    const uint8_t *frame_start = frame;
    const uint8_t *frame_end   = frame + width * height;
    int mask = 0x10000, bitbuf = 0;
    int i, v, offset, count, segments;

144
    segments = bytestream2_get_le16(gb);
145
    while (segments--) {
146
        if (bytestream2_get_bytes_left(gb) < 2)
147
            return AVERROR_INVALIDDATA;
148
        if (mask == 0x10000) {
149
            bitbuf = bytestream2_get_le16u(gb);
150 151
            mask = 1;
        }
152
        if (frame_end - frame < width + 2)
153
            return AVERROR_INVALIDDATA;
154
        if (bitbuf & mask) {
155
            v = bytestream2_get_le16(gb);
156 157
            offset = (v & 0x1FFF) << 2;
            count = ((v >> 13) + 2) << 1;
158
            if (frame - frame_start < offset || frame_end - frame < count*2 + width)
159
                return AVERROR_INVALIDDATA;
160 161 162 163 164 165 166
            for (i = 0; i < count; i++) {
                frame[0] = frame[1] =
                frame[width] = frame[width + 1] = frame[-offset];

                frame += 2;
            }
        } else if (bitbuf & (mask << 1)) {
167
            frame += bytestream2_get_le16(gb) * 2;
168
        } else {
169 170
            if (frame_end - frame < width + 2)
                return AVERROR_INVALIDDATA;
171
            frame[0] = frame[1] =
172
            frame[width] = frame[width + 1] =  bytestream2_get_byte(gb);
173 174
            frame += 2;
            frame[0] = frame[1] =
175
            frame[width] = frame[width + 1] =  bytestream2_get_byte(gb);
176 177 178 179 180 181 182 183
            frame += 2;
        }
        mask <<= 2;
    }

    return 0;
}

184
static int decode_bdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
185 186 187 188
{
    uint8_t *line_ptr;
    int count, lines, segments;

189
    count = bytestream2_get_le16(gb);
190
    if (count >= height)
191
        return AVERROR_INVALIDDATA;
192
    frame += width * count;
193 194
    lines = bytestream2_get_le16(gb);
    if (count + lines > height)
195
        return AVERROR_INVALIDDATA;
196 197

    while (lines--) {
198
        if (bytestream2_get_bytes_left(gb) < 1)
199
            return AVERROR_INVALIDDATA;
200 201
        line_ptr = frame;
        frame += width;
202
        segments = bytestream2_get_byteu(gb);
203
        while (segments--) {
204
            if (frame - line_ptr <= bytestream2_peek_byte(gb))
205
                return AVERROR_INVALIDDATA;
206 207
            line_ptr += bytestream2_get_byte(gb);
            count = (int8_t)bytestream2_get_byte(gb);
208
            if (count >= 0) {
209
                if (frame - line_ptr < count)
210
                    return AVERROR_INVALIDDATA;
211
                if (bytestream2_get_buffer(gb, line_ptr, count) != count)
212
                    return AVERROR_INVALIDDATA;
213 214
            } else {
                count = -count;
215
                if (frame - line_ptr < count)
216
                    return AVERROR_INVALIDDATA;
217
                memset(line_ptr, bytestream2_get_byte(gb), count);
218 219 220 221 222 223 224 225
            }
            line_ptr += count;
        }
    }

    return 0;
}

226
static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
227 228 229 230
{
    const uint8_t *frame_end   = frame + width * height;
    uint8_t *line_ptr;
    int count, i, v, lines, segments;
231
    int y = 0;
232

233 234
    lines = bytestream2_get_le16(gb);
    if (lines > height)
235
        return AVERROR_INVALIDDATA;
236 237

    while (lines--) {
238
        if (bytestream2_get_bytes_left(gb) < 2)
239
            return AVERROR_INVALIDDATA;
240
        segments = bytestream2_get_le16u(gb);
241
        while ((segments & 0xC000) == 0xC000) {
242
            unsigned skip_lines = -(int16_t)segments;
243
            unsigned delta = -((int16_t)segments * width);
244
            if (frame_end - frame <= delta || y + lines + skip_lines > height)
245
                return AVERROR_INVALIDDATA;
246
            frame    += delta;
247
            y        += skip_lines;
248
            segments = bytestream2_get_le16(gb);
249
        }
250 251
        if (frame_end <= frame)
            return -1;
252 253
        if (segments & 0x8000) {
            frame[width - 1] = segments & 0xFF;
254
            segments = bytestream2_get_le16(gb);
255 256 257
        }
        line_ptr = frame;
        frame += width;
258
        y++;
259
        while (segments--) {
260
            if (frame - line_ptr <= bytestream2_peek_byte(gb))
261
                return AVERROR_INVALIDDATA;
262 263
            line_ptr += bytestream2_get_byte(gb);
            count = (int8_t)bytestream2_get_byte(gb);
264
            if (count >= 0) {
265
                if (frame - line_ptr < count * 2)
266
                    return AVERROR_INVALIDDATA;
267
                if (bytestream2_get_buffer(gb, line_ptr, count * 2) != count * 2)
268
                    return AVERROR_INVALIDDATA;
269 270 271
                line_ptr += count * 2;
            } else {
                count = -count;
272
                if (frame - line_ptr < count * 2)
273
                    return AVERROR_INVALIDDATA;
274
                v = bytestream2_get_le16(gb);
275 276 277 278 279 280 281 282 283
                for (i = 0; i < count; i++)
                    bytestream_put_le16(&line_ptr, v);
            }
        }
    }

    return 0;
}

284
static int decode_unk6(GetByteContext *gb, uint8_t *frame, int width, int height)
285
{
286
    return AVERROR_PATCHWELCOME;
287 288
}

289
static int decode_blck(GetByteContext *gb, uint8_t *frame, int width, int height)
290 291 292 293 294 295
{
    memset(frame, 0, width * height);
    return 0;
}


296
typedef int (*chunk_decoder)(GetByteContext *gb, uint8_t *frame, int width, int height);
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

static const chunk_decoder decoder[8] = {
    decode_copy, decode_tsw1, decode_bdlt, decode_wdlt,
    decode_unk6, decode_dsw1, decode_blck, decode_dds1,
};

static const char* chunk_name[8] = {
    "COPY", "TSW1", "BDLT", "WDLT", "????", "DSW1", "BLCK", "DDS1"
};

static int dfa_decode_frame(AVCodecContext *avctx,
                            void *data, int *data_size,
                            AVPacket *avpkt)
{
    DfaContext *s = avctx->priv_data;
312
    GetByteContext gb;
313 314 315 316 317 318 319 320 321 322 323 324 325 326
    const uint8_t *buf = avpkt->data;
    uint32_t chunk_type, chunk_size;
    uint8_t *dst;
    int ret;
    int i, pal_elems;

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

    if ((ret = avctx->get_buffer(avctx, &s->pic))) {
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
        return ret;
    }

327 328 329 330 331
    bytestream2_init(&gb, avpkt->data, avpkt->size);
    while (bytestream2_get_bytes_left(&gb) > 0) {
        bytestream2_skip(&gb, 4);
        chunk_size = bytestream2_get_le32(&gb);
        chunk_type = bytestream2_get_le32(&gb);
332 333 334 335 336
        if (!chunk_type)
            break;
        if (chunk_type == 1) {
            pal_elems = FFMIN(chunk_size / 3, 256);
            for (i = 0; i < pal_elems; i++) {
337
                s->pal[i] = bytestream2_get_be24(&gb) << 2;
338
                s->pal[i] |= 0xFF << 24 | (s->pal[i] >> 6) & 0x30303;
339 340 341
            }
            s->pic.palette_has_changed = 1;
        } else if (chunk_type <= 9) {
342
            if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) {
343 344
                av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n",
                       chunk_name[chunk_type - 2]);
345
                return AVERROR_INVALIDDATA;
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 375 376 377 378 379 380 381
            }
        } else {
            av_log(avctx, AV_LOG_WARNING, "Ignoring unknown chunk type %d\n",
                   chunk_type);
        }
        buf += chunk_size;
    }

    buf = s->frame_buf;
    dst = s->pic.data[0];
    for (i = 0; i < avctx->height; i++) {
        memcpy(dst, buf, avctx->width);
        dst += s->pic.linesize[0];
        buf += avctx->width;
    }
    memcpy(s->pic.data[1], s->pal, sizeof(s->pal));

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

    return avpkt->size;
}

static av_cold int dfa_decode_end(AVCodecContext *avctx)
{
    DfaContext *s = avctx->priv_data;

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

    av_freep(&s->frame_buf);

    return 0;
}

AVCodec ff_dfa_decoder = {
382 383
    .name           = "dfa",
    .type           = AVMEDIA_TYPE_VIDEO,
384
    .id             = AV_CODEC_ID_DFA,
385 386 387 388 389
    .priv_data_size = sizeof(DfaContext),
    .init           = dfa_decode_init,
    .close          = dfa_decode_end,
    .decode         = dfa_decode_frame,
    .capabilities   = CODEC_CAP_DR1,
390
    .long_name      = NULL_IF_CONFIG_SMALL("Chronomaster DFA"),
391
};