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