Statistics
| Branch: | Revision:

ffmpeg / libavcodec / msrle.c @ e4141433

History | View | Annotate | Download (9.61 KB)

1
/*
2
 * Micrsoft RLE Video Decoder
3
 * Copyright (C) 2003 the ffmpeg project
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 msrle.c
24
 * MS RLE Video Decoder by Mike Melanson (melanson@pcisys.net)
25
 * For more information about the MS RLE format, visit:
26
 *   http://www.pcisys.net/~melanson/codecs/
27
 *
28
 * The MS RLE decoder outputs PAL8 colorspace data.
29
 *
30
 * Note that this decoder expects the palette colors from the end of the
31
 * BITMAPINFO header passed through palctrl.
32
 */
33

    
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38

    
39
#include "common.h"
40
#include "avcodec.h"
41
#include "dsputil.h"
42

    
43
typedef struct MsrleContext {
44
    AVCodecContext *avctx;
45
    AVFrame frame;
46

    
47
    unsigned char *buf;
48
    int size;
49

    
50
} MsrleContext;
51

    
52
#define FETCH_NEXT_STREAM_BYTE() \
53
    if (stream_ptr >= s->size) \
54
    { \
55
      av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \
56
      return; \
57
    } \
58
    stream_byte = s->buf[stream_ptr++];
59

    
60
static void msrle_decode_pal4(MsrleContext *s)
61
{
62
    int stream_ptr = 0;
63
    unsigned char rle_code;
64
    unsigned char extra_byte, odd_pixel;
65
    unsigned char stream_byte;
66
    int pixel_ptr = 0;
67
    int row_dec = s->frame.linesize[0];
68
    int row_ptr = (s->avctx->height - 1) * row_dec;
69
    int frame_size = row_dec * s->avctx->height;
70
    int i;
71

    
72
    /* make the palette available */
73
    memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
74
    if (s->avctx->palctrl->palette_changed) {
75
        s->frame.palette_has_changed = 1;
76
        s->avctx->palctrl->palette_changed = 0;
77
    }
78

    
79
    while (row_ptr >= 0) {
80
        FETCH_NEXT_STREAM_BYTE();
81
        rle_code = stream_byte;
82
        if (rle_code == 0) {
83
            /* fetch the next byte to see how to handle escape code */
84
            FETCH_NEXT_STREAM_BYTE();
85
            if (stream_byte == 0) {
86
                /* line is done, goto the next one */
87
                row_ptr -= row_dec;
88
                pixel_ptr = 0;
89
            } else if (stream_byte == 1) {
90
                /* decode is done */
91
                return;
92
            } else if (stream_byte == 2) {
93
                /* reposition frame decode coordinates */
94
                FETCH_NEXT_STREAM_BYTE();
95
                pixel_ptr += stream_byte;
96
                FETCH_NEXT_STREAM_BYTE();
97
                row_ptr -= stream_byte * row_dec;
98
        } else {
99
            // copy pixels from encoded stream
100
            odd_pixel =  stream_byte & 1;
101
            rle_code = (stream_byte + 1) / 2;
102
            extra_byte = rle_code & 0x01;
103
            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
104
                (row_ptr < 0)) {
105
                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
106
                return;
107
            }
108

    
109
            for (i = 0; i < rle_code; i++) {
110
                if (pixel_ptr >= s->avctx->width)
111
                    break;
112
                FETCH_NEXT_STREAM_BYTE();
113
                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
114
                pixel_ptr++;
115
                if (i + 1 == rle_code && odd_pixel)
116
                    break;
117
                if (pixel_ptr >= s->avctx->width)
118
                    break;
119
                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
120
                pixel_ptr++;
121
            }
122

    
123
            // if the RLE code is odd, skip a byte in the stream
124
            if (extra_byte)
125
              stream_ptr++;
126
            }
127
        } else {
128
            // decode a run of data
129
            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
130
                (row_ptr < 0)) {
131
                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
132
                return;
133
            }
134
            FETCH_NEXT_STREAM_BYTE();
135
            for (i = 0; i < rle_code; i++) {
136
                if (pixel_ptr >= s->avctx->width)
137
                    break;
138
                if ((i & 1) == 0)
139
                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
140
                else
141
                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
142
                pixel_ptr++;
143
            }
144
        }
145
    }
146

    
147
    /* one last sanity check on the way out */
148
    if (stream_ptr < s->size)
149
        av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n",
150
            stream_ptr, s->size);
151
}
152

    
153

    
154

    
155
static void msrle_decode_pal8(MsrleContext *s)
156
{
157
    int stream_ptr = 0;
158
    unsigned char rle_code;
159
    unsigned char extra_byte;
160
    unsigned char stream_byte;
161
    int pixel_ptr = 0;
162
    int row_dec = s->frame.linesize[0];
163
    int row_ptr = (s->avctx->height - 1) * row_dec;
164
    int frame_size = row_dec * s->avctx->height;
165

    
166
    /* make the palette available */
167
    memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
168
    if (s->avctx->palctrl->palette_changed) {
169
        s->frame.palette_has_changed = 1;
170
        s->avctx->palctrl->palette_changed = 0;
171
    }
172

    
173
    while (row_ptr >= 0) {
174
        FETCH_NEXT_STREAM_BYTE();
175
        rle_code = stream_byte;
176
        if (rle_code == 0) {
177
            /* fetch the next byte to see how to handle escape code */
178
            FETCH_NEXT_STREAM_BYTE();
179
            if (stream_byte == 0) {
180
                /* line is done, goto the next one */
181
                row_ptr -= row_dec;
182
                pixel_ptr = 0;
183
            } else if (stream_byte == 1) {
184
                /* decode is done */
185
                return;
186
            } else if (stream_byte == 2) {
187
                /* reposition frame decode coordinates */
188
                FETCH_NEXT_STREAM_BYTE();
189
                pixel_ptr += stream_byte;
190
                FETCH_NEXT_STREAM_BYTE();
191
                row_ptr -= stream_byte * row_dec;
192
            } else {
193
                /* copy pixels from encoded stream */
194
                if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
195
                    (row_ptr < 0)) {
196
                    av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
197
                    return;
198
                }
199

    
200
                rle_code = stream_byte;
201
                extra_byte = stream_byte & 0x01;
202
                if (stream_ptr + rle_code + extra_byte > s->size) {
203
                    av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (2)\n");
204
                    return;
205
                }
206

    
207
                while (rle_code--) {
208
                    FETCH_NEXT_STREAM_BYTE();
209
                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
210
                    pixel_ptr++;
211
                }
212

    
213
                /* if the RLE code is odd, skip a byte in the stream */
214
                if (extra_byte)
215
                    stream_ptr++;
216
            }
217
        } else {
218
            /* decode a run of data */
219
            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
220
                (row_ptr < 0)) {
221
                av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (2)\n");
222
                return;
223
            }
224

    
225
            FETCH_NEXT_STREAM_BYTE();
226

    
227
            while(rle_code--) {
228
                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
229
                pixel_ptr++;
230
            }
231
        }
232
    }
233

    
234
    /* one last sanity check on the way out */
235
    if (stream_ptr < s->size)
236
        av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n",
237
            stream_ptr, s->size);
238
}
239

    
240
static int msrle_decode_init(AVCodecContext *avctx)
241
{
242
    MsrleContext *s = avctx->priv_data;
243

    
244
    s->avctx = avctx;
245

    
246
    avctx->pix_fmt = PIX_FMT_PAL8;
247
    s->frame.data[0] = NULL;
248

    
249
    return 0;
250
}
251

    
252
static int msrle_decode_frame(AVCodecContext *avctx,
253
                              void *data, int *data_size,
254
                              uint8_t *buf, int buf_size)
255
{
256
    MsrleContext *s = avctx->priv_data;
257

    
258
    s->buf = buf;
259
    s->size = buf_size;
260

    
261
    s->frame.reference = 1;
262
    s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
263
    if (avctx->reget_buffer(avctx, &s->frame)) {
264
        av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
265
        return -1;
266
    }
267

    
268
    switch (avctx->bits_per_sample) {
269
        case 8:
270
            msrle_decode_pal8(s);
271
            break;
272
        case 4:
273
            msrle_decode_pal4(s);
274
            break;
275
        default:
276
            av_log(avctx, AV_LOG_ERROR, "Don't know how to decode depth %u.\n",
277
                   avctx->bits_per_sample);
278
    }
279

    
280
    *data_size = sizeof(AVFrame);
281
    *(AVFrame*)data = s->frame;
282

    
283
    /* report that the buffer was completely consumed */
284
    return buf_size;
285
}
286

    
287
static int msrle_decode_end(AVCodecContext *avctx)
288
{
289
    MsrleContext *s = avctx->priv_data;
290

    
291
    /* release the last frame */
292
    if (s->frame.data[0])
293
        avctx->release_buffer(avctx, &s->frame);
294

    
295
    return 0;
296
}
297

    
298
AVCodec msrle_decoder = {
299
    "msrle",
300
    CODEC_TYPE_VIDEO,
301
    CODEC_ID_MSRLE,
302
    sizeof(MsrleContext),
303
    msrle_decode_init,
304
    NULL,
305
    msrle_decode_end,
306
    msrle_decode_frame,
307
    CODEC_CAP_DR1,
308
};