Statistics
| Branch: | Revision:

ffmpeg / libavcodec / msrle.c @ 58c2182d

History | View | Annotate | Download (9.73 KB)

1 2fdf638b Mike Melanson
/*
2
 * Micrsoft RLE Video 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
 * @file msrle.c
22
 * MS RLE Video Decoder by Mike Melanson (melanson@pcisys.net)
23
 * For more information about the MS RLE format, visit:
24
 *   http://www.pcisys.net/~melanson/codecs/
25
 *
26
 * The MS RLE decoder outputs PAL8 colorspace data.
27
 *
28
 * Note that this decoder expects the palette colors from the end of the
29 875efafa Roberto Togni
 * BITMAPINFO header passed through palctrl.
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
typedef struct MsrleContext {
42
    AVCodecContext *avctx;
43
    AVFrame frame;
44
45
    unsigned char *buf;
46
    int size;
47
48
} MsrleContext;
49
50
#define FETCH_NEXT_STREAM_BYTE() \
51
    if (stream_ptr >= s->size) \
52
    { \
53 9b879566 Michel Bardiaux
      av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \
54 2fdf638b Mike Melanson
      return; \
55
    } \
56
    stream_byte = s->buf[stream_ptr++];
57
58 aa39a622 Roberto Togni
static void msrle_decode_pal4(MsrleContext *s)
59
{
60
    int stream_ptr = 0;
61
    unsigned char rle_code;
62
    unsigned char extra_byte, odd_pixel;
63
    unsigned char stream_byte;
64
    int pixel_ptr = 0;
65
    int row_dec = s->frame.linesize[0];
66
    int row_ptr = (s->avctx->height - 1) * row_dec;
67
    int frame_size = row_dec * s->avctx->height;
68
    int i;
69
70
    /* make the palette available */
71
    memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
72
    if (s->avctx->palctrl->palette_changed) {
73
        s->frame.palette_has_changed = 1;
74
        s->avctx->palctrl->palette_changed = 0;
75
    }
76
77
    while (row_ptr >= 0) {
78
        FETCH_NEXT_STREAM_BYTE();
79
        rle_code = stream_byte;
80
        if (rle_code == 0) {
81
            /* fetch the next byte to see how to handle escape code */
82
            FETCH_NEXT_STREAM_BYTE();
83
            if (stream_byte == 0) {
84
                /* line is done, goto the next one */
85
                row_ptr -= row_dec;
86
                pixel_ptr = 0;
87
            } else if (stream_byte == 1) {
88
                /* decode is done */
89
                return;
90
            } else if (stream_byte == 2) {
91
                /* reposition frame decode coordinates */
92
                FETCH_NEXT_STREAM_BYTE();
93
                pixel_ptr += stream_byte;
94
                FETCH_NEXT_STREAM_BYTE();
95
                row_ptr -= stream_byte * row_dec;
96
        } else {
97
            // copy pixels from encoded stream
98
            odd_pixel =  stream_byte & 1;
99
            rle_code = (stream_byte + 1) / 2;
100
            extra_byte = rle_code & 0x01;
101
            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
102
                (row_ptr < 0)) {
103
                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
104
                return;
105
            }
106
107
            for (i = 0; i < rle_code; i++) {
108
                if (pixel_ptr >= s->avctx->width)
109
                    break;
110
                FETCH_NEXT_STREAM_BYTE();
111
                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
112
                pixel_ptr++;
113 155aa417 Mike Melanson
                if (i + 1 == rle_code && odd_pixel)
114
                    break;
115 aa39a622 Roberto Togni
                if (pixel_ptr >= s->avctx->width)
116
                    break;
117
                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
118
                pixel_ptr++;
119
            }
120
121
            // if the RLE code is odd, skip a byte in the stream
122
            if (extra_byte)
123
              stream_ptr++;
124
            }
125
        } else {
126
            // decode a run of data
127
            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
128
                (row_ptr < 0)) {
129
                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
130
                return;
131
            }
132
            FETCH_NEXT_STREAM_BYTE();
133
            for (i = 0; i < rle_code; i++) {
134
                if (pixel_ptr >= s->avctx->width)
135
                    break;
136
                if ((i & 1) == 0)
137
                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
138
                else
139
                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
140
                pixel_ptr++;
141
            }
142
        }
143
    }
144
145
    /* one last sanity check on the way out */
146
    if (stream_ptr < s->size)
147
        av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n",
148
            stream_ptr, s->size);
149
}
150
151
152
153 2fdf638b Mike Melanson
static void msrle_decode_pal8(MsrleContext *s)
154
{
155
    int stream_ptr = 0;
156
    unsigned char rle_code;
157
    unsigned char extra_byte;
158
    unsigned char stream_byte;
159
    int pixel_ptr = 0;
160
    int row_dec = s->frame.linesize[0];
161
    int row_ptr = (s->avctx->height - 1) * row_dec;
162
    int frame_size = row_dec * s->avctx->height;
163
164 1d768c3c Roberto Togni
    /* make the palette available */
165
    memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
166
    if (s->avctx->palctrl->palette_changed) {
167
        s->frame.palette_has_changed = 1;
168
        s->avctx->palctrl->palette_changed = 0;
169
    }
170
171 2fdf638b Mike Melanson
    while (row_ptr >= 0) {
172
        FETCH_NEXT_STREAM_BYTE();
173
        rle_code = stream_byte;
174
        if (rle_code == 0) {
175
            /* fetch the next byte to see how to handle escape code */
176
            FETCH_NEXT_STREAM_BYTE();
177
            if (stream_byte == 0) {
178
                /* line is done, goto the next one */
179
                row_ptr -= row_dec;
180
                pixel_ptr = 0;
181
            } else if (stream_byte == 1) {
182
                /* decode is done */
183
                return;
184
            } else if (stream_byte == 2) {
185
                /* reposition frame decode coordinates */
186
                FETCH_NEXT_STREAM_BYTE();
187
                pixel_ptr += stream_byte;
188
                FETCH_NEXT_STREAM_BYTE();
189
                row_ptr -= stream_byte * row_dec;
190
            } else {
191
                /* copy pixels from encoded stream */
192
                if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
193
                    (row_ptr < 0)) {
194 9b879566 Michel Bardiaux
                    av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
195 2fdf638b Mike Melanson
                    return;
196
                }
197
198
                rle_code = stream_byte;
199
                extra_byte = stream_byte & 0x01;
200
                if (stream_ptr + rle_code + extra_byte > s->size) {
201 9b879566 Michel Bardiaux
                    av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (2)\n");
202 2fdf638b Mike Melanson
                    return;
203
                }
204
205
                while (rle_code--) {
206
                    FETCH_NEXT_STREAM_BYTE();
207
                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
208
                    pixel_ptr++;
209
                }
210
211
                /* if the RLE code is odd, skip a byte in the stream */
212
                if (extra_byte)
213
                    stream_ptr++;
214
            }
215
        } else {
216
            /* decode a run of data */
217
            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
218
                (row_ptr < 0)) {
219 9b879566 Michel Bardiaux
                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (2)\n");
220 2fdf638b Mike Melanson
                return;
221
            }
222
223
            FETCH_NEXT_STREAM_BYTE();
224
225
            while(rle_code--) {
226
                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
227
                pixel_ptr++;
228
            }
229
        }
230
    }
231
232
    /* one last sanity check on the way out */
233
    if (stream_ptr < s->size)
234 9b879566 Michel Bardiaux
        av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n",
235 2fdf638b Mike Melanson
            stream_ptr, s->size);
236
}
237
238
static int msrle_decode_init(AVCodecContext *avctx)
239
{
240
    MsrleContext *s = (MsrleContext *)avctx->priv_data;
241
242
    s->avctx = avctx;
243
244
    avctx->pix_fmt = PIX_FMT_PAL8;
245
    avctx->has_b_frames = 0;
246 e1c2a5a0 Roberto Togni
    s->frame.data[0] = NULL;
247 2fdf638b Mike Melanson
248
    return 0;
249
}
250
251
static int msrle_decode_frame(AVCodecContext *avctx,
252
                              void *data, int *data_size,
253
                              uint8_t *buf, int buf_size)
254
{
255
    MsrleContext *s = (MsrleContext *)avctx->priv_data;
256
257 155aa417 Mike Melanson
    /* no supplementary picture */
258
    if (buf_size == 0)
259
        return 0;
260 e02c251e Roberto Togni
261 2fdf638b Mike Melanson
    s->buf = buf;
262
    s->size = buf_size;
263
264 04939fb7 Roberto Togni
    s->frame.reference = 1;
265 e1c2a5a0 Roberto Togni
    s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
266
    if (avctx->reget_buffer(avctx, &s->frame)) {
267
        av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
268 2fdf638b Mike Melanson
        return -1;
269
    }
270
271 aa39a622 Roberto Togni
    switch (avctx->bits_per_sample) {
272
        case 8:
273
            msrle_decode_pal8(s);
274
            break;
275
        case 4:
276
            msrle_decode_pal4(s);
277
            break;
278
        default:
279
            av_log(avctx, AV_LOG_ERROR, "Don't know how to decode depth %u.\n",
280
                   avctx->bits_per_sample);
281
    }
282 2fdf638b Mike Melanson
283
    *data_size = sizeof(AVFrame);
284
    *(AVFrame*)data = s->frame;
285
286
    /* report that the buffer was completely consumed */
287
    return buf_size;
288
}
289
290
static int msrle_decode_end(AVCodecContext *avctx)
291
{
292
    MsrleContext *s = (MsrleContext *)avctx->priv_data;
293
294
    /* release the last frame */
295 e1c2a5a0 Roberto Togni
    if (s->frame.data[0])
296
        avctx->release_buffer(avctx, &s->frame);
297 2fdf638b Mike Melanson
298
    return 0;
299
}
300
301
AVCodec msrle_decoder = {
302
    "msrle",
303
    CODEC_TYPE_VIDEO,
304
    CODEC_ID_MSRLE,
305
    sizeof(MsrleContext),
306
    msrle_decode_init,
307
    NULL,
308
    msrle_decode_end,
309
    msrle_decode_frame,
310 e1c2a5a0 Roberto Togni
    CODEC_CAP_DR1,
311 2fdf638b Mike Melanson
};