Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2003 Rich Felker
  3.  * Copyright (c) 2012 Stefano Sabatini
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License along
  18.  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
  19.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  */
  21.  
  22. /**
  23.  * @file mpdecimate filter, ported from libmpcodecs/vf_decimate.c by
  24.  * Rich Felker.
  25.  */
  26.  
  27. #include "libavutil/opt.h"
  28. #include "libavutil/pixdesc.h"
  29. #include "libavutil/pixelutils.h"
  30. #include "libavutil/timestamp.h"
  31. #include "avfilter.h"
  32. #include "internal.h"
  33. #include "formats.h"
  34. #include "video.h"
  35.  
  36. typedef struct {
  37.     const AVClass *class;
  38.     int lo, hi;                    ///< lower and higher threshold number of differences
  39.                                    ///< values for 8x8 blocks
  40.  
  41.     float frac;                    ///< threshold of changed pixels over the total fraction
  42.  
  43.     int max_drop_count;            ///< if positive: maximum number of sequential frames to drop
  44.                                    ///< if negative: minimum number of frames between two drops
  45.  
  46.     int drop_count;                ///< if positive: number of frames sequentially dropped
  47.                                    ///< if negative: number of sequential frames which were not dropped
  48.  
  49.     int hsub, vsub;                ///< chroma subsampling values
  50.     AVFrame *ref;                  ///< reference picture
  51.     av_pixelutils_sad_fn sad;      ///< sum of absolute difference function
  52. } DecimateContext;
  53.  
  54. #define OFFSET(x) offsetof(DecimateContext, x)
  55. #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
  56.  
  57. static const AVOption mpdecimate_options[] = {
  58.     { "max",  "set the maximum number of consecutive dropped frames (positive), or the minimum interval between dropped frames (negative)",
  59.       OFFSET(max_drop_count), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGS },
  60.     { "hi",   "set high dropping threshold", OFFSET(hi), AV_OPT_TYPE_INT, {.i64=64*12}, INT_MIN, INT_MAX, FLAGS },
  61.     { "lo",   "set low dropping threshold", OFFSET(lo), AV_OPT_TYPE_INT, {.i64=64*5}, INT_MIN, INT_MAX, FLAGS },
  62.     { "frac", "set fraction dropping threshold",  OFFSET(frac), AV_OPT_TYPE_FLOAT, {.dbl=0.33}, 0, 1, FLAGS },
  63.     { NULL }
  64. };
  65.  
  66. AVFILTER_DEFINE_CLASS(mpdecimate);
  67.  
  68. /**
  69.  * Return 1 if the two planes are different, 0 otherwise.
  70.  */
  71. static int diff_planes(AVFilterContext *ctx,
  72.                        uint8_t *cur, int cur_linesize,
  73.                        uint8_t *ref, int ref_linesize,
  74.                        int w, int h)
  75. {
  76.     DecimateContext *decimate = ctx->priv;
  77.  
  78.     int x, y;
  79.     int d, c = 0;
  80.     int t = (w/16)*(h/16)*decimate->frac;
  81.  
  82.     /* compute difference for blocks of 8x8 bytes */
  83.     for (y = 0; y < h-7; y += 4) {
  84.         for (x = 8; x < w-7; x += 4) {
  85.             d = decimate->sad(cur + y*cur_linesize + x, cur_linesize,
  86.                               ref + y*ref_linesize + x, ref_linesize);
  87.             if (d > decimate->hi) {
  88.                 av_log(ctx, AV_LOG_DEBUG, "%d>=hi ", d);
  89.                 return 1;
  90.             }
  91.             if (d > decimate->lo) {
  92.                 c++;
  93.                 if (c > t) {
  94.                     av_log(ctx, AV_LOG_DEBUG, "lo:%d>=%d ", c, t);
  95.                     return 1;
  96.                 }
  97.             }
  98.         }
  99.     }
  100.  
  101.     av_log(ctx, AV_LOG_DEBUG, "lo:%d<%d ", c, t);
  102.     return 0;
  103. }
  104.  
  105. /**
  106.  * Tell if the frame should be decimated, for example if it is no much
  107.  * different with respect to the reference frame ref.
  108.  */
  109. static int decimate_frame(AVFilterContext *ctx,
  110.                           AVFrame *cur, AVFrame *ref)
  111. {
  112.     DecimateContext *decimate = ctx->priv;
  113.     int plane;
  114.  
  115.     if (decimate->max_drop_count > 0 &&
  116.         decimate->drop_count >= decimate->max_drop_count)
  117.         return 0;
  118.     if (decimate->max_drop_count < 0 &&
  119.         (decimate->drop_count-1) > decimate->max_drop_count)
  120.         return 0;
  121.  
  122.     for (plane = 0; ref->data[plane] && ref->linesize[plane]; plane++) {
  123.         /* use 8x8 SAD even on subsampled planes.  The blocks won't match up with
  124.          * luma blocks, but hopefully nobody is depending on this to catch
  125.          * localized chroma changes that wouldn't exceed the thresholds when
  126.          * diluted by using what's effectively a larger block size.
  127.          */
  128.         int vsub = plane == 1 || plane == 2 ? decimate->vsub : 0;
  129.         int hsub = plane == 1 || plane == 2 ? decimate->hsub : 0;
  130.         if (diff_planes(ctx,
  131.                         cur->data[plane], cur->linesize[plane],
  132.                         ref->data[plane], ref->linesize[plane],
  133.                         FF_CEIL_RSHIFT(ref->width,  hsub),
  134.                         FF_CEIL_RSHIFT(ref->height, vsub))) {
  135.             emms_c();
  136.             return 0;
  137.         }
  138.     }
  139.  
  140.     emms_c();
  141.     return 1;
  142. }
  143.  
  144. static av_cold int init(AVFilterContext *ctx)
  145. {
  146.     DecimateContext *decimate = ctx->priv;
  147.  
  148.     decimate->sad = av_pixelutils_get_sad_fn(3, 3, 0, ctx); // 8x8, not aligned on blocksize
  149.     if (!decimate->sad)
  150.         return AVERROR(EINVAL);
  151.  
  152.     av_log(ctx, AV_LOG_VERBOSE, "max_drop_count:%d hi:%d lo:%d frac:%f\n",
  153.            decimate->max_drop_count, decimate->hi, decimate->lo, decimate->frac);
  154.  
  155.     return 0;
  156. }
  157.  
  158. static av_cold void uninit(AVFilterContext *ctx)
  159. {
  160.     DecimateContext *decimate = ctx->priv;
  161.     av_frame_free(&decimate->ref);
  162. }
  163.  
  164. static int query_formats(AVFilterContext *ctx)
  165. {
  166.     static const enum AVPixelFormat pix_fmts[] = {
  167.         AV_PIX_FMT_YUV444P,      AV_PIX_FMT_YUV422P,
  168.         AV_PIX_FMT_YUV420P,      AV_PIX_FMT_YUV411P,
  169.         AV_PIX_FMT_YUV410P,      AV_PIX_FMT_YUV440P,
  170.         AV_PIX_FMT_YUVJ444P,     AV_PIX_FMT_YUVJ422P,
  171.         AV_PIX_FMT_YUVJ420P,     AV_PIX_FMT_YUVJ440P,
  172.         AV_PIX_FMT_YUVA420P,
  173.  
  174.         AV_PIX_FMT_GBRP,
  175.  
  176.         AV_PIX_FMT_YUVA444P,
  177.         AV_PIX_FMT_YUVA422P,
  178.  
  179.         AV_PIX_FMT_NONE
  180.     };
  181.     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
  182.     if (!fmts_list)
  183.         return AVERROR(ENOMEM);
  184.     return ff_set_common_formats(ctx, fmts_list);
  185. }
  186.  
  187. static int config_input(AVFilterLink *inlink)
  188. {
  189.     AVFilterContext *ctx = inlink->dst;
  190.     DecimateContext *decimate = ctx->priv;
  191.     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
  192.     decimate->hsub = pix_desc->log2_chroma_w;
  193.     decimate->vsub = pix_desc->log2_chroma_h;
  194.  
  195.     return 0;
  196. }
  197.  
  198. static int filter_frame(AVFilterLink *inlink, AVFrame *cur)
  199. {
  200.     DecimateContext *decimate = inlink->dst->priv;
  201.     AVFilterLink *outlink = inlink->dst->outputs[0];
  202.     int ret;
  203.  
  204.     if (decimate->ref && decimate_frame(inlink->dst, cur, decimate->ref)) {
  205.         decimate->drop_count = FFMAX(1, decimate->drop_count+1);
  206.     } else {
  207.         av_frame_free(&decimate->ref);
  208.         decimate->ref = cur;
  209.         decimate->drop_count = FFMIN(-1, decimate->drop_count-1);
  210.  
  211.         if ((ret = ff_filter_frame(outlink, av_frame_clone(cur))) < 0)
  212.             return ret;
  213.     }
  214.  
  215.     av_log(inlink->dst, AV_LOG_DEBUG,
  216.            "%s pts:%s pts_time:%s drop_count:%d\n",
  217.            decimate->drop_count > 0 ? "drop" : "keep",
  218.            av_ts2str(cur->pts), av_ts2timestr(cur->pts, &inlink->time_base),
  219.            decimate->drop_count);
  220.  
  221.     if (decimate->drop_count > 0)
  222.         av_frame_free(&cur);
  223.  
  224.     return 0;
  225. }
  226.  
  227. static int request_frame(AVFilterLink *outlink)
  228. {
  229.     DecimateContext *decimate = outlink->src->priv;
  230.     AVFilterLink *inlink = outlink->src->inputs[0];
  231.     int ret;
  232.  
  233.     do {
  234.         ret = ff_request_frame(inlink);
  235.     } while (decimate->drop_count > 0 && ret >= 0);
  236.  
  237.     return ret;
  238. }
  239.  
  240. static const AVFilterPad mpdecimate_inputs[] = {
  241.     {
  242.         .name         = "default",
  243.         .type         = AVMEDIA_TYPE_VIDEO,
  244.         .config_props = config_input,
  245.         .filter_frame = filter_frame,
  246.     },
  247.     { NULL }
  248. };
  249.  
  250. static const AVFilterPad mpdecimate_outputs[] = {
  251.     {
  252.         .name          = "default",
  253.         .type          = AVMEDIA_TYPE_VIDEO,
  254.         .request_frame = request_frame,
  255.     },
  256.     { NULL }
  257. };
  258.  
  259. AVFilter ff_vf_mpdecimate = {
  260.     .name          = "mpdecimate",
  261.     .description   = NULL_IF_CONFIG_SMALL("Remove near-duplicate frames."),
  262.     .init          = init,
  263.     .uninit        = uninit,
  264.     .priv_size     = sizeof(DecimateContext),
  265.     .priv_class    = &mpdecimate_class,
  266.     .query_formats = query_formats,
  267.     .inputs        = mpdecimate_inputs,
  268.     .outputs       = mpdecimate_outputs,
  269. };
  270.