[MPlayer-dev-eng] FLI File Support Complete

Mike Melanson melanson at pcisys.net
Sat Nov 24 23:01:36 CET 2001


Hi team,
	All right, disregard the last set of patches I sent for the FLI
demuxer. Attached to this email are the patches for both the demuxer and
the image decoder for FLI files. Of course, fli.c goes in the main
directory and demux_fli.c belongs in libmpdemux.

	My FLI collection is limited to 7 files, 4 of which were already
on the samples FTP. I've uploaded the other 3 I have. If people have
collections of FLI files, please test this support. If you have any FLI
files that don't work with MPlayer now, I'd be very interested to get
ahold of them.

-- 
	-Mike Melanson
-------------- next part --------------
Index: Makefile
===================================================================
RCS file: /cvsroot/mplayer/main/Makefile,v
retrieving revision 1.105
diff -r1.105 Makefile
24c24
< SRCS_MENCODER = libao2/afmt.c divx4_vbr.c mencoder.c libvo/aclib.c libvo/img_format.c ima4.c xacodec.c cpudetect.c mp_msg.c ac3-iec958.c dec_audio.c dec_video.c msvidc.c codec-cfg.c cfgparser.c my_profile.c
---
> SRCS_MENCODER = libao2/afmt.c divx4_vbr.c mencoder.c libvo/aclib.c libvo/img_format.c ima4.c xacodec.c cpudetect.c mp_msg.c ac3-iec958.c dec_audio.c dec_video.c msvidc.c codec-cfg.c cfgparser.c my_profile.c fli.c
27c27
< SRCS_MPLAYER = mplayer.c ima4.c xacodec.c cpudetect.c mp_msg.c ac3-iec958.c find_sub.c dec_audio.c dec_video.c msvidc.c codec-cfg.c subreader.c lirc_mp.c cfgparser.c mixer.c spudec.c my_profile.c
---
> SRCS_MPLAYER = mplayer.c ima4.c xacodec.c cpudetect.c mp_msg.c ac3-iec958.c find_sub.c dec_audio.c dec_video.c msvidc.c codec-cfg.c subreader.c lirc_mp.c cfgparser.c mixer.c spudec.c my_profile.c fli.c
Index: codec-cfg.c
===================================================================
RCS file: /cvsroot/mplayer/main/codec-cfg.c,v
retrieving revision 1.47
diff -r1.47 codec-cfg.c
230a231
> 		"fli",
Index: codec-cfg.h
===================================================================
RCS file: /cvsroot/mplayer/main/codec-cfg.h,v
retrieving revision 1.23
diff -r1.23 codec-cfg.h
45a46
> #define VFM_FLI 12
Index: dec_video.c
===================================================================
RCS file: /cvsroot/mplayer/main/dec_video.c,v
retrieving revision 1.67
diff -r1.67 dec_video.c
125a126,134
> void AVI_Decode_Fli(
>   unsigned char *encoded,
>   int encoded_size,
>   unsigned char *decoded,
>   int width,
>   int height,
>   int bytes_per_pixel);
> 
> 
558a568,573
>  case VFM_FLI: {
>    int bpp=((out_fmt&255)+7)/8; // RGB only
>    sh_video->our_out_buffer = 
>      (char*)memalign(64, sh_video->disp_w*sh_video->disp_h*bpp); // FIXME!!!
>    }
>    break;
805a821,827
>     blit_frame = 3;
>     break;
>   case VFM_FLI:
>       AVI_Decode_Fli(
>         start, in_size, sh_video->our_out_buffer,
>         sh_video->disp_w, sh_video->disp_h,
>         ((out_fmt&255)+7)/8);
Index: help_mp-cz.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-cz.h,v
retrieving revision 1.3
diff -r1.3 help_mp-cz.h
134a135
> #define MSGTR_DetectedFLIfile "Detekov?n FLI form?t souboru!\n"
Index: help_mp-de.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-de.h,v
retrieving revision 1.14
diff -r1.14 help_mp-de.h
133a134
> #define MSGTR_DetectedFLIfile "FLI Dateiformat erkannt!\n"
Index: help_mp-dk.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-dk.h,v
retrieving revision 1.1
diff -r1.1 help_mp-dk.h
132a133
> #define MSGTR_DetectedFLIfile "Detecterede FLI fil format!\n"
Index: help_mp-en.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-en.h,v
retrieving revision 1.12
diff -r1.12 help_mp-en.h
137a138
> #define MSGTR_DetectedFLIfile "Detected FLI file format!\n"
Index: help_mp-es.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-es.h,v
retrieving revision 1.1
diff -r1.1 help_mp-es.h
134a135
> #define MSGTR_DetectedFLIfile "Detectado formato de archivo FLI!\n"
Index: help_mp-fr.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-fr.h,v
retrieving revision 1.4
diff -r1.4 help_mp-fr.h
143a144
> #define MSGTR_DetectedFLIfile "Format de fichier FLI d?tect?!\n"
Index: help_mp-hu.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-hu.h,v
retrieving revision 1.17
diff -r1.17 help_mp-hu.h
133a134
> #define MSGTR_DetectedFLIfile "Ez egy FLI form?tum? file!\n"
Index: help_mp-nl.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-nl.h,v
retrieving revision 1.3
diff -r1.3 help_mp-nl.h
133a134
> #define MSGTR_DetectedFLIfile "FLI bestandsformaat gedetecteerd!\n"
Index: help_mp-no.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-no.h,v
retrieving revision 1.1
diff -r1.1 help_mp-no.h
132a133
> #define MSGTR_DetectedFLIfile "Detekterte FLI filformat!\n"
Index: help_mp-pl.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-pl.h,v
retrieving revision 1.13
diff -r1.13 help_mp-pl.h
136a137
> #define MSGTR_DetectedFLIfile "Wykryto format FLI!\n"
Index: help_mp-ro.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-ro.h,v
retrieving revision 1.1
diff -r1.1 help_mp-ro.h
132a133
> #define MSGTR_DetectedFLIfile "Format fi?ier detectat: FLI\n"
Index: help_mp-ru.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-ru.h,v
retrieving revision 1.2
diff -r1.2 help_mp-ru.h
132a133
> #define MSGTR_DetectedFLIfile "????????? FLI ?????? ?????!\n"
Index: libmpdemux/Makefile
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/Makefile,v
retrieving revision 1.10
diff -r1.10 Makefile
6c6
< SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c frequencies.c
---
> SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c frequencies.c demux_fli.c
Index: libmpdemux/demuxer.c
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/demuxer.c,v
retrieving revision 1.50
diff -r1.50 demuxer.c
151a152
> int demux_fli_fill_buffer(demuxer_t *demux);
172a174
>     case DEMUXER_TYPE_FLI: return demux_fli_fill_buffer(demux);
356a359
> int demux_open_fli(demuxer_t* demuxer);
383a387,400
> //=============== Try to open as FLI file: =================
> if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_FLI){
>   demuxer=new_demuxer(stream,DEMUXER_TYPE_FLI,audio_id,video_id,dvdsub_id);
>   {
>     int size=stream_read_dword_le(demuxer->stream);
>     int id=stream_read_word_le(demuxer->stream);
>     // chech for the FLI file magic number
>     if((id==0xAF11) || (id==0xAF12)){ 
>       mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_DetectedFLIfile);
>       file_format=DEMUXER_TYPE_FLI;
>     }
>   }
> }
> 
483a501,504
>  case DEMUXER_TYPE_FLI: {
>   if (!demux_open_fli(demuxer)) return NULL;
>   break;
>  }
Index: libmpdemux/demuxer.h
===================================================================
RCS file: /cvsroot/mplayer/main/libmpdemux/demuxer.h,v
retrieving revision 1.21
diff -r1.21 demuxer.h
14a15
> #define DEMUXER_TYPE_FLI 10

-------------- next part --------------
/*
    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[257 * 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;
  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  // copy bytes if byte_run < 0
            {
              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:
// currently unimplemented
stream_ptr += chunk_size - 6;
      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
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--;
  }
}
-------------- next part --------------
/*
	FLI file parser for the MPlayer program
	by Mike Melanson
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "config.h"
#include "mp_msg.h"
#include "help_mp.h"

#include "stream.h"
#include "demuxer.h"
#include "stheader.h"

typedef struct _fli_frames_t {
  int num_frames;
  int current_frame;
  off_t *filepos;
  unsigned int *frame_size;
} fli_frames_t;

// return value:
//     0 = EOF or no stream found
//     1 = successfully read a packet
int demux_fli_fill_buffer(demuxer_t *demuxer){
  fli_frames_t *frames = (fli_frames_t *)demuxer->priv;

  // see if the end has been reached
  if (frames->current_frame == frames->num_frames)
    return 0;

  // fetch the frame from the file
  // first, position the file properly since ds_read_packet() doesn't
  // seem to do it, even though it takes a file offset as a parameter
  stream_seek(demuxer->stream, frames->filepos[frames->current_frame]);
  ds_read_packet(demuxer->video,
    demuxer->stream, 
    frames->frame_size[frames->current_frame],
    0, /* not sure what pts is for */
    frames->filepos[frames->current_frame],
    0 /* what flags? */
  );

  // get the next frame ready
  frames->current_frame++;

  return 1;
}

demuxer_t* demux_open_fli(demuxer_t* demuxer){
  sh_video_t *sh_video = NULL;
  fli_frames_t *frames = (fli_frames_t *)malloc(sizeof(fli_frames_t));
  int frame_number;

  // go back to the beginning
  stream_reset(demuxer->stream);
  stream_seek(demuxer->stream, 0);
  demuxer->movi_start = 128;
  demuxer->movi_end = stream_read_dword_le(demuxer->stream);

  // skip the magic number
  stream_skip(demuxer->stream, 2);

  // fetch the number of frames
  frames->num_frames = stream_read_word_le(demuxer->stream);
  frames->current_frame = 0;

  // allocate enough entries for the indices
  frames->filepos = (off_t *)malloc(frames->num_frames * sizeof(off_t));
  frames->frame_size = (int *)malloc(frames->num_frames * sizeof(int));

  // create a new video stream header
  sh_video = new_sh_video(demuxer, 0);

  // make sure the demuxer knows about the new video stream header
  // (even though new_sh_video() ought to take care of it)
  demuxer->video->sh = sh_video;

  // make sure that the video demuxer stream header knows about its
  // parent video demuxer stream (this is getting wacky), or else
  // video_read_properties() will choke
  sh_video->ds = demuxer->video;

  // custom fourcc for internal MPlayer use
  sh_video->format = mmioFOURCC('F', 'L', 'I', 'C');

  sh_video->disp_w = stream_read_word_le(demuxer->stream);
  sh_video->disp_h = stream_read_word_le(demuxer->stream);

  // skip the video depth and flags
  stream_skip(demuxer->stream, 4);

  // get the speed
  sh_video->fps = 1000 / stream_read_word_le(demuxer->stream);
  sh_video->frametime = 1/sh_video->fps;

  // build the frame index
  stream_seek(demuxer->stream, demuxer->movi_start);
  frame_number = 0;
  while ((!stream_eof(demuxer->stream)) && (frame_number < frames->num_frames))
  {
    frames->filepos[frame_number] = stream_tell(demuxer->stream);
    frames->frame_size[frame_number] = stream_read_dword_le(demuxer->stream);
    stream_skip(demuxer->stream, frames->frame_size[frame_number] - 4);
    frame_number++;
  }

  demuxer->priv = frames;

  return demuxer;
}


More information about the MPlayer-dev-eng mailing list