X-Git-Url: https://git.piment-noir.org/?p=deb_ffmpeg.git;a=blobdiff_plain;f=ffmpeg%2Flibavcodec%2Flibwebpenc.c;h=95d56acd0b9bae8085eff4056cb5bad1f8c84782;hp=4cb8dc384e463935b9c3e81c371a705c13d06d12;hb=f6fa7814ccfe3e76514b36cf04f5cd3cb657c8cf;hpb=2ba45a602cbfa7b771effba9b11bb4245c21bc00 diff --git a/ffmpeg/libavcodec/libwebpenc.c b/ffmpeg/libavcodec/libwebpenc.c index 4cb8dc3..95d56ac 100644 --- a/ffmpeg/libavcodec/libwebpenc.c +++ b/ffmpeg/libavcodec/libwebpenc.c @@ -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; } @@ -243,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[] = { @@ -255,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, @@ -279,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,