Line | Branch | Exec | Source |
---|---|---|---|
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 | 2 | 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 | 2 | int pixel_ptr = 0; | |
40 | 2 | int line = avctx->height - 1; | |
41 | int i; | ||
42 | |||
43 |
2/4✓ Branch 0 taken 754 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 754 times.
✗ Branch 3 not taken.
|
754 | while (line >= 0 && pixel_ptr <= avctx->width) { |
44 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 754 times.
|
754 | 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 | 754 | rle_code = stream_byte = bytestream2_get_byteu(gb); | |
51 |
2/2✓ Branch 0 taken 138 times.
✓ Branch 1 taken 616 times.
|
754 | if (rle_code == 0) { |
52 | /* fetch the next byte to see how to handle escape code */ | ||
53 | 138 | stream_byte = bytestream2_get_byte(gb); | |
54 |
2/2✓ Branch 0 taken 126 times.
✓ Branch 1 taken 12 times.
|
138 | if (stream_byte == 0) { |
55 | /* line is done, goto the next one */ | ||
56 | 126 | line--; | |
57 | 126 | pixel_ptr = 0; | |
58 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
|
12 | } else if (stream_byte == 1) { |
59 | /* decode is done */ | ||
60 | 2 | return 0; | |
61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | } 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 | 10 | odd_pixel = stream_byte & 1; | |
70 | 10 | rle_code = (stream_byte + 1) / 2; | |
71 | 10 | extra_byte = rle_code & 0x01; | |
72 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (pixel_ptr + 2*rle_code - odd_pixel > avctx->width || |
73 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | 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 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 10 times.
|
100 | for (i = 0; i < rle_code; i++) { |
80 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (pixel_ptr >= avctx->width) |
81 | ✗ | break; | |
82 | 90 | stream_byte = bytestream2_get_byteu(gb); | |
83 | 90 | pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte >> 4; | |
84 | 90 | pixel_ptr++; | |
85 |
3/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
90 | if (i + 1 == rle_code && odd_pixel) |
86 | ✗ | break; | |
87 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (pixel_ptr >= avctx->width) |
88 | ✗ | break; | |
89 | 90 | pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte & 0x0F; | |
90 | 90 | pixel_ptr++; | |
91 | } | ||
92 | |||
93 | // if the RLE code is odd, skip a byte in the stream | ||
94 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (extra_byte) |
95 | 10 | bytestream2_skip(gb, 1); | |
96 | } | ||
97 | } else { | ||
98 | // decode a run of data | ||
99 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 616 times.
|
616 | 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 | 616 | stream_byte = bytestream2_get_byte(gb); | |
105 |
2/2✓ Branch 0 taken 16204 times.
✓ Branch 1 taken 488 times.
|
16692 | for (i = 0; i < rle_code; i++) { |
106 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 16076 times.
|
16204 | if (pixel_ptr >= avctx->width) |
107 | 128 | break; | |
108 |
2/2✓ Branch 0 taken 8102 times.
✓ Branch 1 taken 7974 times.
|
16076 | if ((i & 1) == 0) |
109 | 8102 | pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte >> 4; | |
110 | else | ||
111 | 7974 | pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte & 0x0F; | |
112 | 16076 | 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 | 387 | 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 | 387 | int p1, p2, line=avctx->height - 1, pos=0, i; | |
134 | uint16_t pix16; | ||
135 | uint32_t pix32; | ||
136 | 387 | unsigned int width= FFABS(pic->linesize[0]) / (depth >> 3); | |
137 | |||
138 | 387 | output = pic->data[0] + (avctx->height - 1) * pic->linesize[0]; | |
139 |
1/2✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
|
387 | output_end = output + FFABS(pic->linesize[0]); |
140 | |||
141 |
1/2✓ Branch 1 taken 1387495 times.
✗ Branch 2 not taken.
|
1387495 | while (bytestream2_get_bytes_left(gb) > 0) { |
142 | 1387495 | p1 = bytestream2_get_byteu(gb); | |
143 |
2/2✓ Branch 0 taken 886860 times.
✓ Branch 1 taken 500635 times.
|
1387495 | if(p1 == 0) { //Escape code |
144 | 886860 | p2 = bytestream2_get_byte(gb); | |
145 |
2/2✓ Branch 0 taken 55384 times.
✓ Branch 1 taken 831476 times.
|
886860 | if(p2 == 0) { //End-of-line |
146 |
2/2✓ Branch 0 taken 200 times.
✓ Branch 1 taken 55184 times.
|
55384 | if (--line < 0) { |
147 |
1/2✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
|
200 | if (bytestream2_get_be16(gb) == 1) { // end-of-picture |
148 | 200 | 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 | 55184 | output = pic->data[0] + line * pic->linesize[0]; | |
157 |
1/2✓ Branch 0 taken 55184 times.
✗ Branch 1 not taken.
|
55184 | output_end = output + FFABS(pic->linesize[0]); |
158 | 55184 | pos = 0; | |
159 | 55184 | continue; | |
160 |
2/2✓ Branch 0 taken 186 times.
✓ Branch 1 taken 831290 times.
|
831476 | } else if(p2 == 1) { //End-of-picture |
161 | 186 | return 0; | |
162 |
2/2✓ Branch 0 taken 327474 times.
✓ Branch 1 taken 503816 times.
|
831290 | } else if(p2 == 2) { //Skip |
163 | 327474 | p1 = bytestream2_get_byte(gb); | |
164 | 327474 | p2 = bytestream2_get_byte(gb); | |
165 | 327474 | line -= p2; | |
166 | 327474 | pos += p1; | |
167 |
2/4✓ Branch 0 taken 327474 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 327474 times.
|
327474 | if (line < 0 || pos >= width){ |
168 | ✗ | av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n"); | |
169 | ✗ | return -1; | |
170 | } | ||
171 | 327474 | output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3); | |
172 |
1/2✓ Branch 0 taken 327474 times.
✗ Branch 1 not taken.
|
327474 | output_end = pic->data[0] + line * pic->linesize[0] + FFABS(pic->linesize[0]); |
173 | 327474 | continue; | |
174 | } | ||
175 | // Copy data | ||
176 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 503816 times.
|
503816 | if (output + p2 * (depth >> 3) > output_end) { |
177 | ✗ | bytestream2_skip(gb, 2 * (depth >> 3)); | |
178 | ✗ | continue; | |
179 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 503815 times.
|
503816 | } else if (bytestream2_get_bytes_left(gb) < p2 * (depth >> 3)) { |
180 | 1 | av_log(avctx, AV_LOG_ERROR, "bytestream overrun\n"); | |
181 | 1 | return AVERROR_INVALIDDATA; | |
182 | } | ||
183 | |||
184 |
3/4✓ Branch 0 taken 27328 times.
✓ Branch 1 taken 476487 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27328 times.
|
503815 | if ((depth == 8) || (depth == 24)) { |
185 | 476487 | bytestream2_get_bufferu(gb, output, p2 * (depth >> 3)); | |
186 | 476487 | output += p2 * (depth >> 3); | |
187 | |||
188 | // RLE8 copy is actually padded - and runs are not! | ||
189 |
3/4✓ Branch 0 taken 476487 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 246264 times.
✓ Branch 3 taken 230223 times.
|
476487 | if(depth == 8 && (p2 & 1)) { |
190 | 246264 | bytestream2_skip(gb, 1); | |
191 | } | ||
192 |
2/2✓ Branch 0 taken 9361 times.
✓ Branch 1 taken 17967 times.
|
27328 | } else if (depth == 16) { |
193 |
2/2✓ Branch 0 taken 65383 times.
✓ Branch 1 taken 9361 times.
|
74744 | for(i = 0; i < p2; i++) { |
194 | 65383 | *(uint16_t*)output = bytestream2_get_le16u(gb); | |
195 | 65383 | output += 2; | |
196 | } | ||
197 |
1/2✓ Branch 0 taken 17967 times.
✗ Branch 1 not taken.
|
17967 | } else if (depth == 32) { |
198 |
2/2✓ Branch 0 taken 147617 times.
✓ Branch 1 taken 17967 times.
|
165584 | for(i = 0; i < p2; i++) { |
199 | 147617 | *(uint32_t*)output = bytestream2_get_le32u(gb); | |
200 | 147617 | output += 4; | |
201 | } | ||
202 | } | ||
203 | 503815 | pos += p2; | |
204 | } else { //run of pixels | ||
205 | uint8_t pix[3]; //original pixel | ||
206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 500635 times.
|
500635 | if (output + p1 * (depth >> 3) > output_end) |
207 | ✗ | continue; | |
208 | |||
209 |
3/5✓ Branch 0 taken 434052 times.
✓ Branch 1 taken 19869 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 46714 times.
✗ Branch 4 not taken.
|
500635 | switch(depth){ |
210 | 434052 | case 8: | |
211 | 434052 | pix[0] = bytestream2_get_byte(gb); | |
212 | 434052 | memset(output, pix[0], p1); | |
213 | 434052 | output += p1; | |
214 | 434052 | break; | |
215 | 19869 | case 16: | |
216 | 19869 | pix16 = bytestream2_get_le16(gb); | |
217 |
2/2✓ Branch 0 taken 918191 times.
✓ Branch 1 taken 19869 times.
|
938060 | for(i = 0; i < p1; i++) { |
218 | 918191 | *(uint16_t*)output = pix16; | |
219 | 918191 | output += 2; | |
220 | } | ||
221 | 19869 | 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 | 46714 | case 32: | |
233 | 46714 | pix32 = bytestream2_get_le32(gb); | |
234 |
2/2✓ Branch 0 taken 1569831 times.
✓ Branch 1 taken 46714 times.
|
1616545 | for(i = 0; i < p1; i++) { |
235 | 1569831 | *(uint32_t*)output = pix32; | |
236 | 1569831 | output += 4; | |
237 | } | ||
238 | 46714 | break; | |
239 | } | ||
240 | 500635 | 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 | 389 | int ff_msrle_decode(AVCodecContext *avctx, AVFrame *pic, | |
250 | int depth, GetByteContext *gb) | ||
251 | { | ||
252 |
2/3✓ Branch 0 taken 2 times.
✓ Branch 1 taken 387 times.
✗ Branch 2 not taken.
|
389 | switch(depth){ |
253 | 2 | case 4: | |
254 | 2 | return msrle_decode_pal4(avctx, pic, gb); | |
255 | 387 | case 8: | |
256 | case 16: | ||
257 | case 24: | ||
258 | case 32: | ||
259 | 387 | 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 |