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