Statistics
| Branch: | Revision:

ffmpeg / libavcodec / msvideo1.c @ e40f5d3c

History | View | Annotate | Download (11.2 KB)

1 2fdf638b Mike Melanson
/*
2
 * Microsoft Video-1 Decoder
3
 * Copyright (C) 2003 the ffmpeg project
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 *
19
 */
20
21
/**
22
 * @file msvideo1.c
23
 * Microsoft Video-1 Decoder by Mike Melanson (melanson@pcisys.net)
24
 * For more information about the MS Video-1 format, visit:
25
 *   http://www.pcisys.net/~melanson/codecs/
26
 *
27
 * This decoder outputs either PAL8 or RGB555 data, depending on the
28 875efafa Roberto Togni
 * whether a RGB palette was passed through palctrl;
29
 * if it's present, then the data is PAL8; RGB555 otherwise.
30 2fdf638b Mike Melanson
 */
31
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
37
#include "common.h"
38
#include "avcodec.h"
39
#include "dsputil.h"
40
41
#define PALETTE_COUNT 256
42
#define LE_16(x)  ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
43
#define CHECK_STREAM_PTR(n) \
44
  if ((stream_ptr + n) > s->size ) { \
45 9b879566 Michel Bardiaux
    av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \
46 2fdf638b Mike Melanson
      stream_ptr + n, s->size); \
47
    return; \
48
  }
49
50
typedef struct Msvideo1Context {
51
52
    AVCodecContext *avctx;
53
    DSPContext dsp;
54
    AVFrame frame;
55
56
    unsigned char *buf;
57
    int size;
58
59
    int mode_8bit;  /* if it's not 8-bit, it's 16-bit */
60
61
} Msvideo1Context;
62
63
static int msvideo1_decode_init(AVCodecContext *avctx)
64
{
65
    Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
66
67
    s->avctx = avctx;
68
69 875efafa Roberto Togni
    /* figure out the colorspace based on the presence of a palette */
70
    if (s->avctx->palctrl) {
71 2fdf638b Mike Melanson
        s->mode_8bit = 1;
72
        avctx->pix_fmt = PIX_FMT_PAL8;
73
    } else {
74
        s->mode_8bit = 0;
75
        avctx->pix_fmt = PIX_FMT_RGB555;
76
    }
77
78
    avctx->has_b_frames = 0;
79
    dsputil_init(&s->dsp, avctx);
80
81 e1c2a5a0 Roberto Togni
    s->frame.data[0] = NULL;
82 2fdf638b Mike Melanson
83
    return 0;
84
}
85
86
static void msvideo1_decode_8bit(Msvideo1Context *s)
87
{
88
    int block_ptr, pixel_ptr;
89
    int total_blocks;
90
    int pixel_x, pixel_y;  /* pixel width and height iterators */
91
    int block_x, block_y;  /* block width and height iterators */
92
    int blocks_wide, blocks_high;  /* width and height in 4x4 blocks */
93
    int block_inc;
94
    int row_dec;
95
96
    /* decoding parameters */
97
    int stream_ptr;
98
    unsigned char byte_a, byte_b;
99
    unsigned short flags;
100
    int skip_blocks;
101
    unsigned char colors[8];
102
    unsigned char *pixels = s->frame.data[0];
103
    int stride = s->frame.linesize[0];
104
105
    stream_ptr = 0;
106
    skip_blocks = 0;
107
    blocks_wide = s->avctx->width / 4;
108
    blocks_high = s->avctx->height / 4;
109
    total_blocks = blocks_wide * blocks_high;
110
    block_inc = 4;
111
    row_dec = stride + 4;
112
113
    for (block_y = blocks_high; block_y > 0; block_y--) {
114
        block_ptr = ((block_y * 4) - 1) * stride;
115
        for (block_x = blocks_wide; block_x > 0; block_x--) {
116
            /* check if this block should be skipped */
117
            if (skip_blocks) {
118
                block_ptr += block_inc;
119
                skip_blocks--;
120
                total_blocks--;
121
                continue;
122
            }
123
124
            pixel_ptr = block_ptr;
125
126
            /* get the next two bytes in the encoded data stream */
127
            CHECK_STREAM_PTR(2);
128
            byte_a = s->buf[stream_ptr++];
129
            byte_b = s->buf[stream_ptr++];
130
131
            /* check if the decode is finished */
132
            if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
133
                return;
134
            else if ((byte_b & 0xFC) == 0x84) {
135
                /* skip code, but don't count the current block */
136
                skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
137
            } else if (byte_b < 0x80) {
138
                /* 2-color encoding */
139
                flags = (byte_b << 8) | byte_a;
140
141
                CHECK_STREAM_PTR(2);
142
                colors[0] = s->buf[stream_ptr++];
143
                colors[1] = s->buf[stream_ptr++];
144
145
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
146
                    for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
147
                        pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
148
                    pixel_ptr -= row_dec;
149
                }
150
            } else if (byte_b >= 0x90) {
151
                /* 8-color encoding */
152
                flags = (byte_b << 8) | byte_a;
153
154
                CHECK_STREAM_PTR(8);
155
                memcpy(colors, &s->buf[stream_ptr], 8);
156
                stream_ptr += 8;
157
158
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
159
                    for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
160
                        pixels[pixel_ptr++] = 
161
                            colors[((pixel_y & 0x2) << 1) + 
162
                                (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
163
                    pixel_ptr -= row_dec;
164
                }
165
            } else {
166
                /* 1-color encoding */
167
                colors[0] = byte_a;
168
169
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
170
                    for (pixel_x = 0; pixel_x < 4; pixel_x++)
171
                        pixels[pixel_ptr++] = colors[0];
172
                    pixel_ptr -= row_dec;
173
                }
174
            }
175
176
            block_ptr += block_inc;
177
            total_blocks--;
178
        }
179
    }
180
181
    /* make the palette available on the way out */
182 875efafa Roberto Togni
    if (s->avctx->pix_fmt == PIX_FMT_PAL8) {
183
        memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
184
        if (s->avctx->palctrl->palette_changed) {
185
            s->frame.palette_has_changed = 1;
186
            s->avctx->palctrl->palette_changed = 0;
187
        }
188
    }
189 2fdf638b Mike Melanson
}
190
191
static void msvideo1_decode_16bit(Msvideo1Context *s)
192
{
193
    int block_ptr, pixel_ptr;
194
    int total_blocks;
195
    int pixel_x, pixel_y;  /* pixel width and height iterators */
196
    int block_x, block_y;  /* block width and height iterators */
197
    int blocks_wide, blocks_high;  /* width and height in 4x4 blocks */
198
    int block_inc;
199
    int row_dec;
200
201
    /* decoding parameters */
202
    int stream_ptr;
203
    unsigned char byte_a, byte_b;
204
    unsigned short flags;
205
    int skip_blocks;
206
    unsigned short colors[8];
207
    unsigned short *pixels = (unsigned short *)s->frame.data[0];
208
    int stride = s->frame.linesize[0] / 2;
209
210
    stream_ptr = 0;
211
    skip_blocks = 0;
212
    blocks_wide = s->avctx->width / 4;
213
    blocks_high = s->avctx->height / 4;
214
    total_blocks = blocks_wide * blocks_high;
215
    block_inc = 4;
216
    row_dec = stride + 4;
217
218
    for (block_y = blocks_high; block_y > 0; block_y--) {
219
        block_ptr = ((block_y * 4) - 1) * stride;
220
        for (block_x = blocks_wide; block_x > 0; block_x--) {
221
            /* check if this block should be skipped */
222
            if (skip_blocks) {
223
                block_ptr += block_inc;
224
                skip_blocks--;
225
                total_blocks--;
226
                continue;
227
            }
228
229
            pixel_ptr = block_ptr;
230
231
            /* get the next two bytes in the encoded data stream */
232
            CHECK_STREAM_PTR(2);
233
            byte_a = s->buf[stream_ptr++];
234
            byte_b = s->buf[stream_ptr++];
235
236
            /* check if the decode is finished */
237
            if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
238
                return;
239
            } else if ((byte_b & 0xFC) == 0x84) {
240
                /* skip code, but don't count the current block */
241
                skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
242
            } else if (byte_b < 0x80) {
243
                /* 2- or 8-color encoding modes */
244
                flags = (byte_b << 8) | byte_a;
245
246
                CHECK_STREAM_PTR(4);
247
                colors[0] = LE_16(&s->buf[stream_ptr]);
248
                stream_ptr += 2;
249
                colors[1] = LE_16(&s->buf[stream_ptr]);
250
                stream_ptr += 2;
251
252
                if (colors[0] & 0x8000) {
253
                    /* 8-color encoding */
254
                    CHECK_STREAM_PTR(12);
255
                    colors[2] = LE_16(&s->buf[stream_ptr]);
256
                    stream_ptr += 2;
257
                    colors[3] = LE_16(&s->buf[stream_ptr]);
258
                    stream_ptr += 2;
259
                    colors[4] = LE_16(&s->buf[stream_ptr]);
260
                    stream_ptr += 2;
261
                    colors[5] = LE_16(&s->buf[stream_ptr]);
262
                    stream_ptr += 2;
263
                    colors[6] = LE_16(&s->buf[stream_ptr]);
264
                    stream_ptr += 2;
265
                    colors[7] = LE_16(&s->buf[stream_ptr]);
266
                    stream_ptr += 2;
267
268
                    for (pixel_y = 0; pixel_y < 4; pixel_y++) {
269
                        for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
270
                            pixels[pixel_ptr++] = 
271
                                colors[((pixel_y & 0x2) << 1) + 
272
                                    (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
273
                        pixel_ptr -= row_dec;
274
                    }
275
                } else {
276
                    /* 2-color encoding */
277
                    for (pixel_y = 0; pixel_y < 4; pixel_y++) {
278
                        for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
279
                            pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
280
                        pixel_ptr -= row_dec;
281
                    }
282
                }
283
            } else {
284
                /* otherwise, it's a 1-color block */
285
                colors[0] = (byte_b << 8) | byte_a;
286
287
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
288
                    for (pixel_x = 0; pixel_x < 4; pixel_x++)
289
                        pixels[pixel_ptr++] = colors[0];
290
                    pixel_ptr -= row_dec;
291
                }
292
            }
293
294
            block_ptr += block_inc;
295
            total_blocks--;
296
        }
297
    }
298
}
299
300
static int msvideo1_decode_frame(AVCodecContext *avctx,
301
                                void *data, int *data_size,
302
                                uint8_t *buf, int buf_size)
303
{
304
    Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
305
306 e02c251e Roberto Togni
        /* no supplementary picture */
307
        if (buf_size == 0)
308
                return 0;
309
310 2fdf638b Mike Melanson
    s->buf = buf;
311
    s->size = buf_size;
312
313 e02c251e Roberto Togni
        s->frame.reference = 1;
314 e1c2a5a0 Roberto Togni
        s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
315
    if (avctx->reget_buffer(avctx, &s->frame)) {
316
        av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
317 2fdf638b Mike Melanson
        return -1;
318
    }
319
320
    if (s->mode_8bit)
321
        msvideo1_decode_8bit(s);
322
    else
323
        msvideo1_decode_16bit(s);
324
325
    *data_size = sizeof(AVFrame);
326
    *(AVFrame*)data = s->frame;
327
328
    /* report that the buffer was completely consumed */
329
    return buf_size;
330
}
331
332
static int msvideo1_decode_end(AVCodecContext *avctx)
333
{
334
    Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
335
336 e1c2a5a0 Roberto Togni
    if (s->frame.data[0])
337
        avctx->release_buffer(avctx, &s->frame);
338 2fdf638b Mike Melanson
339
    return 0;
340
}
341
342
AVCodec msvideo1_decoder = {
343
    "msvideo1",
344
    CODEC_TYPE_VIDEO,
345
    CODEC_ID_MSVIDEO1,
346
    sizeof(Msvideo1Context),
347
    msvideo1_decode_init,
348
    NULL,
349
    msvideo1_decode_end,
350
    msvideo1_decode_frame,
351 e1c2a5a0 Roberto Togni
    CODEC_CAP_DR1,
352 2fdf638b Mike Melanson
};