summaryrefslogtreecommitdiffstats
path: root/fli.c
diff options
context:
space:
mode:
authormelanson <melanson@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-11-27 05:43:03 +0000
committermelanson <melanson@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-11-27 05:43:03 +0000
commit56aa85c7a24c6612c758d2a7a7059507d488cb00 (patch)
tree06bbd10a7483b044ccaf21c8eb2ad99b45dd08ee /fli.c
parentb5c58f8381a8c5f566f522cb4119f23bc21304e3 (diff)
downloadmpv-56aa85c7a24c6612c758d2a7a7059507d488cb00.tar.bz2
mpv-56aa85c7a24c6612c758d2a7a7059507d488cb00.tar.xz
initial commit
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@3156 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'fli.c')
-rw-r--r--fli.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/fli.c b/fli.c
new file mode 100644
index 0000000000..d18dc87826
--- /dev/null
+++ b/fli.c
@@ -0,0 +1,273 @@
+/*
+ FLI Decoder for MPlayer
+
+ (C) 2001 Mike Melanson
+*/
+
+#define LE_16(x) *(unsigned short *)(x)
+#define LE_32(x) *(unsigned int *)(x)
+
+#define FLI_256_COLOR 4
+#define FLI_DELTA 7
+#define FLI_COLOR 11
+#define FLI_LC 12
+#define FLI_BLACK 13
+#define FLI_BRUN 15
+#define FLI_COPY 16
+#define FLI_MINI 18
+
+// 256 RGB entries; 25% of these bytes will be unused, but it's faster
+// to index 4-byte entries
+static unsigned char palette[256 * 4];
+
+void AVI_Decode_Fli(
+ unsigned char *encoded,
+ int encoded_size,
+ unsigned char *decoded,
+ int width,
+ int height,
+ int bytes_per_pixel)
+{
+ int stream_ptr = 0;
+ int pixel_ptr;
+ int palette_ptr1;
+ int palette_ptr2;
+
+ unsigned int frame_size;
+ int num_chunks;
+
+ unsigned int chunk_size;
+ int chunk_type;
+
+ int i, j;
+
+ int color_packets;
+ int color_changes;
+ int color_scale;
+
+ int lines;
+ int compressed_lines;
+ int starting_line;
+ signed short line_packets;
+ int y_ptr;
+ int line_inc;
+ signed char byte_run;
+
+ frame_size = LE_32(&encoded[stream_ptr]);
+ stream_ptr += 6; // skip the magic number
+ num_chunks = LE_16(&encoded[stream_ptr]);
+ stream_ptr += 10; // skip padding
+
+ // iterate through the chunks
+ frame_size -= 16;
+ while ((frame_size > 0) && (num_chunks > 0))
+ {
+ chunk_size = LE_32(&encoded[stream_ptr]);
+ stream_ptr += 4;
+ chunk_type = LE_16(&encoded[stream_ptr]);
+ stream_ptr += 2;
+
+ switch (chunk_type)
+ {
+ case FLI_256_COLOR:
+ case FLI_COLOR:
+ if (chunk_type == FLI_COLOR)
+ color_scale = 4;
+ else
+ color_scale = 1;
+ // set up the palette
+ color_packets = LE_16(&encoded[stream_ptr]);
+ stream_ptr += 2;
+ palette_ptr1 = 0;
+ for (i = 0; i < color_packets; i++)
+ {
+ // first byte is how many colors to skip
+ palette_ptr1 += (encoded[stream_ptr++] * 4);
+ // next byte indicates how many entries to change
+ color_changes = encoded[stream_ptr++];
+ // if there are 0 color changes, there are actually 256
+ if (color_changes == 0)
+ color_changes = 256;
+ for (j = 0; j < color_changes; j++)
+ {
+ palette[palette_ptr1++] = encoded[stream_ptr + 2] * color_scale;
+ palette[palette_ptr1++] = encoded[stream_ptr + 1] * color_scale;
+ palette[palette_ptr1++] = encoded[stream_ptr + 0] * color_scale;
+ palette_ptr1++;
+ stream_ptr += 3;
+ }
+ }
+ break;
+
+ case FLI_DELTA:
+ line_inc = width * bytes_per_pixel;
+ y_ptr = 0;
+ compressed_lines = LE_16(&encoded[stream_ptr]);
+ stream_ptr += 2;
+ while (compressed_lines > 0)
+ {
+ line_packets = LE_16(&encoded[stream_ptr]);
+ stream_ptr += 2;
+ if (line_packets < 0)
+ {
+ line_packets = -line_packets;
+ y_ptr += (line_packets * line_inc);
+ }
+ else
+ {
+ pixel_ptr = y_ptr;
+ for (i = 0; i < line_packets; i++)
+ {
+ // account for the skip bytes
+ pixel_ptr += encoded[stream_ptr++] * 3;
+ byte_run = encoded[stream_ptr++];
+ if (byte_run < 0)
+ {
+ byte_run = -byte_run;
+ palette_ptr1 = encoded[stream_ptr++] * 4;
+ palette_ptr2 = encoded[stream_ptr++] * 4;
+ for (j = 0; j < byte_run; j++)
+ {
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
+
+ decoded[pixel_ptr++] = palette[palette_ptr2 + 0];
+ decoded[pixel_ptr++] = palette[palette_ptr2 + 1];
+ decoded[pixel_ptr++] = palette[palette_ptr2 + 2];
+ }
+ }
+ else
+ {
+ for (j = 0; j < byte_run * 2; j++)
+ {
+ palette_ptr1 = encoded[stream_ptr++] * 4;
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
+ }
+ }
+ }
+ y_ptr += line_inc;
+ compressed_lines--;
+ }
+ }
+ break;
+
+ case FLI_LC:
+ // line compressed
+ line_inc = width * bytes_per_pixel;
+ starting_line = LE_16(&encoded[stream_ptr]);
+ stream_ptr += 2;
+ y_ptr = starting_line * line_inc;
+
+ compressed_lines = LE_16(&encoded[stream_ptr]);
+ stream_ptr += 2;
+ while (compressed_lines > 0)
+ {
+ pixel_ptr = y_ptr;
+ line_packets = encoded[stream_ptr++];
+ if (line_packets > 0)
+ {
+ for (i = 0; i < line_packets; i++)
+ {
+ // account for the skip bytes
+ pixel_ptr += encoded[stream_ptr++] * 3;
+ byte_run = encoded[stream_ptr++];
+ if (byte_run > 0)
+ {
+ for (j = 0; j < byte_run; j++)
+ {
+ palette_ptr1 = encoded[stream_ptr++] * 4;
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
+ }
+ }
+ else
+ {
+ byte_run = -byte_run;
+ palette_ptr1 = encoded[stream_ptr++] * 4;
+ for (j = 0; j < byte_run; j++)
+ {
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
+ }
+ }
+ }
+ }
+
+ y_ptr += line_inc;
+ compressed_lines--;
+ }
+ break;
+
+ case FLI_BLACK:
+ // set the whole frame to color 0 (which is usually black)
+ for (pixel_ptr = 0; pixel_ptr < (width * height * 3); pixel_ptr++)
+ {
+ decoded[pixel_ptr++] = palette[0];
+ decoded[pixel_ptr++] = palette[1];
+ decoded[pixel_ptr++] = palette[2];
+ }
+ break;
+
+ case FLI_BRUN:
+ // byte run compression
+ line_inc = width * bytes_per_pixel;
+ y_ptr = 0;
+ for (lines = 0; lines < height; lines++)
+ {
+ pixel_ptr = y_ptr;
+ line_packets = encoded[stream_ptr++];
+ for (i = 0; i < line_packets; i++)
+ {
+ byte_run = encoded[stream_ptr++];
+ if (byte_run > 0)
+ {
+ palette_ptr1 = encoded[stream_ptr++] * 4;
+ for (j = 0; j < byte_run; j++)
+ {
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
+ }
+ }
+ else // copy bytes if byte_run < 0
+ {
+ byte_run = -byte_run;
+ for (j = 0; j < byte_run; j++)
+ {
+ palette_ptr1 = encoded[stream_ptr++] * 4;
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 0];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 1];
+ decoded[pixel_ptr++] = palette[palette_ptr1 + 2];
+ }
+ }
+ }
+
+ y_ptr += line_inc;
+ }
+ break;
+
+ case FLI_COPY:
+// currently unimplemented
+printf ("FLI_COPY chunk (currently unimplemented)\n");
+stream_ptr += chunk_size - 6;
+ break;
+
+ case FLI_MINI:
+ // sort of a thumbnail? disregard this chunk...
+ stream_ptr += chunk_size - 6;
+ break;
+
+ default:
+ printf ("FLI: Unrecognized chunk type: %d\n", chunk_type);
+ break;
+ }
+
+ frame_size -= chunk_size;
+ num_chunks--;
+ }
+}