FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 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 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 pix16;
137  uint32_t 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 = output + FFABS(pic->linesize[0]);
142 
143  while (bytestream2_get_bytes_left(gb) > 0) {
144  p1 = bytestream2_get_byteu(gb);
145  if(p1 == 0) { //Escape code
146  p2 = bytestream2_get_byte(gb);
147  if(p2 == 0) { //End-of-line
148  if (--line < 0) {
149  if (bytestream2_get_be16(gb) == 1) { // end-of-picture
150  return 0;
151  } else {
152  av_log(avctx, AV_LOG_ERROR,
153  "Next line is beyond picture bounds (%d bytes left)\n",
155  return AVERROR_INVALIDDATA;
156  }
157  }
158  output = pic->data[0] + line * pic->linesize[0];
159  output_end = output + FFABS(pic->linesize[0]);
160  pos = 0;
161  continue;
162  } else if(p2 == 1) { //End-of-picture
163  return 0;
164  } else if(p2 == 2) { //Skip
165  p1 = bytestream2_get_byte(gb);
166  p2 = bytestream2_get_byte(gb);
167  line -= p2;
168  pos += p1;
169  if (line < 0 || pos >= width){
170  av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n");
171  return -1;
172  }
173  output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3);
174  output_end = pic->data[0] + line * pic->linesize[0] + FFABS(pic->linesize[0]);
175  continue;
176  }
177  // Copy data
178  if (output + p2 * (depth >> 3) > output_end) {
179  bytestream2_skip(gb, 2 * (depth >> 3));
180  continue;
181  } else if (bytestream2_get_bytes_left(gb) < p2 * (depth >> 3)) {
182  av_log(avctx, AV_LOG_ERROR, "bytestream overrun\n");
183  return AVERROR_INVALIDDATA;
184  }
185 
186  if ((depth == 8) || (depth == 24)) {
187  bytestream2_get_bufferu(gb, output, p2 * (depth >> 3));
188  output += p2 * (depth >> 3);
189 
190  // RLE8 copy is actually padded - and runs are not!
191  if(depth == 8 && (p2 & 1)) {
192  bytestream2_skip(gb, 1);
193  }
194  } else if (depth == 16) {
195  for(i = 0; i < p2; i++) {
196  *(uint16_t*)output = bytestream2_get_le16u(gb);
197  output += 2;
198  }
199  } else if (depth == 32) {
200  for(i = 0; i < p2; i++) {
201  *(uint32_t*)output = bytestream2_get_le32u(gb);
202  output += 4;
203  }
204  }
205  pos += p2;
206  } else { //run of pixels
207  uint8_t pix[3]; //original pixel
208  if (output + p1 * (depth >> 3) > output_end)
209  continue;
210 
211  switch(depth){
212  case 8:
213  pix[0] = bytestream2_get_byte(gb);
214  memset(output, pix[0], p1);
215  output += p1;
216  break;
217  case 16:
218  pix16 = bytestream2_get_le16(gb);
219  for(i = 0; i < p1; i++) {
220  *(uint16_t*)output = pix16;
221  output += 2;
222  }
223  break;
224  case 24:
225  pix[0] = bytestream2_get_byte(gb);
226  pix[1] = bytestream2_get_byte(gb);
227  pix[2] = bytestream2_get_byte(gb);
228  for(i = 0; i < p1; i++) {
229  *output++ = pix[0];
230  *output++ = pix[1];
231  *output++ = pix[2];
232  }
233  break;
234  case 32:
235  pix32 = bytestream2_get_le32(gb);
236  for(i = 0; i < p1; i++) {
237  *(uint32_t*)output = pix32;
238  output += 4;
239  }
240  break;
241  }
242  pos += p1;
243  }
244  }
245 
246  av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no end-of-picture code\n");
247  return 0;
248 }
249 
250 
252  int depth, GetByteContext *gb)
253 {
254  switch(depth){
255  case 4:
256  return msrle_decode_pal4(avctx, pic, gb);
257  case 8:
258  case 16:
259  case 24:
260  case 32:
261  return msrle_decode_8_16_24_32(avctx, pic, depth, gb);
262  default:
263  av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth);
264  return -1;
265  }
266 }