Statistics
| Branch: | Revision:

ffmpeg / libavcodec / pictordec.c @ 2912e87a

History | View | Annotate | Download (7.47 KB)

1
/*
2
 * Pictor/PC Paint decoder
3
 * Copyright (c) 2010 Peter Ross <pross@xvid.org>
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav 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
 * Libav 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 Libav; 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
 * Pictor/PC Paint decoder
25
 */
26

    
27
#include "libavutil/imgutils.h"
28
#include "avcodec.h"
29
#include "bytestream.h"
30
#include "cga_data.h"
31

    
32
typedef struct PicContext {
33
    AVFrame frame;
34
    int width, height;
35
    int nb_planes;
36
} PicContext;
37

    
38
static void picmemset_8bpp(PicContext *s, int value, int run, int *x, int *y)
39
{
40
    while (run > 0) {
41
        uint8_t *d = s->frame.data[0] + *y * s->frame.linesize[0];
42
        if (*x + run >= s->width) {
43
            int n = s->width - *x;
44
            memset(d + *x, value, n);
45
            run -= n;
46
            *x = 0;
47
            *y -= 1;
48
            if (*y < 0)
49
                break;
50
        } else {
51
            memset(d + *x, value, run);
52
            *x += run;
53
            break;
54
        }
55
    }
56
}
57

    
58
static void picmemset(PicContext *s, int value, int run, int *x, int *y, int *plane, int bits_per_plane)
59
{
60
    uint8_t *d;
61
    int shift = *plane * bits_per_plane;
62
    int mask  = ((1 << bits_per_plane) - 1) << shift;
63
    value   <<= shift;
64

    
65
    while (run > 0) {
66
        int j;
67
        for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
68
            d = s->frame.data[0] + *y * s->frame.linesize[0];
69
            d[*x] |= (value >> j) & mask;
70
            *x += 1;
71
            if (*x == s->width) {
72
                *y -= 1;
73
                *x = 0;
74
                if (*y < 0) {
75
                   *y = s->height - 1;
76
                   *plane += 1;
77
                   value <<= bits_per_plane;
78
                   mask  <<= bits_per_plane;
79
                   if (*plane >= s->nb_planes)
80
                       break;
81
                }
82
            }
83
        }
84
        run--;
85
    }
86
}
87

    
88
static const uint8_t cga_mode45_index[6][4] = {
89
    [0] = { 0, 3,  5,   7 }, // mode4, palette#1, low intensity
90
    [1] = { 0, 2,  4,   6 }, // mode4, palette#2, low intensity
91
    [2] = { 0, 3,  4,   7 }, // mode5, low intensity
92
    [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
93
    [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
94
    [5] = { 0, 11, 12, 15 }, // mode5, high intensity
95
};
96

    
97
static int decode_frame(AVCodecContext *avctx,
98
                        void *data, int *data_size,
99
                        AVPacket *avpkt)
100
{
101
    PicContext *s = avctx->priv_data;
102
    int buf_size = avpkt->size;
103
    const uint8_t *buf = avpkt->data;
104
    const uint8_t *buf_end = avpkt->data + buf_size;
105
    uint32_t *palette;
106
    int bits_per_plane, bpp, etype, esize, npal;
107
    int i, x, y, plane;
108

    
109
    if (buf_size < 11)
110
        return AVERROR_INVALIDDATA;
111

    
112
    if (bytestream_get_le16(&buf) != 0x1234)
113
        return AVERROR_INVALIDDATA;
114
    s->width  = bytestream_get_le16(&buf);
115
    s->height = bytestream_get_le16(&buf);
116
    buf += 4;
117
    bits_per_plane    = *buf & 0xF;
118
    s->nb_planes      = (*buf++ >> 4) + 1;
119
    bpp               = s->nb_planes ? bits_per_plane*s->nb_planes : bits_per_plane;
120
    if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
121
        av_log_ask_for_sample(s, "unsupported bit depth\n");
122
        return AVERROR_INVALIDDATA;
123
    }
124

    
125
    if (*buf == 0xFF) {
126
        buf += 2;
127
        etype  = bytestream_get_le16(&buf);
128
        esize  = bytestream_get_le16(&buf);
129
        if (buf_end - buf < esize)
130
            return AVERROR_INVALIDDATA;
131
    } else {
132
        etype = -1;
133
        esize = 0;
134
    }
135

    
136
    avctx->pix_fmt = PIX_FMT_PAL8;
137

    
138
    if (s->width != avctx->width && s->height != avctx->height) {
139
        if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
140
            return -1;
141
        avcodec_set_dimensions(avctx, s->width, s->height);
142
        if (s->frame.data[0])
143
            avctx->release_buffer(avctx, &s->frame);
144
    }
145

    
146
    if (avctx->get_buffer(avctx, &s->frame) < 0){
147
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
148
        return -1;
149
    }
150
    memset(s->frame.data[0], 0, s->height * s->frame.linesize[0]);
151
    s->frame.pict_type           = FF_I_TYPE;
152
    s->frame.palette_has_changed = 1;
153

    
154
    palette = (uint32_t*)s->frame.data[1];
155
    if (etype == 1 && esize > 1 && *buf < 6) {
156
        int idx = *buf;
157
        npal = 4;
158
        for (i = 0; i < npal; i++)
159
            palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
160
    } else if (etype == 2) {
161
        npal = FFMIN(esize, 16);
162
        for (i = 0; i < npal; i++)
163
            palette[i] = ff_cga_palette[ FFMIN(buf[i], 16)];
164
    } else if (etype == 3) {
165
        npal = FFMIN(esize, 16);
166
        for (i = 0; i < npal; i++)
167
            palette[i] = ff_ega_palette[ FFMIN(buf[i], 63)];
168
    } else if (etype == 4 || etype == 5) {
169
        npal = FFMIN(esize / 3, 256);
170
        for (i = 0; i < npal; i++)
171
            palette[i] = AV_RB24(buf + i*3) << 2;
172
    } else {
173
        if (bpp == 1) {
174
            npal = 2;
175
            palette[0] = 0x000000;
176
            palette[1] = 0xFFFFFF;
177
        } else if (bpp == 2) {
178
            npal = 4;
179
            for (i = 0; i < npal; i++)
180
                palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
181
        } else {
182
            npal = 16;
183
            memcpy(palette, ff_cga_palette, npal * 4);
184
        }
185
    }
186
    // fill remaining palette entries
187
    memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
188
    buf += esize;
189

    
190

    
191
    x = 0;
192
    y = s->height - 1;
193
    plane = 0;
194
    if (bytestream_get_le16(&buf)) {
195
        while (buf_end - buf >= 6) {
196
            const uint8_t *buf_pend = buf + FFMIN(AV_RL16(buf), buf_end - buf);
197
            //ignore uncompressed block size reported at buf[2]
198
            int marker = buf[4];
199
            buf += 5;
200

    
201
            while (plane < s->nb_planes && buf_pend - buf >= 1) {
202
                int run = 1;
203
                int val = *buf++;
204
                if (val == marker) {
205
                    run = *buf++;
206
                    if (run == 0)
207
                        run = bytestream_get_le16(&buf);
208
                    val = *buf++;
209
                }
210
                if (buf > buf_end)
211
                    break;
212

    
213
                if (bits_per_plane == 8) {
214
                    picmemset_8bpp(s, val, run, &x, &y);
215
                    if (y < 0)
216
                        break;
217
                } else {
218
                    picmemset(s, val, run, &x, &y, &plane, bits_per_plane);
219
                }
220
            }
221
        }
222
    } else {
223
        av_log_ask_for_sample(s, "uncompressed image\n");
224
        return buf_size;
225
    }
226

    
227
    *data_size = sizeof(AVFrame);
228
    *(AVFrame*)data = s->frame;
229
    return buf_size;
230
}
231

    
232
static av_cold int decode_end(AVCodecContext *avctx)
233
{
234
    PicContext *s = avctx->priv_data;
235
    if (s->frame.data[0])
236
        avctx->release_buffer(avctx, &s->frame);
237
    return 0;
238
}
239

    
240
AVCodec ff_pictor_decoder = {
241
    "pictor",
242
    AVMEDIA_TYPE_VIDEO,
243
    CODEC_ID_PICTOR,
244
    sizeof(PicContext),
245
    NULL,
246
    NULL,
247
    decode_end,
248
    decode_frame,
249
    CODEC_CAP_DR1,
250
    .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
251
};