1/*
2 * Tiertex Limited SEQ Video Decoder
3 * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
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 * Tiertex Limited SEQ video decoder
25 */
26
27#define BITSTREAM_READER_LE
28#include "avcodec.h"
29#include "codec_internal.h"
30#include "get_bits.h"
31#include "internal.h"
32
33
34typedef struct SeqVideoContext {
35    AVCodecContext *avctx;
36    AVFrame *frame;
37} SeqVideoContext;
38
39
40static const unsigned char *seq_unpack_rle_block(const unsigned char *src,
41                                                 const unsigned char *src_end,
42                                                 unsigned char *dst, int dst_size)
43{
44    int i, len, sz;
45    GetBitContext gb;
46    int code_table[64];
47
48    /* get the rle codes */
49    init_get_bits(&gb, src, (src_end - src) * 8);
50    for (i = 0, sz = 0; i < 64 && sz < dst_size; i++) {
51        if (get_bits_left(&gb) < 4)
52            return NULL;
53        code_table[i] = get_sbits(&gb, 4);
54        sz += FFABS(code_table[i]);
55    }
56    src += (get_bits_count(&gb) + 7) / 8;
57
58    /* do the rle unpacking */
59    for (i = 0; i < 64 && dst_size > 0; i++) {
60        len = code_table[i];
61        if (len < 0) {
62            len = -len;
63            if (src_end - src < 1)
64                return NULL;
65            memset(dst, *src++, FFMIN(len, dst_size));
66        } else {
67            if (src_end - src < len)
68                return NULL;
69            memcpy(dst, src, FFMIN(len, dst_size));
70            src += len;
71        }
72        dst += len;
73        dst_size -= len;
74    }
75    return src;
76}
77
78static const unsigned char *seq_decode_op1(SeqVideoContext *seq,
79                                           const unsigned char *src,
80                                           const unsigned char *src_end,
81                                           unsigned char *dst)
82{
83    const unsigned char *color_table;
84    int b, i, len, bits;
85    GetBitContext gb;
86    unsigned char block[8 * 8];
87
88    if (src_end - src < 1)
89        return NULL;
90    len = *src++;
91    if (len & 0x80) {
92        switch (len & 3) {
93        case 1:
94            src = seq_unpack_rle_block(src, src_end, block, sizeof(block));
95            for (b = 0; b < 8; b++) {
96                memcpy(dst, &block[b * 8], 8);
97                dst += seq->frame->linesize[0];
98            }
99            break;
100        case 2:
101            src = seq_unpack_rle_block(src, src_end, block, sizeof(block));
102            for (i = 0; i < 8; i++) {
103                for (b = 0; b < 8; b++)
104                    dst[b * seq->frame->linesize[0]] = block[i * 8 + b];
105                ++dst;
106            }
107            break;
108        }
109    } else {
110        if (len <= 0)
111            return NULL;
112        bits = ff_log2_tab[len - 1] + 1;
113        if (src_end - src < len + 8 * bits)
114            return NULL;
115        color_table = src;
116        src += len;
117        init_get_bits(&gb, src, bits * 8 * 8); src += bits * 8;
118        for (b = 0; b < 8; b++) {
119            for (i = 0; i < 8; i++)
120                dst[i] = color_table[get_bits(&gb, bits)];
121            dst += seq->frame->linesize[0];
122        }
123    }
124
125    return src;
126}
127
128static const unsigned char *seq_decode_op2(SeqVideoContext *seq,
129                                           const unsigned char *src,
130                                           const unsigned char *src_end,
131                                           unsigned char *dst)
132{
133    int i;
134
135    if (src_end - src < 8 * 8)
136        return NULL;
137
138    for (i = 0; i < 8; i++) {
139        memcpy(dst, src, 8);
140        src += 8;
141        dst += seq->frame->linesize[0];
142    }
143
144    return src;
145}
146
147static const unsigned char *seq_decode_op3(SeqVideoContext *seq,
148                                           const unsigned char *src,
149                                           const unsigned char *src_end,
150                                           unsigned char *dst)
151{
152    int pos, offset;
153
154    do {
155        if (src_end - src < 2)
156            return NULL;
157        pos = *src++;
158        offset = ((pos >> 3) & 7) * seq->frame->linesize[0] + (pos & 7);
159        dst[offset] = *src++;
160    } while (!(pos & 0x80));
161
162    return src;
163}
164
165static int seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int data_size)
166{
167    const unsigned char *data_end = data + data_size;
168    GetBitContext gb;
169    int flags, i, j, x, y, op;
170    unsigned char c[3];
171    unsigned char *dst;
172    uint32_t *palette;
173
174    flags = *data++;
175
176    if (flags & 1) {
177        palette = (uint32_t *)seq->frame->data[1];
178        if (data_end - data < 256 * 3)
179            return AVERROR_INVALIDDATA;
180        for (i = 0; i < 256; i++) {
181            for (j = 0; j < 3; j++, data++)
182                c[j] = (*data << 2) | (*data >> 4);
183            palette[i] = 0xFFU << 24 | AV_RB24(c);
184        }
185        seq->frame->palette_has_changed = 1;
186    }
187
188    if (flags & 2) {
189        if (data_end - data < 128)
190            return AVERROR_INVALIDDATA;
191        init_get_bits(&gb, data, 128 * 8); data += 128;
192        for (y = 0; y < 128; y += 8)
193            for (x = 0; x < 256; x += 8) {
194                dst = &seq->frame->data[0][y * seq->frame->linesize[0] + x];
195                op = get_bits(&gb, 2);
196                switch (op) {
197                case 1:
198                    data = seq_decode_op1(seq, data, data_end, dst);
199                    break;
200                case 2:
201                    data = seq_decode_op2(seq, data, data_end, dst);
202                    break;
203                case 3:
204                    data = seq_decode_op3(seq, data, data_end, dst);
205                    break;
206                }
207                if (!data)
208                    return AVERROR_INVALIDDATA;
209            }
210    }
211    return 0;
212}
213
214static av_cold int seqvideo_decode_init(AVCodecContext *avctx)
215{
216    SeqVideoContext *seq = avctx->priv_data;
217    int ret;
218
219    seq->avctx = avctx;
220    avctx->pix_fmt = AV_PIX_FMT_PAL8;
221
222    ret = ff_set_dimensions(avctx, 256, 128);
223    if (ret < 0)
224        return ret;
225
226    seq->frame = av_frame_alloc();
227    if (!seq->frame)
228        return AVERROR(ENOMEM);
229
230    return 0;
231}
232
233static int seqvideo_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
234                                 int *got_frame, AVPacket *avpkt)
235{
236    const uint8_t *buf = avpkt->data;
237    int buf_size = avpkt->size;
238    int ret;
239
240    SeqVideoContext *seq = avctx->priv_data;
241
242    if ((ret = ff_reget_buffer(avctx, seq->frame, 0)) < 0)
243        return ret;
244
245    if (seqvideo_decode(seq, buf, buf_size))
246        return AVERROR_INVALIDDATA;
247
248    if ((ret = av_frame_ref(rframe, seq->frame)) < 0)
249        return ret;
250    *got_frame       = 1;
251
252    return buf_size;
253}
254
255static av_cold int seqvideo_decode_end(AVCodecContext *avctx)
256{
257    SeqVideoContext *seq = avctx->priv_data;
258
259    av_frame_free(&seq->frame);
260
261    return 0;
262}
263
264const FFCodec ff_tiertexseqvideo_decoder = {
265    .p.name         = "tiertexseqvideo",
266    .p.long_name    = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ video"),
267    .p.type         = AVMEDIA_TYPE_VIDEO,
268    .p.id           = AV_CODEC_ID_TIERTEXSEQVIDEO,
269    .priv_data_size = sizeof(SeqVideoContext),
270    .init           = seqvideo_decode_init,
271    .close          = seqvideo_decode_end,
272    FF_CODEC_DECODE_CB(seqvideo_decode_frame),
273    .p.capabilities = AV_CODEC_CAP_DR1,
274    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
275};
276