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  for(i = 0; i < p2 * (depth >> 3); i++) {
188  *output++ = bytestream2_get_byteu(gb);
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  for(i = 0; i < p1; i++)
215  *output++ = pix[0];
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 }
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int linesize[AV_NUM_DATA_POINTERS]
number of bytes per line
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic, int depth, GetByteContext *gb)
Definition: msrledec.c:131
four components are given, that&#39;s all.
uint8_t
uint8_t * data[AV_NUM_DATA_POINTERS]
static const uint8_t frame_size[4]
Definition: g723_1_data.h:58
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:159
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:149
Definition: graph2dot.c:48
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
external API header
int depth
Definition: v4l.c:62
int width
picture width / height.
#define FFABS(a)
Definition: common.h:53
static int width
Definition: tests/utils.c:158
main external API structure.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
synthesis window for stochastic i
these buffered frames must be flushed immediately if a new input produces new output(Example:frame rate-doubling filter:filter_frame must(1) flush the second copy of the previous frame, if it is still there,(2) push the first copy of the incoming frame,(3) keep the second copy for later.) If the input frame is not enough to produce output
int ff_msrle_decode(AVCodecContext *avctx, AVPicture *pic, int depth, GetByteContext *gb)
Decode stream in MS RLE format into frame.
Definition: msrledec.c:251
static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic, GetByteContext *gb)
Definition: msrledec.c:33