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