From patchwork Mon Sep 24 14:58:25 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: 10472 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:1286:0:0:0:0:0 with SMTP id 6-v6csp2591251jap; Mon, 24 Sep 2018 07:58:46 -0700 (PDT) X-Google-Smtp-Source: ACcGV6043JJj0IDDJbUbXNihN2FgU/9Tv9mYi8Rz+qYgPXj7lwx3MxyQgzYLKhlgt0BNgXBbXbq0 X-Received: by 2002:a5d:6451:: with SMTP id d17-v6mr8539959wrw.64.1537801126723; Mon, 24 Sep 2018 07:58:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1537801126; cv=none; d=google.com; s=arc-20160816; b=pI5uRoCF6F9NgVhSdewxFEwcrCqEtFyY4/C77ni965T6gThG4fQysqQOiydYxk894x fbAIkq6DlPCNUMBzjLl5nP63TiOUssCAr2lQjW4wCVfN/xG37XIdx6SX2rc6yjSZaHyR dIHwscjX6+dCirxjPIf8cdB7X93tsoz8LuXLRECjpls17qvxtgQ74bDAqMyz70IiyYdP KrzKD6Fz/1Ky7leSh7cEa6lP9nAuybGG5fdjIys3ObDaSdc5dTavLMZT3te3ggfTXGic aG1sT4/eu0kUNS9TT7YDkBMJUvqBjCmXCoddXwugKEBnaJ74efOhxd/437xuqFZHdsne 57xQ== 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:message-id:date:to:from:dkim-signature :delivered-to; bh=AwQn6Yxho2p99ma+Rd5edquG+8j7GLOG6p4kc8XwVhc=; b=EgATtvLRIOsdsCnzY1KeubfJDNDyH1Jq8L/iMUwwDRbMOPR70lgXThzxp0yJnXGW5x U9ZCuvTtdHBsxt90K9JhtNOp9T1ZZFrfxTukJ3WFUvwYzhQ3YqGztKuZTZH0vAdH7e4K 4UBWbLGG4SgAVakXKVgZiuBFrO+AsoCt1OBi8tcBQ96/x1+QHAVb39U72wHw1MFE664w tICxKeUM67J7Sc/OhOTLBunDMfJSxlgvrK0eKDJmAB+O8TK0EZsGYI2gqcAlEH/lgpl7 vjYBV22WAGOiA0W//ySO9aFlTjFnNEUeCNBGyeyraNSJ7ldbGEkfhvZQy4g/tKZIDSD7 JZ2Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b="EpeB9T/6"; 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 v7-v6si2825587wre.88.2018.09.24.07.58.44; Mon, 24 Sep 2018 07:58:46 -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="EpeB9T/6"; 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 0698668A482; Mon, 24 Sep 2018 17:58:27 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f67.google.com (mail-ed1-f67.google.com [209.85.208.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id DA3D068A054 for ; Mon, 24 Sep 2018 17:58:20 +0300 (EEST) Received: by mail-ed1-f67.google.com with SMTP id y21-v6so4294865edr.2 for ; Mon, 24 Sep 2018 07:58:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=yONKNkc3u8nX5HuRpUnQgu+HxUvis9DvOjzVdRi0wcE=; b=EpeB9T/6VEPUXpmD4mNsIqi/Z5wBxjqCv7diAWnok2P7rhkgmXB0dncQqVmdWR6Te9 NTnFsoS9u0pbVkAnjrYM/+87aBXKid++Rlqk7oh9ijGBMi1/O7fXqI3neoSNNInYSF3e wR1tlWbmOX8fk2S7jxiaXvSW7iXMHQTThlZBoaK5cpH5EN4An6lZzffTw8jMAfvvKNoc Ge5VSaBGXs25E6rb3pmdDnuaegvdYmOX//iqSfVBQd8J8FfUj1Hm2qhpkEkYrOrwczKW vUZlV8W8BZK6drDtDwIohLbBYHs3PY1869ASfO1CrD/E9XzN/KBhBsaCGLc7ELG4CSfn JZ6A== 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; bh=yONKNkc3u8nX5HuRpUnQgu+HxUvis9DvOjzVdRi0wcE=; b=mS8keJKKr7WNSaJ52EHBtv+0IHdNUKJUBmPDO8VWySlEfteOhza6FOXHjJDZKpUoOj URxM6VOGV28vfJIShYax3IBLjemieaUCW8DGU6qhqN4VioyzZ5elvRGVFqtGmdX15Gaw uw3xkkUKUCIT20VKDm80O4x1sMGzfmZO6ql5eg2gwIk2B+hpBcGRkGmU9KD06bX5Lr3u hZjPueuADjt8lzR6+POLf9g2JKU+Q8WsGcGcHnXrDDLZtQxdZ90x8UNH6VmQF4Z7j0ME 0/Sdiv1+PXiy3NZ0S5Oxezwu6lxUQL14dzbXRQ2YXKmgcXVf0BwFIArmyo9uzq4eYxmX noCA== X-Gm-Message-State: ABuFfoi05RvB6eY/pUPozK2LqA3XJJddhU3KSoWOrGTWOnJ/vKQFEKse nWBI45DRXMTitf92XFyRAtdu+5gj X-Received: by 2002:a50:b37a:: with SMTP id r55-v6mr17897803edd.145.1537801115506; Mon, 24 Sep 2018 07:58:35 -0700 (PDT) Received: from localhost.localdomain ([94.250.174.60]) by smtp.gmail.com with ESMTPSA id r23-v6sm6351092edi.17.2018.09.24.07.58.33 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Sep 2018 07:58:34 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Mon, 24 Sep 2018 16:58:25 +0200 Message-Id: <20180924145825.23804-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] avfilter/vf_curves: add planar rgb support 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 --- libavfilter/vf_curves.c | 194 +++++++++++++++++++++++++---------- tests/ref/fate/filter-curves | 10 +- 2 files changed, 146 insertions(+), 58 deletions(-) diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c index 19ab789152..883cc1c90c 100644 --- a/libavfilter/vf_curves.c +++ b/libavfilter/vf_curves.c @@ -70,6 +70,9 @@ typedef struct CurvesContext { int step; char *plot_filename; int is_16bit; + int depth; + + int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } CurvesContext; typedef struct ThreadData { @@ -209,7 +212,7 @@ static int get_nb_points(const struct keypoint *d) * @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf */ -#define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uint16(v)) +#define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uintp2_c(v, nbits)) static inline int interpolate(void *log_ctx, uint16_t *y, const struct keypoint *points, int nbits) @@ -341,6 +344,10 @@ static int interpolate##nbits(void *log_ctx, uint16_t *y, \ } DECLARE_INTERPOLATE_FUNC(8) +DECLARE_INTERPOLATE_FUNC(9) +DECLARE_INTERPOLATE_FUNC(10) +DECLARE_INTERPOLATE_FUNC(12) +DECLARE_INTERPOLATE_FUNC(14) DECLARE_INTERPOLATE_FUNC(16) static int parse_psfile(AVFilterContext *ctx, const char *fname) @@ -512,6 +519,12 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + AV_PIX_FMT_GBRP9, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, + AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); @@ -520,6 +533,120 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_formats(ctx, fmts_list); } +static int filter_slice_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + int x, y; + const CurvesContext *curves = ctx->priv; + const ThreadData *td = arg; + const AVFrame *in = td->in; + const AVFrame *out = td->out; + const int direct = out == in; + const int step = curves->step; + const uint8_t r = curves->rgba_map[R]; + const uint8_t g = curves->rgba_map[G]; + const uint8_t b = curves->rgba_map[B]; + const uint8_t a = curves->rgba_map[A]; + const int slice_start = (in->height * jobnr ) / nb_jobs; + const int slice_end = (in->height * (jobnr+1)) / nb_jobs; + + if (curves->is_16bit) { + for (y = slice_start; y < slice_end; y++) { + uint16_t *dstp = ( uint16_t *)(out->data[0] + y * out->linesize[0]); + const uint16_t *srcp = (const uint16_t *)(in ->data[0] + y * in->linesize[0]); + + for (x = 0; x < in->width * step; x += step) { + dstp[x + r] = curves->graph[R][srcp[x + r]]; + dstp[x + g] = curves->graph[G][srcp[x + g]]; + dstp[x + b] = curves->graph[B][srcp[x + b]]; + if (!direct && step == 4) + dstp[x + a] = srcp[x + a]; + } + } + } else { + uint8_t *dst = out->data[0] + slice_start * out->linesize[0]; + const uint8_t *src = in->data[0] + slice_start * in->linesize[0]; + + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < in->width * step; x += step) { + dst[x + r] = curves->graph[R][src[x + r]]; + dst[x + g] = curves->graph[G][src[x + g]]; + dst[x + b] = curves->graph[B][src[x + b]]; + if (!direct && step == 4) + dst[x + a] = src[x + a]; + } + dst += out->linesize[0]; + src += in ->linesize[0]; + } + } + return 0; +} + +static int filter_slice_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + int x, y; + const CurvesContext *curves = ctx->priv; + const ThreadData *td = arg; + const AVFrame *in = td->in; + const AVFrame *out = td->out; + const int direct = out == in; + const int step = curves->step; + const uint8_t r = curves->rgba_map[R]; + const uint8_t g = curves->rgba_map[G]; + const uint8_t b = curves->rgba_map[B]; + const uint8_t a = curves->rgba_map[A]; + const int slice_start = (in->height * jobnr ) / nb_jobs; + const int slice_end = (in->height * (jobnr+1)) / nb_jobs; + + if (curves->is_16bit) { + for (y = slice_start; y < slice_end; y++) { + uint16_t *dstrp = ( uint16_t *)(out->data[r] + y * out->linesize[r]); + uint16_t *dstgp = ( uint16_t *)(out->data[g] + y * out->linesize[g]); + uint16_t *dstbp = ( uint16_t *)(out->data[b] + y * out->linesize[b]); + uint16_t *dstap = ( uint16_t *)(out->data[a] + y * out->linesize[a]); + const uint16_t *srcrp = (const uint16_t *)(in ->data[r] + y * in->linesize[r]); + const uint16_t *srcgp = (const uint16_t *)(in ->data[g] + y * in->linesize[g]); + const uint16_t *srcbp = (const uint16_t *)(in ->data[b] + y * in->linesize[b]); + const uint16_t *srcap = (const uint16_t *)(in ->data[a] + y * in->linesize[a]); + + for (x = 0; x < in->width; x++) { + dstrp[x] = curves->graph[R][srcrp[x]]; + dstgp[x] = curves->graph[G][srcgp[x]]; + dstbp[x] = curves->graph[B][srcbp[x]]; + if (!direct && step == 4) + dstap[x] = srcap[x]; + } + } + } else { + uint8_t *dstr = out->data[r] + slice_start * out->linesize[r]; + uint8_t *dstg = out->data[g] + slice_start * out->linesize[g]; + uint8_t *dstb = out->data[b] + slice_start * out->linesize[b]; + uint8_t *dsta = out->data[a] + slice_start * out->linesize[a]; + const uint8_t *srcr = in->data[r] + slice_start * in->linesize[r]; + const uint8_t *srcg = in->data[g] + slice_start * in->linesize[g]; + const uint8_t *srcb = in->data[b] + slice_start * in->linesize[b]; + const uint8_t *srca = in->data[a] + slice_start * in->linesize[a]; + + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < in->width; x++) { + dstr[x] = curves->graph[R][srcr[x]]; + dstg[x] = curves->graph[G][srcg[x]]; + dstb[x] = curves->graph[B][srcb[x]]; + if (!direct && step == 4) + dsta[x] = srca[x]; + } + dstr += out->linesize[r]; + dstg += out->linesize[g]; + dstb += out->linesize[b]; + dsta += out->linesize[a]; + srcr += in ->linesize[r]; + srcg += in ->linesize[g]; + srcb += in ->linesize[b]; + srca += in ->linesize[a]; + } + } + return 0; +} + static int config_input(AVFilterLink *inlink) { int i, j, ret; @@ -531,8 +658,10 @@ static int config_input(AVFilterLink *inlink) ff_fill_rgba_map(curves->rgba_map, inlink->format); curves->is_16bit = desc->comp[0].depth > 8; - curves->lut_size = curves->is_16bit ? 1<<16 : 1<<8; + curves->depth = desc->comp[0].depth; + curves->lut_size = 1 << curves->depth; curves->step = av_get_padded_bits_per_pixel(desc) >> (3 + curves->is_16bit); + curves->filter_slice = desc->flags & AV_PIX_FMT_FLAG_PLANAR ? filter_slice_planar : filter_slice_packed; for (i = 0; i < NB_COMP + 1; i++) { curves->graph[i] = av_mallocz_array(curves->lut_size, sizeof(*curves->graph[0])); @@ -541,8 +670,14 @@ static int config_input(AVFilterLink *inlink) ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size); if (ret < 0) return ret; - if (curves->is_16bit) ret = interpolate16(ctx, curves->graph[i], comp_points[i]); - else ret = interpolate8(ctx, curves->graph[i], comp_points[i]); + switch (curves->depth) { + case 8: ret = interpolate8 (ctx, curves->graph[i], comp_points[i]); break; + case 9: ret = interpolate9 (ctx, curves->graph[i], comp_points[i]); break; + case 10: ret = interpolate10(ctx, curves->graph[i], comp_points[i]); break; + case 12: ret = interpolate12(ctx, curves->graph[i], comp_points[i]); break; + case 14: ret = interpolate14(ctx, curves->graph[i], comp_points[i]); break; + case 16: ret = interpolate16(ctx, curves->graph[i], comp_points[i]); break; + } if (ret < 0) return ret; } @@ -579,57 +714,10 @@ static int config_input(AVFilterLink *inlink) return 0; } -static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -{ - int x, y; - const CurvesContext *curves = ctx->priv; - const ThreadData *td = arg; - const AVFrame *in = td->in; - const AVFrame *out = td->out; - const int direct = out == in; - const int step = curves->step; - const uint8_t r = curves->rgba_map[R]; - const uint8_t g = curves->rgba_map[G]; - const uint8_t b = curves->rgba_map[B]; - const uint8_t a = curves->rgba_map[A]; - const int slice_start = (in->height * jobnr ) / nb_jobs; - const int slice_end = (in->height * (jobnr+1)) / nb_jobs; - - if (curves->is_16bit) { - for (y = slice_start; y < slice_end; y++) { - uint16_t *dstp = ( uint16_t *)(out->data[0] + y * out->linesize[0]); - const uint16_t *srcp = (const uint16_t *)(in ->data[0] + y * in->linesize[0]); - - for (x = 0; x < in->width * step; x += step) { - dstp[x + r] = curves->graph[R][srcp[x + r]]; - dstp[x + g] = curves->graph[G][srcp[x + g]]; - dstp[x + b] = curves->graph[B][srcp[x + b]]; - if (!direct && step == 4) - dstp[x + a] = srcp[x + a]; - } - } - } else { - uint8_t *dst = out->data[0] + slice_start * out->linesize[0]; - const uint8_t *src = in->data[0] + slice_start * in->linesize[0]; - - for (y = slice_start; y < slice_end; y++) { - for (x = 0; x < in->width * step; x += step) { - dst[x + r] = curves->graph[R][src[x + r]]; - dst[x + g] = curves->graph[G][src[x + g]]; - dst[x + b] = curves->graph[B][src[x + b]]; - if (!direct && step == 4) - dst[x + a] = src[x + a]; - } - dst += out->linesize[0]; - src += in ->linesize[0]; - } - } - return 0; -} - static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; + CurvesContext *curves = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out; ThreadData td; @@ -647,7 +735,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) td.in = in; td.out = out; - ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, curves->filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); if (out != in) av_frame_free(&in); diff --git a/tests/ref/fate/filter-curves b/tests/ref/fate/filter-curves index 401bd2eaf9..fd427e2370 100644 --- a/tests/ref/fate/filter-curves +++ b/tests/ref/fate/filter-curves @@ -3,8 +3,8 @@ #codec_id 0: rawvideo #dimensions 0: 640x480 #sar 0: 0/1 -0, 0, 0, 1, 921600, 0xcf426780 -0, 1, 1, 1, 921600, 0x7642892d -0, 2, 2, 1, 921600, 0x13c1ab7e -0, 3, 3, 1, 921600, 0x3eca04bf -0, 4, 4, 1, 921600, 0x61539162 +0, 0, 0, 1, 921600, 0x3ed36780 +0, 1, 1, 1, 921600, 0x7dbd892d +0, 2, 2, 1, 921600, 0x0894ab7e +0, 3, 3, 1, 921600, 0x471004bf +0, 4, 4, 1, 921600, 0x79c79162