Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2002 A'rpi
  3.  * This file is part of FFmpeg.
  4.  *
  5.  * FFmpeg is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * FFmpeg is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License along
  16.  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
  17.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18.  */
  19.  
  20. /**
  21.  * @file
  22.  * border detection filter
  23.  * Ported from MPlayer libmpcodecs/vf_cropdetect.c.
  24.  */
  25.  
  26. #include "libavutil/imgutils.h"
  27. #include "libavutil/internal.h"
  28. #include "libavutil/opt.h"
  29.  
  30. #include "avfilter.h"
  31. #include "formats.h"
  32. #include "internal.h"
  33. #include "video.h"
  34.  
  35. typedef struct {
  36.     const AVClass *class;
  37.     int x1, y1, x2, y2;
  38.     int limit;
  39.     int round;
  40.     int reset_count;
  41.     int frame_nb;
  42.     int max_pixsteps[4];
  43. } CropDetectContext;
  44.  
  45. static int query_formats(AVFilterContext *ctx)
  46. {
  47.     static const enum AVPixelFormat pix_fmts[] = {
  48.         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P,
  49.         AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P,
  50.         AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
  51.         AV_PIX_FMT_YUV411P, AV_PIX_FMT_GRAY8,
  52.         AV_PIX_FMT_NV12,    AV_PIX_FMT_NV21,
  53.         AV_PIX_FMT_NONE
  54.     };
  55.  
  56.     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
  57.     return 0;
  58. }
  59.  
  60. static int checkline(void *ctx, const unsigned char *src, int stride, int len, int bpp)
  61. {
  62.     int total = 0;
  63.     int div = len;
  64.  
  65.     switch (bpp) {
  66.     case 1:
  67.         while (--len >= 0) {
  68.             total += src[0];
  69.             src += stride;
  70.         }
  71.         break;
  72.     case 3:
  73.     case 4:
  74.         while (--len >= 0) {
  75.             total += src[0] + src[1] + src[2];
  76.             src += stride;
  77.         }
  78.         div *= 3;
  79.         break;
  80.     }
  81.     total /= div;
  82.  
  83.     av_log(ctx, AV_LOG_DEBUG, "total:%d\n", total);
  84.     return total;
  85. }
  86.  
  87. static av_cold int init(AVFilterContext *ctx)
  88. {
  89.     CropDetectContext *s = ctx->priv;
  90.  
  91.     s->frame_nb = -2;
  92.  
  93.     av_log(ctx, AV_LOG_VERBOSE, "limit:%d round:%d reset_count:%d\n",
  94.            s->limit, s->round, s->reset_count);
  95.  
  96.     return 0;
  97. }
  98.  
  99. static int config_input(AVFilterLink *inlink)
  100. {
  101.     AVFilterContext *ctx = inlink->dst;
  102.     CropDetectContext *s = ctx->priv;
  103.  
  104.     av_image_fill_max_pixsteps(s->max_pixsteps, NULL,
  105.                                av_pix_fmt_desc_get(inlink->format));
  106.  
  107.     s->x1 = inlink->w - 1;
  108.     s->y1 = inlink->h - 1;
  109.     s->x2 = 0;
  110.     s->y2 = 0;
  111.  
  112.     return 0;
  113. }
  114.  
  115. #define SET_META(key, value) \
  116.     snprintf(buf, sizeof(buf), "%d", value);  \
  117.     av_dict_set(metadata, key, buf, 0)
  118.  
  119. static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
  120. {
  121.     AVFilterContext *ctx = inlink->dst;
  122.     CropDetectContext *s = ctx->priv;
  123.     int bpp = s->max_pixsteps[0];
  124.     int w, h, x, y, shrink_by;
  125.     AVDictionary **metadata;
  126.     char buf[32];
  127.  
  128.     // ignore first 2 frames - they may be empty
  129.     if (++s->frame_nb > 0) {
  130.         metadata = avpriv_frame_get_metadatap(frame);
  131.  
  132.         // Reset the crop area every reset_count frames, if reset_count is > 0
  133.         if (s->reset_count > 0 && s->frame_nb > s->reset_count) {
  134.             s->x1 = frame->width  - 1;
  135.             s->y1 = frame->height - 1;
  136.             s->x2 = 0;
  137.             s->y2 = 0;
  138.             s->frame_nb = 1;
  139.         }
  140.  
  141.         for (y = 0; y < s->y1; y++) {
  142.             if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->width, bpp) > s->limit) {
  143.                 s->y1 = y;
  144.                 break;
  145.             }
  146.         }
  147.  
  148.         for (y = frame->height - 1; y > s->y2; y--) {
  149.             if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->width, bpp) > s->limit) {
  150.                 s->y2 = y;
  151.                 break;
  152.             }
  153.         }
  154.  
  155.         for (y = 0; y < s->x1; y++) {
  156.             if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->height, bpp) > s->limit) {
  157.                 s->x1 = y;
  158.                 break;
  159.             }
  160.         }
  161.  
  162.         for (y = frame->width - 1; y > s->x2; y--) {
  163.             if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->height, bpp) > s->limit) {
  164.                 s->x2 = y;
  165.                 break;
  166.             }
  167.         }
  168.  
  169.         // round x and y (up), important for yuv colorspaces
  170.         // make sure they stay rounded!
  171.         x = (s->x1+1) & ~1;
  172.         y = (s->y1+1) & ~1;
  173.  
  174.         w = s->x2 - x + 1;
  175.         h = s->y2 - y + 1;
  176.  
  177.         // w and h must be divisible by 2 as well because of yuv
  178.         // colorspace problems.
  179.         if (s->round <= 1)
  180.             s->round = 16;
  181.         if (s->round % 2)
  182.             s->round *= 2;
  183.  
  184.         shrink_by = w % s->round;
  185.         w -= shrink_by;
  186.         x += (shrink_by/2 + 1) & ~1;
  187.  
  188.         shrink_by = h % s->round;
  189.         h -= shrink_by;
  190.         y += (shrink_by/2 + 1) & ~1;
  191.  
  192.         SET_META("lavfi.cropdetect.x1", s->x1);
  193.         SET_META("lavfi.cropdetect.x2", s->x2);
  194.         SET_META("lavfi.cropdetect.y1", s->y1);
  195.         SET_META("lavfi.cropdetect.y2", s->y2);
  196.         SET_META("lavfi.cropdetect.w",  w);
  197.         SET_META("lavfi.cropdetect.h",  h);
  198.         SET_META("lavfi.cropdetect.x",  x);
  199.         SET_META("lavfi.cropdetect.y",  y);
  200.  
  201.         av_log(ctx, AV_LOG_INFO,
  202.                "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n",
  203.                s->x1, s->x2, s->y1, s->y2, w, h, x, y, frame->pts,
  204.                frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base),
  205.                w, h, x, y);
  206.     }
  207.  
  208.     return ff_filter_frame(inlink->dst->outputs[0], frame);
  209. }
  210.  
  211. #define OFFSET(x) offsetof(CropDetectContext, x)
  212. #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
  213.  
  214. static const AVOption cropdetect_options[] = {
  215.     { "limit", "Threshold below which the pixel is considered black", OFFSET(limit),       AV_OPT_TYPE_INT, { .i64 = 24 }, 0, 255, FLAGS },
  216.     { "round", "Value by which the width/height should be divisible", OFFSET(round),       AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, FLAGS },
  217.     { "reset", "Recalculate the crop area after this many frames",    OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, FLAGS },
  218.     { "reset_count", "Recalculate the crop area after this many frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 },  0, INT_MAX, FLAGS },
  219.     { NULL }
  220. };
  221.  
  222. AVFILTER_DEFINE_CLASS(cropdetect);
  223.  
  224. static const AVFilterPad avfilter_vf_cropdetect_inputs[] = {
  225.     {
  226.         .name         = "default",
  227.         .type         = AVMEDIA_TYPE_VIDEO,
  228.         .config_props = config_input,
  229.         .filter_frame = filter_frame,
  230.     },
  231.     { NULL }
  232. };
  233.  
  234. static const AVFilterPad avfilter_vf_cropdetect_outputs[] = {
  235.     {
  236.         .name = "default",
  237.         .type = AVMEDIA_TYPE_VIDEO
  238.     },
  239.     { NULL }
  240. };
  241.  
  242. AVFilter avfilter_vf_cropdetect = {
  243.     .name          = "cropdetect",
  244.     .description   = NULL_IF_CONFIG_SMALL("Auto-detect crop size."),
  245.     .priv_size     = sizeof(CropDetectContext),
  246.     .priv_class    = &cropdetect_class,
  247.     .init          = init,
  248.     .query_formats = query_formats,
  249.     .inputs        = avfilter_vf_cropdetect_inputs,
  250.     .outputs       = avfilter_vf_cropdetect_outputs,
  251.     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
  252. };
  253.