4bpp support
[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., 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 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     AVFrame prev_frame;
45
46     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 = (MsrleContext *)avctx->priv_data;
242
243     s->avctx = avctx;
244
245     avctx->pix_fmt = PIX_FMT_PAL8;
246     avctx->has_b_frames = 0;
247     s->frame.data[0] = s->prev_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 = (MsrleContext *)avctx->priv_data;
257
258         /* no supplementary picture */
259         if (buf_size == 0)
260                 return 0;
261
262     s->buf = buf;
263     s->size = buf_size;
264
265     s->frame.reference = 1;
266     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE;
267     if (avctx->cr_available)
268         s->frame.buffer_hints |= FF_BUFFER_HINTS_REUSABLE;
269     else
270         s->frame.buffer_hints |= FF_BUFFER_HINTS_READABLE;
271     if (avctx->get_buffer(avctx, &s->frame)) {
272         av_log(avctx, AV_LOG_ERROR, "  MS RLE: get_buffer() failed\n");
273         return -1;
274     }
275
276     if (s->prev_frame.data[0] && (s->frame.linesize[0] != s->prev_frame.linesize[0]))
277         av_log(avctx, AV_LOG_ERROR, "  MS RLE: Buffer linesize changed: current %u, previous %u.\n"
278                 "          Expect wrong image and/or crash!\n",
279                 s->frame.linesize[0], s->prev_frame.linesize[0]);
280
281     /* grossly inefficient, but...oh well */
282     if (s->prev_frame.data[0] != NULL)
283         memcpy(s->frame.data[0], s->prev_frame.data[0], 
284         s->frame.linesize[0] * s->avctx->height);
285
286     switch (avctx->bits_per_sample) {
287         case 8:
288             msrle_decode_pal8(s);
289             break;
290         case 4:
291             msrle_decode_pal4(s);
292             break;
293         default:
294             av_log(avctx, AV_LOG_ERROR, "Don't know how to decode depth %u.\n",
295                    avctx->bits_per_sample);
296     }
297
298     if (s->prev_frame.data[0])
299         avctx->release_buffer(avctx, &s->prev_frame);
300
301     /* shuffle frames */
302   if (!avctx->cr_available)
303     s->prev_frame = s->frame;
304
305     *data_size = sizeof(AVFrame);
306     *(AVFrame*)data = s->frame;
307
308     /* report that the buffer was completely consumed */
309     return buf_size;
310 }
311
312 static int msrle_decode_end(AVCodecContext *avctx)
313 {
314     MsrleContext *s = (MsrleContext *)avctx->priv_data;
315
316     /* release the last frame */
317     if (s->prev_frame.data[0])
318         avctx->release_buffer(avctx, &s->prev_frame);
319
320     return 0;
321 }
322
323 AVCodec msrle_decoder = {
324     "msrle",
325     CODEC_TYPE_VIDEO,
326     CODEC_ID_MSRLE,
327     sizeof(MsrleContext),
328     msrle_decode_init,
329     NULL,
330     msrle_decode_end,
331     msrle_decode_frame,
332     CODEC_CAP_DR1 | CODEC_CAP_CR,
333 };