xref: /third_party/ffmpeg/libavcodec/aasc.c (revision cabdff1a)
1/*
2 * Autodesk RLE Decoder
3 * Copyright (C) 2005 The FFmpeg project
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * 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 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * 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 * @file
24 * Autodesk RLE Video Decoder by Konstantin Shishkov
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "avcodec.h"
32#include "codec_internal.h"
33#include "internal.h"
34#include "msrledec.h"
35
36typedef struct AascContext {
37    AVCodecContext *avctx;
38    GetByteContext gb;
39    AVFrame *frame;
40
41    uint32_t palette[AVPALETTE_COUNT];
42    int palette_size;
43} AascContext;
44
45static av_cold int aasc_decode_init(AVCodecContext *avctx)
46{
47    AascContext *s = avctx->priv_data;
48    uint8_t *ptr;
49    int i;
50
51    s->avctx = avctx;
52    switch (avctx->bits_per_coded_sample) {
53    case 8:
54        avctx->pix_fmt = AV_PIX_FMT_PAL8;
55
56        ptr = avctx->extradata;
57        s->palette_size = FFMIN(avctx->extradata_size, AVPALETTE_SIZE);
58        for (i = 0; i < s->palette_size / 4; i++) {
59            s->palette[i] = 0xFFU << 24 | AV_RL32(ptr);
60            ptr += 4;
61        }
62        break;
63    case 16:
64        avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
65        break;
66    case 24:
67        avctx->pix_fmt = AV_PIX_FMT_BGR24;
68        break;
69    default:
70        av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth: %d\n", avctx->bits_per_coded_sample);
71        return -1;
72    }
73
74    s->frame = av_frame_alloc();
75    if (!s->frame)
76        return AVERROR(ENOMEM);
77
78    return 0;
79}
80
81static int aasc_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
82                             int *got_frame, AVPacket *avpkt)
83{
84    const uint8_t *buf = avpkt->data;
85    int buf_size       = avpkt->size;
86    AascContext *s     = avctx->priv_data;
87    int compr, i, stride, psize, ret;
88
89    if (buf_size < 4) {
90        av_log(avctx, AV_LOG_ERROR, "frame too short\n");
91        return AVERROR_INVALIDDATA;
92    }
93
94    if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
95        return ret;
96
97    compr     = AV_RL32(buf);
98    buf      += 4;
99    buf_size -= 4;
100    psize = avctx->bits_per_coded_sample / 8;
101    switch (avctx->codec_tag) {
102    case MKTAG('A', 'A', 'S', '4'):
103        bytestream2_init(&s->gb, buf - 4, buf_size + 4);
104        ff_msrle_decode(avctx, s->frame, 8, &s->gb);
105        break;
106    case MKTAG('A', 'A', 'S', 'C'):
107        switch (compr) {
108        case 0:
109            stride = (avctx->width * psize + psize) & ~psize;
110            if (buf_size < stride * avctx->height)
111                return AVERROR_INVALIDDATA;
112            for (i = avctx->height - 1; i >= 0; i--) {
113                memcpy(s->frame->data[0] + i * s->frame->linesize[0], buf, avctx->width * psize);
114                buf += stride;
115                buf_size -= stride;
116            }
117            break;
118        case 1:
119            bytestream2_init(&s->gb, buf, buf_size);
120            ff_msrle_decode(avctx, s->frame, 8, &s->gb);
121            break;
122        default:
123            av_log(avctx, AV_LOG_ERROR, "Unknown compression type %d\n", compr);
124            return AVERROR_INVALIDDATA;
125        }
126        break;
127    default:
128        av_log(avctx, AV_LOG_ERROR, "Unknown FourCC: %X\n", avctx->codec_tag);
129        return -1;
130    }
131
132    if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
133        memcpy(s->frame->data[1], s->palette, s->palette_size);
134
135    *got_frame = 1;
136    if ((ret = av_frame_ref(rframe, s->frame)) < 0)
137        return ret;
138
139    /* report that the buffer was completely consumed */
140    return avpkt->size;
141}
142
143static av_cold int aasc_decode_end(AVCodecContext *avctx)
144{
145    AascContext *s = avctx->priv_data;
146
147    av_frame_free(&s->frame);
148
149    return 0;
150}
151
152const FFCodec ff_aasc_decoder = {
153    .p.name         = "aasc",
154    .p.long_name    = NULL_IF_CONFIG_SMALL("Autodesk RLE"),
155    .p.type         = AVMEDIA_TYPE_VIDEO,
156    .p.id           = AV_CODEC_ID_AASC,
157    .priv_data_size = sizeof(AascContext),
158    .init           = aasc_decode_init,
159    .close          = aasc_decode_end,
160    FF_CODEC_DECODE_CB(aasc_decode_frame),
161    .p.capabilities = AV_CODEC_CAP_DR1,
162    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
163};
164