[MPlayer-dev-eng] [PATCH] Various updates to GIF demuxer
Diego Biurrun
diego at biurrun.de
Sat Jan 13 10:01:49 CET 2007
On Sat, Jan 13, 2007 at 07:15:22AM +0100, Diego Biurrun wrote:
> On Sat, Jan 13, 2007 at 06:59:26AM +0100, Diego Biurrun wrote:
> > On Fri, Feb 03, 2006 at 04:55:34PM -0500, John Koleszar wrote:
> > >
> > > Attached patch adds support for several animated gif features that
> > > either weren't supported by or outright crashed mplayer, including
> > > variable frame sizes, interlacing, transparency, and some alternative
> > > frame update methods. Also fixed a bug extracting timestamps, which was
> > > probably introduced by a change in giflib, since the code in question
> > > dates back to rev 1.1.
> > >
> > > --- libmpdemux/demux_gif.c 5 Aug 2005 19:57:46 -0000 1.5
> > > +++ libmpdemux/demux_gif.c 3 Feb 2006 20:50:45 -0000
> > > @@ -70,8 +86,13 @@
> > > }
> > > if (code == 0xF9) {
> > > int frametime = 0;
> > > if (p[0] == 4) // is the length correct?
> > > - frametime = (p[1] << 8) | p[2]; // set the time, centiseconds
> > > + frametime = (p[3] << 8) | p[2]; // set the time, centiseconds
> >
> > This is the frametime fix, compare
> >
> > http://www.onicos.com/staff/iz/formats/gif.html#gceb
> >
> > to see that if p[0] is block size p[3] and p[2], not p[1] and p[2] must
> > be the delay time.
> >
> > This hunk committed, it fixes several of the samples above.
>
> Here is the rest of the patch, updated for Subversion HEAD, plus a few
> cosmetical fixes.
I think it's time that I found a club for scatterbrained patch
attachers. Reimar will be invited in as exclusive member...
Diego
-------------- next part --------------
Index: libmpdemux/demux_gif.c
===================================================================
--- libmpdemux/demux_gif.c (revision 21895)
+++ libmpdemux/demux_gif.c (working copy)
@@ -17,9 +17,22 @@
#include "stheader.h"
#include <gif_lib.h>
-static int current_pts = 0;
-static unsigned char *palette = NULL;
+struct gif_priv_s {
+ GifFileType* gif_hndl;
+ unsigned char* palette;
+ unsigned char* canvas;
+ unsigned int canvas_sz;
+};
+#define gif_hndl (((struct gif_priv_s*)(demuxer->priv))->gif_hndl)
+#define palette (((struct gif_priv_s*)(demuxer->priv))->palette)
+#define canvas (((struct gif_priv_s*)(demuxer->priv))->canvas)
+#define canvas_sz (((struct gif_priv_s*)(demuxer->priv))->canvas_sz)
+
+static int current_pts = 0,
+ ilace_offset[] = { 0, 4, 2, 1 },
+ ilace_jmp[] = { 8, 8, 4, 2 };
+
#define GIF_SIGNATURE (('G' << 16) | ('I' << 8) | 'F')
#ifndef HAVE_GIF_TVT_HACK
@@ -38,12 +51,15 @@
static int demux_gif_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
{
- GifFileType *gif = (GifFileType *)demuxer->priv;
+ GifFileType *gif = gif_hndl;
GifRecordType type = UNDEFINED_RECORD_TYPE;
int len = 0;
demux_packet_t *dp = NULL;
ColorMapObject *effective_map = NULL;
char *buf = NULL;
+ int trans = 0;
+ int trans_color = 0;
+ int reaction = 0;
while (type != IMAGE_DESC_RECORD_TYPE) {
if (DGifGetRecordType(gif, &type) == GIF_ERROR) {
@@ -67,8 +83,13 @@
}
if (code == 0xF9) {
int frametime = 0;
- if (p[0] == 4) // is the length correct?
+ if (p[0] == 4) { // Is the length correct?
frametime = (p[3] << 8) | p[2]; // set the time, centiseconds
+ reaction = (p[1] >> 2) & 0x3;
+ // Get transparency info.
+ trans = p[1] & 0x1;
+ trans_color = p[4];
+ }
current_pts += frametime;
} else if ((code == 0xFE) && (verbose)) { // comment extension
// print iff verbose
@@ -100,23 +121,37 @@
}
len = gif->Image.Width * gif->Image.Height;
- dp = new_demux_packet(len);
+ dp = new_demux_packet(canvas_sz);
buf = malloc(len);
memset(buf, 0, len);
- memset(dp->buffer, 0, len);
+ memcpy(dp->buffer, canvas, canvas_sz);
- if (DGifGetLine(gif, buf, len) == GIF_ERROR) {
- PrintGifError();
- return 0; // oops
+ if(gif->Image.Interlace) {
+ int i,j;
+ for(i = 0; i < 4; i++) {
+ for(j = ilace_offset[i]; j < gif->Image.Height; j += ilace_jmp[i]) {
+ if (DGifGetLine(gif, buf + (j * gif->Image.Width), gif->Image.Width)
+ == GIF_ERROR)
+ {
+ PrintGifError();
+ return 0; // oops
+ }
+ }
+ }
+ } else {
+ if (DGifGetLine(gif, buf, len) == GIF_ERROR) {
+ PrintGifError();
+ return 0; // oops
+ }
}
effective_map = gif->Image.ColorMap;
if (effective_map == NULL) effective_map = gif->SColorMap;
{
- int y;
+ int y, x, width, height;
- // copy the palette
+ // Copy the palette.
for (y = 0; y < 256; y++) {
palette[(y * 4) + 0] = effective_map->Colors[y].Blue;
palette[(y * 4) + 1] = effective_map->Colors[y].Green;
@@ -124,15 +159,55 @@
palette[(y * 4) + 3] = 0;
}
- for (y = 0; y < gif->Image.Height; y++) {
+ // Use the canvas w/h as a bounding box for the blit.
+ height = gif->Image.Height;
+ width = gif->Image.Width;
+ if(gif->Image.Top + gif->Image.Height > gif->SHeight)
+ height = gif->SHeight - gif->Image.Top;
+ if(gif->Image.Left + gif->Image.Width > gif->SWidth)
+ width = gif->SWidth - gif->Image.Left;
+
+ for (y = 0; y < height; y++) {
unsigned char *drow = dp->buffer;
unsigned char *gbuf = buf + (y * gif->Image.Width);
- drow += gif->Image.Width * (y + gif->Image.Top);
+ drow += gif->SWidth * (y + gif->Image.Top);
drow += gif->Image.Left;
- memcpy(drow, gbuf, gif->Image.Width);
+ if(!trans) {
+ // No transparency, can do a fast blit.
+ memcpy(drow, gbuf, width);
+ } else {
+ // Do a byte by byte blit for all non-transparent pixels.
+ for (x = 0; x < width; x++) {
+ if(gbuf[x] != trans_color)
+ drow[x] = gbuf[x];
+ }
+ }
}
+
+ switch(reaction) {
+ case 1:
+ // Preserve the current frame contents for the next frame.
+ memcpy(canvas, dp->buffer, canvas_sz);
+ break;
+ case 2:
+ // Fill the image area with the background color.
+ for (y = 0; y < height; y++) {
+ unsigned char *drow = canvas;
+ drow += gif->SWidth * (y + gif->Image.Top);
+ drow += gif->Image.Left;
+ memset(drow, gif->SBackGroundColor, width);
+ }
+ break;
+ case 3:
+ // Preserve the previous frame contents for the next frame.
+ // No action required.
+ break;
+ default:
+ // Wipe the whole canvas with the background color.
+ memset(canvas, gif->SBackGroundColor, canvas_sz);
+ }
}
free(buf);
@@ -196,16 +271,19 @@
sh_video->bih->biCompression = sh_video->format;
sh_video->bih->biBitCount = 8;
sh_video->bih->biPlanes = 2;
+ demuxer->priv = malloc(sizeof(struct gif_priv_s));
palette = (unsigned char *)(sh_video->bih + 1);
+ canvas_sz = gif->SWidth * gif->SHeight;
+ gif_hndl = gif;
+ canvas = malloc(canvas_sz);
+ memset(canvas, gif->SBackGroundColor, canvas_sz);
- demuxer->priv = gif;
-
return demuxer;
}
static void demux_close_gif(demuxer_t* demuxer)
{
- GifFileType *gif = (GifFileType *)demuxer->priv;
+ GifFileType *gif = (demuxer->priv)?gif_hndl:NULL;
if(!gif)
return;
@@ -214,6 +292,8 @@
PrintGifError();
demuxer->stream->fd = 0;
+ if(demuxer->priv)
+ free(demuxer->priv);
demuxer->priv = NULL;
}
More information about the MPlayer-dev-eng
mailing list