3155
|
1 /*
|
|
2 FLI Decoder for MPlayer
|
|
3
|
|
4 (C) 2001 Mike Melanson
|
3185
|
5
|
|
6 32bpp support (c) alex
|
3155
|
7 */
|
|
8
|
|
9 #define LE_16(x) *(unsigned short *)(x)
|
|
10 #define LE_32(x) *(unsigned int *)(x)
|
|
11
|
|
12 #define FLI_256_COLOR 4
|
|
13 #define FLI_DELTA 7
|
|
14 #define FLI_COLOR 11
|
|
15 #define FLI_LC 12
|
|
16 #define FLI_BLACK 13
|
|
17 #define FLI_BRUN 15
|
|
18 #define FLI_COPY 16
|
|
19 #define FLI_MINI 18
|
|
20
|
|
21 // 256 RGB entries; 25% of these bytes will be unused, but it's faster
|
|
22 // to index 4-byte entries
|
|
23 static unsigned char palette[256 * 4];
|
|
24
|
|
25 void AVI_Decode_Fli(
|
|
26 unsigned char *encoded,
|
|
27 int encoded_size,
|
|
28 unsigned char *decoded,
|
|
29 int width,
|
|
30 int height,
|
|
31 int bytes_per_pixel)
|
|
32 {
|
|
33 int stream_ptr = 0;
|
|
34 int pixel_ptr;
|
|
35 int palette_ptr1;
|
|
36 int palette_ptr2;
|
|
37
|
|
38 unsigned int frame_size;
|
|
39 int num_chunks;
|
|
40
|
|
41 unsigned int chunk_size;
|
|
42 int chunk_type;
|
|
43
|
|
44 int i, j;
|
|
45
|
|
46 int color_packets;
|
|
47 int color_changes;
|
|
48 int color_scale;
|
|
49
|
|
50 int lines;
|
|
51 int compressed_lines;
|
|
52 int starting_line;
|
|
53 signed short line_packets;
|
|
54 int y_ptr;
|
|
55 int line_inc;
|
|
56 signed char byte_run;
|
|
57
|
|
58 frame_size = LE_32(&encoded[stream_ptr]);
|
|
59 stream_ptr += 6; // skip the magic number
|
|
60 num_chunks = LE_16(&encoded[stream_ptr]);
|
|
61 stream_ptr += 10; // skip padding
|
|
62
|
|
63 // iterate through the chunks
|
|
64 frame_size -= 16;
|
|
65 while ((frame_size > 0) && (num_chunks > 0))
|
|
66 {
|
|
67 chunk_size = LE_32(&encoded[stream_ptr]);
|
|
68 stream_ptr += 4;
|
|
69 chunk_type = LE_16(&encoded[stream_ptr]);
|
|
70 stream_ptr += 2;
|
|
71
|
|
72 switch (chunk_type)
|
|
73 {
|
|
74 case FLI_256_COLOR:
|
|
75 case FLI_COLOR:
|
|
76 if (chunk_type == FLI_COLOR)
|
|
77 color_scale = 4;
|
|
78 else
|
|
79 color_scale = 1;
|
|
80 // set up the palette
|
|
81 color_packets = LE_16(&encoded[stream_ptr]);
|
|
82 stream_ptr += 2;
|
|
83 palette_ptr1 = 0;
|
|
84 for (i = 0; i < color_packets; i++)
|
|
85 {
|
|
86 // first byte is how many colors to skip
|
|
87 palette_ptr1 += (encoded[stream_ptr++] * 4);
|
|
88 // next byte indicates how many entries to change
|
|
89 color_changes = encoded[stream_ptr++];
|
|
90 // if there are 0 color changes, there are actually 256
|
|
91 if (color_changes == 0)
|
|
92 color_changes = 256;
|
|
93 for (j = 0; j < color_changes; j++)
|
|
94 {
|
|
95 palette[palette_ptr1++] = encoded[stream_ptr + 2] * color_scale;
|
|
96 palette[palette_ptr1++] = encoded[stream_ptr + 1] * color_scale;
|
|
97 palette[palette_ptr1++] = encoded[stream_ptr + 0] * color_scale;
|
|
98 palette_ptr1++;
|
|
99 stream_ptr += 3;
|
|
100 }
|
|
101 }
|
|
102 break;
|
|
103
|
|
104 case FLI_DELTA:
|
|
105 line_inc = width * bytes_per_pixel;
|
|
106 y_ptr = 0;
|
|
107 compressed_lines = LE_16(&encoded[stream_ptr]);
|
|
108 stream_ptr += 2;
|
|
109 while (compressed_lines > 0)
|
|
110 {
|
|
111 line_packets = LE_16(&encoded[stream_ptr]);
|
|
112 stream_ptr += 2;
|
|
113 if (line_packets < 0)
|
|
114 {
|
|
115 line_packets = -line_packets;
|
|
116 y_ptr += (line_packets * line_inc);
|
|
117 }
|
|
118 else
|
|
119 {
|
|
120 pixel_ptr = y_ptr;
|
|
121 for (i = 0; i < line_packets; i++)
|
|
122 {
|
|
123 // account for the skip bytes
|
3185
|
124 pixel_ptr += encoded[stream_ptr++] * bytes_per_pixel;
|
3155
|
125 byte_run = encoded[stream_ptr++];
|
|
126 if (byte_run < 0)
|
|
127 {
|
|
128 byte_run = -byte_run;
|
|
129 palette_ptr1 = encoded[stream_ptr++] * 4;
|
|
130 palette_ptr2 = encoded[stream_ptr++] * 4;
|
|
131 for (j = 0; j < byte_run; j++)
|
|
132 {
|
|
133 decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
|
|
134 decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
|
|
135 decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
|
3185
|
136 if (bytes_per_pixel == 4) /* 32bpp */
|
|
137 pixel_ptr++;
|
3155
|
138
|
|
139 decoded[pixel_ptr++] = palette[palette_ptr2 + 0];
|
|
140 decoded[pixel_ptr++] = palette[palette_ptr2 + 1];
|
|
141 decoded[pixel_ptr++] = palette[palette_ptr2 + 2];
|
3185
|
142 if (bytes_per_pixel == 4) /* 32bpp */
|
|
143 pixel_ptr++;
|
3155
|
144 }
|
|
145 }
|
|
146 else
|
|
147 {
|
|
148 for (j = 0; j < byte_run * 2; j++)
|
|
149 {
|
|
150 palette_ptr1 = encoded[stream_ptr++] * 4;
|
|
151 decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
|
|
152 decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
|
|
153 decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
|
3185
|
154 if (bytes_per_pixel == 4) /* 32bpp */
|
|
155 pixel_ptr++;
|
3155
|
156 }
|
|
157 }
|
|
158 }
|
|
159 y_ptr += line_inc;
|
|
160 compressed_lines--;
|
|
161 }
|
|
162 }
|
|
163 break;
|
|
164
|
|
165 case FLI_LC:
|
|
166 // line compressed
|
|
167 line_inc = width * bytes_per_pixel;
|
|
168 starting_line = LE_16(&encoded[stream_ptr]);
|
|
169 stream_ptr += 2;
|
|
170 y_ptr = starting_line * line_inc;
|
|
171
|
|
172 compressed_lines = LE_16(&encoded[stream_ptr]);
|
|
173 stream_ptr += 2;
|
|
174 while (compressed_lines > 0)
|
|
175 {
|
|
176 pixel_ptr = y_ptr;
|
|
177 line_packets = encoded[stream_ptr++];
|
|
178 if (line_packets > 0)
|
|
179 {
|
|
180 for (i = 0; i < line_packets; i++)
|
|
181 {
|
|
182 // account for the skip bytes
|
3185
|
183 pixel_ptr += encoded[stream_ptr++] * bytes_per_pixel;
|
3155
|
184 byte_run = encoded[stream_ptr++];
|
|
185 if (byte_run > 0)
|
|
186 {
|
|
187 for (j = 0; j < byte_run; j++)
|
|
188 {
|
|
189 palette_ptr1 = encoded[stream_ptr++] * 4;
|
|
190 decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
|
|
191 decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
|
|
192 decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
|
3185
|
193 if (bytes_per_pixel == 4) /* 32bpp */
|
|
194 pixel_ptr++;
|
3155
|
195 }
|
|
196 }
|
|
197 else
|
|
198 {
|
|
199 byte_run = -byte_run;
|
|
200 palette_ptr1 = encoded[stream_ptr++] * 4;
|
|
201 for (j = 0; j < byte_run; j++)
|
|
202 {
|
|
203 decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
|
|
204 decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
|
|
205 decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
|
3185
|
206 if (bytes_per_pixel == 4) /* 32bpp */
|
|
207 pixel_ptr++;
|
3155
|
208 }
|
|
209 }
|
|
210 }
|
|
211 }
|
|
212
|
|
213 y_ptr += line_inc;
|
|
214 compressed_lines--;
|
|
215 }
|
|
216 break;
|
|
217
|
|
218 case FLI_BLACK:
|
|
219 // set the whole frame to color 0 (which is usually black)
|
3185
|
220 for (pixel_ptr = 0; pixel_ptr < (width * height * bytes_per_pixel); pixel_ptr++)
|
3155
|
221 {
|
|
222 decoded[pixel_ptr++] = palette[0];
|
|
223 decoded[pixel_ptr++] = palette[1];
|
|
224 decoded[pixel_ptr++] = palette[2];
|
3185
|
225 if (bytes_per_pixel == 4) /* 32bpp */
|
|
226 pixel_ptr++;
|
3155
|
227 }
|
|
228 break;
|
|
229
|
|
230 case FLI_BRUN:
|
|
231 // byte run compression
|
|
232 line_inc = width * bytes_per_pixel;
|
|
233 y_ptr = 0;
|
|
234 for (lines = 0; lines < height; lines++)
|
|
235 {
|
|
236 pixel_ptr = y_ptr;
|
|
237 line_packets = encoded[stream_ptr++];
|
|
238 for (i = 0; i < line_packets; i++)
|
|
239 {
|
|
240 byte_run = encoded[stream_ptr++];
|
|
241 if (byte_run > 0)
|
|
242 {
|
|
243 palette_ptr1 = encoded[stream_ptr++] * 4;
|
|
244 for (j = 0; j < byte_run; j++)
|
|
245 {
|
|
246 decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
|
|
247 decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
|
|
248 decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
|
3185
|
249 if (bytes_per_pixel == 4) /* 32bpp */
|
|
250 pixel_ptr++;
|
3155
|
251 }
|
|
252 }
|
|
253 else // copy bytes if byte_run < 0
|
|
254 {
|
|
255 byte_run = -byte_run;
|
|
256 for (j = 0; j < byte_run; j++)
|
|
257 {
|
|
258 palette_ptr1 = encoded[stream_ptr++] * 4;
|
|
259 decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
|
|
260 decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
|
|
261 decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
|
3185
|
262 if (bytes_per_pixel == 4) /* 32bpp */
|
|
263 pixel_ptr++;
|
3155
|
264 }
|
|
265 }
|
|
266 }
|
|
267
|
|
268 y_ptr += line_inc;
|
|
269 }
|
|
270 break;
|
|
271
|
|
272 case FLI_COPY:
|
|
273 // currently unimplemented
|
|
274 printf ("FLI_COPY chunk (currently unimplemented)\n");
|
|
275 stream_ptr += chunk_size - 6;
|
|
276 break;
|
|
277
|
|
278 case FLI_MINI:
|
|
279 // sort of a thumbnail? disregard this chunk...
|
|
280 stream_ptr += chunk_size - 6;
|
|
281 break;
|
|
282
|
|
283 default:
|
|
284 printf ("FLI: Unrecognized chunk type: %d\n", chunk_type);
|
|
285 break;
|
|
286 }
|
|
287
|
|
288 frame_size -= chunk_size;
|
|
289 num_chunks--;
|
|
290 }
|
|
291 }
|