You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

242 lines
7.6KB

  1. /*
  2. * Animated GIF muxer
  3. * Copyright (c) 2000 Fabrice Bellard
  4. *
  5. * first version by Francois Revol <revol@free.fr>
  6. *
  7. * This file is part of FFmpeg.
  8. *
  9. * FFmpeg is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2.1 of the License, or (at your option) any later version.
  13. *
  14. * FFmpeg is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with FFmpeg; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * Features and limitations:
  25. * - currently no compression is performed,
  26. * in fact the size of the data is 9/8 the size of the image in 8bpp
  27. * - uses only a global standard palette
  28. * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
  29. *
  30. * Reference documents:
  31. * http://www.goice.co.jp/member/mo/formats/gif.html
  32. * http://astronomy.swin.edu.au/pbourke/dataformats/gif/
  33. * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
  34. *
  35. * this url claims to have an LZW algorithm not covered by Unisys patent:
  36. * http://www.msg.net/utility/whirlgif/gifencod.html
  37. * could help reduce the size of the files _a lot_...
  38. * some sites mentions an RLE type compression also.
  39. */
  40. #include "avformat.h"
  41. #include "libavutil/avassert.h"
  42. #include "libavutil/imgutils.h"
  43. #include "libavutil/log.h"
  44. #include "libavutil/opt.h"
  45. /* slows down the decoding (and some browsers don't like it) */
  46. /* update on the 'some browsers don't like it issue from above:
  47. * this was probably due to missing 'Data Sub-block Terminator'
  48. * (byte 19) in the app_header */
  49. #define GIF_ADD_APP_HEADER // required to enable looping of animated gif
  50. static int gif_image_write_header(AVIOContext *pb, int width, int height,
  51. int loop_count, uint32_t *palette)
  52. {
  53. int i;
  54. unsigned int v;
  55. avio_write(pb, "GIF", 3);
  56. avio_write(pb, "89a", 3);
  57. avio_wl16(pb, width);
  58. avio_wl16(pb, height);
  59. if (palette) {
  60. /* TODO: reindent */
  61. avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
  62. avio_w8(pb, 0x1f); /* background color index */
  63. avio_w8(pb, 0); /* aspect ratio */
  64. for (i = 0; i < 256; i++) {
  65. v = palette[i];
  66. avio_w8(pb, (v >> 16) & 0xff);
  67. avio_w8(pb, (v >> 8) & 0xff);
  68. avio_w8(pb, (v) & 0xff);
  69. }
  70. } else {
  71. avio_w8(pb, 0); /* flags */
  72. avio_w8(pb, 0); /* background color index */
  73. avio_w8(pb, 0); /* aspect ratio */
  74. }
  75. /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated
  76. * GIF, see http://members.aol.com/royalef/gifabout.htm#net-extension
  77. *
  78. * byte 1 : 33 (hex 0x21) GIF Extension code
  79. * byte 2 : 255 (hex 0xFF) Application Extension Label
  80. * byte 3 : 11 (hex (0x0B) Length of Application Block
  81. * (eleven bytes of data to follow)
  82. * bytes 4 to 11 : "NETSCAPE"
  83. * bytes 12 to 14 : "2.0"
  84. * byte 15 : 3 (hex 0x03) Length of Data Sub-Block
  85. * (three bytes of data to follow)
  86. * byte 16 : 1 (hex 0x01)
  87. * bytes 17 to 18 : 0 to 65535, an unsigned integer in
  88. * lo-hi byte format. This indicate the
  89. * number of iterations the loop should
  90. * be executed.
  91. * bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator
  92. */
  93. /* application extension header */
  94. #ifdef GIF_ADD_APP_HEADER
  95. if (loop_count >= 0 && loop_count <= 65535) {
  96. avio_w8(pb, 0x21);
  97. avio_w8(pb, 0xff);
  98. avio_w8(pb, 0x0b);
  99. // bytes 4 to 14
  100. avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
  101. avio_w8(pb, 0x03); // byte 15
  102. avio_w8(pb, 0x01); // byte 16
  103. avio_wl16(pb, (uint16_t)loop_count);
  104. avio_w8(pb, 0x00); // byte 19
  105. }
  106. #endif
  107. return 0;
  108. }
  109. typedef struct {
  110. AVClass *class; /** Class for private options. */
  111. int64_t time, file_time;
  112. uint8_t buffer[100]; /* data chunks */
  113. int loop;
  114. } GIFContext;
  115. static int gif_write_header(AVFormatContext *s)
  116. {
  117. GIFContext *gif = s->priv_data;
  118. AVIOContext *pb = s->pb;
  119. AVCodecContext *enc, *video_enc;
  120. int i, width, height /*, rate*/;
  121. uint32_t palette[AVPALETTE_COUNT];
  122. /* XXX: do we reject audio streams or just ignore them ?
  123. * if (s->nb_streams > 1)
  124. * return -1;
  125. */
  126. gif->time = 0;
  127. gif->file_time = 0;
  128. video_enc = NULL;
  129. for (i = 0; i < s->nb_streams; i++) {
  130. enc = s->streams[i]->codec;
  131. if (enc->codec_type != AVMEDIA_TYPE_AUDIO)
  132. video_enc = enc;
  133. }
  134. if (!video_enc) {
  135. av_free(gif);
  136. return -1;
  137. } else {
  138. width = video_enc->width;
  139. height = video_enc->height;
  140. // rate = video_enc->time_base.den;
  141. }
  142. if (avpriv_set_systematic_pal2(palette, video_enc->pix_fmt) < 0) {
  143. av_assert0(video_enc->pix_fmt == AV_PIX_FMT_PAL8);
  144. gif_image_write_header(pb, width, height, gif->loop, NULL);
  145. } else {
  146. gif_image_write_header(pb, width, height, gif->loop, palette);
  147. }
  148. avio_flush(s->pb);
  149. return 0;
  150. }
  151. static int gif_write_video(AVFormatContext *s, AVCodecContext *enc,
  152. const uint8_t *buf, int size)
  153. {
  154. AVIOContext *pb = s->pb;
  155. int jiffies;
  156. /* graphic control extension block */
  157. avio_w8(pb, 0x21);
  158. avio_w8(pb, 0xf9);
  159. avio_w8(pb, 0x04); /* block size */
  160. avio_w8(pb, 0x04); /* flags */
  161. /* 1 jiffy is 1/70 s */
  162. /* the delay_time field indicates the number of jiffies - 1 */
  163. /* XXX: should use delay, in order to be more accurate */
  164. /* instead of using the same rounded value each time */
  165. /* XXX: don't even remember if I really use it for now */
  166. jiffies = (70 * enc->time_base.num / enc->time_base.den) - 1;
  167. avio_wl16(pb, jiffies);
  168. avio_w8(pb, 0x1f); /* transparent color index */
  169. avio_w8(pb, 0x00);
  170. avio_write(pb, buf, size);
  171. return 0;
  172. }
  173. static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
  174. {
  175. AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
  176. if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
  177. return 0; /* just ignore audio */
  178. else
  179. return gif_write_video(s, codec, pkt->data, pkt->size);
  180. }
  181. static int gif_write_trailer(AVFormatContext *s)
  182. {
  183. AVIOContext *pb = s->pb;
  184. avio_w8(pb, 0x3b);
  185. return 0;
  186. }
  187. #define OFFSET(x) offsetof(GIFContext, x)
  188. #define ENC AV_OPT_FLAG_ENCODING_PARAM
  189. static const AVOption options[] = {
  190. { "loop", "Number of times to loop the output.", OFFSET(loop),
  191. AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 65535, ENC },
  192. { NULL },
  193. };
  194. static const AVClass gif_muxer_class = {
  195. .class_name = "GIF muxer",
  196. .item_name = av_default_item_name,
  197. .version = LIBAVUTIL_VERSION_INT,
  198. .option = options,
  199. };
  200. AVOutputFormat ff_gif_muxer = {
  201. .name = "gif",
  202. .long_name = NULL_IF_CONFIG_SMALL("GIF Animation"),
  203. .mime_type = "image/gif",
  204. .extensions = "gif",
  205. .priv_data_size = sizeof(GIFContext),
  206. .audio_codec = AV_CODEC_ID_NONE,
  207. .video_codec = AV_CODEC_ID_GIF,
  208. .write_header = gif_write_header,
  209. .write_packet = gif_write_packet,
  210. .write_trailer = gif_write_trailer,
  211. .priv_class = &gif_muxer_class,
  212. };