mirror of https://git.ffmpeg.org/ffmpeg.git
added 8 bit palette support for non animated GIF
Originally committed as revision 1562 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
3ce27f13b9
commit
84ab361f3e
|
@ -167,9 +167,11 @@ static void gif_flush_put_bits_rev(PutBitContext *s)
|
||||||
/* !RevPutBitContext */
|
/* !RevPutBitContext */
|
||||||
|
|
||||||
/* GIF header */
|
/* GIF header */
|
||||||
static int gif_image_write_header(ByteIOContext *pb, int width, int height)
|
static int gif_image_write_header(ByteIOContext *pb,
|
||||||
|
int width, int height, uint32_t *palette)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
unsigned int v;
|
||||||
|
|
||||||
put_tag(pb, "GIF");
|
put_tag(pb, "GIF");
|
||||||
put_tag(pb, "89a");
|
put_tag(pb, "89a");
|
||||||
|
@ -181,10 +183,18 @@ static int gif_image_write_header(ByteIOContext *pb, int width, int height)
|
||||||
put_byte(pb, 0); /* aspect ratio */
|
put_byte(pb, 0); /* aspect ratio */
|
||||||
|
|
||||||
/* the global palette */
|
/* the global palette */
|
||||||
|
if (!palette) {
|
||||||
put_buffer(pb, (unsigned char *)gif_clut, 216*3);
|
put_buffer(pb, (unsigned char *)gif_clut, 216*3);
|
||||||
for(i=0;i<((256-216)*3);i++)
|
for(i=0;i<((256-216)*3);i++)
|
||||||
put_byte(pb, 0);
|
put_byte(pb, 0);
|
||||||
|
} else {
|
||||||
|
for(i=0;i<256;i++) {
|
||||||
|
v = palette[i];
|
||||||
|
put_byte(pb, (v >> 16) & 0xff);
|
||||||
|
put_byte(pb, (v >> 8) & 0xff);
|
||||||
|
put_byte(pb, (v) & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* application extension header */
|
/* application extension header */
|
||||||
/* XXX: not really sure what to put in here... */
|
/* XXX: not really sure what to put in here... */
|
||||||
|
@ -202,7 +212,7 @@ static int gif_image_write_header(ByteIOContext *pb, int width, int height)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this is maybe slow, but allows for extensions */
|
/* this is maybe slow, but allows for extensions */
|
||||||
static inline unsigned char gif_clut_index(rgb_triplet *clut, UINT8 r, UINT8 g, UINT8 b)
|
static inline unsigned char gif_clut_index(UINT8 r, UINT8 g, UINT8 b)
|
||||||
{
|
{
|
||||||
return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
|
return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
|
||||||
}
|
}
|
||||||
|
@ -210,11 +220,11 @@ static inline unsigned char gif_clut_index(rgb_triplet *clut, UINT8 r, UINT8 g,
|
||||||
|
|
||||||
static int gif_image_write_image(ByteIOContext *pb,
|
static int gif_image_write_image(ByteIOContext *pb,
|
||||||
int x1, int y1, int width, int height,
|
int x1, int y1, int width, int height,
|
||||||
uint8_t *buf, int linesize)
|
uint8_t *buf, int linesize, int pix_fmt)
|
||||||
{
|
{
|
||||||
PutBitContext p;
|
PutBitContext p;
|
||||||
UINT8 buffer[200]; /* 100 * 9 / 8 = 113 */
|
UINT8 buffer[200]; /* 100 * 9 / 8 = 113 */
|
||||||
int i, left, w;
|
int i, left, w, v;
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
/* image block */
|
/* image block */
|
||||||
|
|
||||||
|
@ -243,8 +253,13 @@ static int gif_image_write_image(ByteIOContext *pb,
|
||||||
gif_put_bits_rev(&p, 9, 0x0100); /* clear code */
|
gif_put_bits_rev(&p, 9, 0x0100); /* clear code */
|
||||||
|
|
||||||
for(i=0;i<GIF_CHUNKS;i++) {
|
for(i=0;i<GIF_CHUNKS;i++) {
|
||||||
gif_put_bits_rev(&p, 9, gif_clut_index(NULL, ptr[0], ptr[1], ptr[2]));
|
if (pix_fmt == PIX_FMT_RGB24) {
|
||||||
ptr+=3;
|
v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
|
||||||
|
ptr+=3;
|
||||||
|
} else {
|
||||||
|
v = *ptr++;
|
||||||
|
}
|
||||||
|
gif_put_bits_rev(&p, 9, v);
|
||||||
if (--w == 0) {
|
if (--w == 0) {
|
||||||
w = width;
|
w = width;
|
||||||
buf += linesize;
|
buf += linesize;
|
||||||
|
@ -309,22 +324,12 @@ static int gif_write_header(AVFormatContext *s)
|
||||||
/* XXX: is it allowed ? seems to work so far... */
|
/* XXX: is it allowed ? seems to work so far... */
|
||||||
video_enc->pix_fmt = PIX_FMT_RGB24;
|
video_enc->pix_fmt = PIX_FMT_RGB24;
|
||||||
|
|
||||||
gif_image_write_header(pb, width, height);
|
gif_image_write_header(pb, width, height, NULL);
|
||||||
|
|
||||||
put_flush_packet(&s->pb);
|
put_flush_packet(&s->pb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* chunk writer callback */
|
|
||||||
/* !!! XXX:deprecated
|
|
||||||
static void gif_put_chunk(void *pbctx, UINT8 *buffer, int count)
|
|
||||||
{
|
|
||||||
ByteIOContext *pb = (ByteIOContext *)pbctx;
|
|
||||||
put_byte(pb, (UINT8)count);
|
|
||||||
put_buffer(pb, buffer, count);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int gif_write_video(AVFormatContext *s,
|
static int gif_write_video(AVFormatContext *s,
|
||||||
AVCodecContext *enc, UINT8 *buf, int size)
|
AVCodecContext *enc, UINT8 *buf, int size)
|
||||||
{
|
{
|
||||||
|
@ -354,7 +359,7 @@ static int gif_write_video(AVFormatContext *s,
|
||||||
put_byte(pb, 0x00);
|
put_byte(pb, 0x00);
|
||||||
|
|
||||||
gif_image_write_image(pb, 0, 0, enc->width, enc->height,
|
gif_image_write_image(pb, 0, 0, enc->width, enc->height,
|
||||||
buf, enc->width * 3);
|
buf, enc->width * 3, PIX_FMT_RGB24);
|
||||||
|
|
||||||
put_flush_packet(&s->pb);
|
put_flush_packet(&s->pb);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -382,9 +387,11 @@ static int gif_write_trailer(AVFormatContext *s)
|
||||||
/* better than nothing gif image writer */
|
/* better than nothing gif image writer */
|
||||||
int gif_write(ByteIOContext *pb, AVImageInfo *info)
|
int gif_write(ByteIOContext *pb, AVImageInfo *info)
|
||||||
{
|
{
|
||||||
gif_image_write_header(pb, info->width, info->height);
|
gif_image_write_header(pb, info->width, info->height,
|
||||||
|
(uint32_t *)info->pict.data[1]);
|
||||||
gif_image_write_image(pb, 0, 0, info->width, info->height,
|
gif_image_write_image(pb, 0, 0, info->width, info->height,
|
||||||
info->pict.data[0], info->pict.linesize[0]);
|
info->pict.data[0], info->pict.linesize[0],
|
||||||
|
PIX_FMT_PAL8);
|
||||||
put_byte(pb, 0x3b);
|
put_byte(pb, 0x3b);
|
||||||
put_flush_packet(pb);
|
put_flush_packet(pb);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -39,6 +39,9 @@ typedef struct GifState {
|
||||||
int color_resolution;
|
int color_resolution;
|
||||||
uint8_t *image_buf;
|
uint8_t *image_buf;
|
||||||
int image_linesize;
|
int image_linesize;
|
||||||
|
uint32_t *image_palette;
|
||||||
|
int pix_fmt;
|
||||||
|
|
||||||
/* after the frame is displayed, the disposal method is used */
|
/* after the frame is displayed, the disposal method is used */
|
||||||
int gce_disposal;
|
int gce_disposal;
|
||||||
/* delay during which the frame is shown */
|
/* delay during which the frame is shown */
|
||||||
|
@ -274,7 +277,7 @@ static int gif_read_image(GifState *s)
|
||||||
{
|
{
|
||||||
ByteIOContext *f = s->f;
|
ByteIOContext *f = s->f;
|
||||||
int left, top, width, height, bits_per_pixel, code_size, flags;
|
int left, top, width, height, bits_per_pixel, code_size, flags;
|
||||||
int is_interleaved, has_local_palette, y, x, pass, y1, linesize;
|
int is_interleaved, has_local_palette, y, x, pass, y1, linesize, n, i;
|
||||||
uint8_t *ptr, *line, *d, *spal, *palette, *sptr, *ptr1;
|
uint8_t *ptr, *line, *d, *spal, *palette, *sptr, *ptr1;
|
||||||
|
|
||||||
left = get_le16(f);
|
left = get_le16(f);
|
||||||
|
@ -294,6 +297,7 @@ static int gif_read_image(GifState *s)
|
||||||
palette = s->local_palette;
|
palette = s->local_palette;
|
||||||
} else {
|
} else {
|
||||||
palette = s->global_palette;
|
palette = s->global_palette;
|
||||||
|
bits_per_pixel = s->bits_per_pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* verify that all the image is inside the screen dimensions */
|
/* verify that all the image is inside the screen dimensions */
|
||||||
|
@ -301,32 +305,51 @@ static int gif_read_image(GifState *s)
|
||||||
top + height > s->screen_height)
|
top + height > s->screen_height)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
line = av_malloc(width);
|
/* build the palette */
|
||||||
if (!line)
|
if (s->pix_fmt == PIX_FMT_RGB24) {
|
||||||
return -ENOMEM;
|
line = av_malloc(width);
|
||||||
|
if (!line)
|
||||||
|
return -ENOMEM;
|
||||||
|
} else {
|
||||||
|
n = (1 << bits_per_pixel);
|
||||||
|
spal = palette;
|
||||||
|
for(i = 0; i < n; i++) {
|
||||||
|
s->image_palette[i] = (0xff << 24) |
|
||||||
|
(spal[0] << 16) | (spal[1] << 8) | (spal[2]);
|
||||||
|
spal += 3;
|
||||||
|
}
|
||||||
|
for(; i < 256; i++)
|
||||||
|
s->image_palette[i] = (0xff << 24);
|
||||||
|
line = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* now get the image data */
|
/* now get the image data */
|
||||||
s->f = f;
|
s->f = f;
|
||||||
code_size = get_byte(f);
|
code_size = get_byte(f);
|
||||||
GLZWDecodeInit(s, code_size);
|
GLZWDecodeInit(s, code_size);
|
||||||
|
|
||||||
/* read all the image and transcode it to RGB24 (horrible) */
|
/* read all the image */
|
||||||
linesize = s->image_linesize;
|
linesize = s->image_linesize;
|
||||||
ptr1 = s->image_buf + top * linesize + (left * 3);
|
ptr1 = s->image_buf + top * linesize + (left * 3);
|
||||||
ptr = ptr1;
|
ptr = ptr1;
|
||||||
pass = 0;
|
pass = 0;
|
||||||
y1 = 0;
|
y1 = 0;
|
||||||
for (y = 0; y < height; y++) {
|
for (y = 0; y < height; y++) {
|
||||||
GLZWDecode(s, line, width);
|
if (s->pix_fmt == PIX_FMT_RGB24) {
|
||||||
d = ptr;
|
/* transcode to RGB24 */
|
||||||
sptr = line;
|
GLZWDecode(s, line, width);
|
||||||
for(x = 0; x < width; x++) {
|
d = ptr;
|
||||||
spal = palette + sptr[0] * 3;
|
sptr = line;
|
||||||
d[0] = spal[0];
|
for(x = 0; x < width; x++) {
|
||||||
d[1] = spal[1];
|
spal = palette + sptr[0] * 3;
|
||||||
d[2] = spal[2];
|
d[0] = spal[0];
|
||||||
d += 3;
|
d[1] = spal[1];
|
||||||
sptr++;
|
d[2] = spal[2];
|
||||||
|
d += 3;
|
||||||
|
sptr++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GLZWDecode(s, ptr, width);
|
||||||
}
|
}
|
||||||
if (is_interleaved) {
|
if (is_interleaved) {
|
||||||
switch(pass) {
|
switch(pass) {
|
||||||
|
@ -504,6 +527,7 @@ static int gif_read_header(AVFormatContext * s1,
|
||||||
s->image_buf = av_malloc(s->screen_height * s->image_linesize);
|
s->image_buf = av_malloc(s->screen_height * s->image_linesize);
|
||||||
if (!s->image_buf)
|
if (!s->image_buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
s->pix_fmt = PIX_FMT_RGB24;
|
||||||
/* now we are ready: build format streams */
|
/* now we are ready: build format streams */
|
||||||
st = av_new_stream(s1, 0);
|
st = av_new_stream(s1, 0);
|
||||||
if (!st)
|
if (!st)
|
||||||
|
@ -559,13 +583,14 @@ static int gif_read(ByteIOContext *f,
|
||||||
return -1;
|
return -1;
|
||||||
info->width = s->screen_width;
|
info->width = s->screen_width;
|
||||||
info->height = s->screen_height;
|
info->height = s->screen_height;
|
||||||
info->pix_fmt = PIX_FMT_RGB24;
|
info->pix_fmt = PIX_FMT_PAL8;
|
||||||
ret = alloc_cb(opaque, info);
|
ret = alloc_cb(opaque, info);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
s->image_buf = info->pict.data[0];
|
s->image_buf = info->pict.data[0];
|
||||||
s->image_linesize = info->pict.linesize[0];
|
s->image_linesize = info->pict.linesize[0];
|
||||||
|
s->image_palette = (uint32_t *)info->pict.data[1];
|
||||||
|
|
||||||
if (gif_parse_next_image(s) < 0)
|
if (gif_parse_next_image(s) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -587,6 +612,6 @@ AVImageFormat gif_image_format = {
|
||||||
"gif",
|
"gif",
|
||||||
gif_image_probe,
|
gif_image_probe,
|
||||||
gif_read,
|
gif_read,
|
||||||
(1 << PIX_FMT_RGB24),
|
(1 << PIX_FMT_PAL8),
|
||||||
gif_write,
|
gif_write,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue