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