Statistics
| Branch: | Revision:

ffmpeg / libavcodec / msvideo1.c @ 2912e87a

History | View | Annotate | Download (11.1 KB)

1
/*
2
 * Microsoft Video-1 Decoder
3
 * Copyright (C) 2003 the ffmpeg project
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
 * Microsoft Video-1 Decoder by Mike Melanson (melanson@pcisys.net)
25
 * For more information about the MS Video-1 format, visit:
26
 *   http://www.pcisys.net/~melanson/codecs/
27
 *
28
 * This decoder outputs either PAL8 or RGB555 data, depending on the
29
 * whether a RGB palette was passed through palctrl;
30
 * if it's present, then the data is PAL8; RGB555 otherwise.
31
 */
32

    
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36

    
37
#include "libavutil/intreadwrite.h"
38
#include "avcodec.h"
39

    
40
#define PALETTE_COUNT 256
41
#define CHECK_STREAM_PTR(n) \
42
  if ((stream_ptr + n) > s->size ) { \
43
    av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \
44
      stream_ptr + n, s->size); \
45
    return; \
46
  }
47

    
48
typedef struct Msvideo1Context {
49

    
50
    AVCodecContext *avctx;
51
    AVFrame frame;
52

    
53
    const unsigned char *buf;
54
    int size;
55

    
56
    int mode_8bit;  /* if it's not 8-bit, it's 16-bit */
57

    
58
} Msvideo1Context;
59

    
60
static av_cold int msvideo1_decode_init(AVCodecContext *avctx)
61
{
62
    Msvideo1Context *s = avctx->priv_data;
63

    
64
    s->avctx = avctx;
65

    
66
    /* figure out the colorspace based on the presence of a palette */
67
    if (s->avctx->palctrl) {
68
        s->mode_8bit = 1;
69
        avctx->pix_fmt = PIX_FMT_PAL8;
70
    } else {
71
        s->mode_8bit = 0;
72
        avctx->pix_fmt = PIX_FMT_RGB555;
73
    }
74

    
75
    s->frame.data[0] = NULL;
76

    
77
    return 0;
78
}
79

    
80
static void msvideo1_decode_8bit(Msvideo1Context *s)
81
{
82
    int block_ptr, pixel_ptr;
83
    int total_blocks;
84
    int pixel_x, pixel_y;  /* pixel width and height iterators */
85
    int block_x, block_y;  /* block width and height iterators */
86
    int blocks_wide, blocks_high;  /* width and height in 4x4 blocks */
87
    int block_inc;
88
    int row_dec;
89

    
90
    /* decoding parameters */
91
    int stream_ptr;
92
    unsigned char byte_a, byte_b;
93
    unsigned short flags;
94
    int skip_blocks;
95
    unsigned char colors[8];
96
    unsigned char *pixels = s->frame.data[0];
97
    int stride = s->frame.linesize[0];
98

    
99
    stream_ptr = 0;
100
    skip_blocks = 0;
101
    blocks_wide = s->avctx->width / 4;
102
    blocks_high = s->avctx->height / 4;
103
    total_blocks = blocks_wide * blocks_high;
104
    block_inc = 4;
105
    row_dec = stride + 4;
106

    
107
    for (block_y = blocks_high; block_y > 0; block_y--) {
108
        block_ptr = ((block_y * 4) - 1) * stride;
109
        for (block_x = blocks_wide; block_x > 0; block_x--) {
110
            /* check if this block should be skipped */
111
            if (skip_blocks) {
112
                block_ptr += block_inc;
113
                skip_blocks--;
114
                total_blocks--;
115
                continue;
116
            }
117

    
118
            pixel_ptr = block_ptr;
119

    
120
            /* get the next two bytes in the encoded data stream */
121
            CHECK_STREAM_PTR(2);
122
            byte_a = s->buf[stream_ptr++];
123
            byte_b = s->buf[stream_ptr++];
124

    
125
            /* check if the decode is finished */
126
            if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
127
                return;
128
            else if ((byte_b & 0xFC) == 0x84) {
129
                /* skip code, but don't count the current block */
130
                skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
131
            } else if (byte_b < 0x80) {
132
                /* 2-color encoding */
133
                flags = (byte_b << 8) | byte_a;
134

    
135
                CHECK_STREAM_PTR(2);
136
                colors[0] = s->buf[stream_ptr++];
137
                colors[1] = s->buf[stream_ptr++];
138

    
139
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
140
                    for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
141
                        pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
142
                    pixel_ptr -= row_dec;
143
                }
144
            } else if (byte_b >= 0x90) {
145
                /* 8-color encoding */
146
                flags = (byte_b << 8) | byte_a;
147

    
148
                CHECK_STREAM_PTR(8);
149
                memcpy(colors, &s->buf[stream_ptr], 8);
150
                stream_ptr += 8;
151

    
152
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
153
                    for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
154
                        pixels[pixel_ptr++] =
155
                            colors[((pixel_y & 0x2) << 1) +
156
                                (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
157
                    pixel_ptr -= row_dec;
158
                }
159
            } else {
160
                /* 1-color encoding */
161
                colors[0] = byte_a;
162

    
163
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
164
                    for (pixel_x = 0; pixel_x < 4; pixel_x++)
165
                        pixels[pixel_ptr++] = colors[0];
166
                    pixel_ptr -= row_dec;
167
                }
168
            }
169

    
170
            block_ptr += block_inc;
171
            total_blocks--;
172
        }
173
    }
174

    
175
    /* make the palette available on the way out */
176
    if (s->avctx->pix_fmt == PIX_FMT_PAL8) {
177
        memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
178
        if (s->avctx->palctrl->palette_changed) {
179
            s->frame.palette_has_changed = 1;
180
            s->avctx->palctrl->palette_changed = 0;
181
        }
182
    }
183
}
184

    
185
static void msvideo1_decode_16bit(Msvideo1Context *s)
186
{
187
    int block_ptr, pixel_ptr;
188
    int total_blocks;
189
    int pixel_x, pixel_y;  /* pixel width and height iterators */
190
    int block_x, block_y;  /* block width and height iterators */
191
    int blocks_wide, blocks_high;  /* width and height in 4x4 blocks */
192
    int block_inc;
193
    int row_dec;
194

    
195
    /* decoding parameters */
196
    int stream_ptr;
197
    unsigned char byte_a, byte_b;
198
    unsigned short flags;
199
    int skip_blocks;
200
    unsigned short colors[8];
201
    unsigned short *pixels = (unsigned short *)s->frame.data[0];
202
    int stride = s->frame.linesize[0] / 2;
203

    
204
    stream_ptr = 0;
205
    skip_blocks = 0;
206
    blocks_wide = s->avctx->width / 4;
207
    blocks_high = s->avctx->height / 4;
208
    total_blocks = blocks_wide * blocks_high;
209
    block_inc = 4;
210
    row_dec = stride + 4;
211

    
212
    for (block_y = blocks_high; block_y > 0; block_y--) {
213
        block_ptr = ((block_y * 4) - 1) * stride;
214
        for (block_x = blocks_wide; block_x > 0; block_x--) {
215
            /* check if this block should be skipped */
216
            if (skip_blocks) {
217
                block_ptr += block_inc;
218
                skip_blocks--;
219
                total_blocks--;
220
                continue;
221
            }
222

    
223
            pixel_ptr = block_ptr;
224

    
225
            /* get the next two bytes in the encoded data stream */
226
            CHECK_STREAM_PTR(2);
227
            byte_a = s->buf[stream_ptr++];
228
            byte_b = s->buf[stream_ptr++];
229

    
230
            /* check if the decode is finished */
231
            if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
232
                return;
233
            } else if ((byte_b & 0xFC) == 0x84) {
234
                /* skip code, but don't count the current block */
235
                skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
236
            } else if (byte_b < 0x80) {
237
                /* 2- or 8-color encoding modes */
238
                flags = (byte_b << 8) | byte_a;
239

    
240
                CHECK_STREAM_PTR(4);
241
                colors[0] = AV_RL16(&s->buf[stream_ptr]);
242
                stream_ptr += 2;
243
                colors[1] = AV_RL16(&s->buf[stream_ptr]);
244
                stream_ptr += 2;
245

    
246
                if (colors[0] & 0x8000) {
247
                    /* 8-color encoding */
248
                    CHECK_STREAM_PTR(12);
249
                    colors[2] = AV_RL16(&s->buf[stream_ptr]);
250
                    stream_ptr += 2;
251
                    colors[3] = AV_RL16(&s->buf[stream_ptr]);
252
                    stream_ptr += 2;
253
                    colors[4] = AV_RL16(&s->buf[stream_ptr]);
254
                    stream_ptr += 2;
255
                    colors[5] = AV_RL16(&s->buf[stream_ptr]);
256
                    stream_ptr += 2;
257
                    colors[6] = AV_RL16(&s->buf[stream_ptr]);
258
                    stream_ptr += 2;
259
                    colors[7] = AV_RL16(&s->buf[stream_ptr]);
260
                    stream_ptr += 2;
261

    
262
                    for (pixel_y = 0; pixel_y < 4; pixel_y++) {
263
                        for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
264
                            pixels[pixel_ptr++] =
265
                                colors[((pixel_y & 0x2) << 1) +
266
                                    (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
267
                        pixel_ptr -= row_dec;
268
                    }
269
                } else {
270
                    /* 2-color encoding */
271
                    for (pixel_y = 0; pixel_y < 4; pixel_y++) {
272
                        for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
273
                            pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
274
                        pixel_ptr -= row_dec;
275
                    }
276
                }
277
            } else {
278
                /* otherwise, it's a 1-color block */
279
                colors[0] = (byte_b << 8) | byte_a;
280

    
281
                for (pixel_y = 0; pixel_y < 4; pixel_y++) {
282
                    for (pixel_x = 0; pixel_x < 4; pixel_x++)
283
                        pixels[pixel_ptr++] = colors[0];
284
                    pixel_ptr -= row_dec;
285
                }
286
            }
287

    
288
            block_ptr += block_inc;
289
            total_blocks--;
290
        }
291
    }
292
}
293

    
294
static int msvideo1_decode_frame(AVCodecContext *avctx,
295
                                void *data, int *data_size,
296
                                AVPacket *avpkt)
297
{
298
    const uint8_t *buf = avpkt->data;
299
    int buf_size = avpkt->size;
300
    Msvideo1Context *s = avctx->priv_data;
301

    
302
    s->buf = buf;
303
    s->size = buf_size;
304

    
305
    s->frame.reference = 1;
306
    s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
307
    if (avctx->reget_buffer(avctx, &s->frame)) {
308
        av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
309
        return -1;
310
    }
311

    
312
    if (s->mode_8bit)
313
        msvideo1_decode_8bit(s);
314
    else
315
        msvideo1_decode_16bit(s);
316

    
317
    *data_size = sizeof(AVFrame);
318
    *(AVFrame*)data = s->frame;
319

    
320
    /* report that the buffer was completely consumed */
321
    return buf_size;
322
}
323

    
324
static av_cold int msvideo1_decode_end(AVCodecContext *avctx)
325
{
326
    Msvideo1Context *s = avctx->priv_data;
327

    
328
    if (s->frame.data[0])
329
        avctx->release_buffer(avctx, &s->frame);
330

    
331
    return 0;
332
}
333

    
334
AVCodec ff_msvideo1_decoder = {
335
    "msvideo1",
336
    AVMEDIA_TYPE_VIDEO,
337
    CODEC_ID_MSVIDEO1,
338
    sizeof(Msvideo1Context),
339
    msvideo1_decode_init,
340
    NULL,
341
    msvideo1_decode_end,
342
    msvideo1_decode_frame,
343
    CODEC_CAP_DR1,
344
    .long_name= NULL_IF_CONFIG_SMALL("Microsoft Video 1"),
345
};