| 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 | 381 | 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 | 381 | int p1, p2, line=avctx->height - 1, pos=0, i; | |
| 134 | uint16_t pix16; | ||
| 135 | uint32_t pix32; | ||
| 136 | 381 | unsigned int width= FFABS(pic->linesize[0]) / (depth >> 3); | |
| 137 | |||
| 138 | 381 | output = pic->data[0] + (avctx->height - 1) * pic->linesize[0]; | |
| 139 |
1/2✓ Branch 0 taken 381 times.
✗ Branch 1 not taken.
|
381 | output_end = output + FFABS(pic->linesize[0]); |
| 140 | |||
| 141 |
1/2✓ Branch 1 taken 1377093 times.
✗ Branch 2 not taken.
|
1377093 | while (bytestream2_get_bytes_left(gb) > 0) { |
| 142 | 1377093 | p1 = bytestream2_get_byteu(gb); | |
| 143 |
2/2✓ Branch 0 taken 881725 times.
✓ Branch 1 taken 495368 times.
|
1377093 | if(p1 == 0) { //Escape code |
| 144 | 881725 | p2 = bytestream2_get_byte(gb); | |
| 145 |
2/2✓ Branch 0 taken 54234 times.
✓ Branch 1 taken 827491 times.
|
881725 | if(p2 == 0) { //End-of-line |
| 146 |
2/2✓ Branch 0 taken 200 times.
✓ Branch 1 taken 54034 times.
|
54234 | 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 | 54034 | output = pic->data[0] + line * pic->linesize[0]; | |
| 157 |
1/2✓ Branch 0 taken 54034 times.
✗ Branch 1 not taken.
|
54034 | output_end = output + FFABS(pic->linesize[0]); |
| 158 | 54034 | pos = 0; | |
| 159 | 54034 | continue; | |
| 160 |
2/2✓ Branch 0 taken 180 times.
✓ Branch 1 taken 827311 times.
|
827491 | } else if(p2 == 1) { //End-of-picture |
| 161 | 180 | return 0; | |
| 162 |
2/2✓ Branch 0 taken 325453 times.
✓ Branch 1 taken 501858 times.
|
827311 | } else if(p2 == 2) { //Skip |
| 163 | 325453 | p1 = bytestream2_get_byte(gb); | |
| 164 | 325453 | p2 = bytestream2_get_byte(gb); | |
| 165 | 325453 | line -= p2; | |
| 166 | 325453 | pos += p1; | |
| 167 |
2/4✓ Branch 0 taken 325453 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 325453 times.
|
325453 | if (line < 0 || pos >= width){ |
| 168 | ✗ | av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n"); | |
| 169 | ✗ | return -1; | |
| 170 | } | ||
| 171 | 325453 | output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3); | |
| 172 |
1/2✓ Branch 0 taken 325453 times.
✗ Branch 1 not taken.
|
325453 | output_end = pic->data[0] + line * pic->linesize[0] + FFABS(pic->linesize[0]); |
| 173 | 325453 | continue; | |
| 174 | } | ||
| 175 | // Copy data | ||
| 176 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 501858 times.
|
501858 | 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 501857 times.
|
501858 | } 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 25370 times.
✓ Branch 1 taken 476487 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25370 times.
|
501857 | 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 7403 times.
✓ Branch 1 taken 17967 times.
|
25370 | } else if (depth == 16) { |
| 193 |
2/2✓ Branch 0 taken 52841 times.
✓ Branch 1 taken 7403 times.
|
60244 | for(i = 0; i < p2; i++) { |
| 194 | 52841 | *(uint16_t*)output = bytestream2_get_le16u(gb); | |
| 195 | 52841 | 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 | 501857 | pos += p2; | |
| 204 | } else { //run of pixels | ||
| 205 | uint8_t pix[3]; //original pixel | ||
| 206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 495368 times.
|
495368 | if (output + p1 * (depth >> 3) > output_end) |
| 207 | ✗ | continue; | |
| 208 | |||
| 209 |
3/5✓ Branch 0 taken 434052 times.
✓ Branch 1 taken 14602 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 46714 times.
✗ Branch 4 not taken.
|
495368 | 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 | 14602 | case 16: | |
| 216 | 14602 | pix16 = bytestream2_get_le16(gb); | |
| 217 |
2/2✓ Branch 0 taken 702795 times.
✓ Branch 1 taken 14602 times.
|
717397 | for(i = 0; i < p1; i++) { |
| 218 | 702795 | *(uint16_t*)output = pix16; | |
| 219 | 702795 | output += 2; | |
| 220 | } | ||
| 221 | 14602 | 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 | 495368 | 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 | 383 | 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 381 times.
✗ Branch 2 not taken.
|
383 | switch(depth){ |
| 253 | 2 | case 4: | |
| 254 | 2 | return msrle_decode_pal4(avctx, pic, gb); | |
| 255 | 381 | case 8: | |
| 256 | case 16: | ||
| 257 | case 24: | ||
| 258 | case 32: | ||
| 259 | 381 | 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 |