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#include "avcodec.h"
28#define ALT_BITSTREAM_READER_LE
29#include "get_bits.h"
30
31
32typedef struct SeqVideoContext {
33    AVCodecContext *avctx;
34    AVFrame frame;
35} SeqVideoContext;
36
37
38static const unsigned char *seq_unpack_rle_block(const unsigned char *src, unsigned char *dst, int dst_size)
39{
40    int i, len, sz;
41    GetBitContext gb;
42    int code_table[64];
43
44    /* get the rle codes (at most 64 bytes) */
45    init_get_bits(&gb, src, 64 * 8);
46    for (i = 0, sz = 0; i < 64 && sz < dst_size; i++) {
47        code_table[i] = get_sbits(&gb, 4);
48        sz += FFABS(code_table[i]);
49    }
50    src += (get_bits_count(&gb) + 7) / 8;
51
52    /* do the rle unpacking */
53    for (i = 0; i < 64 && dst_size > 0; i++) {
54        len = code_table[i];
55        if (len < 0) {
56            len = -len;
57            memset(dst, *src++, FFMIN(len, dst_size));
58        } else {
59            memcpy(dst, src, FFMIN(len, dst_size));
60            src += len;
61        }
62        dst += len;
63        dst_size -= len;
64    }
65    return src;
66}
67
68static const unsigned char *seq_decode_op1(SeqVideoContext *seq, const unsigned char *src, unsigned char *dst)
69{
70    const unsigned char *color_table;
71    int b, i, len, bits;
72    GetBitContext gb;
73    unsigned char block[8 * 8];
74
75    len = *src++;
76    if (len & 0x80) {
77        switch (len & 3) {
78        case 1:
79            src = seq_unpack_rle_block(src, block, sizeof(block));
80            for (b = 0; b < 8; b++) {
81                memcpy(dst, &block[b * 8], 8);
82                dst += seq->frame.linesize[0];
83            }
84            break;
85        case 2:
86            src = seq_unpack_rle_block(src, block, sizeof(block));
87            for (i = 0; i < 8; i++) {
88                for (b = 0; b < 8; b++)
89                    dst[b * seq->frame.linesize[0]] = block[i * 8 + b];
90                ++dst;
91            }
92            break;
93        }
94    } else {
95        color_table = src;
96        src += len;
97        bits = ff_log2_tab[len - 1] + 1;
98        init_get_bits(&gb, src, bits * 8 * 8); src += bits * 8;
99        for (b = 0; b < 8; b++) {
100            for (i = 0; i < 8; i++)
101                dst[i] = color_table[get_bits(&gb, bits)];
102            dst += seq->frame.linesize[0];
103        }
104    }
105
106    return src;
107}
108
109static const unsigned char *seq_decode_op2(SeqVideoContext *seq, const unsigned char *src, unsigned char *dst)
110{
111    int i;
112
113    for (i = 0; i < 8; i++) {
114        memcpy(dst, src, 8);
115        src += 8;
116        dst += seq->frame.linesize[0];
117    }
118
119    return src;
120}
121
122static const unsigned char *seq_decode_op3(SeqVideoContext *seq, const unsigned char *src, unsigned char *dst)
123{
124    int pos, offset;
125
126    do {
127        pos = *src++;
128        offset = ((pos >> 3) & 7) * seq->frame.linesize[0] + (pos & 7);
129        dst[offset] = *src++;
130    } while (!(pos & 0x80));
131
132    return src;
133}
134
135static void seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int data_size)
136{
137    GetBitContext gb;
138    int flags, i, j, x, y, op;
139    unsigned char c[3];
140    unsigned char *dst;
141    uint32_t *palette;
142
143    flags = *data++;
144
145    if (flags & 1) {
146        palette = (uint32_t *)seq->frame.data[1];
147        for (i = 0; i < 256; i++) {
148            for (j = 0; j < 3; j++, data++)
149                c[j] = (*data << 2) | (*data >> 4);
150            palette[i] = AV_RB24(c);
151        }
152        seq->frame.palette_has_changed = 1;
153    }
154
155    if (flags & 2) {
156        init_get_bits(&gb, data, 128 * 8); data += 128;
157        for (y = 0; y < 128; y += 8)
158            for (x = 0; x < 256; x += 8) {
159                dst = &seq->frame.data[0][y * seq->frame.linesize[0] + x];
160                op = get_bits(&gb, 2);
161                switch (op) {
162                case 1:
163                    data = seq_decode_op1(seq, data, dst);
164                    break;
165                case 2:
166                    data = seq_decode_op2(seq, data, dst);
167                    break;
168                case 3:
169                    data = seq_decode_op3(seq, data, dst);
170                    break;
171                }
172            }
173    }
174}
175
176static av_cold int seqvideo_decode_init(AVCodecContext *avctx)
177{
178    SeqVideoContext *seq = avctx->priv_data;
179
180    seq->avctx = avctx;
181    avctx->pix_fmt = PIX_FMT_PAL8;
182
183    seq->frame.data[0] = NULL;
184
185    return 0;
186}
187
188static int seqvideo_decode_frame(AVCodecContext *avctx,
189                                 void *data, int *data_size,
190                                 AVPacket *avpkt)
191{
192    const uint8_t *buf = avpkt->data;
193    int buf_size = avpkt->size;
194
195    SeqVideoContext *seq = avctx->priv_data;
196
197    seq->frame.reference = 1;
198    seq->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
199    if (avctx->reget_buffer(avctx, &seq->frame)) {
200        av_log(seq->avctx, AV_LOG_ERROR, "tiertexseqvideo: reget_buffer() failed\n");
201        return -1;
202    }
203
204    seqvideo_decode(seq, buf, buf_size);
205
206    *data_size = sizeof(AVFrame);
207    *(AVFrame *)data = seq->frame;
208
209    return buf_size;
210}
211
212static av_cold int seqvideo_decode_end(AVCodecContext *avctx)
213{
214    SeqVideoContext *seq = avctx->priv_data;
215
216    if (seq->frame.data[0])
217        avctx->release_buffer(avctx, &seq->frame);
218
219    return 0;
220}
221
222AVCodec tiertexseqvideo_decoder = {
223    "tiertexseqvideo",
224    AVMEDIA_TYPE_VIDEO,
225    CODEC_ID_TIERTEXSEQVIDEO,
226    sizeof(SeqVideoContext),
227    seqvideo_decode_init,
228    NULL,
229    seqvideo_decode_end,
230    seqvideo_decode_frame,
231    CODEC_CAP_DR1,
232    .long_name = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ video"),
233};
234