[FFmpeg-devel] [PATCH] lavc/gif: crop image when possible.

Paul B Mahol onemda at gmail.com
Wed Apr 17 22:52:10 CEST 2013


On 4/17/13, Clement Boesch <ubitux at gmail.com> wrote:
> Increase compression when pictures are similar.
>
> -f lavfi testsrc=300: 61M -> 21M
>
> ---
> To be applied on top of the previous patch
> ---
>  libavcodec/gif.c | 87
> +++++++++++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 77 insertions(+), 10 deletions(-)
>
> diff --git a/libavcodec/gif.c b/libavcodec/gif.c
> index 0b8abb1..200d343 100644
> --- a/libavcodec/gif.c
> +++ b/libavcodec/gif.c
> @@ -49,6 +49,7 @@ typedef struct {
>      AVFrame picture;
>      LZWState *lzw;
>      uint8_t *buf;
> +    AVFrame *last_frame;
>  } GIFContext;
>
>  static int gif_image_write_image(AVCodecContext *avctx,
> @@ -57,15 +58,71 @@ static int gif_image_write_image(AVCodecContext *avctx,
>                                   const uint8_t *buf, int linesize)
>  {
>      GIFContext *s = avctx->priv_data;
> -    int len = 0, height;
> +    int len = 0, height = avctx->height, width = avctx->width, y;
> +    int x_start = 0, y_start = 0;
>      const uint8_t *ptr;
> -    /* image block */
>
> +    /* crop image */
> +    // TODO support with palette change
> +    if (s->last_frame && !palette) {
> +        const AVFrame *last = s->last_frame;
> +        int x_end = avctx->width  - 1,
> +            y_end = avctx->height - 1;
> +
> +        /* skip common lines */
> +        while (y_start < height) {
> +            if (memcmp(last->data[0] + y_start*last->linesize[0],
> +                       buf           + y_start*      linesize,
> +                       width))
> +                break;
> +            y_start++;
> +        }
> +        while (y_end > y_start) {
> +            if (memcmp(last->data[0] + y_end*last->linesize[0],
> +                       buf           + y_end*      linesize,
> +                       width))
> +                break;
> +            y_end--;
> +        }
> +        height = y_end + 1 - y_start;
> +
> +        /* skip common columns */
> +        while (x_start < width) {
> +            int same_column = 1;
> +            for (y = y_start; y < y_end; y++) {
> +                if (last->data[0][y*last->linesize[0] + x_start] !=
> buf[y*linesize + x_start]) {
> +                    same_column = 0;
> +                    break;
> +                }
> +            }
> +            if (!same_column)
> +                break;
> +            x_start++;
> +        }
> +        while (x_end > x_start) {
> +            int same_column = 1;
> +            for (y = y_start; y < y_end; y++) {
> +                if (last->data[0][y*last->linesize[0] + x_end] !=
> buf[y*linesize + x_end]) {
> +                    same_column = 0;
> +                    break;
> +                }
> +            }
> +            if (!same_column)
> +                break;
> +            x_end--;
> +        }
> +        width = x_end + 1 - x_start;
> +
> +        av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d)
> [area:%dx%d]\n",
> +               width, height, x_start, y_start, avctx->width,
> avctx->height);
> +    }
> +
> +    /* image block */
>      bytestream_put_byte(bytestream, 0x2c);
> -    bytestream_put_le16(bytestream, 0);
> -    bytestream_put_le16(bytestream, 0);
> -    bytestream_put_le16(bytestream, avctx->width);
> -    bytestream_put_le16(bytestream, avctx->height);
> +    bytestream_put_le16(bytestream, x_start);
> +    bytestream_put_le16(bytestream, y_start);
> +    bytestream_put_le16(bytestream, width);
> +    bytestream_put_le16(bytestream, height);
>
>      if (!palette) {
>      bytestream_put_byte(bytestream, 0x00); /* flags */
> @@ -82,12 +139,12 @@ static int gif_image_write_image(AVCodecContext
> *avctx,
>
>      bytestream_put_byte(bytestream, 0x08);
>
> -    ff_lzw_encode_init(s->lzw, s->buf, avctx->width*avctx->height,
> +    ff_lzw_encode_init(s->lzw, s->buf, width * height,
>                         12, FF_LZW_GIF, put_bits);
>
> -    ptr = buf;
> -    for (height = avctx->height; height--;) {
> -        len += ff_lzw_encode(s->lzw, ptr, avctx->width);
> +    ptr = buf + y_start*linesize + x_start;
> +    for (y = 0; y < height; y++) {
> +        len += ff_lzw_encode(s->lzw, ptr, width);
>          ptr += linesize;
>      }
>      len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
> @@ -148,6 +205,15 @@ 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]);
> +    if (!s->last_frame) {
> +        s->last_frame = av_frame_alloc();
> +        if (!s->last_frame)
> +            return AVERROR(ENOMEM);
> +    }
> +    av_frame_unref(s->last_frame);
> +    ret = av_frame_ref(s->last_frame, (AVFrame*)pict);
> +    if (ret < 0)
> +        return ret;
>
>      pkt->size   = outbuf_ptr - pkt->data;
>      pkt->flags |= AV_PKT_FLAG_KEY;
> @@ -162,6 +228,7 @@ static int gif_encode_close(AVCodecContext *avctx)
>
>      av_freep(&s->lzw);
>      av_freep(&s->buf);
> +    av_frame_free(&s->last_frame);
>      return 0;
>  }
>
> --
> 1.8.2.1

lgtm

>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>


More information about the ffmpeg-devel mailing list