summaryrefslogtreecommitdiff
path: root/libavformat/gif.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/gif.c')
-rw-r--r--libavformat/gif.c171
1 files changed, 16 insertions, 155 deletions
diff --git a/libavformat/gif.c b/libavformat/gif.c
index 11f9c171cf..55f6a581ac 100644
--- a/libavformat/gif.c
+++ b/libavformat/gif.c
@@ -40,84 +40,17 @@
*/
#include "avformat.h"
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
-/* The GIF format uses reversed order for bitstreams... */
-/* at least they don't use PDP_ENDIAN :) */
-#define BITSTREAM_WRITER_LE
-
-#include "libavcodec/put_bits.h"
-
-/* bitstream minipacket size */
-#define GIF_CHUNKS 100
-
/* slows down the decoding (and some browsers don't like it) */
/* update on the 'some browsers don't like it issue from above:
* this was probably due to missing 'Data Sub-block Terminator'
* (byte 19) in the app_header */
#define GIF_ADD_APP_HEADER // required to enable looping of animated gif
-typedef struct {
- unsigned char r;
- unsigned char g;
- unsigned char b;
-} rgb_triplet;
-
-/* we use the standard 216 color palette */
-
-/* this script was used to create the palette:
- * for r in 00 33 66 99 cc ff; do
- * for g in 00 33 66 99 cc ff; do
- * echo -n " "
- * for b in 00 33 66 99 cc ff; do
- * echo -n "{ 0x$r, 0x$g, 0x$b }, "
- * done
- * echo ""
- * done
- * done
- */
-
-static const rgb_triplet gif_clut[216] = {
- { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
- { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
- { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
- { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
- { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
- { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
- { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
- { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
- { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
- { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
- { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
- { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
- { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
- { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
- { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
- { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
- { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
- { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
- { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
- { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
- { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
- { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
- { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
- { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
- { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
- { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
- { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
- { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
- { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
- { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
- { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
- { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
- { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
- { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
- { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
- { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
-};
-
-/* GIF header */
static int gif_image_write_header(AVIOContext *pb, int width, int height,
int loop_count, uint32_t *palette)
{
@@ -129,22 +62,21 @@ static int gif_image_write_header(AVIOContext *pb, int width, int height,
avio_wl16(pb, width);
avio_wl16(pb, height);
+ if (palette) {
+ /* TODO: reindent */
avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
avio_w8(pb, 0x1f); /* background color index */
avio_w8(pb, 0); /* aspect ratio */
-
- /* the global palette */
- if (!palette) {
- avio_write(pb, (const unsigned char *)gif_clut, 216 * 3);
- for (i = 0; i < ((256 - 216) * 3); i++)
- avio_w8(pb, 0);
- } else {
for (i = 0; i < 256; i++) {
v = palette[i];
avio_w8(pb, (v >> 16) & 0xff);
avio_w8(pb, (v >> 8) & 0xff);
avio_w8(pb, (v) & 0xff);
}
+ } else {
+ avio_w8(pb, 0); /* flags */
+ avio_w8(pb, 0); /* background color index */
+ avio_w8(pb, 0); /* aspect ratio */
}
/* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated
@@ -183,76 +115,6 @@ static int gif_image_write_header(AVIOContext *pb, int width, int height,
return 0;
}
-/* this is maybe slow, but allows for extensions */
-static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
-{
- return (((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6);
-}
-
-static int gif_image_write_image(AVIOContext *pb,
- int x1, int y1, int width, int height,
- const uint8_t *buf, int linesize, int pix_fmt)
-{
- PutBitContext p;
- uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */
- int i, left, w, v;
- const uint8_t *ptr;
- /* image block */
-
- avio_w8(pb, 0x2c);
- avio_wl16(pb, x1);
- avio_wl16(pb, y1);
- avio_wl16(pb, width);
- avio_wl16(pb, height);
- avio_w8(pb, 0x00); /* flags */
- /* no local clut */
-
- avio_w8(pb, 0x08);
-
- left = width * height;
-
- init_put_bits(&p, buffer, 130);
-
-/*
- * the thing here is the bitstream is written as little packets, with a size
- * byte before but it's still the same bitstream between packets (no flush !)
- */
- ptr = buf;
- w = width;
- while (left > 0) {
- put_bits(&p, 9, 0x0100); /* clear code */
-
- for (i = (left < GIF_CHUNKS) ? left : GIF_CHUNKS; i; i--) {
- if (pix_fmt == AV_PIX_FMT_RGB24) {
- v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
- ptr += 3;
- } else {
- v = *ptr++;
- }
- put_bits(&p, 9, v);
- if (--w == 0) {
- w = width;
- buf += linesize;
- ptr = buf;
- }
- }
-
- if (left <= GIF_CHUNKS) {
- put_bits(&p, 9, 0x101); /* end of stream */
- flush_put_bits(&p);
- }
- if (put_bits_ptr(&p) - p.buf > 0) {
- avio_w8(pb, put_bits_ptr(&p) - p.buf); /* byte count of the packet */
- avio_write(pb, p.buf, put_bits_ptr(&p) - p.buf); /* the actual buffer */
- p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
- }
- left -= GIF_CHUNKS;
- }
- avio_w8(pb, 0x00); /* end of image block */
-
- return 0;
-}
-
typedef struct {
AVClass *class; /** Class for private options. */
int64_t time, file_time;
@@ -266,6 +128,7 @@ static int gif_write_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
AVCodecContext *enc, *video_enc;
int i, width, height /*, rate*/;
+ uint32_t palette[AVPALETTE_COUNT];
/* XXX: do we reject audio streams or just ignore them ?
* if (s->nb_streams > 1)
@@ -290,14 +153,13 @@ static int gif_write_header(AVFormatContext *s)
// rate = video_enc->time_base.den;
}
- if (video_enc->pix_fmt != AV_PIX_FMT_RGB24) {
- av_log(s, AV_LOG_ERROR,
- "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n");
- return AVERROR(EIO);
+ if (avpriv_set_systematic_pal2(palette, video_enc->pix_fmt) < 0) {
+ av_assert0(video_enc->pix_fmt == AV_PIX_FMT_PAL8);
+ gif_image_write_header(pb, width, height, gif->loop, NULL);
+ } else {
+ gif_image_write_header(pb, width, height, gif->loop, palette);
}
- gif_image_write_header(pb, width, height, gif->loop, NULL);
-
avio_flush(s->pb);
return 0;
}
@@ -326,8 +188,7 @@ static int gif_write_video(AVFormatContext *s, AVCodecContext *enc,
avio_w8(pb, 0x1f); /* transparent color index */
avio_w8(pb, 0x00);
- gif_image_write_image(pb, 0, 0, enc->width, enc->height,
- buf, enc->width * 3, AV_PIX_FMT_RGB24);
+ avio_write(pb, buf, size);
return 0;
}
@@ -372,7 +233,7 @@ AVOutputFormat ff_gif_muxer = {
.extensions = "gif",
.priv_data_size = sizeof(GIFContext),
.audio_codec = AV_CODEC_ID_NONE,
- .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .video_codec = AV_CODEC_ID_GIF,
.write_header = gif_write_header,
.write_packet = gif_write_packet,
.write_trailer = gif_write_trailer,