msrledec.c
Go to the documentation of this file.
1 /*
2  * Microsoft RLE decoder
3  * Copyright (C) 2008 Konstantin Shishkov
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
29 #include "libavutil/intreadwrite.h"
30 #include "avcodec.h"
31 #include "msrledec.h"
32 
33 static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
34  GetByteContext *gb)
35 {
36  unsigned char rle_code;
37  unsigned char extra_byte, odd_pixel;
38  unsigned char stream_byte;
39  unsigned int pixel_ptr = 0;
40  int row_dec = pic->linesize[0];
41  int row_ptr = (avctx->height - 1) * row_dec;
42  int frame_size = row_dec * avctx->height;
43  int i;
44 
45  while (row_ptr >= 0) {
46  if (bytestream2_get_bytes_left(gb) <= 0) {
47  av_log(avctx, AV_LOG_ERROR,
48  "MS RLE: bytestream overrun, %d rows left\n",
49  row_ptr);
50  return AVERROR_INVALIDDATA;
51  }
52  rle_code = stream_byte = bytestream2_get_byteu(gb);
53  if (rle_code == 0) {
54  /* fetch the next byte to see how to handle escape code */
55  stream_byte = bytestream2_get_byte(gb);
56  if (stream_byte == 0) {
57  /* line is done, goto the next one */
58  row_ptr -= row_dec;
59  pixel_ptr = 0;
60  } else if (stream_byte == 1) {
61  /* decode is done */
62  return 0;
63  } else if (stream_byte == 2) {
64  /* reposition frame decode coordinates */
65  stream_byte = bytestream2_get_byte(gb);
66  pixel_ptr += stream_byte;
67  stream_byte = bytestream2_get_byte(gb);
68  row_ptr -= stream_byte * row_dec;
69  } else {
70  // copy pixels from encoded stream
71  odd_pixel = stream_byte & 1;
72  rle_code = (stream_byte + 1) / 2;
73  extra_byte = rle_code & 0x01;
74  if (row_ptr + pixel_ptr + stream_byte > frame_size ||
75  bytestream2_get_bytes_left(gb) < rle_code) {
76  av_log(avctx, AV_LOG_ERROR,
77  "MS RLE: frame/stream ptr just went out of bounds (copy)\n");
78  return AVERROR_INVALIDDATA;
79  }
80 
81  for (i = 0; i < rle_code; i++) {
82  if (pixel_ptr >= avctx->width)
83  break;
84  stream_byte = bytestream2_get_byteu(gb);
85  pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
86  pixel_ptr++;
87  if (i + 1 == rle_code && odd_pixel)
88  break;
89  if (pixel_ptr >= avctx->width)
90  break;
91  pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
92  pixel_ptr++;
93  }
94 
95  // if the RLE code is odd, skip a byte in the stream
96  if (extra_byte)
97  bytestream2_skip(gb, 1);
98  }
99  } else {
100  // decode a run of data
101  if (row_ptr + pixel_ptr + stream_byte > frame_size) {
102  av_log(avctx, AV_LOG_ERROR,
103  "MS RLE: frame ptr just went out of bounds (run)\n");
104  return AVERROR_INVALIDDATA;
105  }
106  stream_byte = bytestream2_get_byte(gb);
107  for (i = 0; i < rle_code; i++) {
108  if (pixel_ptr >= avctx->width)
109  break;
110  if ((i & 1) == 0)
111  pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
112  else
113  pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
114  pixel_ptr++;
115  }
116  }
117  }
118 
119  /* one last sanity check on the way out */
120  if (bytestream2_get_bytes_left(gb)) {
121  av_log(avctx, AV_LOG_ERROR,
122  "MS RLE: ended frame decode with %d bytes left over\n",
124  return AVERROR_INVALIDDATA;
125  }
126 
127  return 0;
128 }
129 
130 
132  int depth, GetByteContext *gb)
133 {
134  uint8_t *output, *output_end;
135  int p1, p2, line=avctx->height - 1, pos=0, i;
136  uint16_t av_uninit(pix16);
137  uint32_t av_uninit(pix32);
138  unsigned int width= FFABS(pic->linesize[0]) / (depth >> 3);
139 
140  output = pic->data[0] + (avctx->height - 1) * pic->linesize[0];
141  output_end = pic->data[0] + avctx->height * pic->linesize[0];
142  while (bytestream2_get_bytes_left(gb) > 0) {
143  p1 = bytestream2_get_byteu(gb);
144  if(p1 == 0) { //Escape code
145  p2 = bytestream2_get_byte(gb);
146  if(p2 == 0) { //End-of-line
147  if (--line < 0) {
148  if (bytestream2_get_be16(gb) == 1) { // end-of-picture
149  return 0;
150  } else {
151  av_log(avctx, AV_LOG_ERROR,
152  "Next line is beyond picture bounds (%d bytes left)\n",
154  return AVERROR_INVALIDDATA;
155  }
156  }
157  output = pic->data[0] + line * 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  continue;
173  }
174  // Copy data
175  if ((pic->linesize[0] > 0 && output + p2 * (depth >> 3) > output_end) ||
176  (pic->linesize[0] < 0 && 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  for(i = 0; i < p2 * (depth >> 3); i++) {
186  *output++ = bytestream2_get_byteu(gb);
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  switch(depth){
207  case 8: pix[0] = bytestream2_get_byte(gb);
208  break;
209  case 16: pix16 = bytestream2_get_le16(gb);
210  break;
211  case 24: pix[0] = bytestream2_get_byte(gb);
212  pix[1] = bytestream2_get_byte(gb);
213  pix[2] = bytestream2_get_byte(gb);
214  break;
215  case 32: pix32 = bytestream2_get_le32(gb);
216  break;
217  }
218  if ((pic->linesize[0] > 0 && output + p1 * (depth >> 3) > output_end) ||
219  (pic->linesize[0] < 0 && output + p1 * (depth >> 3) < output_end))
220  continue;
221  for(i = 0; i < p1; i++) {
222  switch(depth){
223  case 8: *output++ = pix[0];
224  break;
225  case 16: *(uint16_t*)output = pix16;
226  output += 2;
227  break;
228  case 24: *output++ = pix[0];
229  *output++ = pix[1];
230  *output++ = pix[2];
231  break;
232  case 32: *(uint32_t*)output = pix32;
233  output += 4;
234  break;
235  }
236  }
237  pos += p1;
238  }
239  }
240 
241  av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no end-of-picture code\n");
242  return 0;
243 }
244 
245 
247  int depth, GetByteContext *gb)
248 {
249  switch(depth){
250  case 4:
251  return msrle_decode_pal4(avctx, pic, gb);
252  case 8:
253  case 16:
254  case 24:
255  case 32:
256  return msrle_decode_8_16_24_32(avctx, pic, depth, gb);
257  default:
258  av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth);
259  return -1;
260  }
261 }
262