diff options
Diffstat (limited to 'libavcodec/libwebpenc.c')
-rw-r--r-- | libavcodec/libwebpenc.c | 100 |
1 files changed, 89 insertions, 11 deletions
diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c index b981f48..95d56ac 100644 --- a/libavcodec/libwebpenc.c +++ b/libavcodec/libwebpenc.c @@ -2,20 +2,20 @@ * WebP encoding support via libwebp * Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com> * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -41,6 +41,9 @@ typedef struct LibWebPContext { int chroma_warning; // chroma linesize mismatch warning has been printed int conversion_warning; // pixel format conversion warning has been printed WebPConfig config; // libwebp configuration + AVFrame *ref; + int cr_size; + int cr_threshold; } LibWebPContext; static int libwebp_error_to_averror(int err) @@ -62,10 +65,9 @@ static av_cold int libwebp_encode_init(AVCodecContext *avctx) LibWebPContext *s = avctx->priv_data; int ret; - if (avctx->global_quality < 0) - avctx->global_quality = 75 * FF_QP2LAMBDA; - s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA, - 0.0f, 100.0f); + if (avctx->global_quality >= 0) + s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA, + 0.0f, 100.0f); if (avctx->compression_level < 0 || avctx->compression_level > 6) { av_log(avctx, AV_LOG_WARNING, "invalid compression level: %d\n", @@ -144,8 +146,8 @@ static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt, pic->argb = (uint32_t *)frame->data[0]; pic->argb_stride = frame->linesize[0] / 4; } else { - if (frame->linesize[1] != frame->linesize[2]) { - if (!s->chroma_warning) { + if (frame->linesize[1] != frame->linesize[2] || s->cr_threshold) { + if (!s->chroma_warning && !s->cr_threshold) { av_log(avctx, AV_LOG_WARNING, "Copying frame due to differing chroma linesizes.\n"); s->chroma_warning = 1; @@ -158,22 +160,80 @@ static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt, alt_frame->width = frame->width; alt_frame->height = frame->height; alt_frame->format = frame->format; + if (s->cr_threshold) + alt_frame->format = AV_PIX_FMT_YUVA420P; ret = av_frame_get_buffer(alt_frame, 32); if (ret < 0) goto end; + alt_frame->format = frame->format; av_frame_copy(alt_frame, frame); frame = alt_frame; + if (s->cr_threshold) { + int x,y, x2, y2, p; + int bs = s->cr_size; + + if (!s->ref) { + s->ref = av_frame_clone(frame); + if (!s->ref) { + ret = AVERROR(ENOMEM); + goto end; + } + } + + alt_frame->format = AV_PIX_FMT_YUVA420P; + for (y = 0; y < frame->height; y+= bs) { + for (x = 0; x < frame->width; x+= bs) { + int skip; + int sse = 0; + for (p = 0; p < 3; p++) { + int bs2 = bs >> !!p; + int w = FF_CEIL_RSHIFT(frame->width , !!p); + int h = FF_CEIL_RSHIFT(frame->height, !!p); + int xs = x >> !!p; + int ys = y >> !!p; + for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) { + for (x2 = xs; x2 < FFMIN(xs + bs2, w); x2++) { + int diff = frame->data[p][frame->linesize[p] * y2 + x2] + -s->ref->data[p][frame->linesize[p] * y2 + x2]; + sse += diff*diff; + } + } + } + skip = sse < s->cr_threshold && frame->data[3] != s->ref->data[3]; + if (!skip) + for (p = 0; p < 3; p++) { + int bs2 = bs >> !!p; + int w = FF_CEIL_RSHIFT(frame->width , !!p); + int h = FF_CEIL_RSHIFT(frame->height, !!p); + int xs = x >> !!p; + int ys = y >> !!p; + for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) { + memcpy(&s->ref->data[p][frame->linesize[p] * y2 + xs], + & frame->data[p][frame->linesize[p] * y2 + xs], FFMIN(bs2, w-xs)); + } + } + for (y2 = y; y2 < FFMIN(y+bs, frame->height); y2++) { + memset(&frame->data[3][frame->linesize[3] * y2 + x], + skip ? 0 : 255, + FFMIN(bs, frame->width-x)); + } + } + } + } } + pic->use_argb = 0; pic->y = frame->data[0]; pic->u = frame->data[1]; pic->v = frame->data[2]; pic->y_stride = frame->linesize[0]; pic->uv_stride = frame->linesize[1]; - if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) { + if (frame->format == AV_PIX_FMT_YUVA420P) { pic->colorspace = WEBP_YUV420A; pic->a = frame->data[3]; pic->a_stride = frame->linesize[3]; + if (alt_frame) + WebPCleanupTransparentArea(pic); } else { pic->colorspace = WEBP_YUV420; } @@ -231,7 +291,11 @@ static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt, *got_packet = 1; end: +#if (WEBP_ENCODER_ABI_VERSION > 0x0203) + WebPMemoryWriterClear(&mw); +#else free(mw.mem); /* must use free() according to libwebp documentation */ +#endif WebPPictureFree(pic); av_freep(&pic); av_frame_free(&alt_frame); @@ -239,6 +303,15 @@ end: return ret; } +static int libwebp_encode_close(AVCodecContext *avctx) +{ + LibWebPContext *s = avctx->priv_data; + + av_frame_free(&s->ref); + + return 0; +} + #define OFFSET(x) offsetof(LibWebPContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -251,9 +324,13 @@ static const AVOption options[] = { { "drawing", "hand or line drawing, with high-contrast details", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DRAWING }, 0, 0, VE, "preset" }, { "icon", "small-sized colorful images", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_ICON }, 0, 0, VE, "preset" }, { "text", "text-like", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_TEXT }, 0, 0, VE, "preset" }, + { "cr_threshold","Conditional replenishment threshold", OFFSET(cr_threshold), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + { "cr_size" ,"Conditional replenishment block size", OFFSET(cr_size) , AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 256, VE }, + { "quality" ,"Quality", OFFSET(quality), AV_OPT_TYPE_FLOAT, { .dbl = 75 }, 0, 100, VE }, { NULL }, }; + static const AVClass class = { .class_name = "libwebp", .item_name = av_default_item_name, @@ -275,6 +352,7 @@ AVCodec ff_libwebp_encoder = { .priv_data_size = sizeof(LibWebPContext), .init = libwebp_encode_init, .encode2 = libwebp_encode_frame, + .close = libwebp_encode_close, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB32, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, |