blob: f0cbde67ffc298a72534ec80b9773948d70fccff
1 | /* |
2 | * Microsoft RLE decoder |
3 | * Copyright (C) 2008 Konstantin Shishkov |
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 |
24 | * MS RLE decoder based on decoder by Mike Melanson and my own for TSCC |
25 | * For more information about the MS RLE format, visit: |
26 | * http://www.multimedia.cx/msrle.txt |
27 | */ |
28 | |
29 | #include "libavutil/intreadwrite.h" |
30 | #include "avcodec.h" |
31 | #include "msrledec.h" |
32 | |
33 | static int msrle_decode_pal4(AVCodecContext *avctx, AVFrame *pic, |
34 | GetByteContext *gb) |
35 | { |
36 | unsigned char rle_code; |
37 | unsigned char extra_byte, odd_pixel; |
38 | unsigned char stream_byte; |
39 | int pixel_ptr = 0; |
40 | int line = avctx->height - 1; |
41 | int i; |
42 | |
43 | while (line >= 0 && pixel_ptr <= avctx->width) { |
44 | if (bytestream2_get_bytes_left(gb) <= 0) { |
45 | av_log(avctx, AV_LOG_ERROR, |
46 | "MS RLE: bytestream overrun, %dx%d left\n", |
47 | avctx->width - pixel_ptr, line); |
48 | return AVERROR_INVALIDDATA; |
49 | } |
50 | rle_code = stream_byte = bytestream2_get_byteu(gb); |
51 | if (rle_code == 0) { |
52 | /* fetch the next byte to see how to handle escape code */ |
53 | stream_byte = bytestream2_get_byte(gb); |
54 | if (stream_byte == 0) { |
55 | /* line is done, goto the next one */ |
56 | line--; |
57 | pixel_ptr = 0; |
58 | } else if (stream_byte == 1) { |
59 | /* decode is done */ |
60 | return 0; |
61 | } else if (stream_byte == 2) { |
62 | /* reposition frame decode coordinates */ |
63 | stream_byte = bytestream2_get_byte(gb); |
64 | pixel_ptr += stream_byte; |
65 | stream_byte = bytestream2_get_byte(gb); |
66 | line -= stream_byte; |
67 | } else { |
68 | // copy pixels from encoded stream |
69 | odd_pixel = stream_byte & 1; |
70 | rle_code = (stream_byte + 1) / 2; |
71 | extra_byte = rle_code & 0x01; |
72 | if (pixel_ptr + 2*rle_code - odd_pixel > avctx->width || |
73 | bytestream2_get_bytes_left(gb) < rle_code) { |
74 | av_log(avctx, AV_LOG_ERROR, |
75 | "MS RLE: frame/stream ptr just went out of bounds (copy)\n"); |
76 | return AVERROR_INVALIDDATA; |
77 | } |
78 | |
79 | for (i = 0; i < rle_code; i++) { |
80 | if (pixel_ptr >= avctx->width) |
81 | break; |
82 | stream_byte = bytestream2_get_byteu(gb); |
83 | pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte >> 4; |
84 | pixel_ptr++; |
85 | if (i + 1 == rle_code && odd_pixel) |
86 | break; |
87 | if (pixel_ptr >= avctx->width) |
88 | break; |
89 | pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte & 0x0F; |
90 | pixel_ptr++; |
91 | } |
92 | |
93 | // if the RLE code is odd, skip a byte in the stream |
94 | if (extra_byte) |
95 | bytestream2_skip(gb, 1); |
96 | } |
97 | } else { |
98 | // decode a run of data |
99 | if (pixel_ptr + rle_code > avctx->width + 1) { |
100 | av_log(avctx, AV_LOG_ERROR, |
101 | "MS RLE: frame ptr just went out of bounds (run) %d %d %d\n", pixel_ptr, rle_code, avctx->width); |
102 | return AVERROR_INVALIDDATA; |
103 | } |
104 | stream_byte = bytestream2_get_byte(gb); |
105 | for (i = 0; i < rle_code; i++) { |
106 | if (pixel_ptr >= avctx->width) |
107 | break; |
108 | if ((i & 1) == 0) |
109 | pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte >> 4; |
110 | else |
111 | pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte & 0x0F; |
112 | pixel_ptr++; |
113 | } |
114 | } |
115 | } |
116 | |
117 | /* one last sanity check on the way out */ |
118 | if (bytestream2_get_bytes_left(gb)) { |
119 | av_log(avctx, AV_LOG_ERROR, |
120 | "MS RLE: ended frame decode with %d bytes left over\n", |
121 | bytestream2_get_bytes_left(gb)); |
122 | return AVERROR_INVALIDDATA; |
123 | } |
124 | |
125 | return 0; |
126 | } |
127 | |
128 | |
129 | static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVFrame *pic, |
130 | int depth, GetByteContext *gb) |
131 | { |
132 | uint8_t *output, *output_end; |
133 | int p1, p2, line=avctx->height - 1, pos=0, i; |
134 | uint16_t pix16; |
135 | uint32_t pix32; |
136 | unsigned int width= FFABS(pic->linesize[0]) / (depth >> 3); |
137 | |
138 | output = pic->data[0] + (avctx->height - 1) * pic->linesize[0]; |
139 | output_end = output + FFABS(pic->linesize[0]); |
140 | |
141 | while (bytestream2_get_bytes_left(gb) > 0) { |
142 | p1 = bytestream2_get_byteu(gb); |
143 | if(p1 == 0) { //Escape code |
144 | p2 = bytestream2_get_byte(gb); |
145 | if(p2 == 0) { //End-of-line |
146 | if (--line < 0) { |
147 | if (bytestream2_get_be16(gb) == 1) { // end-of-picture |
148 | return 0; |
149 | } else { |
150 | av_log(avctx, AV_LOG_ERROR, |
151 | "Next line is beyond picture bounds (%d bytes left)\n", |
152 | bytestream2_get_bytes_left(gb)); |
153 | return AVERROR_INVALIDDATA; |
154 | } |
155 | } |
156 | output = pic->data[0] + line * pic->linesize[0]; |
157 | output_end = output + FFABS(pic->linesize[0]); |
158 | pos = 0; |
159 | continue; |
160 | } else if(p2 == 1) { //End-of-picture |
161 | return 0; |
162 | } else if(p2 == 2) { //Skip |
163 | p1 = bytestream2_get_byte(gb); |
164 | p2 = bytestream2_get_byte(gb); |
165 | line -= p2; |
166 | pos += p1; |
167 | if (line < 0 || pos >= width){ |
168 | av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n"); |
169 | return -1; |
170 | } |
171 | output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3); |
172 | output_end = pic->data[0] + line * pic->linesize[0] + FFABS(pic->linesize[0]); |
173 | continue; |
174 | } |
175 | // Copy data |
176 | if (output + p2 * (depth >> 3) > output_end) { |
177 | bytestream2_skip(gb, 2 * (depth >> 3)); |
178 | continue; |
179 | } else if (bytestream2_get_bytes_left(gb) < p2 * (depth >> 3)) { |
180 | av_log(avctx, AV_LOG_ERROR, "bytestream overrun\n"); |
181 | return AVERROR_INVALIDDATA; |
182 | } |
183 | |
184 | if ((depth == 8) || (depth == 24)) { |
185 | bytestream2_get_bufferu(gb, output, p2 * (depth >> 3)); |
186 | output += p2 * (depth >> 3); |
187 | |
188 | // RLE8 copy is actually padded - and runs are not! |
189 | if(depth == 8 && (p2 & 1)) { |
190 | bytestream2_skip(gb, 1); |
191 | } |
192 | } else if (depth == 16) { |
193 | for(i = 0; i < p2; i++) { |
194 | *(uint16_t*)output = bytestream2_get_le16u(gb); |
195 | output += 2; |
196 | } |
197 | } else if (depth == 32) { |
198 | for(i = 0; i < p2; i++) { |
199 | *(uint32_t*)output = bytestream2_get_le32u(gb); |
200 | output += 4; |
201 | } |
202 | } |
203 | pos += p2; |
204 | } else { //run of pixels |
205 | uint8_t pix[3]; //original pixel |
206 | if (output + p1 * (depth >> 3) > output_end) |
207 | continue; |
208 | |
209 | switch(depth){ |
210 | case 8: |
211 | pix[0] = bytestream2_get_byte(gb); |
212 | memset(output, pix[0], p1); |
213 | output += p1; |
214 | break; |
215 | case 16: |
216 | pix16 = bytestream2_get_le16(gb); |
217 | for(i = 0; i < p1; i++) { |
218 | *(uint16_t*)output = pix16; |
219 | output += 2; |
220 | } |
221 | break; |
222 | case 24: |
223 | pix[0] = bytestream2_get_byte(gb); |
224 | pix[1] = bytestream2_get_byte(gb); |
225 | pix[2] = bytestream2_get_byte(gb); |
226 | for(i = 0; i < p1; i++) { |
227 | *output++ = pix[0]; |
228 | *output++ = pix[1]; |
229 | *output++ = pix[2]; |
230 | } |
231 | break; |
232 | case 32: |
233 | pix32 = bytestream2_get_le32(gb); |
234 | for(i = 0; i < p1; i++) { |
235 | *(uint32_t*)output = pix32; |
236 | output += 4; |
237 | } |
238 | break; |
239 | } |
240 | pos += p1; |
241 | } |
242 | } |
243 | |
244 | av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no end-of-picture code\n"); |
245 | return 0; |
246 | } |
247 | |
248 | |
249 | int ff_msrle_decode(AVCodecContext *avctx, AVFrame *pic, |
250 | int depth, GetByteContext *gb) |
251 | { |
252 | switch(depth){ |
253 | case 4: |
254 | return msrle_decode_pal4(avctx, pic, gb); |
255 | case 8: |
256 | case 16: |
257 | case 24: |
258 | case 32: |
259 | return msrle_decode_8_16_24_32(avctx, pic, depth, gb); |
260 | default: |
261 | av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth); |
262 | return -1; |
263 | } |
264 | } |
265 |