Commit 635389cc authored by Clément Bœsch's avatar Clément Bœsch

Cleanse GIF muxer and encoder.

This commit removes the badly duplicated code between the encoder and
the muxer. That may sound surprising, but the encoder is now responsible
from the encoding of the picture when muxing to a .gif file. It also
does not require anymore a manual user intervention such as a -pix_fmt
rgb24 to work properly. To summarize, output gif are now easier to
generate, code is saner and simpler, and files are smaller (thanks to
the lzw encoding which was unused so far with the default .gif output).
We can certainly make things even better, but this is the first step.

FATE is updated because of the output being produced by the encoder and
not the muxer (no lzw in the muxer), and in the seek test only the size
mismatches.

Fixes Ticket #2262
parent 1efcab02
......@@ -51,61 +51,54 @@ typedef struct {
uint8_t *buf;
} GIFContext;
/* GIF header */
static int gif_image_write_header(AVCodecContext *avctx,
uint8_t **bytestream, uint32_t *palette)
{
int i;
unsigned int v, smallest_alpha = 0xFF, alpha_component = 0;
bytestream_put_buffer(bytestream, "GIF", 3);
bytestream_put_buffer(bytestream, "89a", 3);
bytestream_put_le16(bytestream, avctx->width);
bytestream_put_le16(bytestream, avctx->height);
bytestream_put_byte(bytestream, 0xf7); /* flags: global clut, 256 entries */
bytestream_put_byte(bytestream, 0x1f); /* background color index */
bytestream_put_byte(bytestream, 0); /* aspect ratio */
/* the global palette */
for(i=0;i<256;i++) {
v = palette[i];
bytestream_put_be24(bytestream, v);
if (v >> 24 < smallest_alpha) {
smallest_alpha = v >> 24;
alpha_component = i;
}
}
if (smallest_alpha < 128) {
bytestream_put_byte(bytestream, 0x21); /* Extension Introducer */
bytestream_put_byte(bytestream, 0xf9); /* Graphic Control Label */
bytestream_put_byte(bytestream, 0x04); /* block length */
bytestream_put_byte(bytestream, 0x01); /* Transparent Color Flag */
bytestream_put_le16(bytestream, 0x00); /* no delay */
bytestream_put_byte(bytestream, alpha_component);
bytestream_put_byte(bytestream, 0x00);
}
return 0;
}
static int gif_image_write_image(AVCodecContext *avctx,
uint8_t **bytestream, uint8_t *end,
const uint32_t *palette,
const uint8_t *buf, int linesize)
{
GIFContext *s = avctx->priv_data;
int len = 0, height;
const uint8_t *ptr;
/* image block */
/* Mark one colour as transparent if the input palette contains at least
* one colour that is more than 50% transparent. */
if (palette) {
unsigned i, smallest_alpha = 0xFF, alpha_component = 0;
for (i = 0; i < AVPALETTE_COUNT; i++) {
const uint32_t v = palette[i];
if (v >> 24 < smallest_alpha) {
smallest_alpha = v >> 24;
alpha_component = i;
}
}
if (smallest_alpha < 128) {
bytestream_put_byte(bytestream, 0x21); /* Extension Introducer */
bytestream_put_byte(bytestream, 0xf9); /* Graphic Control Label */
bytestream_put_byte(bytestream, 0x04); /* block length */
bytestream_put_byte(bytestream, 0x01); /* Transparent Color Flag */
bytestream_put_le16(bytestream, 0x00); /* no delay */
bytestream_put_byte(bytestream, alpha_component);
bytestream_put_byte(bytestream, 0x00);
}
}
/* image block */
bytestream_put_byte(bytestream, 0x2c);
bytestream_put_le16(bytestream, 0);
bytestream_put_le16(bytestream, 0);
bytestream_put_le16(bytestream, avctx->width);
bytestream_put_le16(bytestream, avctx->height);
if (!palette) {
bytestream_put_byte(bytestream, 0x00); /* flags */
/* no local clut */
} else {
unsigned i;
bytestream_put_byte(bytestream, 1<<7 | 0x7); /* flags */
for (i = 0; i < AVPALETTE_COUNT; i++) {
const uint32_t v = palette[i];
bytestream_put_be24(bytestream, v);
}
}
bytestream_put_byte(bytestream, 0x08);
......@@ -130,7 +123,6 @@ static int gif_image_write_image(AVCodecContext *avctx,
len -= size;
}
bytestream_put_byte(bytestream, 0x00); /* end of image block */
bytestream_put_byte(bytestream, 0x3b);
return 0;
}
......@@ -160,6 +152,7 @@ static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
GIFContext *s = avctx->priv_data;
AVFrame *const p = &s->picture;
uint8_t *outbuf_ptr, *end;
const uint32_t *palette = NULL;
int ret;
if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*7/5 + FF_MIN_BUFFER_SIZE)) < 0)
......@@ -170,8 +163,11 @@ static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
*p = *pict;
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]);
gif_image_write_image(avctx, &outbuf_ptr, end, pict->data[0], pict->linesize[0]);
if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
palette = (uint32_t*)p->data[1];
gif_image_write_image(avctx, &outbuf_ptr, end, palette, pict->data[0], pict->linesize[0]);
pkt->size = outbuf_ptr - pkt->data;
pkt->flags |= AV_PKT_FLAG_KEY;
......
This diff is collapsed.
......@@ -50,7 +50,6 @@ static const IdStrMap img_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, "y" },
{ AV_CODEC_ID_RAWVIDEO, "raw" },
{ AV_CODEC_ID_BMP, "bmp" },
{ AV_CODEC_ID_GIF, "gif" },
{ AV_CODEC_ID_TARGA, "tga" },
{ AV_CODEC_ID_TIFF, "tiff" },
{ AV_CODEC_ID_TIFF, "tif" },
......
e6089fd4ef3b9df44090ab3650bdd810 *./tests/data/lavf/lavf.gif
2906401 ./tests/data/lavf/lavf.gif
./tests/data/lavf/lavf.gif CRC=0x9825d7c0
66398be6fafa026fb0fa5f2978fa3446 *./tests/data/lavf/lavf.gif
2011766 ./tests/data/lavf/lavf.gif
./tests/data/lavf/lavf.gif CRC=0x0d96deb8
022dc66b5068404e88c618ce79d9eb5f *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x032e0034
./tests/data/images/gif/%02d.gif CRC=0x51811243
81538 ./tests/data/images/gif/02.gif
759522b3025fcf8ed6aae582a18c5a14 *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x4c8f8a89
38715 ./tests/data/images/gif/02.gif
21e802ae7a2239bdbea6f915da1134b9 *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x4c8f8a89
38715 ./tests/data/images/gif/02.gif
fc4792ac40319344dc7027668a403fc3 *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x032e0034
022dc66b5068404e88c618ce79d9eb5f *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x006183fd
81538 ./tests/data/images/gif/02.gif
022dc66b5068404e88c618ce79d9eb5f *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x006183fd
81538 ./tests/data/images/gif/02.gif
022dc66b5068404e88c618ce79d9eb5f *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x51811243
81538 ./tests/data/images/gif/02.gif
022dc66b5068404e88c618ce79d9eb5f *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x51811243
81538 ./tests/data/images/gif/02.gif
022dc66b5068404e88c618ce79d9eb5f *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x032e0034
./tests/data/images/gif/%02d.gif CRC=0xd742fb02
81538 ./tests/data/images/gif/02.gif
e3392f49c55aa794d3dc49189f52f257 *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x22d67c27
63144 ./tests/data/images/gif/02.gif
022dc66b5068404e88c618ce79d9eb5f *./tests/data/images/gif/02.gif
./tests/data/images/gif/%02d.gif CRC=0x032e0034
./tests/data/images/gif/%02d.gif CRC=0x51811243
81538 ./tests/data/images/gif/02.gif
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret: 0 st:-1 flags:1 ts: 1.894167
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret:-1 st: 0 flags:0 ts: 0.790000
ret:-1 st: 0 flags:1 ts:-0.320000
ret:-1 st:-1 flags:0 ts: 2.576668
ret: 0 st:-1 flags:1 ts: 1.470835
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret:-1 st: 0 flags:0 ts: 0.370000
ret:-1 st: 0 flags:1 ts:-0.740000
ret:-1 st:-1 flags:0 ts: 2.153336
ret: 0 st:-1 flags:1 ts: 1.047503
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret: 0 st: 0 flags:0 ts:-0.060000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret: 0 st: 0 flags:1 ts: 2.840000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret:-1 st:-1 flags:0 ts: 1.730004
ret: 0 st:-1 flags:1 ts: 0.624171
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret: 0 st: 0 flags:0 ts:-0.480000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret: 0 st: 0 flags:1 ts: 2.410000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret:-1 st:-1 flags:0 ts: 1.306672
ret: 0 st:-1 flags:1 ts: 0.200839
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret: 0 st: 0 flags:0 ts:-0.900000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret: 0 st: 0 flags:1 ts: 1.990000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret:-1 st:-1 flags:0 ts: 0.883340
ret:-1 st:-1 flags:1 ts:-0.222493
ret:-1 st: 0 flags:0 ts: 2.670000
ret: 0 st: 0 flags:1 ts: 1.570000
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:117024
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
ret:-1 st:-1 flags:0 ts: 0.460008
ret:-1 st:-1 flags:1 ts:-0.645825
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment