summaryrefslogtreecommitdiff
path: root/Source/DirectFB/interfaces/IDirectFBVideoProvider/idirectfbvideoprovider_gif.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/interfaces/IDirectFBVideoProvider/idirectfbvideoprovider_gif.c')
-rwxr-xr-xSource/DirectFB/interfaces/IDirectFBVideoProvider/idirectfbvideoprovider_gif.c1075
1 files changed, 1075 insertions, 0 deletions
diff --git a/Source/DirectFB/interfaces/IDirectFBVideoProvider/idirectfbvideoprovider_gif.c b/Source/DirectFB/interfaces/IDirectFBVideoProvider/idirectfbvideoprovider_gif.c
new file mode 100755
index 0000000..65f3fbb
--- /dev/null
+++ b/Source/DirectFB/interfaces/IDirectFBVideoProvider/idirectfbvideoprovider_gif.c
@@ -0,0 +1,1075 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <pthread.h>
+
+#include <directfb.h>
+
+#include <direct/types.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+#include <direct/thread.h>
+#include <direct/util.h>
+
+#include <idirectfb.h>
+
+#include <core/surface.h>
+
+#include <display/idirectfbsurface.h>
+
+#include <media/idirectfbdatabuffer.h>
+#include <media/idirectfbvideoprovider.h>
+
+#include <misc/gfx_util.h>
+
+
+static DFBResult Probe( IDirectFBVideoProvider_ProbeContext *ctx );
+
+static DFBResult Construct( IDirectFBVideoProvider *thiz,
+ IDirectFBDataBuffer *buffer );
+
+
+#include <direct/interface_implementation.h>
+
+DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBVideoProvider, Gif )
+
+/*****************************************************************************/
+
+#define MAXCOLORMAPSIZE 256
+
+#define CM_RED 0
+#define CM_GREEN 1
+#define CM_BLUE 2
+
+#define MAX_LWZ_BITS 12
+
+#define INTERLACE 0x40
+#define LOCALCOLORMAP 0x80
+
+#define BitSet(byte, bit) (((byte) & (bit)) == (bit))
+
+#define LM_to_uint(a,b) (((b)<<8)|(a))
+
+typedef struct {
+ int ref; /* reference counter */
+
+ IDirectFBDataBuffer *buffer;
+ DFBBoolean seekable;
+
+ IDirectFBSurface *destination;
+ IDirectFBSurface_data *dst_data;
+ DFBRectangle dst_rect;
+
+ u32 *image;
+
+ DirectThread *thread;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+
+ DFBVideoProviderStatus status;
+ DFBVideoProviderPlaybackFlags flags;
+ double speed;
+
+ unsigned int start_pos;
+
+ char Version[4];
+ unsigned int Width;
+ unsigned int Height;
+ u8 ColorMap[3][MAXCOLORMAPSIZE];
+ unsigned int BitPixel;
+ unsigned int ColorResolution;
+ u32 Background;
+ unsigned int AspectRatio;
+
+ int transparent;
+ unsigned int delayTime;
+ int inputFlag;
+ int disposal;
+
+ u8 buf[280];
+ int curbit, lastbit, done, last_byte;
+
+ int fresh;
+ int code_size, set_code_size;
+ int max_code, max_code_size;
+ int firstcode, oldcode;
+ int clear_code, end_code;
+ int table[2][(1<< MAX_LWZ_BITS)];
+ int stack[(1<<(MAX_LWZ_BITS))*2], *sp;
+
+ DVFrameCallback callback;
+ void *callback_ctx;
+} IDirectFBVideoProvider_GIF_data;
+
+#define GIFERRORMSG(x, ...) \
+ D_ERROR( "IDirectFBVideoProvider_GIF: " #x "!\n", ## __VA_ARGS__ )
+
+#define GIFDEBUGMSG(x, ...) \
+ D_DEBUG( "IDirectFBVideoProvider_GIF: " #x "!\n", ## __VA_ARGS__ )
+
+/*****************************************************************************/
+
+static int ZeroDataBlock = 0;
+
+static DFBResult
+FetchData( IDirectFBDataBuffer *buffer, void *data, unsigned int len )
+{
+ DFBResult ret = DFB_OK;
+
+ do {
+ unsigned int read = 0;
+
+ ret = buffer->WaitForData( buffer, len );
+ if (ret == DFB_OK)
+ ret = buffer->GetData( buffer, len, data, &read );
+ if (ret)
+ break;
+
+ data += read;
+ len -= read;
+ } while (len);
+
+ return ret;
+}
+
+static int ReadColorMap( IDirectFBDataBuffer *buffer, int number,
+ u8 buf[3][MAXCOLORMAPSIZE] )
+{
+ int i;
+ u8 rgb[3*number];
+
+ if (FetchData( buffer, rgb, sizeof(rgb) )) {
+ GIFERRORMSG("bad colormap");
+ return -1;
+ }
+
+ for (i = 0; i < number; ++i) {
+ buf[CM_RED][i] = rgb[i*3+0];
+ buf[CM_GREEN][i] = rgb[i*3+1];
+ buf[CM_BLUE][i] = rgb[i*3+2];
+ }
+
+ return 0;
+}
+
+static int GetDataBlock(IDirectFBDataBuffer *buffer, u8 *buf)
+{
+ unsigned char count;
+
+ if (FetchData( buffer, &count, 1 )) {
+ GIFERRORMSG("error in getting DataBlock size");
+ return -1;
+ }
+ ZeroDataBlock = (count == 0);
+
+ if ((count != 0) && FetchData( buffer, buf, count )) {
+ GIFERRORMSG("error in reading DataBlock");
+ return -1;
+ }
+
+ return count;
+}
+
+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) {
+ GIFERRORMSG("ran off the end of my bits");
+ }
+ return -1;
+ }
+ data->buf[0] = data->buf[data->last_byte-2];
+ data->buf[1] = data->buf[data->last_byte-1];
+
+ if ((count = GetDataBlock( 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 DoExtension( IDirectFBVideoProvider_GIF_data *data, int label )
+{
+ unsigned char buf[256] = { 0 };
+ char *str;
+
+ switch (label) {
+ case 0x01: /* Plain Text Extension */
+ str = "Plain Text Extension";
+ break;
+ case 0xff: /* Application Extension */
+ str = "Application Extension";
+ break;
+ case 0xfe: /* Comment Extension */
+ str = "Comment Extension";
+ while (GetDataBlock( data->buffer, (u8*) buf ) != 0)
+ GIFDEBUGMSG("gif comment: %s", buf);
+ return false;
+ case 0xf9: /* Graphic Control Extension */
+ str = "Graphic Control Extension";
+ (void) GetDataBlock( data->buffer, (u8*) buf );
+ data->disposal = (buf[0] >> 2) & 0x7;
+ data->inputFlag = (buf[0] >> 1) & 0x1;
+ if (LM_to_uint( buf[1], buf[2] ))
+ data->delayTime = LM_to_uint( buf[1], buf[2] ) * 10000;
+ if ((buf[0] & 0x1) != 0)
+ data->transparent = buf[3];
+ else
+ data->transparent = -1;
+ while (GetDataBlock( data->buffer, (u8*) buf ) != 0)
+ ;
+ return false;
+ default:
+ str = (char*) buf;
+ snprintf(str, 256, "UNKNOWN (0x%02x)", label);
+ break;
+ }
+
+ GIFDEBUGMSG("got a '%s' extension", str );
+
+ while (GetDataBlock( data->buffer, (u8*) buf ) != 0);
+
+ return 0;
+}
+
+static int LWZReadByte( 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];
+
+ if (ZeroDataBlock) {
+ return -2;
+ }
+
+ while ((count = GetDataBlock( data->buffer, buf )) > 0)
+ ;
+
+ if (count != 0)
+ GIFERRORMSG("missing EOD in data stream (common occurence)");
+
+ 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]) {
+ GIFERRORMSG("circular table entry BIG ERROR");
+ }
+ 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 int ReadImage( IDirectFBVideoProvider_GIF_data *data,
+ int left, int top, int width, int height,
+ u8 cmap[3][MAXCOLORMAPSIZE], bool interlace, bool ignore )
+{
+ u8 c;
+ int v;
+ int xpos = 0, ypos = 0, pass = 0;
+ u32 *image, *dst;
+
+ /*
+ ** Initialize the decompression routines
+ */
+ if (FetchData( data->buffer, &c, 1 ))
+ GIFERRORMSG("EOF / read error on image data");
+
+ if (LWZReadByte( data, true, c ) < 0)
+ GIFERRORMSG("error reading image");
+
+ /*
+ ** If this is an "uninteresting picture" ignore it.
+ */
+ if (ignore) {
+ GIFDEBUGMSG("skipping image...");
+
+ while (LWZReadByte( data, false, c ) >= 0)
+ ;
+ return 0;
+ }
+
+ switch (data->disposal) {
+ case 2:
+ GIFDEBUGMSG("restoring to background color...");
+ memset( data->image, 0, data->Width * data->Height * 4 );
+ break;
+ case 3:
+ GIFERRORMSG("restoring to previous frame is unsupported");
+ break;
+ default:
+ break;
+ }
+
+ dst = image = data->image + (top * data->Width + left);
+
+ GIFDEBUGMSG("reading %dx%d at %dx%d %sGIF image",
+ width, height, left, top, interlace ? " interlaced " : "" );
+
+ while ((v = LWZReadByte( data, false, c )) >= 0 ) {
+ if (v != data->transparent) {
+ dst[xpos] = (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:
+ ypos += 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 fini;
+ }
+ }
+ }
+ else {
+ ++ypos;
+ }
+ dst = image + ypos * data->Width;
+ }
+ if (ypos >= height) {
+ break;
+ }
+ }
+
+fini:
+
+ if (LWZReadByte( data, false, c ) >= 0) {
+ GIFERRORMSG("too much input data, ignoring extra...");
+ //while (LWZReadByte( data, false, c ) >= 0);
+ }
+
+ return 0;
+}
+
+static void GIFReset( IDirectFBVideoProvider_GIF_data *data )
+{
+ data->transparent = -1;
+ data->delayTime = 1000000; /* default: 1s */
+ data->inputFlag = -1;
+ data->disposal = 0;
+
+ if (data->image)
+ memset( data->image, 0, data->Width*data->Height*4 );
+}
+
+static DFBResult GIFReadHeader( IDirectFBVideoProvider_GIF_data *data )
+{
+ DFBResult ret;
+ u8 buf[7];
+
+ ret = FetchData( data->buffer, buf, 6 );
+ if (ret) {
+ GIFERRORMSG("error reading header");
+ return ret;
+ }
+
+ if (memcmp( buf, "GIF", 3 )) {
+ GIFERRORMSG("bad magic");
+ return DFB_UNSUPPORTED;
+ }
+
+ memcpy( data->Version, &buf[3], 3 );
+ data->Version[3] = '\0';
+
+ ret = FetchData( data->buffer, buf, 7 );
+ if (ret) {
+ GIFERRORMSG("error reading screen descriptor");
+ return ret;
+ }
+
+ data->Width = LM_to_uint( buf[0], buf[1] );
+ data->Height = LM_to_uint( buf[2], buf[3] );
+ data->BitPixel = 2 << (buf[4] & 0x07);
+ data->ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
+ data->Background = buf[5];
+ data->AspectRatio = buf[6];
+ if (data->AspectRatio)
+ data->AspectRatio = ((data->AspectRatio + 15) << 8) >> 6;
+ else
+ data->AspectRatio = (data->Width << 8) / data->Height;
+
+ if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
+ if (ReadColorMap( data->buffer, data->BitPixel, data->ColorMap )) {
+ GIFERRORMSG("error reading global colormap");
+ return DFB_FAILURE;
+ }
+ }
+
+ return DFB_OK;
+}
+
+static DFBResult GIFReadFrame( IDirectFBVideoProvider_GIF_data *data )
+{
+ u8 buf[16], c;
+ int top, left;
+ int width, height;
+ u8 localColorMap[3][MAXCOLORMAPSIZE];
+ bool useGlobalColormap;
+
+ data->curbit = data->lastbit = data->done = data->last_byte = 0;
+
+ data->fresh =
+ data->code_size = data->set_code_size =
+ data->max_code = data->max_code_size =
+ data->firstcode = data->oldcode =
+ data->clear_code = data->end_code = 0;
+
+ for (;;) {
+ DFBResult ret;
+
+ ret = FetchData( data->buffer, &c, 1);
+ if (ret) {
+ GIFERRORMSG("EOF / read error on image data" );
+ return DFB_EOF;
+ }
+
+ if (c == ';') /* GIF terminator */
+ return DFB_EOF;
+
+ if (c == '!') { /* Extension */
+ if (FetchData( data->buffer, &c, 1)) {
+ GIFERRORMSG("EOF / read error on extention function code");
+ return DFB_EOF;
+ }
+ DoExtension( data, c );
+ continue;
+ }
+
+ if (c != ',') { /* Not a valid start character */
+ GIFERRORMSG("bogus character 0x%02x, ignoring", (int) c );
+ continue;
+ }
+
+ ret = FetchData( data->buffer, buf, 9 );
+ if (ret) {
+ GIFERRORMSG("couldn't read left/top/width/height");
+ return ret;
+ }
+
+ left = LM_to_uint( buf[0], buf[1] );
+ top = LM_to_uint( buf[2], buf[3] );
+ width = LM_to_uint( buf[4], buf[5] );
+ height = LM_to_uint( buf[6], buf[7] );
+
+ useGlobalColormap = !BitSet( buf[8], LOCALCOLORMAP );
+
+ if (!useGlobalColormap) {
+ int bitPixel = 2 << (buf[8] & 0x07);
+ if (ReadColorMap( data->buffer, bitPixel, localColorMap ))
+ GIFERRORMSG("error reading local colormap");
+ }
+
+ if (ReadImage( data, left, top, width, height,
+ (useGlobalColormap ?
+ data->ColorMap : localColorMap),
+ BitSet( buf[8], INTERLACE ), 0 )) {
+ GIFERRORMSG("error reading image");
+ return DFB_FAILURE;
+ }
+
+ break;
+ }
+
+ return DFB_OK;
+}
+
+/*****************************************************************************/
+
+static void
+IDirectFBVideoProvider_GIF_Destruct( IDirectFBVideoProvider *thiz )
+{
+ IDirectFBVideoProvider_GIF_data *data = thiz->priv;
+
+ thiz->Stop( thiz );
+
+ if (data->image)
+ D_FREE( data->image );
+
+ if (data->buffer)
+ data->buffer->Release( data->buffer );
+
+ pthread_cond_destroy( &data->cond );
+ pthread_mutex_destroy( &data->lock );
+
+ DIRECT_DEALLOCATE_INTERFACE( thiz );
+}
+
+static DirectResult
+IDirectFBVideoProvider_GIF_AddRef( IDirectFBVideoProvider *thiz )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ data->ref++;
+
+ return DFB_OK;
+}
+
+static DirectResult
+IDirectFBVideoProvider_GIF_Release( IDirectFBVideoProvider *thiz )
+{
+ DIRECT_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 )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (!caps)
+ return DFB_INVARG;
+
+ *caps = DVCAPS_BASIC | DVCAPS_SCALE | DVCAPS_SPEED;
+
+ return DFB_OK;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_GetSurfaceDescription( IDirectFBVideoProvider *thiz,
+ DFBSurfaceDescription *desc )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (!desc)
+ return DFB_INVARG;
+
+ desc->flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
+ desc->width = data->Width;
+ desc->height = data->Height;
+ desc->pixelformat = DSPF_ARGB;
+
+ return DFB_OK;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_GetStreamDescription( IDirectFBVideoProvider *thiz,
+ DFBStreamDescription *desc )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (!desc)
+ return DFB_INVARG;
+
+ desc->caps = DVSCAPS_VIDEO;
+
+ snprintf( desc->video.encoding,
+ DFB_STREAM_DESC_ENCODING_LENGTH, "GIF %s", data->Version );
+ desc->video.framerate = 0;
+ desc->video.aspect = (double)data->AspectRatio/256.0;
+ desc->video.bitrate = 0;
+
+ desc->title[0] = desc->author[0] =
+ desc->album[0] = desc->genre[0] = desc->comment[0] = 0;
+ desc->year = 0;
+
+ return DFB_OK;
+}
+
+static void*
+GIFVideo( DirectThread *self, void *arg )
+{
+ IDirectFBVideoProvider_GIF_data *data = arg;
+
+ pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
+
+ while (!direct_thread_is_canceled( self )) {
+ DFBResult ret;
+ DFBRectangle rect;
+ DFBRegion clip;
+ CoreSurface *surface;
+ CoreSurfaceBufferLock lock;
+
+ pthread_mutex_lock( &data->lock );
+
+ if (direct_thread_is_canceled( self )) {
+ pthread_mutex_unlock( &data->lock );
+ break;
+ }
+
+ ret = GIFReadFrame( data );
+ if (ret) {
+ if (ret == DFB_EOF) {
+ GIFReset( data );
+ if (data->flags & DVPLAY_LOOPING) {
+ data->buffer->SeekTo( data->buffer, data->start_pos );
+ }
+ else {
+ data->status = DVSTATE_FINISHED;
+ pthread_mutex_unlock( &data->lock );
+ break;
+ }
+ }
+ pthread_mutex_unlock( &data->lock );
+ continue;
+ }
+
+ rect = (data->dst_rect.w == 0)
+ ? data->dst_data->area.wanted : data->dst_rect;
+ dfb_region_from_rectangle( &clip, &data->dst_data->area.current );
+
+ surface = data->dst_data->surface;
+ D_MAGIC_ASSERT( surface, CoreSurface );
+
+ if (dfb_rectangle_region_intersects( &rect, &clip ) &&
+ dfb_surface_lock_buffer( surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock ) == DFB_OK)
+ {
+ dfb_scale_linear_32( data->image, data->Width, data->Height,
+ lock.addr, lock.pitch, &rect, data->dst_data->surface, &clip );
+
+ dfb_surface_unlock_buffer( surface, &lock );
+
+ if (data->callback)
+ data->callback( data->callback_ctx );
+ }
+
+ if (!data->speed) {
+ pthread_cond_wait( &data->cond, &data->lock );
+ }
+ else {
+ struct timespec ts;
+ unsigned long us;
+
+ us = data->delayTime;
+ if (data->speed != 1.0)
+ us = ((double)us / data->speed + .5);
+
+ direct_util_get_monotonic_pthread_timeout(&ts,
+ us/1000000,
+ (us%1000000) * 1000);
+
+ pthread_cond_timedwait( &data->cond, &data->lock, &ts );
+ }
+
+ pthread_mutex_unlock( &data->lock );
+ }
+
+ return (void*)0;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_PlayTo( IDirectFBVideoProvider *thiz,
+ IDirectFBSurface *destination,
+ const DFBRectangle *dest_rect,
+ DVFrameCallback callback,
+ void *ctx )
+{
+ IDirectFBSurface_data *dst_data;
+ DFBRectangle rect = { 0, 0, 0, 0 };
+ DFBResult ret;
+
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (!destination)
+ return DFB_INVARG;
+
+ dst_data = destination->priv;
+ if (!dst_data || !dst_data->surface)
+ return DFB_DESTROYED;
+
+ if (dest_rect) {
+ if (dest_rect->w < 1 || dest_rect->h < 1)
+ return DFB_INVARG;
+
+ rect = *dest_rect;
+ rect.x += dst_data->area.wanted.x;
+ rect.y += dst_data->area.wanted.y;
+ }
+
+ pthread_mutex_lock( &data->lock );
+
+ if (data->status == DVSTATE_FINISHED) {
+ ret = data->buffer->SeekTo( data->buffer, data->start_pos );
+ if (ret) {
+ pthread_mutex_unlock( &data->lock );
+ return ret;
+ }
+ }
+ data->status = DVSTATE_PLAY;
+
+ if (!data->image) {
+ data->image = D_CALLOC( 4, data->Width * data->Height );
+ if (!data->image) {
+ pthread_mutex_unlock( &data->lock );
+ return D_OOM();
+ }
+ }
+
+ if (data->destination)
+ data->destination->Release( data->destination );
+
+ destination->AddRef( destination );
+ data->destination = destination;
+ data->dst_data = dst_data;
+ data->dst_rect = rect;
+
+ data->callback = callback;
+ data->callback_ctx = ctx;
+
+ if (!data->thread) {
+ data->thread = direct_thread_create( DTT_DEFAULT, GIFVideo,
+ (void*)data, "GIF Video" );
+ }
+
+ pthread_mutex_unlock( &data->lock );
+
+ return DFB_OK;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_Stop( IDirectFBVideoProvider *thiz )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (data->thread) {
+ direct_thread_cancel( data->thread );
+ pthread_mutex_lock( &data->lock );
+ pthread_cond_signal( &data->cond );
+ pthread_mutex_unlock( &data->lock );
+ direct_thread_join( data->thread );
+ direct_thread_destroy( data->thread );
+ data->thread = NULL;
+ }
+
+ if (data->destination) {
+ data->destination->Release( data->destination );
+ data->destination = NULL;
+ data->dst_data = NULL;
+ }
+
+ data->status = DVSTATE_STOP;
+
+ return DFB_OK;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_GetStatus( IDirectFBVideoProvider *thiz,
+ DFBVideoProviderStatus *status )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (!status)
+ return DFB_INVARG;
+
+ *status = data->status;
+
+ return DFB_OK;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_SeekTo( IDirectFBVideoProvider *thiz,
+ double seconds )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (seconds < 0.0)
+ return DFB_INVARG;
+
+ return DFB_UNSUPPORTED;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_GetPos( IDirectFBVideoProvider *thiz,
+ double *seconds )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (!seconds)
+ return DFB_INVARG;
+
+ *seconds = 0.0;
+
+ return DFB_UNSUPPORTED;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_GetLength( IDirectFBVideoProvider *thiz,
+ double *seconds )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (!seconds)
+ return DFB_INVARG;
+
+ *seconds = 0.0;
+
+ return DFB_UNSUPPORTED;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_SetPlaybackFlags( IDirectFBVideoProvider *thiz,
+ DFBVideoProviderPlaybackFlags flags )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (flags & ~DVPLAY_LOOPING)
+ return DFB_UNSUPPORTED;
+
+ if (flags & DVPLAY_LOOPING && !data->seekable)
+ return DFB_UNSUPPORTED;
+
+ data->flags = flags;
+
+ return DFB_OK;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_SetSpeed( IDirectFBVideoProvider *thiz,
+ double multiplier )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (multiplier < 0.0)
+ return DFB_INVARG;
+
+ if (data->speed != multiplier) {
+ pthread_mutex_lock( &data->lock );
+ data->speed = multiplier;
+ pthread_cond_signal( &data->cond );
+ pthread_mutex_unlock( &data->lock );
+ }
+
+ return DFB_OK;
+}
+
+static DFBResult
+IDirectFBVideoProvider_GIF_GetSpeed( IDirectFBVideoProvider *thiz,
+ double *multiplier )
+{
+ DIRECT_INTERFACE_GET_DATA( IDirectFBVideoProvider_GIF )
+
+ if (!multiplier)
+ return DFB_INVARG;
+
+ *multiplier = data->speed;
+
+ return DFB_OK;
+}
+
+/* exported symbols */
+static DFBResult
+Probe( IDirectFBVideoProvider_ProbeContext *ctx )
+{
+ if (!memcmp( ctx->header, "GIF89", 5 ))
+ return DFB_OK;
+
+ return DFB_UNSUPPORTED;
+}
+
+static DFBResult
+Construct( IDirectFBVideoProvider *thiz,
+ IDirectFBDataBuffer *buffer )
+{
+ DFBResult ret;
+
+ DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBVideoProvider_GIF )
+
+ data->ref = 1;
+ data->status = DVSTATE_STOP;
+ data->buffer = buffer;
+ data->speed = 1.0;
+
+ buffer->AddRef( buffer );
+ data->seekable = (buffer->SeekTo( buffer, 0 ) == DFB_OK);
+
+ GIFReset( data );
+ ret = GIFReadHeader( data );
+ if (ret) {
+ IDirectFBVideoProvider_GIF_Destruct( thiz );
+ return ret;
+ }
+
+ data->buffer->GetPosition( data->buffer, &data->start_pos );
+
+ direct_util_recursive_pthread_mutex_init( &data->lock );
+ direct_util_monotonic_pthread_cond_init( &data->cond );
+
+ thiz->AddRef = IDirectFBVideoProvider_GIF_AddRef;
+ thiz->Release = IDirectFBVideoProvider_GIF_Release;
+ thiz->GetCapabilities = IDirectFBVideoProvider_GIF_GetCapabilities;
+ thiz->GetSurfaceDescription = IDirectFBVideoProvider_GIF_GetSurfaceDescription;
+ thiz->GetStreamDescription = IDirectFBVideoProvider_GIF_GetStreamDescription;
+ thiz->PlayTo = IDirectFBVideoProvider_GIF_PlayTo;
+ thiz->Stop = IDirectFBVideoProvider_GIF_Stop;
+ thiz->GetStatus = IDirectFBVideoProvider_GIF_GetStatus;
+ thiz->SeekTo = IDirectFBVideoProvider_GIF_SeekTo;
+ thiz->GetPos = IDirectFBVideoProvider_GIF_GetPos;
+ thiz->GetLength = IDirectFBVideoProvider_GIF_GetLength;
+ thiz->SetPlaybackFlags = IDirectFBVideoProvider_GIF_SetPlaybackFlags;
+ thiz->SetSpeed = IDirectFBVideoProvider_GIF_SetSpeed;
+ thiz->GetSpeed = IDirectFBVideoProvider_GIF_GetSpeed;
+
+ return DFB_OK;
+}