Statistics
| Branch: | Revision:

ffmpeg / libavcodec / msrle.c @ bc0219fd

History | View | Annotate | Download (6.35 KB)

1
/*
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
 * BITMAPINFO header passed through extradata.
30
 */
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
    AVFrame prev_frame;
45

    
46
    unsigned char *buf;
47
    int size;
48

    
49
    unsigned int palette[256];
50
} MsrleContext;
51

    
52
#define FETCH_NEXT_STREAM_BYTE() \
53
    if (stream_ptr >= s->size) \
54
    { \
55
      printf(" 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_pal8(MsrleContext *s)
61
{
62
    int stream_ptr = 0;
63
    unsigned char rle_code;
64
    unsigned char extra_byte;
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

    
71
    while (row_ptr >= 0) {
72
        FETCH_NEXT_STREAM_BYTE();
73
        rle_code = stream_byte;
74
        if (rle_code == 0) {
75
            /* fetch the next byte to see how to handle escape code */
76
            FETCH_NEXT_STREAM_BYTE();
77
            if (stream_byte == 0) {
78
                /* line is done, goto the next one */
79
                row_ptr -= row_dec;
80
                pixel_ptr = 0;
81
            } else if (stream_byte == 1) {
82
                /* decode is done */
83
                return;
84
            } else if (stream_byte == 2) {
85
                /* reposition frame decode coordinates */
86
                FETCH_NEXT_STREAM_BYTE();
87
                pixel_ptr += stream_byte;
88
                FETCH_NEXT_STREAM_BYTE();
89
                row_ptr -= stream_byte * row_dec;
90
            } else {
91
                /* copy pixels from encoded stream */
92
                if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
93
                    (row_ptr < 0)) {
94
                    printf(" MS RLE: frame ptr just went out of bounds (1)\n");
95
                    return;
96
                }
97

    
98
                rle_code = stream_byte;
99
                extra_byte = stream_byte & 0x01;
100
                if (stream_ptr + rle_code + extra_byte > s->size) {
101
                    printf(" MS RLE: stream ptr just went out of bounds (2)\n");
102
                    return;
103
                }
104

    
105
                while (rle_code--) {
106
                    FETCH_NEXT_STREAM_BYTE();
107
                    s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
108
                    pixel_ptr++;
109
                }
110

    
111
                /* if the RLE code is odd, skip a byte in the stream */
112
                if (extra_byte)
113
                    stream_ptr++;
114
            }
115
        } else {
116
            /* decode a run of data */
117
            if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
118
                (row_ptr < 0)) {
119
                printf(" MS RLE: frame ptr just went out of bounds (2)\n");
120
                return;
121
            }
122

    
123
            FETCH_NEXT_STREAM_BYTE();
124

    
125
            while(rle_code--) {
126
                s->frame.data[0][row_ptr + pixel_ptr] = stream_byte;
127
                pixel_ptr++;
128
            }
129
        }
130
    }
131

    
132
    /* make the palette available */
133
    memcpy(s->frame.data[1], s->palette, 256 * 4);
134

    
135
    /* one last sanity check on the way out */
136
    if (stream_ptr < s->size)
137
        printf(" MS RLE: ended frame decode with bytes left over (%d < %d)\n",
138
            stream_ptr, s->size);
139
}
140

    
141
static int msrle_decode_init(AVCodecContext *avctx)
142
{
143
    MsrleContext *s = (MsrleContext *)avctx->priv_data;
144
    int i, j;
145
    unsigned char *palette;
146

    
147
    s->avctx = avctx;
148

    
149
    avctx->pix_fmt = PIX_FMT_PAL8;
150
    avctx->has_b_frames = 0;
151
    s->frame.data[0] = s->prev_frame.data[0] = NULL;
152

    
153
    /* convert palette */
154
    palette = (unsigned char *)s->avctx->extradata;
155
    memset (s->palette, 0, 256 * 4);
156
    for (i = 0, j = 0; i < s->avctx->extradata_size / 4; i++, j += 4)
157
        s->palette[i] = 
158
            (palette[j + 2] << 16) |
159
            (palette[j + 1] <<  8) |
160
            (palette[j + 0] <<  0);
161

    
162
    return 0;
163
}
164

    
165
static int msrle_decode_frame(AVCodecContext *avctx,
166
                              void *data, int *data_size,
167
                              uint8_t *buf, int buf_size)
168
{
169
    MsrleContext *s = (MsrleContext *)avctx->priv_data;
170

    
171
    s->buf = buf;
172
    s->size = buf_size;
173

    
174
    if (avctx->get_buffer(avctx, &s->frame)) {
175
        printf ("  MS RLE: get_buffer() failed\n");
176
        return -1;
177
    }
178

    
179
    /* grossly inefficient, but...oh well */
180
    if (s->prev_frame.data[0] != NULL)
181
        memcpy(s->frame.data[0], s->prev_frame.data[0], 
182
        s->frame.linesize[0] * s->avctx->height);
183

    
184
    msrle_decode_pal8(s);
185

    
186
    if (s->frame.data[0])
187
        avctx->release_buffer(avctx, &s->frame);
188

    
189
    /* shuffle frames */
190
    s->prev_frame = s->frame;
191

    
192
    *data_size = sizeof(AVFrame);
193
    *(AVFrame*)data = s->frame;
194

    
195
    /* report that the buffer was completely consumed */
196
    return buf_size;
197
}
198

    
199
static int msrle_decode_end(AVCodecContext *avctx)
200
{
201
    MsrleContext *s = (MsrleContext *)avctx->priv_data;
202

    
203
    /* release the last frame */
204
    if (s->prev_frame.data[0])
205
        avctx->release_buffer(avctx, &s->prev_frame);
206

    
207
    return 0;
208
}
209

    
210
AVCodec msrle_decoder = {
211
    "msrle",
212
    CODEC_TYPE_VIDEO,
213
    CODEC_ID_MSRLE,
214
    sizeof(MsrleContext),
215
    msrle_decode_init,
216
    NULL,
217
    msrle_decode_end,
218
    msrle_decode_frame,
219
    CODEC_CAP_DR1,
220
};