From patchwork Tue Sep 11 19:49:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 10292 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:12c4:0:0:0:0:0 with SMTP id 65-v6csp4039630jap; Tue, 11 Sep 2018 12:56:31 -0700 (PDT) X-Google-Smtp-Source: ANB0VdZ7RFmcJJBIFcQFik+eO3EE0zGJt6TtvwmVjlGBSLvoNJfDkVvtSGtIGms52zKmVVSSIF0P X-Received: by 2002:adf:ed04:: with SMTP id a4-v6mr20497673wro.262.1536695791156; Tue, 11 Sep 2018 12:56:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1536695791; cv=none; d=google.com; s=arc-20160816; b=aEPuzBMrFGsAwyZSij/XwLS0BLLzV9lYI7ovEzVHqIwJfhWLfW3NH/bLaQ7viS+iMT RrUl7ShJaVMuN1RMbHhuD850ybC55DYFoKB6ZPFieRvP4tVIFlTqxiQokd4BYqD2WTgB tvEUSId49E++jh1IcqTaccYzkwTeisSeytZpQVLfFIB7MFTIS83TZun5J/E1Iid9lWcH 0uxQ9oaBWZgaS0Mg833a8aTz+hy987QtIaDcYhd1p9KDM/6IpLsoEHoP1IbEfOpp9hG/ yYSPuK22xijK37ERk/78hgew3E6hGbHLH57eUIUJU9vT6K0r1Cy6SemfnsjoI4l5AqsY wc1w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to; bh=tX6qEjJpiAyFbqL/2kohTU7gLnqtL2mmRv76uIHjh0o=; b=yGZG7h0GzfjlobZbDOseTlrBwpRKo+6ogIUiNsu45aKY7nRyFu8hPhC725IMYiphYQ LSr7tpEmuJjWZCIvWkKTUg4BesZBuY64jGqo/jP9IZFzwGVBFuNcR9RL6nu4ZxnG7RMg ELen7GPMkQRn9/JdwTPB4emxVgqqqnx+tbID1U+qS3wO+3tgSF+DS5mJ/YiwjHvSxufa hxQWbIPephp3xyB7cVre+pM33NyTe7dMGyMOxqrSXQps2V08u4RD7+uewy0yuWlPEIbG XSWhFVZOZbXHAzWgh2wVQTu8sZgIxXF2SoauArFRizHYZrBA5yqgu0mpAD/ozvFzqxC/ GxQQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=mpjwR9xB; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id b13-v6si18575251wrs.197.2018.09.11.12.56.30; Tue, 11 Sep 2018 12:56:31 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=mpjwR9xB; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 97B4568A34F; Tue, 11 Sep 2018 22:56:18 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f41.google.com (mail-ed1-f41.google.com [209.85.208.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1C456689F67 for ; Tue, 11 Sep 2018 22:56:12 +0300 (EEST) Received: by mail-ed1-f41.google.com with SMTP id z27-v6so20203894edb.10 for ; Tue, 11 Sep 2018 12:56:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=TxMXtbuXCCxdDFL6Lf6YmPBXJN5j+oXO4kjwIEIhEgo=; b=mpjwR9xBrbm6TGl1NrmZm3YWskr+ve+4XFhQja81pelK9YRgbpvWEUPDYWMDkzW0Py bnGb5rsQWRRarvgtnAqzzWQ6IANe6geA4NWBC947cPHqE0QRzMV3DaftbzxM/s5rzbJ7 ya36tUxCK5ji3uCfalPibXZA1MLo7heFhnbxiF4gsSFt66VK0/OTWW+0O4oZp8411RQx BBXpP+6KHddoEQ2wbs+VxlfmCpV8rjUjs//7kGHwv8e7mIA5BqPTe6UeXvV2OzdJL0aM RNhvnR71oUF2I36skO4hL533rYu0STSh0K6wBAK+0+yxkxtlzxllZeOZhfke3nOudI7k oZuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=TxMXtbuXCCxdDFL6Lf6YmPBXJN5j+oXO4kjwIEIhEgo=; b=tTQBpaeS4YECmZ0UqTZnX+JYuIBCuhHUzYfIKSSV6L+MZu5TfA/eBJ9DMnOEtm5dfF Og0Wpdveljek+d966nr8zQIFKBklvFFesXS0wiOykNr4R5dEa8Cjy8lLiVhn6yT6qx8f kTIDGdjDECzTBT1bL7hgiD3/ePXSE8/kIcQFJWdTPFhrGTLehdRBp7tUj/UrKcBGNres YK0XxQIzeoZo1YkNL93jp8/CysLHNw6Wlix6e8eMYgC9iRyjOh7FTOqyC5+QHJykg/tS ctrJSG2M4pchSGm4L9yetp5LB7yJwPj2je5D+EFmdvYim5AhNNUt9jlP9GqU7U52moqC Lsbw== X-Gm-Message-State: APzg51DiKOtxITn+FT8bcFvP5WzlniVQVIqCjkl/5qPfs+s+PXg0qF1/ dY/KBPRuCHkDJjIibgayaxe3OtG5 X-Received: by 2002:a50:8f84:: with SMTP id y4-v6mr30226879edy.71.1536695384864; Tue, 11 Sep 2018 12:49:44 -0700 (PDT) Received: from localhost.localdomain ([94.250.174.60]) by smtp.gmail.com with ESMTPSA id w22-v6sm11683377eda.34.2018.09.11.12.49.43 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 11 Sep 2018 12:49:44 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Tue, 11 Sep 2018 21:49:33 +0200 Message-Id: <20180911194933.2374-2-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180911194933.2374-1-onemda@gmail.com> References: <20180911194933.2374-1-onemda@gmail.com> Subject: [FFmpeg-devel] [PATCH 2/2] avfilter/vf_remap: add bilinear interpolation X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- doc/filters.texi | 13 ++++ libavfilter/vf_remap.c | 167 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 166 insertions(+), 14 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 860d1eadca..3c5941d748 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -13675,6 +13675,19 @@ Xmap and Ymap input video streams must be of same dimensions. Output video strea will have Xmap/Ymap video stream dimensions. Xmap and Ymap input video streams are 16bit depth, single channel. +@table @option +@item interpolation + +Select interpolation mode. + +@table @samp +@item nearest +Use values from the nearest neighbor interpolation. +@item bilinear +Interpolate values using the bilinear interpolation. +@end table +@end table + @section removegrain The removegrain filter is a spatial denoiser for progressive video. diff --git a/libavfilter/vf_remap.c b/libavfilter/vf_remap.c index 48ec38af7c..9dfb9ce0be 100644 --- a/libavfilter/vf_remap.c +++ b/libavfilter/vf_remap.c @@ -47,6 +47,7 @@ typedef struct RemapContext { const AVClass *class; + int interpolation; int nb_planes; int nb_components; int step; @@ -59,6 +60,9 @@ typedef struct RemapContext { #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM static const AVOption remap_options[] = { + { "interpolation", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT , {.i64=0}, 0, 1, FLAGS, "interp" }, + { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "interp" }, + { "bilinear", "use values from the linear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "interp" }, { NULL } }; @@ -121,6 +125,138 @@ fail: return ret; } +static av_always_inline float lerpf(float s, float e, float t) +{ + return s + (e - s) * t; +} + +static av_always_inline int blerp(int c00, int c10, + int c01, int c11, + float tx, float ty) +{ + return lerpf(lerpf(c00, c10, tx), lerpf(c01, c11, tx), ty); +} + +#define DEFINE_INTERP_NEAREST_PLANAR(bits) \ +static av_always_inline int interp_nearest_planar##bits(const uint##bits##_t *src, \ + int slinesize, \ + const uint16_t *xmap, int xlinesize, \ + const uint16_t *ymap, int ylinesize, \ + int w, int h, int x, int y) \ +{ \ + if (ymap[x] < h && xmap[x] < w) { \ + return src[ymap[x] * slinesize + xmap[x]]; \ + } \ + return 0; \ +} + +#define DEFINE_INTERP_NEAREST_PACKED(bits) \ +static av_always_inline int interp_nearest_packed##bits(const uint##bits##_t *src, \ + int slinesize, \ + const uint16_t *xmap, int xlinesize, \ + const uint16_t *ymap, int ylinesize, \ + int w, int h, int x, int y, \ + int step, int c) \ +{ \ + if (ymap[x] < h && xmap[x] < w) { \ + return src[ymap[x] * slinesize + xmap[x] * step + c]; \ + } \ + return 0; \ +} + +#define DEFINE_INTERP_BILINEAR_PLANAR(bits) \ +static av_always_inline int interp_bilinear_planar##bits(const uint##bits##_t *src, \ + int slinesize, \ + const uint16_t *xmap, int xlinesize, \ + const uint16_t *ymap, int ylinesize, \ + int w, int h, int x, int y) \ +{ \ + int c00, c10, c01, c11; \ + float xa, ya, ymin, ymax, xmin, xmax; \ + const int x00 = xmap[x]; \ + const int x10 = xmap[x + (y < h - 1 ? xlinesize : 0)]; \ + const int x01 = xmap[FFMIN(x + 1, w-1)]; \ + const int x11 = xmap[FFMIN(x + 1, w-1) + (y < h - 1 ? xlinesize : 0)]; \ + \ + const int y00 = ymap[x]; \ + const int y10 = ymap[x + (y < h - 1 ? ylinesize : 0)]; \ + const int y01 = ymap[FFMIN(x + 1, w-1)]; \ + const int y11 = ymap[FFMIN(x + 1, w-1) + (y < h - 1 ? ylinesize : 0)]; \ + \ + if (x00 >= w || x10 >= w || x01 >= w || x11 >= w || \ + y00 >= h || y10 >= h || y01 >= h || y11 >= h) \ + return 0; \ + \ + c00 = src[y00 * slinesize + x00]; \ + c10 = src[y10 * slinesize + x10]; \ + c01 = src[y01 * slinesize + x01]; \ + c11 = src[y11 * slinesize + x11]; \ + \ + xa = (x00 + x10 + x01 + x11) / 4.f; \ + ya = (y00 + y10 + y01 + y11) / 4.f; \ + \ + xmin = FFMIN(FFMIN(x00, x11), FFMIN(x01, x10)); \ + ymin = FFMIN(FFMIN(y00, y11), FFMIN(y01, y10)); \ + xmax = FFMAX(FFMAX(x00, x11), FFMAX(x01, x10)); \ + ymax = FFMAX(FFMAX(y00, y11), FFMAX(y01, y10)); \ + \ + return blerp(c00, c10, c01, c11, (xa - xmin) / FFMAX((xmax - xmin), 1.f), \ + (ya - ymin) / FFMAX((ymax - ymin), 1.f)); \ +} + +#define DEFINE_INTERP_BILINEAR_PACKED(bits) \ +static av_always_inline int interp_bilinear_packed##bits(const uint##bits##_t *src, \ + int slinesize, \ + const uint16_t *xmap, int xlinesize, \ + const uint16_t *ymap, int ylinesize, \ + int w, int h, int x, int y, \ + int step, int c) \ +{ \ + int c00, c10, c01, c11; \ + float xa, ya, ymin, ymax, xmin, xmax; \ + const int x00 = xmap[x]; \ + const int x10 = xmap[x + (y < h - 1 ? xlinesize : 0)]; \ + const int x01 = xmap[FFMIN(x + 1, w-1)]; \ + const int x11 = xmap[FFMIN(x + 1, w-1) + (y < h - 1 ? xlinesize : 0)]; \ + \ + const int y00 = ymap[x]; \ + const int y10 = ymap[x + (y < h - 1 ? ylinesize : 0)]; \ + const int y01 = ymap[FFMIN(x + 1, w-1)]; \ + const int y11 = ymap[FFMIN(x + 1, w-1) + (y < h - 1 ? ylinesize : 0)]; \ + \ + if (x00 >= w || x10 >= w || x01 >= w || x11 >= w || \ + y00 >= h || y10 >= h || y01 >= h || y11 >= h) \ + return 0; \ + \ + c00 = src[y00 * slinesize + x00 * step + c]; \ + c10 = src[y10 * slinesize + x10 * step + c]; \ + c01 = src[y01 * slinesize + x01 * step + c]; \ + c11 = src[y11 * slinesize + x11 * step + c]; \ + \ + xa = (x00 + x10 + x01 + x11) / 4.f; \ + ya = (y00 + y10 + y01 + y11) / 4.f; \ + \ + xmin = FFMIN(FFMIN(x00, x11), FFMIN(x01, x10)); \ + ymin = FFMIN(FFMIN(y00, y11), FFMIN(y01, y10)); \ + xmax = FFMAX(FFMAX(x00, x11), FFMAX(x01, x10)); \ + ymax = FFMAX(FFMAX(y00, y11), FFMAX(y01, y10)); \ + \ + return blerp(c00, c10, c01, c11, (xa - xmin) / FFMAX((xmax - xmin), 1.f), \ + (ya - ymin) / FFMAX((ymax - ymin), 1.f)); \ +} + +DEFINE_INTERP_NEAREST_PLANAR(8) +DEFINE_INTERP_NEAREST_PLANAR(16) + +DEFINE_INTERP_BILINEAR_PLANAR(8) +DEFINE_INTERP_BILINEAR_PLANAR(16) + +DEFINE_INTERP_NEAREST_PACKED(8) +DEFINE_INTERP_NEAREST_PACKED(16) + +DEFINE_INTERP_BILINEAR_PACKED(8) +DEFINE_INTERP_BILINEAR_PACKED(16) + /** * remap_planar algorithm expects planes of same size * pixels are copied from source to target using : @@ -151,11 +287,9 @@ static int remap_planar##bits##_##name##_slice(AVFilterContext *ctx, void *arg, \ for (y = slice_start; y < slice_end; y++) { \ for (x = 0; x < out->width; x++) { \ - if (ymap[x] < in->height && xmap[x] < in->width) { \ - dst[x] = src[ymap[x] * slinesize + xmap[x]]; \ - } else { \ - dst[x] = 0; \ - } \ + dst[x] = interp_##name##_planar##bits(src, slinesize, xmap, xlinesize, \ + ymap, ylinesize, in->width, \ + in->height, x, y); \ } \ dst += dlinesize; \ xmap += xlinesize; \ @@ -169,6 +303,9 @@ static int remap_planar##bits##_##name##_slice(AVFilterContext *ctx, void *arg, DEFINE_REMAP_PLANAR_FUNC(nearest, 8, 1) DEFINE_REMAP_PLANAR_FUNC(nearest, 16, 2) +DEFINE_REMAP_PLANAR_FUNC(bilinear, 8, 1) +DEFINE_REMAP_PLANAR_FUNC(bilinear, 16, 2) + /** * remap_packed algorithm expects pixels with both padded bits (step) and * number of components correctly set. @@ -200,11 +337,10 @@ static int remap_packed##bits##_##name##_slice(AVFilterContext *ctx, void *arg, for (y = slice_start; y < slice_end; y++) { \ for (x = 0; x < out->width; x++) { \ for (c = 0; c < td->nb_components; c++) { \ - if (ymap[x] < in->height && xmap[x] < in->width) { \ - dst[x * step + c] = src[ymap[x] * slinesize + xmap[x] * step + c]; \ - } else { \ - dst[x * step + c] = 0; \ - } \ + dst[x * step + c] = interp_##name##_packed##bits(src, slinesize, \ + xmap, xlinesize, \ + ymap, ylinesize, in->width, \ + in->height, x, y, step, c); \ } \ } \ dst += dlinesize; \ @@ -218,6 +354,9 @@ static int remap_packed##bits##_##name##_slice(AVFilterContext *ctx, void *arg, DEFINE_REMAP_PACKED_FUNC(nearest, 8, 1) DEFINE_REMAP_PACKED_FUNC(nearest, 16, 2) +DEFINE_REMAP_PACKED_FUNC(bilinear, 8, 1) +DEFINE_REMAP_PACKED_FUNC(bilinear, 16, 2) + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; @@ -229,15 +368,15 @@ static int config_input(AVFilterLink *inlink) if (desc->comp[0].depth == 8) { if (s->nb_planes > 1 || s->nb_components == 1) { - s->remap_slice = remap_planar8_nearest_slice; + s->remap_slice = s->interpolation ? remap_planar8_bilinear_slice : remap_planar8_nearest_slice; } else { - s->remap_slice = remap_packed8_nearest_slice; + s->remap_slice = s->interpolation ? remap_packed8_bilinear_slice : remap_packed8_nearest_slice; } } else { if (s->nb_planes > 1 || s->nb_components == 1) { - s->remap_slice = remap_planar16_nearest_slice; + s->remap_slice = s->interpolation ? remap_planar16_bilinear_slice : remap_planar16_nearest_slice; } else { - s->remap_slice = remap_packed16_nearest_slice; + s->remap_slice = s->interpolation ? remap_packed16_bilinear_slice : remap_packed16_nearest_slice; } }