DirectFB - Home of the pragmatist Roadmap


[directfb-users] animated GIF/video playback
Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[directfb-users] animated GIF/video playback




I decided to implement animated graphics playback as a video provider.
It makes the most sense.  My video provider is attached.  I tried to
reuse as much code from the GIF image provider as possible.  It is still
lacking some error checking.  And it won't work with optimized GIF
animations.  ie.  those with only partial graphics on a frame.  I'll
release my flash video provider once I get it working with all flash 5
animations.  The current one wasn't a very complete implementation.
/*
   (c) Copyright 2000-2002  convergence integrated media GmbH.
   (c) Copyright 2002       convergence GmbH.
   
   All rights reserved.

   Written by Denis Oliver Kropp <dok@directfb.org>,
              Andreas Hundt <andi@fischlustig.de> and
              Sven Neumann <sven@convergence.de>.
              
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>

#include <pthread.h>

#include <directfb.h>
#include <directfb_internals.h>

#include <media/idirectfbvideoprovider.h>
#include <media/idirectfbdatabuffer.h>

#include <core/coredefs.h>
#include <core/coretypes.h>

#include <core/layers.h>
#include <core/surfaces.h>

#include <display/idirectfbsurface.h>

#include <misc/gfx_util.h>
#include <misc/util.h>
#include <misc/mem.h>
#include <misc/memcpy.h>

#define MAX_COLORMAP_SIZE 256

#define CM_RED   0
#define CM_GREEN 1
#define CM_BLUE  2

#define MAX_LWZ_BITS 12

#define SOURCE "DirectFB/VideoProvider_GIF"
#define LM_to_uint(a,b) (((b)<<8)|(a))



static DFBResult
Probe(IDirectFBVideoProvider_ProbeContext *ctx);

static DFBResult
Construct(IDirectFBVideoProvider *thiz,
	  const char             *filename);

#include <interface_implementation.h>

DFB_INTERFACE_IMPLEMENTATION(IDirectFBVideoProvider, GIF)

typedef struct
{
  int                  ref;       /* reference counter */
  pthread_t            thread;
  
  int                  width;
  int                  height;
  int                  bpp;
  int                  depth;
  int                  bg;
  int                  aspect_ratio;

  __u8                 colormap[3][MAX_COLORMAP_SIZE];

  IDirectFBSurface    *destination;
  DFBRectangle         dest_rect;
  
  DVFrameCallback      callback;
  void                *ctx;
  
  int                  greyscale;
  int                  transparent;
  int                  delay;
  int                  inputflag;
  int                  disposal;

  int                  set_code_size;
  int                  code_size;
  int                  clear_code;
  int                  end_code;
  int                  max_code_size;
  int                  max_code;

  int                  curbit;
  int                  lastbit;
  int                  done;
  int                  last_byte;

  int                  fresh;
  int                  firstcode;
  int                  oldcode;

  __u8                 buf[280];

  IDirectFBDataBuffer *buffer;
  
  CoreSurface         *source;
  
  int table[2][(1<< MAX_LWZ_BITS)];
  int stack[(1<<(MAX_LWZ_BITS))*2], *sp;

} IDirectFBVideoProvider_GIF_data;



static int
__lzw_read(IDirectFBVideoProvider_GIF_data *data, int flag, int input_code_size);

static __u32
__find_colorkey(int colors, __u8 colormap[3][MAX_COLORMAP_SIZE]);

static int
__read_block(IDirectFBDataBuffer *buffer, __u8 *buf);

static int
__read_colormap(IDirectFBDataBuffer *buffer, int number, __u8 buf[3][MAX_COLORMAP_SIZE]);

static int
__read(IDirectFBDataBuffer *buffer, void *data, unsigned int length);




static void
debug(char *src, char *format, ...)
{
  va_list args;
  
  if (src && *src)
    fprintf(stdout, "(%s) ", src);
  va_start(args, format);
  vfprintf(stdout, format, args);
  va_end(args);
  fflush(stdout);
}

static int
GetCode(IDirectFBVideoProvider_GIF_data *data, int code_size, int flag)
{
  int           i, j, ret;
  unsigned char count;
  
  if (flag)
    {
      data->curbit = 0;
      data->lastbit = 0;
      data->done = false;
      return 0;
    }
  
  if ((data->curbit+code_size) >= data->lastbit)
    {
      if (data->done) {
	if (data->curbit >= data->lastbit) {
	  debug(SOURCE, "ran off end of bits\n");
	}
	return -1;
      }

    data->buf[0] = data->buf[data->last_byte-2];
    data->buf[1] = data->buf[data->last_byte-1];
    
    if ((count = __read_block( data->buffer, &data->buf[2] )) == 0) {
      data->done = true;
    }
    
    data->last_byte = 2 + count;
    data->curbit = (data->curbit - data->lastbit) + 16;
    data->lastbit = (2+count) * 8;
    }
  
  ret = 0;
  for (i = data->curbit, j = 0; j < code_size; ++i, ++j) {
    ret |= ((data->buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  }
  data->curbit += code_size;
  
  return ret;
}


static int
__lzw_read(IDirectFBVideoProvider_GIF_data *data, int flag, int input_code_size)
{
  int code, incode;
     int i;

     if (flag) {
          data->set_code_size = input_code_size;
          data->code_size = data->set_code_size+1;
          data->clear_code = 1 << data->set_code_size ;
          data->end_code = data->clear_code + 1;
          data->max_code_size = 2*data->clear_code;
          data->max_code = data->clear_code+2;
	  
          GetCode(data, 0, true);
	  
          data->fresh = true;

          for (i = 0; i < data->clear_code; ++i) {
               data->table[0][i] = 0;
               data->table[1][i] = i;
          }
          for (; i < (1<<MAX_LWZ_BITS); ++i) {
               data->table[0][i] = data->table[1][0] = 0;
          }
          data->sp = data->stack;

          return 0;
     }
     else if (data->fresh) {
          data->fresh = false;
          do {
               data->firstcode = data->oldcode = GetCode( data, data->code_size, false );
          } while (data->firstcode == data->clear_code);

          return data->firstcode;
     }

     if (data->sp > data->stack) {
          return *--data->sp;
     }

     while ((code = GetCode( data, data->code_size, false )) >= 0) {
          if (code == data->clear_code) {
               for (i = 0; i < data->clear_code; ++i) {
                    data->table[0][i] = 0;
                    data->table[1][i] = i;
               }
               for (; i < (1<<MAX_LWZ_BITS); ++i) {
                    data->table[0][i] = data->table[1][i] = 0;
               }
               data->code_size = data->set_code_size+1;
               data->max_code_size = 2*data->clear_code;
               data->max_code = data->clear_code+2;
               data->sp = data->stack;
               data->firstcode = data->oldcode = GetCode( data, data->code_size, false );

               return data->firstcode;
          }
          else if (code == data->end_code) {
               int count;
               __u8 buf[260];

               
               while ((count = __read_block( data->buffer, buf )) > 0)
                    ;

               if (count != 0)
		 printf("missing EOD in data stream "
			"(common occurence)\n");

               return -2;
          }

          incode = code;

          if (code >= data->max_code) {
               *data->sp++ = data->firstcode;
               code = data->oldcode;
          }

          while (code >= data->clear_code) {
               *data->sp++ = data->table[1][code];
               if (code == data->table[0][code]) {
                    printf("circular table entry BIG ERROR\n");
               }
               code = data->table[0][code];
          }

          *data->sp++ = data->firstcode = data->table[1][code];

          if ((code = data->max_code) <(1<<MAX_LWZ_BITS)) {
               data->table[0][code] = data->oldcode;
               data->table[1][code] = data->firstcode;
               ++data->max_code;
               if ((data->max_code >= data->max_code_size)
                   && (data->max_code_size < (1<<MAX_LWZ_BITS)))
               {
                    data->max_code_size *= 2;
                    ++data->code_size;
               }
          }

          data->oldcode = incode;

          if (data->sp > data->stack) {
               return *--data->sp;
          }
     }
     return code;
}


static __u32 *
__read_image(IDirectFBVideoProvider_GIF_data *data, int width, int height,
	     __u8 cmap[3][MAX_COLORMAP_SIZE], __u32 key_rgb, int interlace)
{
  __u8   c;
  int    v;
  
  int    xpos = 0;
  int    ypos = 0;
  int    pass = 0;

  __u32 *image  = 0;

  __read(data->buffer, &c, 1);
  
  if (__lzw_read(data, 1, c) < 0)
    {
      debug(SOURCE, "error reading image\n");
      return 0;
    }

  if (!(image = DFBMALLOC(width * height * 4)))
    {
      debug(SOURCE, "cannot allocate image\n");
      return 0;
    }
  
  //debug(SOURCE, "reading %dx%d GIF image\n",
  //width, height);

  while ((v = __lzw_read(data, 0, c)) >= 0)
    {
      __u32 *dst = image + (ypos * width + xpos);
      
      if (v == data->transparent)
	*dst++ = key_rgb;
      
      else
	{
	  *dst++ = 
	    (0xff000000               |
	     cmap[CM_RED][v]    << 16 |
	     cmap[CM_GREEN][v]  << 8  |
	     cmap[CM_BLUE][v]);
	}

      ++xpos;
      if (xpos == width)
	{
	  xpos = 0;
	  if (interlace)
	    {
	      switch (pass)
		{
		case 0:
		case 1:
		  xpos +=8;
		  break;
		case 2:
		  ypos += 4;
		  break;
		case 3:
		  ypos +=2;
		  break;
		}

	      if (ypos >= height)
		{
		  ++pass;
		  switch (pass)
		    {
		    case 1:
		      ypos = 4;
		      break;
		    case 2:
		      ypos = 2;
		      break;
		    case 3:
		      ypos = 1;
		      break;
		    default:
		      goto read_image_done;
		    }
		}
	    }

	  else
	    {
	      ++ypos;
	    }
	}

      if (ypos >= height)
	break;
    }
    
 read_image_done:
  if (__lzw_read(data, 0, c) >= 0)
    {
      debug(SOURCE, "too much input data. ignoring extra\n");
    }

  return image;
}


static int
__sort_colors(const void *a, const void *b)
{
  return (*((const __u8 *) a) - *((const __u8 *) b));
}


static __u32
__find_colorkey( int n_colors, __u8 cmap[3][MAX_COLORMAP_SIZE] )
{
     __u32 color = 0xFF000000;
     __u8  csort[MAX_COLORMAP_SIZE];
     int   i, j, index, d;

     if (n_colors < 1)
          return color;

     DFB_ASSERT( n_colors <= MAX_COLORMAP_SIZE );

     for (i = 0; i < 3; i++) {
          dfb_memcpy( csort, cmap[i], n_colors );
          qsort( csort, n_colors, 1, __sort_colors );
          
          for (j = 1, index = 0, d = 0; j < n_colors; j++) {
               if (csort[j] - csort[j-1] > d) {
                    d = csort[j] - csort[j-1];
                    index = j;
               }
          }
          if ((csort[0] - 0x0) > d) {
               d = csort[0] - 0x0;
               index = n_colors;
          }
          if (0xFF - (csort[n_colors - 1]) > d) {
               index = n_colors + 1;
          }
          
          if (index < n_colors)
               csort[0] = csort[index] - (d/2);
          else if (index == n_colors)
               csort[0] = 0x0;
          else
               csort[0] = 0xFF;

          color |= (csort[0] << (8 * (2 - i)));
     }

     return color;
}


static int
__read_block(IDirectFBDataBuffer *buffer, __u8 *buf)
{
  unsigned char count;

  if (!(__read(buffer, &count, 1)))
    {
      debug(SOURCE, "error getting block size\n");
      return -1;
    }

  if ((count != 0) && (!(__read(buffer, buf, count))))
    {
      debug(SOURCE, "error reading data block\n");
      return -1;
    }

  return count;
}

static int
__read_colormap(IDirectFBDataBuffer *buffer, int number, __u8 buf[3][MAX_COLORMAP_SIZE])
{
  int    i;
  __u8   rgb[3];

  for (i=0; i<number; ++i)
    {
      if (!(__read(buffer, rgb, sizeof(rgb))))
	{
	  debug(SOURCE, "bad colormap\n");
	  return 1;
	}
      
      buf[CM_RED][i]    = rgb[0];
      buf[CM_GREEN][i]  = rgb[1];
      buf[CM_BLUE][i]   = rgb[2];
    }

  return 0;
}

static int
__read(IDirectFBDataBuffer *buffer, void *data, unsigned int length)
{
  DFBResult ret;
  
  if ((ret = buffer->WaitForData(buffer, length)))
    return 0;

  if ((ret = buffer->GetData(buffer, length, data, 0)))
    return 0;

  return 1;
}


static int
__read_gif_header(IDirectFBVideoProvider_GIF_data *data,
		  int *width, int *height, int *transparency)
{
  __u8   buf[16];
  
  if (data->buffer->SeekTo(data->buffer, 0))
    {
      debug(SOURCE, "unable to seek\n");
      return -1;
    }

  if (!(__read(data->buffer, buf, 6)))
    {
      debug(SOURCE, "error reading magic number\n");
      return -1;
    }

  if (strncmp((char *)buf, "GIF", 3))
    {
      debug(SOURCE, "not a GIF file\n");
      return -1;
    }

  if (strncmp((char *)buf+3, "87a", 3) &&
      strncmp((char *)buf+3, "89a", 3))
    {
      debug(SOURCE, "invalid GIF version\n");
      return -1;
    }

  if (!(__read(data->buffer, buf, 7)))
    {
      debug(SOURCE, "failed to read screen descriptor\n");
      return -1;
    }
  
  *width  = LM_to_uint(buf[0], buf[1]);
  *height = LM_to_uint(buf[2], buf[3]);

  return 0;
}


static void *
FrameThread(void *ctx)
{
  DFBResult                ret;
  __u8                     buf[256], c;
  int                      image_start = 0;
  int     colorkey, transparent, bpp, alpha;
	__u32   key_rgb = 0;
	__u8    local_colormap[3][MAX_COLORMAP_SIZE];
	__u32  *image_data;
	int     g_colormap;
  
  IDirectFBVideoProvider_GIF_data *data = (IDirectFBVideoProvider_GIF_data *)ctx;
  
  
  ret = data->buffer->SeekTo(data->buffer, 0);
  if (ret)
    {
      debug(SOURCE, "unable to seek\n");
      return 0;
    }

  if (!(__read(data->buffer, buf, 6)))
    debug(SOURCE, "error reading magic number\n");

  if (strncmp((char *)buf, "GIF", 3))
    debug(SOURCE, "probably not a GIF\n");

  if (strncmp((char *)(buf+3), "87a", 3) &&
      strncmp((char *)(buf+3), "89a", 3))
    {
      debug(SOURCE, "bad version number, not '87a' or '89a'\n");
    }

  if (!(__read(data->buffer, buf, 7)))
    {
      debug(SOURCE, "failed to read screen descriptor\n");
      return 0;
    }

  data->width           = LM_to_uint(buf[0], buf[1]);
  data->height          = LM_to_uint(buf[2], buf[3]);
  data->bpp             = 2 << (buf[4] & 0x07);
  data->depth           = (((buf[4] & 0x70) >> 3) + 1);
  data->bg              = buf[5];
  data->aspect_ratio    = buf[6];

  if (buf[4] & 0x80)
    {
      if (__read_colormap(data->buffer, data->bpp, data->colormap))
	debug(SOURCE, "error reading colormap\n");
    }

  if (data->aspect_ratio && data->aspect_ratio != 49)
    debug(SOURCE, "non-square pixels\n");
  
  data->transparent   = -1;
  data->delay         = -1;
  data->inputflag     = -1;
  data->disposal      = 0;

  data->buffer->GetPosition(data->buffer, &image_start);
  
  for (;;)
    {
      if (!(__read(data->buffer, &c, 1)))
	debug(SOURCE, "EOF/read error on image data\n");

      if (c == ';')  //  GIF terminator
	{
	  data->buffer->SeekTo(data->buffer, image_start);
	  continue;
	}

      if (c == '!')  //  GIF extension
	{
	  __read(data->buffer, &c, 1);
	  
	  switch (c)
	    {
	    case 0x01: //  plain text extension
	      break;
	    case 0xff: //  application extension
	      break;
	    case 0xfe: //  comment
	      while (__read_block(data->buffer, (__u8 *)buf))
		{
		  //debug("", "%s\n", buf);
		}
	      break;
	    case 0xf9: //  graphic control extension
	      __read_block(data->buffer, (__u8 *)buf);
	      data->disposal     = (buf[0] >> 2) & 0x07;
	      data->inputflag    = (buf[0] >> 1) & 0x01;
	      data->delay        = LM_to_uint(buf[1], buf[2]);
	      
	      if ((buf[0] & 0x01))
		data->transparent = buf[3];
	      break;
	    default:
	      debug(SOURCE, "unknown extension 0x%02x\n", c);
	      break;
	    }
	}

      if (c != ',')
	continue;

      //  image block
      {
	alpha = 0;
	
	__read(data->buffer, buf, 9);
	
	transparent = (data->transparent != -1);
	
	g_colormap = !(buf[8] & 0x80);
	
	if (g_colormap)
	  {
	    if (transparent)
	      colorkey = __find_colorkey(data->bpp, data->colormap);
	  }
	
	else
	  {
	    bpp = 2 << (buf[8] & 0x07);
	    if (__read_colormap(data->buffer, data->bpp, local_colormap))
	      debug(SOURCE, "error reading local colormap\n");
	    
	    if (transparent)
	      colorkey = __find_colorkey(bpp, local_colormap);
	  }
	
	if (key_rgb)
	  key_rgb  = colorkey;
	
	if (alpha)
	  colorkey = 0x00ffffff;
	
	image_data = __read_image(data, data->width, data->height,
				  (g_colormap) ? data->colormap : local_colormap,
				  colorkey, (buf[8] & 0x40));
	
	if (image_data)
	  {
	    DFBRectangle   rect, drect;
	    void          *dst;
	    int            pitch;
	    
	    rect.x = 0;
	    rect.y = 0;
	    rect.w = (int) data->width;
	    rect.h = (int) data->height;
	    
	    drect = data->dest_rect;
	    
	    data->destination->Lock(data->destination, DSLF_WRITE, &dst, &pitch);
	    
	    dfb_scale_linear_32(image_data, data->width, data->height,
				dst, pitch, &drect, data->source);
	    data->destination->Unlock(data->destination);
	    
	    if (data->callback)
	      data->callback (data->ctx);
	    
	    DFBFREE(image_data);
	    
	    //  delay frame time
	    usleep(data->delay * 10000);
	  }
      }
    }
}


static void
IDirectFBVideoProvider_GIF_Destruct(IDirectFBVideoProvider *thiz)
{
  IDirectFBVideoProvider_GIF_data *data;
  
  data = (IDirectFBVideoProvider_GIF_data*)thiz->priv;
  
  thiz->Stop(thiz);
  
  dfb_surface_unref(data->source);
  
  DFB_DEALLOCATE_INTERFACE(thiz);
}

static DFBResult
IDirectFBVideoProvider_GIF_AddRef(IDirectFBVideoProvider *thiz)
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)
    
  data->ref++;
  
  return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GIF_Release(IDirectFBVideoProvider *thiz)
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)
    
  if (--data->ref == 0)
    {
      IDirectFBVideoProvider_GIF_Destruct(thiz);
    }

  return DFB_OK;
}

static DFBResult 
IDirectFBVideoProvider_GIF_GetCapabilities(IDirectFBVideoProvider       *thiz,
					   DFBVideoProviderCapabilities *caps)
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)

   if (!caps)
     return DFB_INVARG;
  
  *caps = DVCAPS_BASIC | DVCAPS_SCALE;
  
  return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GIF_GetSurfaceDescription(IDirectFBVideoProvider *thiz,
						 DFBSurfaceDescription  *desc)
{
  int width  = 0;
  int height = 0;
  int transparency;

  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)
    
  if (!desc)
    return DFB_INVARG;
  
  //__read_gif_header(data, &width, &height, &transparency);
  
  memset(desc, 0, sizeof(DFBSurfaceDescription));
  
  desc->flags = (DFBSurfaceDescriptionFlags)
    (DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT);

  desc->width  = (int) data->width;
  desc->height = (int) data->height;
  desc->pixelformat = dfb_primary_layer_pixelformat();
  
  return DFB_OK;
}


static DFBResult
IDirectFBVideoProvider_GIF_PlayTo(IDirectFBVideoProvider *thiz,
				   IDirectFBSurface       *destination,
				   const DFBRectangle     *dstrect,
				   DVFrameCallback         callback,
				   void                   *ctx )
{
  DFBRectangle           rect;
  IDirectFBSurface_data *dst_data;
  
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)
    
  if (!destination)
    return DFB_INVARG;
  
  dst_data = (IDirectFBSurface_data *)destination->priv;
  
  if (!dst_data)
    return DFB_DEAD;
  
  /* build the destination rectangle */
  if (dstrect)
    {
      if (dstrect->w < 1  ||  dstrect->h < 1)
	return DFB_INVARG;
      
      rect = *dstrect;
      
      rect.x += dst_data->area.wanted.x;
      rect.y += dst_data->area.wanted.y;
    }
  
  else
    rect = dst_data->area.wanted;
  
  /* save for later blitting operation */
  data->dest_rect = rect;
  
  /* build the clip rectangle */
  if (!dfb_rectangle_intersect( &rect, &dst_data->area.current ))
    return DFB_INVARG;
  
  if (data->destination)
    {
      data->destination->Release(data->destination);
      data->destination = NULL;     /* FIXME: remove listener */
    }
  
  destination->AddRef(destination);
  data->destination = destination;   /* FIXME: install listener */
  
  data->callback = callback;
  data->ctx = ctx;
  
  if (data->thread == -1)
    pthread_create(&data->thread, NULL, FrameThread, data);
  
  return DFB_OK;
}


static DFBResult
IDirectFBVideoProvider_GIF_Stop(IDirectFBVideoProvider *thiz )
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)
    
  if (data->thread != -1)
    {
      pthread_cancel( data->thread );
      pthread_join( data->thread, NULL );
      data->thread = -1;
    }
  
  if (data->destination)
    {
      data->destination->Release(data->destination);
      data->destination = NULL;     /* FIXME: remove listener */
    }
  
  return DFB_OK;
}

static DFBResult
IDirectFBVideoProvider_GIF_SeekTo(IDirectFBVideoProvider *thiz,
				  double                   seconds)
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)
    
  return DFB_UNIMPLEMENTED;
}

static DFBResult
IDirectFBVideoProvider_GIF_GetPos(IDirectFBVideoProvider *thiz,
				   double                 *seconds)
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)
    
  *seconds = 0.0;
  
  return DFB_UNIMPLEMENTED;
}

static DFBResult
IDirectFBVideoProvider_GIF_GetLength(IDirectFBVideoProvider *thiz,
				     double                 *seconds)
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)

  *seconds = 0.0;
  
  return DFB_UNIMPLEMENTED;
}

static DFBResult
IDirectFBVideoProvider_GIF_GetColorAdjustment(IDirectFBVideoProvider *thiz,
					      DFBColorAdjustment     *adj)
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)

  if (!adj)
    return DFB_INVARG;
  
  return DFB_UNIMPLEMENTED;
}

static DFBResult
IDirectFBVideoProvider_GIF_SetColorAdjustment(IDirectFBVideoProvider *thiz,
					       DFBColorAdjustment     *adj)
{
  INTERFACE_GET_DATA(IDirectFBVideoProvider_GIF)

  if (!adj)
    return DFB_INVARG;
  
  return DFB_UNIMPLEMENTED;
}


/* exported symbols */

static DFBResult
Probe(IDirectFBVideoProvider_ProbeContext *ctx)
{
  char *ext;
  
  if ((ext = strrchr(ctx->filename, '.')) &&
      !(strcasecmp(ext, ".gif")))
    {
      return DFB_OK;
    }
  
  return DFB_UNSUPPORTED;
}

static DFBResult
Construct(IDirectFBVideoProvider *thiz, const char *filename)
{
  IDirectFBDataBuffer *buffer = 0;
  
  DFB_ALLOCATE_INTERFACE_DATA(thiz, IDirectFBVideoProvider_GIF)
  
  //  setup data buffer so we can reuse some of the
  //  code from the GIF image provider.
  
  buffer = calloc(1, sizeof(IDirectFBDataBuffer));
  IDirectFBDataBuffer_File_Construct(buffer, filename);

  data->ref    = 1;
  data->buffer = buffer;

  buffer->AddRef(buffer);
  
  data->greyscale   = -1;
  data->transparent = -1;
  data->delay       = -1;
  
  __read_gif_header(data, &data->width, &data->height, &data->transparent);
  
  dfb_surface_create(data->width, data->height,
		     dfb_primary_layer_pixelformat(),
		     CSP_SYSTEMONLY, DSCAPS_SYSTEMONLY, NULL,
		     &(data->source));
  
  data->thread = -1;     

  
  thiz->AddRef    = IDirectFBVideoProvider_GIF_AddRef;
  thiz->Release   = IDirectFBVideoProvider_GIF_Release;
  thiz->GetCapabilities = IDirectFBVideoProvider_GIF_GetCapabilities;
  thiz->GetSurfaceDescription = 
    IDirectFBVideoProvider_GIF_GetSurfaceDescription;
  thiz->PlayTo    = IDirectFBVideoProvider_GIF_PlayTo;
  thiz->Stop      = IDirectFBVideoProvider_GIF_Stop;
  thiz->SeekTo    = IDirectFBVideoProvider_GIF_SeekTo;
  thiz->GetPos    = IDirectFBVideoProvider_GIF_GetPos;
  thiz->GetLength = IDirectFBVideoProvider_GIF_GetLength;
  thiz->GetColorAdjustment = 
    IDirectFBVideoProvider_GIF_GetColorAdjustment;
  thiz->SetColorAdjustment = 
    IDirectFBVideoProvider_GIF_SetColorAdjustment;
  
  return DFB_OK;
}

Home | Main Index | Thread Index


directfb.org / Development / Old Archives