]> git.sesse.net Git - ffmpeg/blob - libavcodec/msrledec.c
Fix misspelled parameter names in Doxygen documentation.
[ffmpeg] / libavcodec / msrledec.c
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 #define FETCH_NEXT_STREAM_BYTE() \
34     if (stream_ptr >= data_size) \
35     { \
36       av_log(avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \
37       return -1; \
38     } \
39     stream_byte = data[stream_ptr++];
40
41 static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
42                               const uint8_t *data, int data_size)
43 {
44     int stream_ptr = 0;
45     unsigned char rle_code;
46     unsigned char extra_byte, odd_pixel;
47     unsigned char stream_byte;
48     int pixel_ptr = 0;
49     int row_dec = pic->linesize[0];
50     int row_ptr = (avctx->height - 1) * row_dec;
51     int frame_size = row_dec * avctx->height;
52     int i;
53
54     while (row_ptr >= 0) {
55         FETCH_NEXT_STREAM_BYTE();
56         rle_code = stream_byte;
57         if (rle_code == 0) {
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 */
62                 row_ptr -= row_dec;
63                 pixel_ptr = 0;
64             } else if (stream_byte == 1) {
65                 /* decode is done */
66                 return 0;
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;
73         } else {
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) ||
79                 (row_ptr < 0)) {
80                 av_log(avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
81                 return -1;
82             }
83
84             for (i = 0; i < rle_code; i++) {
85                 if (pixel_ptr >= avctx->width)
86                     break;
87                 FETCH_NEXT_STREAM_BYTE();
88                 pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
89                 pixel_ptr++;
90                 if (i + 1 == rle_code && odd_pixel)
91                     break;
92                 if (pixel_ptr >= avctx->width)
93                     break;
94                 pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
95                 pixel_ptr++;
96             }
97
98             // if the RLE code is odd, skip a byte in the stream
99             if (extra_byte)
100               stream_ptr++;
101             }
102         } else {
103             // decode a run of data
104             if ((row_ptr + pixel_ptr + stream_byte > frame_size) ||
105                 (row_ptr < 0)) {
106                 av_log(avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n");
107                 return -1;
108             }
109             FETCH_NEXT_STREAM_BYTE();
110             for (i = 0; i < rle_code; i++) {
111                 if (pixel_ptr >= avctx->width)
112                     break;
113                 if ((i & 1) == 0)
114                     pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
115                 else
116                     pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
117                 pixel_ptr++;
118             }
119         }
120     }
121
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);
126         return -1;
127     }
128
129     return 0;
130 }
131
132
133 static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic, int depth,
134                                     const uint8_t *data, int srcsize)
135 {
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);
141
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) {
145         p1 = *src++;
146         if(p1 == 0) { //Escape code
147             p2 = *src++;
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");
152                     return -1;
153                 }
154                 pos = 0;
155                 continue;
156             } else if(p2 == 1) { //End-of-picture
157                 return 0;
158             } else if(p2 == 2) { //Skip
159                 p1 = *src++;
160                 p2 = *src++;
161                 line -= p2;
162                 if (line < 0){
163                     av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n");
164                     return -1;
165                 }
166                 pos += p1;
167                 output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3);
168                 continue;
169             }
170             // Copy data
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);
174                 continue;
175             }
176             if ((depth == 8) || (depth == 24)) {
177                 for(i = 0; i < p2 * (depth >> 3); i++) {
178                     *output++ = *src++;
179                 }
180                 // RLE8 copy is actually padded - and runs are not!
181                 if(depth == 8 && (p2 & 1)) {
182                     src++;
183                 }
184             } else if (depth == 16) {
185                 for(i = 0; i < p2; i++) {
186                     pix16 = AV_RL16(src);
187                     src += 2;
188                     *(uint16_t*)output = pix16;
189                     output += 2;
190                 }
191             } else if (depth == 32) {
192                 for(i = 0; i < p2; i++) {
193                     pix32 = AV_RL32(src);
194                     src += 4;
195                     *(uint32_t*)output = pix32;
196                     output += 4;
197                 }
198             }
199             pos += p2;
200         } else { //run of pixels
201             uint8_t pix[3]; //original pixel
202             switch(depth){
203             case  8: pix[0] = *src++;
204                      break;
205             case 16: pix16 = AV_RL16(src);
206                      src += 2;
207                      break;
208             case 24: pix[0] = *src++;
209                      pix[1] = *src++;
210                      pix[2] = *src++;
211                      break;
212             case 32: pix32 = AV_RL32(src);
213                      src += 4;
214                      break;
215             }
216             if ((pic->linesize[0] > 0 && output + p1 * (depth >> 3) > output_end)
217               ||(pic->linesize[0] < 0 && output + p1 * (depth >> 3) < output_end))
218                 continue;
219             for(i = 0; i < p1; i++) {
220                 switch(depth){
221                 case  8: *output++ = pix[0];
222                          break;
223                 case 16: *(uint16_t*)output = pix16;
224                          output += 2;
225                          break;
226                 case 24: *output++ = pix[0];
227                          *output++ = pix[1];
228                          *output++ = pix[2];
229                          break;
230                 case 32: *(uint32_t*)output = pix32;
231                          output += 4;
232                          break;
233                 }
234             }
235             pos += p1;
236         }
237     }
238
239     av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no end-of-picture code\n");
240     return 0;
241 }
242
243
244 int ff_msrle_decode(AVCodecContext *avctx, AVPicture *pic, int depth,
245                     const uint8_t* data, int data_size)
246 {
247     switch(depth){
248     case  4:
249         return msrle_decode_pal4(avctx, pic, data, data_size);
250     case  8:
251     case 16:
252     case 24:
253     case 32:
254         return msrle_decode_8_16_24_32(avctx, pic, depth, data, data_size);
255     default:
256         av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth);
257         return -1;
258     }
259 }
260