changeset 3155:9200edf69d1d

initial commit
author melanson
date Tue, 27 Nov 2001 05:43:03 +0000
parents b2e24fec97bc
children 7d725c118ccf
files fli.c
diffstat 1 files changed, 273 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fli.c	Tue Nov 27 05:43:03 2001 +0000
@@ -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--;
+  }
+}