annotate ffmpeg/libavformat/gif.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * Animated GIF muxer
yading@11 3 * Copyright (c) 2000 Fabrice Bellard
yading@11 4 *
yading@11 5 * first version by Francois Revol <revol@free.fr>
yading@11 6 *
yading@11 7 * This file is part of FFmpeg.
yading@11 8 *
yading@11 9 * FFmpeg is free software; you can redistribute it and/or
yading@11 10 * modify it under the terms of the GNU Lesser General Public
yading@11 11 * License as published by the Free Software Foundation; either
yading@11 12 * version 2.1 of the License, or (at your option) any later version.
yading@11 13 *
yading@11 14 * FFmpeg is distributed in the hope that it will be useful,
yading@11 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 17 * Lesser General Public License for more details.
yading@11 18 *
yading@11 19 * You should have received a copy of the GNU Lesser General Public
yading@11 20 * License along with FFmpeg; if not, write to the Free Software
yading@11 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 22 */
yading@11 23
yading@11 24 #include "avformat.h"
yading@11 25 #include "internal.h"
yading@11 26 #include "libavutil/avassert.h"
yading@11 27 #include "libavutil/imgutils.h"
yading@11 28 #include "libavutil/log.h"
yading@11 29 #include "libavutil/opt.h"
yading@11 30
yading@11 31 static int gif_image_write_header(AVIOContext *pb, int width, int height,
yading@11 32 int loop_count, uint32_t *palette)
yading@11 33 {
yading@11 34 int i;
yading@11 35
yading@11 36 avio_write(pb, "GIF", 3);
yading@11 37 avio_write(pb, "89a", 3);
yading@11 38 avio_wl16(pb, width);
yading@11 39 avio_wl16(pb, height);
yading@11 40
yading@11 41 if (palette) {
yading@11 42 avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
yading@11 43 avio_w8(pb, 0x1f); /* background color index */
yading@11 44 avio_w8(pb, 0); /* aspect ratio */
yading@11 45 for (i = 0; i < 256; i++) {
yading@11 46 const uint32_t v = palette[i] & 0xffffff;
yading@11 47 avio_wb24(pb, v);
yading@11 48 }
yading@11 49 } else {
yading@11 50 avio_w8(pb, 0); /* flags */
yading@11 51 avio_w8(pb, 0); /* background color index */
yading@11 52 avio_w8(pb, 0); /* aspect ratio */
yading@11 53 }
yading@11 54
yading@11 55 /* "NETSCAPE EXTENSION" for looped animation GIF */
yading@11 56 avio_w8(pb, 0x21); /* GIF Extension code */
yading@11 57 avio_w8(pb, 0xff); /* Application Extension Label */
yading@11 58 avio_w8(pb, 0x0b); /* Length of Application Block */
yading@11 59 avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
yading@11 60 avio_w8(pb, 0x03); /* Length of Data Sub-Block */
yading@11 61 avio_w8(pb, 0x01);
yading@11 62 avio_wl16(pb, (uint16_t)loop_count);
yading@11 63 avio_w8(pb, 0x00); /* Data Sub-block Terminator */
yading@11 64
yading@11 65 return 0;
yading@11 66 }
yading@11 67
yading@11 68 typedef struct {
yading@11 69 AVClass *class; /** Class for private options. */
yading@11 70 int loop;
yading@11 71 int last_delay;
yading@11 72 AVPacket *prev_pkt;
yading@11 73 int duration;
yading@11 74 } GIFContext;
yading@11 75
yading@11 76 static int gif_write_header(AVFormatContext *s)
yading@11 77 {
yading@11 78 GIFContext *gif = s->priv_data;
yading@11 79 AVIOContext *pb = s->pb;
yading@11 80 AVCodecContext *video_enc;
yading@11 81 int width, height;
yading@11 82 uint32_t palette[AVPALETTE_COUNT];
yading@11 83
yading@11 84 if (s->nb_streams != 1 ||
yading@11 85 s->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
yading@11 86 s->streams[0]->codec->codec_id != AV_CODEC_ID_GIF) {
yading@11 87 av_log(s, AV_LOG_ERROR,
yading@11 88 "GIF muxer supports only a single video GIF stream.\n");
yading@11 89 return AVERROR(EINVAL);
yading@11 90 }
yading@11 91
yading@11 92 video_enc = s->streams[0]->codec;
yading@11 93 width = video_enc->width;
yading@11 94 height = video_enc->height;
yading@11 95
yading@11 96 avpriv_set_pts_info(s->streams[0], 64, 1, 100);
yading@11 97 if (avpriv_set_systematic_pal2(palette, video_enc->pix_fmt) < 0) {
yading@11 98 av_assert0(video_enc->pix_fmt == AV_PIX_FMT_PAL8);
yading@11 99 gif_image_write_header(pb, width, height, gif->loop, NULL);
yading@11 100 } else {
yading@11 101 gif_image_write_header(pb, width, height, gif->loop, palette);
yading@11 102 }
yading@11 103
yading@11 104 avio_flush(s->pb);
yading@11 105 return 0;
yading@11 106 }
yading@11 107
yading@11 108 static int flush_packet(AVFormatContext *s, AVPacket *new)
yading@11 109 {
yading@11 110 GIFContext *gif = s->priv_data;
yading@11 111 int size;
yading@11 112 AVIOContext *pb = s->pb;
yading@11 113 uint8_t flags = 0x4, transparent_color_index = 0x1f;
yading@11 114 const uint32_t *palette;
yading@11 115 AVPacket *pkt = gif->prev_pkt;
yading@11 116
yading@11 117 if (!pkt)
yading@11 118 return 0;
yading@11 119
yading@11 120 /* Mark one colour as transparent if the input palette contains at least
yading@11 121 * one colour that is more than 50% transparent. */
yading@11 122 palette = (uint32_t*)av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size);
yading@11 123 if (palette && size != AVPALETTE_SIZE) {
yading@11 124 av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n");
yading@11 125 return AVERROR_INVALIDDATA;
yading@11 126 }
yading@11 127 if (palette) {
yading@11 128 unsigned i, smallest_alpha = 0xff;
yading@11 129
yading@11 130 for (i = 0; i < AVPALETTE_COUNT; i++) {
yading@11 131 const uint32_t v = palette[i];
yading@11 132 if (v >> 24 < smallest_alpha) {
yading@11 133 smallest_alpha = v >> 24;
yading@11 134 transparent_color_index = i;
yading@11 135 }
yading@11 136 }
yading@11 137 if (smallest_alpha < 128)
yading@11 138 flags |= 0x1; /* Transparent Color Flag */
yading@11 139 }
yading@11 140
yading@11 141 if (new && new->pts != AV_NOPTS_VALUE)
yading@11 142 gif->duration = av_clip_uint16(new->pts - gif->prev_pkt->pts);
yading@11 143 else if (!new && gif->last_delay >= 0)
yading@11 144 gif->duration = gif->last_delay;
yading@11 145
yading@11 146 /* graphic control extension block */
yading@11 147 avio_w8(pb, 0x21);
yading@11 148 avio_w8(pb, 0xf9);
yading@11 149 avio_w8(pb, 0x04); /* block size */
yading@11 150 avio_w8(pb, flags);
yading@11 151 avio_wl16(pb, gif->duration);
yading@11 152 avio_w8(pb, transparent_color_index);
yading@11 153 avio_w8(pb, 0x00);
yading@11 154
yading@11 155 avio_write(pb, pkt->data, pkt->size);
yading@11 156
yading@11 157 av_free_packet(gif->prev_pkt);
yading@11 158 if (new)
yading@11 159 av_copy_packet(gif->prev_pkt, new);
yading@11 160
yading@11 161 return 0;
yading@11 162 }
yading@11 163
yading@11 164 static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
yading@11 165 {
yading@11 166 GIFContext *gif = s->priv_data;
yading@11 167
yading@11 168 if (!gif->prev_pkt) {
yading@11 169 gif->prev_pkt = av_malloc(sizeof(*gif->prev_pkt));
yading@11 170 if (!gif->prev_pkt)
yading@11 171 return AVERROR(ENOMEM);
yading@11 172 return av_copy_packet(gif->prev_pkt, pkt);
yading@11 173 }
yading@11 174 return flush_packet(s, pkt);
yading@11 175 }
yading@11 176
yading@11 177 static int gif_write_trailer(AVFormatContext *s)
yading@11 178 {
yading@11 179 GIFContext *gif = s->priv_data;
yading@11 180 AVIOContext *pb = s->pb;
yading@11 181
yading@11 182 flush_packet(s, NULL);
yading@11 183 av_freep(&gif->prev_pkt);
yading@11 184 avio_w8(pb, 0x3b);
yading@11 185
yading@11 186 return 0;
yading@11 187 }
yading@11 188
yading@11 189 #define OFFSET(x) offsetof(GIFContext, x)
yading@11 190 #define ENC AV_OPT_FLAG_ENCODING_PARAM
yading@11 191 static const AVOption options[] = {
yading@11 192 { "loop", "Number of times to loop the output.", OFFSET(loop),
yading@11 193 AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 65535, ENC },
yading@11 194 { "final_delay", "Force delay (in ms) after the last frame", OFFSET(last_delay),
yading@11 195 AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 65535, ENC },
yading@11 196 { NULL },
yading@11 197 };
yading@11 198
yading@11 199 static const AVClass gif_muxer_class = {
yading@11 200 .class_name = "GIF muxer",
yading@11 201 .item_name = av_default_item_name,
yading@11 202 .version = LIBAVUTIL_VERSION_INT,
yading@11 203 .option = options,
yading@11 204 };
yading@11 205
yading@11 206 AVOutputFormat ff_gif_muxer = {
yading@11 207 .name = "gif",
yading@11 208 .long_name = NULL_IF_CONFIG_SMALL("GIF Animation"),
yading@11 209 .mime_type = "image/gif",
yading@11 210 .extensions = "gif",
yading@11 211 .priv_data_size = sizeof(GIFContext),
yading@11 212 .audio_codec = AV_CODEC_ID_NONE,
yading@11 213 .video_codec = AV_CODEC_ID_GIF,
yading@11 214 .write_header = gif_write_header,
yading@11 215 .write_packet = gif_write_packet,
yading@11 216 .write_trailer = gif_write_trailer,
yading@11 217 .priv_class = &gif_muxer_class,
yading@11 218 .flags = AVFMT_VARIABLE_FPS,
yading@11 219 };