Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2004 Ville Saari
  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 General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 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
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License along
  17.  * 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/avassert.h"
  22. #include "libavutil/imgutils.h"
  23. #include "libavutil/pixdesc.h"
  24. #include "libavutil/opt.h"
  25. #include "avfilter.h"
  26. #include "formats.h"
  27. #include "internal.h"
  28. #include "video.h"
  29.  
  30. enum PhaseMode {
  31.     PROGRESSIVE,
  32.     TOP_FIRST,
  33.     BOTTOM_FIRST,
  34.     TOP_FIRST_ANALYZE,
  35.     BOTTOM_FIRST_ANALYZE,
  36.     ANALYZE,
  37.     FULL_ANALYZE,
  38.     AUTO,
  39.     AUTO_ANALYZE
  40. };
  41.  
  42. typedef struct PhaseContext {
  43.     const AVClass *class;
  44.     enum PhaseMode mode;
  45.     AVFrame *frame;
  46.     int nb_planes;
  47.     int planeheight[4];
  48.     int linesize[4];
  49. } PhaseContext;
  50.  
  51. #define OFFSET(x) offsetof(PhaseContext, x)
  52. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  53. #define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, FLAGS, unit }
  54.  
  55. static const AVOption phase_options[] = {
  56.     { "mode", "set phase mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=AUTO_ANALYZE}, PROGRESSIVE, AUTO_ANALYZE, FLAGS, "mode" },
  57.     CONST("p", "progressive",          PROGRESSIVE,          "mode"),
  58.     CONST("t", "top first",            TOP_FIRST,            "mode"),
  59.     CONST("b", "bottom first",         BOTTOM_FIRST,         "mode"),
  60.     CONST("T", "top first analyze",    TOP_FIRST_ANALYZE,    "mode"),
  61.     CONST("B", "bottom first analyze", BOTTOM_FIRST_ANALYZE, "mode"),
  62.     CONST("u", "analyze",              ANALYZE,              "mode"),
  63.     CONST("U", "full analyze",         FULL_ANALYZE,         "mode"),
  64.     CONST("a", "auto",                 AUTO,                 "mode"),
  65.     CONST("A", "auto analyze",         AUTO_ANALYZE,         "mode"),
  66.     { NULL }
  67. };
  68.  
  69. AVFILTER_DEFINE_CLASS(phase);
  70.  
  71. static int query_formats(AVFilterContext *ctx)
  72. {
  73.     static const enum AVPixelFormat pix_fmts[] = {
  74.         AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
  75.         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P,
  76.         AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
  77.         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
  78.     };
  79.  
  80.     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
  81.     return 0;
  82. }
  83.  
  84. static int config_input(AVFilterLink *inlink)
  85. {
  86.     PhaseContext *s = inlink->dst->priv;
  87.     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  88.     int ret;
  89.  
  90.     if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
  91.         return ret;
  92.  
  93.     s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
  94.     s->planeheight[0] = s->planeheight[3] = inlink->h;
  95.  
  96.     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
  97.  
  98.     return 0;
  99. }
  100.  
  101. /*
  102.  * This macro interpolates the value of both fields at a point halfway
  103.  * between lines and takes the squared difference. In field resolution
  104.  * the point is a quarter pixel below a line in one field and a quarter
  105.  * pixel above a line in other.
  106.  *
  107.  * (The result is actually multiplied by 25)
  108.  */
  109. #define DIFF(a, as, b, bs) (t = ((*a - b[bs]) << 2) + a[as << 1] - b[-bs], t * t)
  110.  
  111. /*
  112.  * Find which field combination has the smallest average squared difference
  113.  * between the fields.
  114.  */
  115. static enum PhaseMode analyze_plane(AVFilterContext *ctx, PhaseContext *s,
  116.                                     AVFrame *old, AVFrame *new)
  117. {
  118.     double bdiff, tdiff, pdiff, scale;
  119.     const int ns = new->linesize[0];
  120.     const int os = old->linesize[0];
  121.     uint8_t *nptr = new->data[0];
  122.     uint8_t *optr = old->data[0];
  123.     const int h = new->height;
  124.     const int w = new->width;
  125.     int bdif, tdif, pdif;
  126.     enum PhaseMode mode = s->mode;
  127.     uint8_t *end, *rend;
  128.     int top, t;
  129.  
  130.     if (mode == AUTO) {
  131.         mode = new->interlaced_frame ? new->top_field_first ?
  132.                TOP_FIRST : BOTTOM_FIRST : PROGRESSIVE;
  133.     } else if (mode == AUTO_ANALYZE) {
  134.         mode = new->interlaced_frame ? new->top_field_first ?
  135.                TOP_FIRST_ANALYZE : BOTTOM_FIRST_ANALYZE : FULL_ANALYZE;
  136.     }
  137.  
  138.     if (mode <= BOTTOM_FIRST) {
  139.         bdiff = pdiff = tdiff = 65536.0;
  140.     } else {
  141.         bdiff = pdiff = tdiff = 0.0;
  142.  
  143.         for (end = nptr + (h - 2) * ns, nptr += ns, optr += os, top = 0;
  144.              nptr < end; nptr += ns - w, optr += os - w, top ^= 1) {
  145.             pdif = tdif = bdif = 0;
  146.  
  147.             switch (mode) {
  148.             case TOP_FIRST_ANALYZE:
  149.                 if (top) {
  150.                     for (rend = nptr + w; nptr < rend; nptr++, optr++) {
  151.                         pdif += DIFF(nptr, ns, nptr, ns);
  152.                         tdif += DIFF(nptr, ns, optr, os);
  153.                     }
  154.                 } else {
  155.                     for (rend = nptr + w; nptr < rend; nptr++, optr++) {
  156.                         pdif += DIFF(nptr, ns, nptr, ns);
  157.                         tdif += DIFF(optr, os, nptr, ns);
  158.                     }
  159.                 }
  160.                 break;
  161.             case BOTTOM_FIRST_ANALYZE:
  162.                 if (top) {
  163.                     for (rend = nptr + w; nptr < rend; nptr++, optr++) {
  164.                         pdif += DIFF(nptr, ns, nptr, ns);
  165.                         bdif += DIFF(optr, os, nptr, ns);
  166.                     }
  167.                 } else {
  168.                     for (rend = nptr + w; nptr < rend; nptr++, optr++) {
  169.                         pdif += DIFF(nptr, ns, nptr, ns);
  170.                         bdif += DIFF(nptr, ns, optr, os);
  171.                     }
  172.                 }
  173.                 break;
  174.             case ANALYZE:
  175.                 if (top) {
  176.                     for (rend = nptr + w; nptr < rend; nptr++, optr++) {
  177.                         tdif += DIFF(nptr, ns, optr, os);
  178.                         bdif += DIFF(optr, os, nptr, ns);
  179.                     }
  180.                 } else {
  181.                     for (rend = nptr + w; nptr < rend; nptr++, optr++) {
  182.                         bdif += DIFF(nptr, ns, optr, os);
  183.                         tdif += DIFF(optr, os, nptr, ns);
  184.                     }
  185.                 }
  186.                 break;
  187.             case FULL_ANALYZE:
  188.                 if (top) {
  189.                     for (rend = nptr + w; nptr < rend; nptr++, optr++) {
  190.                         pdif += DIFF(nptr, ns, nptr, ns);
  191.                         tdif += DIFF(nptr, ns, optr, os);
  192.                         bdif += DIFF(optr, os, nptr, ns);
  193.                     }
  194.                 } else {
  195.                     for (rend = nptr + w; nptr < rend; nptr++, optr++) {
  196.                         pdif += DIFF(nptr, ns, nptr, ns);
  197.                         bdif += DIFF(nptr, ns, optr, os);
  198.                         tdif += DIFF(optr, os, nptr, ns);
  199.                     }
  200.                 }
  201.                 break;
  202.             default:
  203.                 av_assert0(0);
  204.             }
  205.  
  206.             pdiff += (double)pdif;
  207.             tdiff += (double)tdif;
  208.             bdiff += (double)bdif;
  209.         }
  210.  
  211.         scale = 1.0 / (w * (h - 3)) / 25.0;
  212.         pdiff *= scale;
  213.         tdiff *= scale;
  214.         bdiff *= scale;
  215.  
  216.         if (mode == TOP_FIRST_ANALYZE) {
  217.             bdiff = 65536.0;
  218.         } else if (mode == BOTTOM_FIRST_ANALYZE) {
  219.             tdiff = 65536.0;
  220.         } else if (mode == ANALYZE) {
  221.             pdiff = 65536.0;
  222.         }
  223.  
  224.         if (bdiff < pdiff && bdiff < tdiff) {
  225.             mode = BOTTOM_FIRST;
  226.         } else if (tdiff < pdiff && tdiff < bdiff) {
  227.             mode = TOP_FIRST;
  228.         } else {
  229.             mode = PROGRESSIVE;
  230.         }
  231.     }
  232.  
  233.     av_log(ctx, AV_LOG_DEBUG, "mode=%c tdiff=%f bdiff=%f pdiff=%f\n",
  234.            mode == BOTTOM_FIRST ? 'b' : mode == TOP_FIRST ? 't' : 'p',
  235.            tdiff, bdiff, pdiff);
  236.     return mode;
  237. }
  238.  
  239. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  240. {
  241.     AVFilterContext *ctx = inlink->dst;
  242.     AVFilterLink *outlink = ctx->outputs[0];
  243.     PhaseContext *s = ctx->priv;
  244.     enum PhaseMode mode;
  245.     int plane, top, y;
  246.     AVFrame *out;
  247.  
  248.     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  249.     if (!out) {
  250.         av_frame_free(&in);
  251.         return AVERROR(ENOMEM);
  252.     }
  253.     av_frame_copy_props(out, in);
  254.  
  255.     if (!s->frame) {
  256.         mode = PROGRESSIVE;
  257.         s->frame = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  258.         if (!s->frame) {
  259.             av_frame_free(&in);
  260.             av_frame_free(&out);
  261.             return AVERROR(ENOMEM);
  262.         }
  263.     } else {
  264.         mode = analyze_plane(ctx, s, s->frame, in);
  265.     }
  266.  
  267.     for (plane = 0; plane < s->nb_planes; plane++) {
  268.         uint8_t *buf = s->frame->data[plane];
  269.         uint8_t *from = in->data[plane];
  270.         uint8_t *to = out->data[plane];
  271.  
  272.         for (y = 0, top = 1; y < s->planeheight[plane]; y++, top ^= 1) {
  273.             memcpy(to, mode == (top ? BOTTOM_FIRST : TOP_FIRST) ? buf : from, s->linesize[plane]);
  274.             memcpy(buf, from, s->linesize[plane]);
  275.  
  276.             buf += s->frame->linesize[plane];
  277.             from += in->linesize[plane];
  278.             to += out->linesize[plane];
  279.         }
  280.     }
  281.  
  282.     av_frame_free(&in);
  283.     return ff_filter_frame(outlink, out);
  284. }
  285.  
  286. static av_cold void uninit(AVFilterContext *ctx)
  287. {
  288.     PhaseContext *s = ctx->priv;
  289.  
  290.     av_frame_free(&s->frame);
  291. }
  292.  
  293. static const AVFilterPad phase_inputs[] = {
  294.     {
  295.         .name         = "default",
  296.         .type         = AVMEDIA_TYPE_VIDEO,
  297.         .filter_frame = filter_frame,
  298.         .config_props = config_input,
  299.     },
  300.     { NULL }
  301. };
  302.  
  303. static const AVFilterPad phase_outputs[] = {
  304.     {
  305.         .name = "default",
  306.         .type = AVMEDIA_TYPE_VIDEO,
  307.     },
  308.     { NULL }
  309. };
  310.  
  311. AVFilter avfilter_vf_phase = {
  312.     .name          = "phase",
  313.     .description   = NULL_IF_CONFIG_SMALL("Phase shift fields."),
  314.     .priv_size     = sizeof(PhaseContext),
  315.     .priv_class    = &phase_class,
  316.     .uninit        = uninit,
  317.     .query_formats = query_formats,
  318.     .inputs        = phase_inputs,
  319.     .outputs       = phase_outputs,
  320. };
  321.