100l: free previous frame, not current one!
[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 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     s->frame.reference = 1;
175     if (avctx->get_buffer(avctx, &s->frame)) {
176         printf ("  MS RLE: get_buffer() failed\n");
177         return -1;
178     }
179
180     /* grossly inefficient, but...oh well */
181     if (s->prev_frame.data[0] != NULL)
182         memcpy(s->frame.data[0], s->prev_frame.data[0], 
183         s->frame.linesize[0] * s->avctx->height);
184
185     msrle_decode_pal8(s);
186
187     if (s->prev_frame.data[0])
188         avctx->release_buffer(avctx, &s->prev_frame);
189
190     /* shuffle frames */
191     s->prev_frame = s->frame;
192
193     *data_size = sizeof(AVFrame);
194     *(AVFrame*)data = s->frame;
195
196     /* report that the buffer was completely consumed */
197     return buf_size;
198 }
199
200 static int msrle_decode_end(AVCodecContext *avctx)
201 {
202     MsrleContext *s = (MsrleContext *)avctx->priv_data;
203
204     /* release the last frame */
205     if (s->prev_frame.data[0])
206         avctx->release_buffer(avctx, &s->prev_frame);
207
208     return 0;
209 }
210
211 AVCodec msrle_decoder = {
212     "msrle",
213     CODEC_TYPE_VIDEO,
214     CODEC_ID_MSRLE,
215     sizeof(MsrleContext),
216     msrle_decode_init,
217     NULL,
218     msrle_decode_end,
219     msrle_decode_frame,
220     CODEC_CAP_DR1,
221 };