LCOV - code coverage report
Current view: top level - libavfilter - vf_amplify.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 114 0.0 %
Date: 2018-05-20 11:54:08 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Paul B Mahol
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, or (at your option) any later version.
      10             :  *
      11             :  * FFmpeg is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with FFmpeg; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include "libavutil/imgutils.h"
      22             : #include "libavutil/intreadwrite.h"
      23             : #include "libavutil/opt.h"
      24             : #include "libavutil/pixdesc.h"
      25             : 
      26             : #include "avfilter.h"
      27             : #include "formats.h"
      28             : #include "internal.h"
      29             : #include "video.h"
      30             : 
      31             : typedef struct AmplifyContext {
      32             :     const AVClass *class;
      33             :     const AVPixFmtDescriptor *desc;
      34             :     int radius;
      35             :     float factor;
      36             :     float threshold;
      37             :     int planes;
      38             : 
      39             :     int llimit;
      40             :     int hlimit;
      41             :     int nb_inputs;
      42             :     int nb_frames;
      43             : 
      44             :     int depth;
      45             :     int nb_planes;
      46             :     int linesize[4];
      47             :     int height[4];
      48             : 
      49             :     AVFrame **frames;
      50             : } AmplifyContext;
      51             : 
      52           0 : static int query_formats(AVFilterContext *ctx)
      53             : {
      54             :     static const enum AVPixelFormat pixel_fmts[] = {
      55             :         AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9,
      56             :         AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12,
      57             :         AV_PIX_FMT_GRAY16,
      58             :         AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
      59             :         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
      60             :         AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
      61             :         AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
      62             :         AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
      63             :         AV_PIX_FMT_YUVJ411P,
      64             :         AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
      65             :         AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
      66             :         AV_PIX_FMT_YUV440P10,
      67             :         AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12,
      68             :         AV_PIX_FMT_YUV440P12,
      69             :         AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14,
      70             :         AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
      71             :         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
      72             :         AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
      73             :         AV_PIX_FMT_NONE
      74             :     };
      75           0 :     AVFilterFormats *formats = ff_make_format_list(pixel_fmts);
      76           0 :     if (!formats)
      77           0 :         return AVERROR(ENOMEM);
      78           0 :     return ff_set_common_formats(ctx, formats);
      79             : }
      80             : 
      81           0 : static av_cold int init(AVFilterContext *ctx)
      82             : {
      83           0 :     AmplifyContext *s = ctx->priv;
      84             : 
      85           0 :     s->nb_inputs = s->radius * 2 + 1;
      86             : 
      87           0 :     s->frames = av_calloc(s->nb_inputs, sizeof(*s->frames));
      88           0 :     if (!s->frames)
      89           0 :         return AVERROR(ENOMEM);
      90             : 
      91           0 :     return 0;
      92             : }
      93             : 
      94             : typedef struct ThreadData {
      95             :     AVFrame **in, *out;
      96             : } ThreadData;
      97             : 
      98           0 : static int amplify_frame(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
      99             : {
     100           0 :     AmplifyContext *s = ctx->priv;
     101           0 :     ThreadData *td = arg;
     102           0 :     AVFrame **in = td->in;
     103           0 :     AVFrame *out = td->out;
     104           0 :     const int radius = s->radius;
     105           0 :     const int nb_inputs = s->nb_inputs;
     106           0 :     const float threshold = s->threshold;
     107           0 :     const float factor = s->factor;
     108           0 :     const int llimit = s->llimit;
     109           0 :     const int hlimit = s->hlimit;
     110           0 :     const int depth = s->depth;
     111             :     int i, p, x, y;
     112             : 
     113           0 :     if (s->depth <= 8) {
     114           0 :         for (p = 0; p < s->nb_planes; p++) {
     115           0 :             const int slice_start = (s->height[p] * jobnr) / nb_jobs;
     116           0 :             const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs;
     117           0 :             uint8_t *dst = out->data[p] + slice_start * out->linesize[p];
     118             : 
     119           0 :             if (!((1 << p) & s->planes)) {
     120           0 :                 av_image_copy_plane(dst, out->linesize[p],
     121           0 :                                     in[radius]->data[p] + slice_start * in[radius]->linesize[p],
     122           0 :                                     in[radius]->linesize[p],
     123             :                                     s->linesize[p], slice_end - slice_start);
     124           0 :                 continue;
     125             :             }
     126             : 
     127           0 :             for (y = slice_start; y < slice_end; y++) {
     128           0 :                 for (x = 0; x < s->linesize[p]; x++) {
     129           0 :                     int src = in[radius]->data[p][y * in[radius]->linesize[p] + x];
     130             :                     float diff, avg;
     131           0 :                     int sum = 0;
     132             : 
     133           0 :                     for (i = 0; i < nb_inputs; i++) {
     134           0 :                         sum += in[i]->data[p][y * in[i]->linesize[p] + x];
     135             :                     }
     136             : 
     137           0 :                     avg = sum / (float)nb_inputs;
     138           0 :                     diff = src - avg;
     139           0 :                     if (fabsf(diff) < threshold) {
     140             :                         int amp;
     141           0 :                         if (diff < 0) {
     142           0 :                             amp = -FFMIN(FFABS(diff * factor), llimit);
     143             :                         } else {
     144           0 :                             amp = FFMIN(FFABS(diff * factor), hlimit);
     145             :                         }
     146           0 :                         dst[x] = av_clip_uint8(src + amp);
     147             :                     } else {
     148           0 :                         dst[x] = src;
     149             :                     }
     150             :                 }
     151             : 
     152           0 :                 dst += out->linesize[p];
     153             :             }
     154             :         }
     155             :     } else {
     156           0 :         for (p = 0; p < s->nb_planes; p++) {
     157           0 :             const int slice_start = (s->height[p] * jobnr) / nb_jobs;
     158           0 :             const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs;
     159           0 :             uint16_t *dst = (uint16_t *)(out->data[p] + slice_start * out->linesize[p]);
     160             : 
     161           0 :             if (!((1 << p) & s->planes)) {
     162           0 :                 av_image_copy_plane((uint8_t *)dst, out->linesize[p],
     163           0 :                                     in[radius]->data[p] + slice_start * in[radius]->linesize[p],
     164           0 :                                     in[radius]->linesize[p],
     165             :                                     s->linesize[p], slice_end - slice_start);
     166           0 :                 continue;
     167             :             }
     168             : 
     169           0 :             for (y = slice_start; y < slice_end; y++) {
     170           0 :                 for (x = 0; x < s->linesize[p] / 2; x++) {
     171           0 :                     int src = AV_RN16(in[radius]->data[p] + y * in[radius]->linesize[p] + x * 2);
     172             :                     float diff, avg;
     173           0 :                     int sum = 0;
     174             : 
     175           0 :                     for (i = 0; i < nb_inputs; i++) {
     176           0 :                         sum += AV_RN16(in[i]->data[p] + y * in[i]->linesize[p] + x * 2);
     177             :                     }
     178             : 
     179           0 :                     avg = sum / (float)nb_inputs;
     180           0 :                     diff = src - avg;
     181             : 
     182           0 :                     if (fabsf(diff) < threshold) {
     183             :                         int amp;
     184           0 :                         if (diff < 0) {
     185           0 :                             amp = -FFMIN(FFABS(diff * factor), llimit);
     186             :                         } else {
     187           0 :                             amp = FFMIN(FFABS(diff * factor), hlimit);
     188             :                         }
     189           0 :                         dst[x] = av_clip_uintp2(src + amp, depth);
     190             :                     } else {
     191           0 :                         dst[x] = src;
     192             :                     }
     193             :                 }
     194             : 
     195           0 :                 dst += out->linesize[p] / 2;
     196             :             }
     197             :         }
     198             :     }
     199             : 
     200           0 :     return 0;
     201             : }
     202             : 
     203           0 : static int config_output(AVFilterLink *outlink)
     204             : {
     205           0 :     AVFilterContext *ctx = outlink->src;
     206           0 :     AmplifyContext *s = ctx->priv;
     207           0 :     AVFilterLink *inlink = ctx->inputs[0];
     208             :     int ret;
     209             : 
     210           0 :     s->desc = av_pix_fmt_desc_get(outlink->format);
     211           0 :     if (!s->desc)
     212           0 :         return AVERROR_BUG;
     213           0 :     s->nb_planes = av_pix_fmt_count_planes(outlink->format);
     214           0 :     s->depth = s->desc->comp[0].depth;
     215             : 
     216           0 :     if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
     217           0 :         return ret;
     218             : 
     219           0 :     s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h);
     220           0 :     s->height[0] = s->height[3] = inlink->h;
     221             : 
     222           0 :     return 0;
     223             : }
     224             : 
     225           0 : static av_cold void uninit(AVFilterContext *ctx)
     226             : {
     227           0 :     AmplifyContext *s = ctx->priv;
     228             :     int i;
     229             : 
     230           0 :     if (s->frames) {
     231           0 :         for (i = 0; i < s->nb_frames; i++)
     232           0 :            av_frame_free(&s->frames[i]);
     233             :     }
     234           0 :     av_freep(&s->frames);
     235           0 : }
     236             : 
     237           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     238             : {
     239           0 :     AVFilterContext *ctx = inlink->dst;
     240           0 :     AVFilterLink *outlink = ctx->outputs[0];
     241           0 :     AmplifyContext *s = ctx->priv;
     242             :     ThreadData td;
     243             :     AVFrame *out;
     244             : 
     245           0 :     if (s->nb_frames < s->nb_inputs) {
     246           0 :         s->frames[s->nb_frames] = in;
     247           0 :         s->nb_frames++;
     248           0 :         return 0;
     249             :     } else {
     250           0 :         av_frame_free(&s->frames[0]);
     251           0 :         memmove(&s->frames[0], &s->frames[1], sizeof(*s->frames) * (s->nb_inputs - 1));
     252           0 :         s->frames[s->nb_inputs - 1] = in;
     253             :     }
     254             : 
     255           0 :     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     256           0 :     if (!out)
     257           0 :         return AVERROR(ENOMEM);
     258           0 :     out->pts = s->frames[0]->pts;
     259             : 
     260           0 :     td.out = out;
     261           0 :     td.in = s->frames;
     262           0 :     ctx->internal->execute(ctx, amplify_frame, &td, NULL, FFMIN(s->height[1], ff_filter_get_nb_threads(ctx)));
     263             : 
     264           0 :     return ff_filter_frame(outlink, out);
     265             : }
     266             : 
     267             : #define OFFSET(x) offsetof(AmplifyContext, x)
     268             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
     269             : 
     270             : static const AVOption amplify_options[] = {
     271             :     { "radius", "set radius", OFFSET(radius), AV_OPT_TYPE_INT, {.i64=2}, 1, 63, .flags = FLAGS },
     272             :     { "factor", "set factor", OFFSET(factor), AV_OPT_TYPE_FLOAT, {.dbl=2}, 0, UINT16_MAX, .flags = FLAGS },
     273             :     { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_FLOAT, {.dbl=10}, 0, UINT16_MAX, .flags = FLAGS },
     274             :     { "low", "set low limit for amplification", OFFSET(llimit), AV_OPT_TYPE_INT, {.i64=UINT16_MAX}, 0, UINT16_MAX, .flags = FLAGS },
     275             :     { "high", "set high limit for amplification", OFFSET(hlimit), AV_OPT_TYPE_INT, {.i64=UINT16_MAX}, 0, UINT16_MAX, .flags = FLAGS },
     276             :     { "planes", "set what planes to filter", OFFSET(planes), AV_OPT_TYPE_FLAGS, {.i64=7},    0, 15,  FLAGS },
     277             :     { NULL },
     278             : };
     279             : 
     280             : static const AVFilterPad inputs[] = {
     281             :     {
     282             :         .name          = "default",
     283             :         .type          = AVMEDIA_TYPE_VIDEO,
     284             :         .filter_frame  = filter_frame,
     285             :     },
     286             :     { NULL }
     287             : };
     288             : 
     289             : static const AVFilterPad outputs[] = {
     290             :     {
     291             :         .name          = "default",
     292             :         .type          = AVMEDIA_TYPE_VIDEO,
     293             :         .config_props  = config_output,
     294             :     },
     295             :     { NULL }
     296             : };
     297             : 
     298             : AVFILTER_DEFINE_CLASS(amplify);
     299             : 
     300             : AVFilter ff_vf_amplify = {
     301             :     .name          = "amplify",
     302             :     .description   = NULL_IF_CONFIG_SMALL("Amplify changes between successive video frames."),
     303             :     .priv_size     = sizeof(AmplifyContext),
     304             :     .priv_class    = &amplify_class,
     305             :     .query_formats = query_formats,
     306             :     .outputs       = outputs,
     307             :     .inputs        = inputs,
     308             :     .init          = init,
     309             :     .uninit        = uninit,
     310             :     .flags         = AVFILTER_FLAG_SLICE_THREADS,
     311             : };

Generated by: LCOV version 1.13