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