LCOV - code coverage report
Current view: top level - libavcodec - gif.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 157 173 90.8 %
Date: 2017-12-12 11:08:38 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2000 Fabrice Bellard
       3             :  * Copyright (c) 2002 Francois Revol
       4             :  * Copyright (c) 2006 Baptiste Coudurier
       5             :  *
       6             :  * first version by Francois Revol <revol@free.fr>
       7             :  *
       8             :  * This file is part of FFmpeg.
       9             :  *
      10             :  * FFmpeg is free software; you can redistribute it and/or
      11             :  * modify it under the terms of the GNU Lesser General Public
      12             :  * License as published by the Free Software Foundation; either
      13             :  * version 2.1 of the License, or (at your option) any later version.
      14             :  *
      15             :  * FFmpeg is distributed in the hope that it will be useful,
      16             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18             :  * Lesser General Public License for more details.
      19             :  *
      20             :  * You should have received a copy of the GNU Lesser General Public
      21             :  * License along with FFmpeg; if not, write to the Free Software
      22             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      23             :  */
      24             : 
      25             : /**
      26             :  * @file
      27             :  * GIF encoder
      28             :  * @see http://www.w3.org/Graphics/GIF/spec-gif89a.txt
      29             :  */
      30             : 
      31             : #define BITSTREAM_WRITER_LE
      32             : #include "libavutil/opt.h"
      33             : #include "libavutil/imgutils.h"
      34             : #include "avcodec.h"
      35             : #include "bytestream.h"
      36             : #include "internal.h"
      37             : #include "lzw.h"
      38             : #include "gif.h"
      39             : 
      40             : #include "put_bits.h"
      41             : 
      42             : typedef struct GIFContext {
      43             :     const AVClass *class;
      44             :     LZWState *lzw;
      45             :     uint8_t *buf;
      46             :     int buf_size;
      47             :     AVFrame *last_frame;
      48             :     int flags;
      49             :     uint32_t palette[AVPALETTE_COUNT];  ///< local reference palette for !pal8
      50             :     int palette_loaded;
      51             :     int transparent_index;
      52             :     uint8_t *pal_exdata;
      53             :     uint8_t *tmpl;                      ///< temporary line buffer
      54             : } GIFContext;
      55             : 
      56             : enum {
      57             :     GF_OFFSETTING = 1<<0,
      58             :     GF_TRANSDIFF  = 1<<1,
      59             : };
      60             : 
      61        1056 : static int pick_palette_entry(const uint8_t *buf, int linesize, int w, int h)
      62             : {
      63        1056 :     int histogram[AVPALETTE_COUNT] = {0};
      64             :     int x, y, i;
      65             : 
      66      133080 :     for (y = 0; y < h; y++) {
      67    26548238 :         for (x = 0; x < w; x++)
      68    26416214 :             histogram[buf[x]]++;
      69      132024 :         buf += linesize;
      70             :     }
      71       12322 :     for (i = 0; i < FF_ARRAY_ELEMS(histogram); i++)
      72       12298 :         if (!histogram[i])
      73        1032 :             return i;
      74          24 :     return -1;
      75             : }
      76             : 
      77        1063 : static int gif_image_write_image(AVCodecContext *avctx,
      78             :                                  uint8_t **bytestream, uint8_t *end,
      79             :                                  const uint32_t *palette,
      80             :                                  const uint8_t *buf, const int linesize,
      81             :                                  AVPacket *pkt)
      82             : {
      83        1063 :     GIFContext *s = avctx->priv_data;
      84        1063 :     int len = 0, height = avctx->height, width = avctx->width, x, y;
      85        1063 :     int x_start = 0, y_start = 0, trans = s->transparent_index;
      86        1063 :     int honor_transparency = (s->flags & GF_TRANSDIFF) && s->last_frame && !palette;
      87             :     const uint8_t *ptr;
      88             : 
      89             :     /* Crop image */
      90        1063 :     if ((s->flags & GF_OFFSETTING) && s->last_frame && !palette) {
      91        1056 :         const uint8_t *ref = s->last_frame->data[0];
      92        1056 :         const int ref_linesize = s->last_frame->linesize[0];
      93        1056 :         int x_end = avctx->width  - 1,
      94        1056 :             y_end = avctx->height - 1;
      95             : 
      96             :         /* skip common lines */
      97       19922 :         while (y_start < y_end) {
      98       18866 :             if (memcmp(ref + y_start*ref_linesize, buf + y_start*linesize, width))
      99        1056 :                 break;
     100       17810 :             y_start++;
     101             :         }
     102       83134 :         while (y_end > y_start) {
     103       82078 :             if (memcmp(ref + y_end*ref_linesize, buf + y_end*linesize, width))
     104        1056 :                 break;
     105       81022 :             y_end--;
     106             :         }
     107        1056 :         height = y_end + 1 - y_start;
     108             : 
     109             :         /* skip common columns */
     110       20918 :         while (x_start < x_end) {
     111       19862 :             int same_column = 1;
     112      431565 :             for (y = y_start; y <= y_end; y++) {
     113      412759 :                 if (ref[y*ref_linesize + x_start] != buf[y*linesize + x_start]) {
     114        1056 :                     same_column = 0;
     115        1056 :                     break;
     116             :                 }
     117             :             }
     118       19862 :             if (!same_column)
     119        1056 :                 break;
     120       18806 :             x_start++;
     121             :         }
     122       53736 :         while (x_end > x_start) {
     123       52680 :             int same_column = 1;
     124     2834370 :             for (y = y_start; y <= y_end; y++) {
     125     2782746 :                 if (ref[y*ref_linesize + x_end] != buf[y*linesize + x_end]) {
     126        1056 :                     same_column = 0;
     127        1056 :                     break;
     128             :                 }
     129             :             }
     130       52680 :             if (!same_column)
     131        1056 :                 break;
     132       51624 :             x_end--;
     133             :         }
     134        1056 :         width = x_end + 1 - x_start;
     135             : 
     136        1056 :         av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d) [area:%dx%d]\n",
     137             :                width, height, x_start, y_start, avctx->width, avctx->height);
     138             :     }
     139             : 
     140             :     /* image block */
     141        1063 :     bytestream_put_byte(bytestream, GIF_IMAGE_SEPARATOR);
     142        1063 :     bytestream_put_le16(bytestream, x_start);
     143        1063 :     bytestream_put_le16(bytestream, y_start);
     144        1063 :     bytestream_put_le16(bytestream, width);
     145        1063 :     bytestream_put_le16(bytestream, height);
     146             : 
     147        1063 :     if (!palette) {
     148        1063 :         bytestream_put_byte(bytestream, 0x00); /* flags */
     149             :     } else {
     150             :         unsigned i;
     151           0 :         bytestream_put_byte(bytestream, 1<<7 | 0x7); /* flags */
     152           0 :         for (i = 0; i < AVPALETTE_COUNT; i++) {
     153           0 :             const uint32_t v = palette[i];
     154           0 :             bytestream_put_be24(bytestream, v);
     155             :         }
     156             :     }
     157             : 
     158        1063 :     if (honor_transparency && trans < 0) {
     159        1056 :         trans = pick_palette_entry(buf + y_start*linesize + x_start,
     160             :                                    linesize, width, height);
     161        1056 :         if (trans < 0) { // TODO, patch welcome
     162          24 :             av_log(avctx, AV_LOG_DEBUG, "No available color, can not use transparency\n");
     163             :         } else {
     164        1032 :             uint8_t *pal_exdata = s->pal_exdata;
     165        1032 :             if (!pal_exdata)
     166         860 :                 pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
     167        1032 :             if (!pal_exdata)
     168           0 :                 return AVERROR(ENOMEM);
     169        1032 :             memcpy(pal_exdata, s->palette, AVPALETTE_SIZE);
     170        1032 :             pal_exdata[trans*4 + 3*!HAVE_BIGENDIAN] = 0x00;
     171             :         }
     172             :     }
     173        1063 :     if (trans < 0)
     174          31 :         honor_transparency = 0;
     175             : 
     176        1063 :     bytestream_put_byte(bytestream, 0x08);
     177             : 
     178        1063 :     ff_lzw_encode_init(s->lzw, s->buf, s->buf_size,
     179             :                        12, FF_LZW_GIF, put_bits);
     180             : 
     181        1063 :     ptr = buf + y_start*linesize + x_start;
     182        1063 :     if (honor_transparency) {
     183        1032 :         const int ref_linesize = s->last_frame->linesize[0];
     184        1032 :         const uint8_t *ref = s->last_frame->data[0] + y_start*ref_linesize + x_start;
     185             : 
     186      126144 :         for (y = 0; y < height; y++) {
     187      125112 :             memcpy(s->tmpl, ptr, width);
     188    24108302 :             for (x = 0; x < width; x++)
     189    23983190 :                 if (ref[x] == ptr[x])
     190    11657111 :                     s->tmpl[x] = trans;
     191      125112 :             len += ff_lzw_encode(s->lzw, s->tmpl, width);
     192      125112 :             ptr += linesize;
     193      125112 :             ref += ref_linesize;
     194             :         }
     195             :     } else {
     196        8533 :         for (y = 0; y < height; y++) {
     197        8502 :             len += ff_lzw_encode(s->lzw, ptr, width);
     198        8502 :             ptr += linesize;
     199             :         }
     200             :     }
     201        1063 :     len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
     202             : 
     203        1063 :     ptr = s->buf;
     204       44444 :     while (len > 0) {
     205       42318 :         int size = FFMIN(255, len);
     206       42318 :         bytestream_put_byte(bytestream, size);
     207       42318 :         if (end - *bytestream < size)
     208           0 :             return -1;
     209       42318 :         bytestream_put_buffer(bytestream, ptr, size);
     210       42318 :         ptr += size;
     211       42318 :         len -= size;
     212             :     }
     213        1063 :     bytestream_put_byte(bytestream, 0x00); /* end of image block */
     214        1063 :     return 0;
     215             : }
     216             : 
     217           7 : static av_cold int gif_encode_init(AVCodecContext *avctx)
     218             : {
     219           7 :     GIFContext *s = avctx->priv_data;
     220             : 
     221           7 :     if (avctx->width > 65535 || avctx->height > 65535) {
     222           0 :         av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n");
     223           0 :         return AVERROR(EINVAL);
     224             :     }
     225             : #if FF_API_CODED_FRAME
     226             : FF_DISABLE_DEPRECATION_WARNINGS
     227           7 :     avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
     228           7 :     avctx->coded_frame->key_frame = 1;
     229             : FF_ENABLE_DEPRECATION_WARNINGS
     230             : #endif
     231             : 
     232           7 :     s->transparent_index = -1;
     233             : 
     234           7 :     s->lzw = av_mallocz(ff_lzw_encode_state_size);
     235           7 :     s->buf_size = avctx->width*avctx->height*2 + 1000;
     236           7 :     s->buf = av_malloc(s->buf_size);
     237           7 :     s->tmpl = av_malloc(avctx->width);
     238           7 :     if (!s->tmpl || !s->buf || !s->lzw)
     239           0 :         return AVERROR(ENOMEM);
     240             : 
     241           7 :     if (avpriv_set_systematic_pal2(s->palette, avctx->pix_fmt) < 0)
     242           1 :         av_assert0(avctx->pix_fmt == AV_PIX_FMT_PAL8);
     243             : 
     244           7 :     return 0;
     245             : }
     246             : 
     247             : /* FIXME: duplicated with lavc */
     248           1 : static int get_palette_transparency_index(const uint32_t *palette)
     249             : {
     250           1 :     int transparent_color_index = -1;
     251           1 :     unsigned i, smallest_alpha = 0xff;
     252             : 
     253           1 :     if (!palette)
     254           0 :         return -1;
     255             : 
     256         257 :     for (i = 0; i < AVPALETTE_COUNT; i++) {
     257         256 :         const uint32_t v = palette[i];
     258         256 :         if (v >> 24 < smallest_alpha) {
     259           0 :             smallest_alpha = v >> 24;
     260           0 :             transparent_color_index = i;
     261             :         }
     262             :     }
     263           1 :     return smallest_alpha < 128 ? transparent_color_index : -1;
     264             : }
     265             : 
     266        1063 : static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
     267             :                             const AVFrame *pict, int *got_packet)
     268             : {
     269        1063 :     GIFContext *s = avctx->priv_data;
     270             :     uint8_t *outbuf_ptr, *end;
     271        1063 :     const uint32_t *palette = NULL;
     272             :     int ret;
     273             : 
     274        1063 :     if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*7/5 + AV_INPUT_BUFFER_MIN_SIZE, 0)) < 0)
     275           0 :         return ret;
     276        1063 :     outbuf_ptr = pkt->data;
     277        1063 :     end        = pkt->data + pkt->size;
     278             : 
     279        1063 :     if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
     280         173 :         uint8_t *pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
     281         173 :         if (!pal_exdata)
     282           0 :             return AVERROR(ENOMEM);
     283         173 :         memcpy(pal_exdata, pict->data[1], AVPALETTE_SIZE);
     284         173 :         palette = (uint32_t*)pict->data[1];
     285             : 
     286         173 :         s->pal_exdata = pal_exdata;
     287             : 
     288             :         /* The first palette with PAL8 will be used as generic palette by the
     289             :          * muxer so we don't need to write it locally in the packet. We store
     290             :          * it as a reference here in case it changes later. */
     291         173 :         if (!s->palette_loaded) {
     292           1 :             memcpy(s->palette, palette, AVPALETTE_SIZE);
     293           1 :             s->transparent_index = get_palette_transparency_index(palette);
     294           1 :             s->palette_loaded = 1;
     295           1 :             palette = NULL;
     296         172 :         } else if (!memcmp(s->palette, palette, AVPALETTE_SIZE)) {
     297         172 :             palette = NULL;
     298             :         }
     299             :     }
     300             : 
     301        2126 :     gif_image_write_image(avctx, &outbuf_ptr, end, palette,
     302        1063 :                           pict->data[0], pict->linesize[0], pkt);
     303        1063 :     if (!s->last_frame) {
     304           7 :         s->last_frame = av_frame_alloc();
     305           7 :         if (!s->last_frame)
     306           0 :             return AVERROR(ENOMEM);
     307             :     }
     308        1063 :     av_frame_unref(s->last_frame);
     309        1063 :     ret = av_frame_ref(s->last_frame, (AVFrame*)pict);
     310        1063 :     if (ret < 0)
     311           0 :         return ret;
     312             : 
     313        1063 :     pkt->size   = outbuf_ptr - pkt->data;
     314        1063 :     pkt->flags |= AV_PKT_FLAG_KEY;
     315        1063 :     *got_packet = 1;
     316             : 
     317        1063 :     return 0;
     318             : }
     319             : 
     320           7 : static int gif_encode_close(AVCodecContext *avctx)
     321             : {
     322           7 :     GIFContext *s = avctx->priv_data;
     323             : 
     324           7 :     av_freep(&s->lzw);
     325           7 :     av_freep(&s->buf);
     326           7 :     s->buf_size = 0;
     327           7 :     av_frame_free(&s->last_frame);
     328           7 :     av_freep(&s->tmpl);
     329           7 :     return 0;
     330             : }
     331             : 
     332             : #define OFFSET(x) offsetof(GIFContext, x)
     333             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
     334             : static const AVOption gif_options[] = {
     335             :     { "gifflags", "set GIF flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = GF_OFFSETTING|GF_TRANSDIFF}, 0, INT_MAX, FLAGS, "flags" },
     336             :         { "offsetting", "enable picture offsetting", 0, AV_OPT_TYPE_CONST, {.i64=GF_OFFSETTING}, INT_MIN, INT_MAX, FLAGS, "flags" },
     337             :         { "transdiff", "enable transparency detection between frames", 0, AV_OPT_TYPE_CONST, {.i64=GF_TRANSDIFF}, INT_MIN, INT_MAX, FLAGS, "flags" },
     338             :     { NULL }
     339             : };
     340             : 
     341             : static const AVClass gif_class = {
     342             :     .class_name = "GIF encoder",
     343             :     .item_name  = av_default_item_name,
     344             :     .option     = gif_options,
     345             :     .version    = LIBAVUTIL_VERSION_INT,
     346             : };
     347             : 
     348             : AVCodec ff_gif_encoder = {
     349             :     .name           = "gif",
     350             :     .long_name      = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
     351             :     .type           = AVMEDIA_TYPE_VIDEO,
     352             :     .id             = AV_CODEC_ID_GIF,
     353             :     .priv_data_size = sizeof(GIFContext),
     354             :     .init           = gif_encode_init,
     355             :     .encode2        = gif_encode_frame,
     356             :     .close          = gif_encode_close,
     357             :     .pix_fmts       = (const enum AVPixelFormat[]){
     358             :         AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE,
     359             :         AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE
     360             :     },
     361             :     .priv_class     = &gif_class,
     362             : };

Generated by: LCOV version 1.13