Mercurial > libavcodec.hg
comparison msrledec.c @ 7885:f874e1d5cf07 libavcodec
Factorize out code used for MS RLE format decoding in different decoders.
author | kostya |
---|---|
date | Thu, 18 Sep 2008 05:20:54 +0000 |
parents | tscc.c@4525dcd81357 |
children | bb310197d59f |
comparison
equal
deleted
inserted
replaced
7884:4077df298ba2 | 7885:f874e1d5cf07 |
---|---|
1 /* | |
2 * Micrsoft 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 msrledec.c | |
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 "avcodec.h" | |
30 | |
31 #define FETCH_NEXT_STREAM_BYTE() \ | |
32 if (stream_ptr >= data_size) \ | |
33 { \ | |
34 av_log(avctx, AV_LOG_ERROR, " MS RLE: stream ptr just went out of bounds (1)\n"); \ | |
35 return -1; \ | |
36 } \ | |
37 stream_byte = data[stream_ptr++]; | |
38 | |
39 static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic, | |
40 const uint8_t *data, int data_size) | |
41 { | |
42 int stream_ptr = 0; | |
43 unsigned char rle_code; | |
44 unsigned char extra_byte, odd_pixel; | |
45 unsigned char stream_byte; | |
46 int pixel_ptr = 0; | |
47 int row_dec = pic->linesize[0]; | |
48 int row_ptr = (avctx->height - 1) * row_dec; | |
49 int frame_size = row_dec * avctx->height; | |
50 int i; | |
51 | |
52 while (row_ptr >= 0) { | |
53 FETCH_NEXT_STREAM_BYTE(); | |
54 rle_code = stream_byte; | |
55 if (rle_code == 0) { | |
56 /* fetch the next byte to see how to handle escape code */ | |
57 FETCH_NEXT_STREAM_BYTE(); | |
58 if (stream_byte == 0) { | |
59 /* line is done, goto the next one */ | |
60 row_ptr -= row_dec; | |
61 pixel_ptr = 0; | |
62 } else if (stream_byte == 1) { | |
63 /* decode is done */ | |
64 return 0; | |
65 } else if (stream_byte == 2) { | |
66 /* reposition frame decode coordinates */ | |
67 FETCH_NEXT_STREAM_BYTE(); | |
68 pixel_ptr += stream_byte; | |
69 FETCH_NEXT_STREAM_BYTE(); | |
70 row_ptr -= stream_byte * row_dec; | |
71 } else { | |
72 // copy pixels from encoded stream | |
73 odd_pixel = stream_byte & 1; | |
74 rle_code = (stream_byte + 1) / 2; | |
75 extra_byte = rle_code & 0x01; | |
76 if ((row_ptr + pixel_ptr + stream_byte > frame_size) || | |
77 (row_ptr < 0)) { | |
78 av_log(avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n"); | |
79 return -1; | |
80 } | |
81 | |
82 for (i = 0; i < rle_code; i++) { | |
83 if (pixel_ptr >= avctx->width) | |
84 break; | |
85 FETCH_NEXT_STREAM_BYTE(); | |
86 pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4; | |
87 pixel_ptr++; | |
88 if (i + 1 == rle_code && odd_pixel) | |
89 break; | |
90 if (pixel_ptr >= avctx->width) | |
91 break; | |
92 pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F; | |
93 pixel_ptr++; | |
94 } | |
95 | |
96 // if the RLE code is odd, skip a byte in the stream | |
97 if (extra_byte) | |
98 stream_ptr++; | |
99 } | |
100 } else { | |
101 // decode a run of data | |
102 if ((row_ptr + pixel_ptr + stream_byte > frame_size) || | |
103 (row_ptr < 0)) { | |
104 av_log(avctx, AV_LOG_ERROR, " MS RLE: frame ptr just went out of bounds (1)\n"); | |
105 return -1; | |
106 } | |
107 FETCH_NEXT_STREAM_BYTE(); | |
108 for (i = 0; i < rle_code; i++) { | |
109 if (pixel_ptr >= avctx->width) | |
110 break; | |
111 if ((i & 1) == 0) | |
112 pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4; | |
113 else | |
114 pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F; | |
115 pixel_ptr++; | |
116 } | |
117 } | |
118 } | |
119 | |
120 /* one last sanity check on the way out */ | |
121 if (stream_ptr < data_size) { | |
122 av_log(avctx, AV_LOG_ERROR, " MS RLE: ended frame decode with bytes left over (%d < %d)\n", | |
123 stream_ptr, data_size); | |
124 return -1; | |
125 } | |
126 | |
127 return 0; | |
128 } | |
129 | |
130 | |
131 static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic, int depth, | |
132 const uint8_t *data, int srcsize) | |
133 { | |
134 uint8_t *output, *output_end; | |
135 const uint8_t* src = data; | |
136 int p1, p2, line=avctx->height, pos=0, i; | |
137 uint16_t pix16; | |
138 uint32_t pix32; | |
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(src < data + srcsize) { | |
143 p1 = *src++; | |
144 if(p1 == 0) { //Escape code | |
145 p2 = *src++; | |
146 if(p2 == 0) { //End-of-line | |
147 output = pic->data[0] + (--line) * pic->linesize[0]; | |
148 if (line < 0) | |
149 return -1; | |
150 pos = 0; | |
151 continue; | |
152 } else if(p2 == 1) { //End-of-picture | |
153 return 0; | |
154 } else if(p2 == 2) { //Skip | |
155 p1 = *src++; | |
156 p2 = *src++; | |
157 line -= p2; | |
158 if (line < 0) | |
159 return -1; | |
160 pos += p1; | |
161 output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3); | |
162 continue; | |
163 } | |
164 // Copy data | |
165 if (output + p2 * (depth >> 3) > output_end) { | |
166 src += p2 * (depth >> 3); | |
167 continue; | |
168 } | |
169 if ((depth == 8) || (depth == 24)) { | |
170 for(i = 0; i < p2 * (depth >> 3); i++) { | |
171 *output++ = *src++; | |
172 } | |
173 // RLE8 copy is actually padded - and runs are not! | |
174 if(depth == 8 && (p2 & 1)) { | |
175 src++; | |
176 } | |
177 } else if (depth == 16) { | |
178 for(i = 0; i < p2; i++) { | |
179 pix16 = AV_RL16(src); | |
180 src += 2; | |
181 *(uint16_t*)output = pix16; | |
182 output += 2; | |
183 } | |
184 } else if (depth == 32) { | |
185 for(i = 0; i < p2; i++) { | |
186 pix32 = AV_RL32(src); | |
187 src += 4; | |
188 *(uint32_t*)output = pix32; | |
189 output += 4; | |
190 } | |
191 } | |
192 pos += p2; | |
193 } else { //Run of pixels | |
194 int pix[4]; //original pixel | |
195 switch(depth){ | |
196 case 8: pix[0] = *src++; | |
197 break; | |
198 case 16: pix16 = AV_RL16(src); | |
199 src += 2; | |
200 *(uint16_t*)pix = pix16; | |
201 break; | |
202 case 24: pix[0] = *src++; | |
203 pix[1] = *src++; | |
204 pix[2] = *src++; | |
205 break; | |
206 case 32: pix32 = AV_RL32(src); | |
207 src += 4; | |
208 *(uint32_t*)pix = pix32; | |
209 break; | |
210 } | |
211 if (output + p1 * (depth >> 3) > output_end) | |
212 continue; | |
213 for(i = 0; i < p1; i++) { | |
214 switch(depth){ | |
215 case 8: *output++ = pix[0]; | |
216 break; | |
217 case 16: *(uint16_t*)output = pix16; | |
218 output += 2; | |
219 break; | |
220 case 24: *output++ = pix[0]; | |
221 *output++ = pix[1]; | |
222 *output++ = pix[2]; | |
223 break; | |
224 case 32: *(uint32_t*)output = pix32; | |
225 output += 4; | |
226 break; | |
227 } | |
228 } | |
229 pos += p1; | |
230 } | |
231 } | |
232 | |
233 av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no End-of-picture code\n"); | |
234 return 0; | |
235 } | |
236 | |
237 | |
238 int ff_msrle_decode(AVCodecContext *avctx, AVPicture *pic, int depth, | |
239 const uint8_t* data, int data_size) | |
240 { | |
241 switch(depth){ | |
242 case 4: | |
243 return msrle_decode_pal4(avctx, pic, data, data_size); | |
244 case 8: | |
245 case 16: | |
246 case 24: | |
247 case 32: | |
248 return msrle_decode_8_16_24_32(avctx, pic, depth, data, data_size); | |
249 default: | |
250 av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth); | |
251 return -1; | |
252 } | |
253 } | |
254 |