2
* Microsoft RLE decoder
3
* Copyright (C) 2008 Konstantin Shishkov
5
* This file is part of FFmpeg.
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.
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.
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
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
29
#include "libavutil/intreadwrite.h"
33
#define FETCH_NEXT_STREAM_BYTE() \
34
if (stream_ptr >= data_size) \
36
av_log(avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \
39
stream_byte = data[stream_ptr++];
41
static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
42
const uint8_t *data, int data_size)
45
unsigned char rle_code;
46
unsigned char extra_byte, odd_pixel;
47
unsigned char stream_byte;
49
int row_dec = pic->linesize[0];
50
int row_ptr = (avctx->height - 1) * row_dec;
51
int frame_size = row_dec * avctx->height;
54
while (row_ptr >= 0) {
55
FETCH_NEXT_STREAM_BYTE();
56
rle_code = stream_byte;
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 */
64
} else if (stream_byte == 1) {
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;
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) ||
80
av_log(avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
84
for (i = 0; i < rle_code; i++) {
85
if (pixel_ptr >= avctx->width)
87
FETCH_NEXT_STREAM_BYTE();
88
pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
90
if (i + 1 == rle_code && odd_pixel)
92
if (pixel_ptr >= avctx->width)
94
pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
98
// if the RLE code is odd, skip a byte in the stream
103
// decode a run of data
104
if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
106
av_log(avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
109
FETCH_NEXT_STREAM_BYTE();
110
for (i = 0; i < rle_code; i++) {
111
if (pixel_ptr >= avctx->width)
114
pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
116
pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
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);
133
static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic, int depth,
134
const uint8_t *data, int srcsize)
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);
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) {
146
if(p1 == 0) { //Escape code
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");
156
} else if(p2 == 1) { //End-of-picture
158
} else if(p2 == 2) { //Skip
163
av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n");
167
output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3);
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);
176
if ((depth == 8) || (depth == 24)) {
177
for(i = 0; i < p2 * (depth >> 3); i++) {
180
// RLE8 copy is actually padded - and runs are not!
181
if(depth == 8 && (p2 & 1)) {
184
} else if (depth == 16) {
185
for(i = 0; i < p2; i++) {
186
pix16 = AV_RL16(src);
188
*(uint16_t*)output = pix16;
191
} else if (depth == 32) {
192
for(i = 0; i < p2; i++) {
193
pix32 = AV_RL32(src);
195
*(uint32_t*)output = pix32;
200
} else { //run of pixels
201
uint8_t pix[3]; //original pixel
203
case 8: pix[0] = *src++;
205
case 16: pix16 = AV_RL16(src);
208
case 24: pix[0] = *src++;
212
case 32: pix32 = AV_RL32(src);
216
if ((pic->linesize[0] > 0 && output + p1 * (depth >> 3) > output_end)
217
||(pic->linesize[0] < 0 && output + p1 * (depth >> 3) < output_end))
219
for(i = 0; i < p1; i++) {
221
case 8: *output++ = pix[0];
223
case 16: *(uint16_t*)output = pix16;
226
case 24: *output++ = pix[0];
230
case 32: *(uint32_t*)output = pix32;
239
av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no end-of-picture code\n");
244
int ff_msrle_decode(AVCodecContext *avctx, AVPicture *pic, int depth,
245
const uint8_t* data, int data_size)
249
return msrle_decode_pal4(avctx, pic, data, data_size);
254
return msrle_decode_8_16_24_32(avctx, pic, depth, data, data_size);
256
av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth);