Commit | Line | Data |
---|---|---|
2fdf638b MM |
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 */ | |
bc0219fd RT |
180 | if (s->prev_frame.data[0] != NULL) |
181 | memcpy(s->frame.data[0], s->prev_frame.data[0], | |
2fdf638b MM |
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 | }; |