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 33static 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 129static 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 249int 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