[FFmpeg-devel] [PATCH] lavc/gif: use transparency.
Paul B Mahol
onemda at gmail.com
Fri Apr 19 21:22:02 CEST 2013
On 4/19/13, Clement Boesch <ubitux at gmail.com> wrote:
> ---
> ffmpeg -i big_buck_bunny_1080p_h264.mov -ss 45 -vf scale=320:160 -gifflags
> -trans -frames:v 50 -y bbb-notrans.gif
> ffmpeg -i big_buck_bunny_1080p_h264.mov -ss 45 -vf scale=320:160 -gifflags
> +trans -frames:v 50 -y bbb-trans.gif
>
> -rw-r--r-- 1 ubitux ubitux 1.1M Apr 19 19:00 bbb-notrans.gif
> -rw-r--r-- 1 ubitux ubitux 378K Apr 19 19:00 bbb-trans.gif
>
> FATE will be updated, 'just avoiding large patches.
> ---
> libavcodec/gif.c | 70
> ++++++++++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 63 insertions(+), 7 deletions(-)
>
> diff --git a/libavcodec/gif.c b/libavcodec/gif.c
> index ad4f08b..0db809b 100644
> --- a/libavcodec/gif.c
> +++ b/libavcodec/gif.c
> @@ -29,6 +29,7 @@
> */
>
> #include "libavutil/opt.h"
> +#include "libavutil/imgutils.h"
> #include "avcodec.h"
> #include "bytestream.h"
> #include "internal.h"
> @@ -47,21 +48,41 @@ typedef struct {
> uint8_t *buf;
> AVFrame *last_frame;
> int flags;
> + uint32_t palette[AVPALETTE_COUNT]; ///< local reference palette for
> !pal8
> + uint8_t *tmpl; ///< temporary line buffer
> } GIFContext;
>
> enum {
> GF_LZW = 1<<0,
> GF_CROP = 1<<1,
> + GF_TRANS = 1<<2,
> };
>
> +static int pick_palette_entry(const uint8_t *buf, int linesize, int w, int
> h)
> +{
> + int histogram[AVPALETTE_COUNT] = {0};
> + int x, y, i;
> +
> + for (y = 0; y < h; y++) {
> + for (x = 0; x < w; x++)
> + histogram[buf[x]]++;
> + buf += linesize;
> + }
> + for (i = 0; i < FF_ARRAY_ELEMS(histogram); i++)
> + if (!histogram[i])
> + return i;
> + return -1;
> +}
> +
> static int gif_image_write_image(AVCodecContext *avctx,
> uint8_t **bytestream, uint8_t *end,
> const uint32_t *palette,
> - const uint8_t *buf, int linesize)
> + const uint8_t *buf, const int linesize,
> + AVPacket *pkt)
> {
> GIFContext *s = avctx->priv_data;
> - int len = 0, height = avctx->height, width = avctx->width, y;
> - int x_start = 0, y_start = 0;
> + int len = 0, height = avctx->height, width = avctx->width, x, y;
> + int x_start = 0, y_start = 0, trans = -1;
> const uint8_t *ptr;
>
> /* Crop image */
> @@ -134,6 +155,21 @@ static int gif_image_write_image(AVCodecContext
> *avctx,
> }
> }
>
> + /* TODO: support with palette change (pal8) */
> + if ((s->flags & GF_TRANS) && s->last_frame && !palette) {
> + trans = pick_palette_entry(buf + y_start*linesize + x_start,
> + linesize, width, height);
> + if (trans < 0) { // TODO, patch welcome
> + av_log(avctx, AV_LOG_DEBUG, "No available color, can not use
> transparency\n");
> + } else {
> + uint8_t *pal_exdata = av_packet_new_side_data(pkt,
> AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
> + if (!pal_exdata)
> + return AVERROR(ENOMEM);
> + memcpy(pal_exdata, s->palette, AVPALETTE_SIZE);
> + pal_exdata[trans*4 + 3] = 0x00;
> + }
> + }
> +
> bytestream_put_byte(bytestream, 0x08);
>
> if (s->flags & GF_LZW) {
> @@ -143,7 +179,19 @@ static int gif_image_write_image(AVCodecContext
> *avctx,
>
> ptr = buf + y_start*linesize + x_start;
> for (y = 0; y < height; y++) {
> - len += ff_lzw_encode(s->lzw, ptr, width);
> + const uint8_t *src_data_line = ptr;
> +
> + if (trans >= 0) {
> + const uint8_t *ref = s->last_frame->data[0];
> + const int ref_linesize = s->last_frame->linesize[0];
> +
> + memcpy(s->tmpl, ptr, width);
> + for (x = 0; x < width; x++)
> + if (ref[(y_start + y) * ref_linesize + x_start + x] ==
This can't overflow?
> ptr[x])
> + s->tmpl[x] = trans;
> + src_data_line = s->tmpl;
> + }
> + len += ff_lzw_encode(s->lzw, src_data_line, width);
> ptr += linesize;
> }
> len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
> @@ -208,8 +256,13 @@ static av_cold int gif_encode_init(AVCodecContext
> *avctx)
> avctx->coded_frame = &s->picture;
> s->lzw = av_mallocz(ff_lzw_encode_state_size);
> s->buf = av_malloc(avctx->width*avctx->height*2);
> - if (!s->buf || !s->lzw)
> + s->tmpl = av_malloc(avctx->width);
> + if (!s->buf || !s->lzw || !s->tmpl)
> return AVERROR(ENOMEM);
> +
> + if (avpriv_set_systematic_pal2(s->palette, avctx->pix_fmt) < 0)
> + av_assert0(avctx->pix_fmt == AV_PIX_FMT_PAL8);
> +
> return 0;
> }
>
> @@ -240,7 +293,8 @@ static int gif_encode_frame(AVCodecContext *avctx,
> AVPacket *pkt,
> palette = (uint32_t*)p->data[1];
> }
>
> - gif_image_write_image(avctx, &outbuf_ptr, end, palette, pict->data[0],
> pict->linesize[0]);
> + gif_image_write_image(avctx, &outbuf_ptr, end, palette,
> + pict->data[0], pict->linesize[0], pkt);
> if (!s->last_frame) {
> s->last_frame = av_frame_alloc();
> if (!s->last_frame)
> @@ -265,15 +319,17 @@ static int gif_encode_close(AVCodecContext *avctx)
> av_freep(&s->lzw);
> av_freep(&s->buf);
> av_frame_free(&s->last_frame);
> + av_freep(&s->tmpl);
> return 0;
> }
>
> #define OFFSET(x) offsetof(GIFContext, x)
> #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
> static const AVOption gif_options[] = {
> - { "gifflags", "set GIF flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64
> = GF_LZW|GF_CROP}, 0, INT_MAX, FLAGS, "flags" },
> + { "gifflags", "set GIF flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64
> = GF_LZW|GF_CROP|GF_TRANS}, 0, INT_MAX, FLAGS, "flags" },
> { "lzw", "enable LZW compression", 0, AV_OPT_TYPE_CONST,
> {.i64=GF_LZW}, INT_MIN, INT_MAX, FLAGS, "flags" },
> { "crop", "enable crop detection", 0, AV_OPT_TYPE_CONST,
> {.i64=GF_CROP}, INT_MIN, INT_MAX, FLAGS, "flags" },
> + { "trans", "enable transparency detection between frames", 0,
> AV_OPT_TYPE_CONST, {.i64=GF_TRANS}, INT_MIN, INT_MAX, FLAGS, "flags" },
> { NULL }
> };
>
> --
> 1.8.2.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
rest looks ok
More information about the ffmpeg-devel
mailing list