Update licensing information: The FSF changed postal address.
[ffmpeg.git] / libavcodec / msrle.c
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 palctrl.
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
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       av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \
54       return; \
55     } \
56     stream_byte = s->buf[stream_ptr++];
57
58 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                 if (i + 1 == rle_code && odd_pixel)
114                     break;
115                 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 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     /* 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     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                     av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
195                     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                     av_log(s->avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (2)\n");
202                     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                 av_log(s->avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (2)\n");
220                 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         av_log(s->avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n",
235             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     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                               uint8_t *buf, int buf_size)
254 {
255     MsrleContext *s = (MsrleContext *)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 = (MsrleContext *)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 };