Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (C) 2012 Michael Niedermayer <michaelni@gmx.at>
  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 <float.h> /* FLT_MAX */
  22.  
  23. #include "libavutil/cpu.h"
  24. #include "libavutil/common.h"
  25. #include "libavutil/opt.h"
  26. #include "internal.h"
  27. #include "vf_idet.h"
  28.  
  29. #define OFFSET(x) offsetof(IDETContext, x)
  30. #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
  31.  
  32. static const AVOption idet_options[] = {
  33.     { "intl_thres", "set interlacing threshold", OFFSET(interlace_threshold),   AV_OPT_TYPE_FLOAT, {.dbl = 1.04}, -1, FLT_MAX, FLAGS },
  34.     { "prog_thres", "set progressive threshold", OFFSET(progressive_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 1.5},  -1, FLT_MAX, FLAGS },
  35.     { "rep_thres",  "set repeat threshold",      OFFSET(repeat_threshold),      AV_OPT_TYPE_FLOAT, {.dbl = 3.0},  -1, FLT_MAX, FLAGS },
  36.     { "half_life", "half life of cumulative statistics", OFFSET(half_life),     AV_OPT_TYPE_FLOAT, {.dbl = 0.0},  -1, INT_MAX, FLAGS },
  37.     { "analyze_interlaced_flag", "set number of frames to use to determine if the interlace flag is accurate", OFFSET(analyze_interlaced_flag), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, FLAGS },
  38.     { NULL }
  39. };
  40.  
  41. AVFILTER_DEFINE_CLASS(idet);
  42.  
  43. static const char *type2str(Type type)
  44. {
  45.     switch(type) {
  46.         case TFF          : return "tff";
  47.         case BFF          : return "bff";
  48.         case PROGRESSIVE  : return "progressive";
  49.         case UNDETERMINED : return "undetermined";
  50.     }
  51.     return NULL;
  52. }
  53.  
  54. #define PRECISION 1048576
  55.  
  56. static uint64_t uintpow(uint64_t b,unsigned int e)
  57. {
  58.     uint64_t r=1;
  59.     while(e--) r*=b;
  60.     return r;
  61. }
  62.  
  63. static int av_dict_set_fxp(AVDictionary **pm, const char *key, uint64_t value, unsigned int digits,
  64.                 int flags)
  65. {
  66.     char valuestr[44];
  67.     uint64_t print_precision = uintpow(10, digits);
  68.  
  69.     value = av_rescale(value, print_precision, PRECISION);
  70.  
  71.     snprintf(valuestr, sizeof(valuestr), "%"PRId64".%0*"PRId64,
  72.              value / print_precision, digits, value % print_precision);
  73.  
  74.     return av_dict_set(pm, key, valuestr, flags);
  75. }
  76.  
  77. static const char *rep2str(RepeatedField repeated_field)
  78. {
  79.     switch(repeated_field) {
  80.         case REPEAT_NONE    : return "neither";
  81.         case REPEAT_TOP     : return "top";
  82.         case REPEAT_BOTTOM  : return "bottom";
  83.     }
  84.     return NULL;
  85. }
  86.  
  87. int ff_idet_filter_line_c(const uint8_t *a, const uint8_t *b, const uint8_t *c, int w)
  88. {
  89.     int x;
  90.     int ret=0;
  91.  
  92.     for(x=0; x<w; x++){
  93.         int v = (*a++ + *c++) - 2 * *b++;
  94.         ret += FFABS(v);
  95.     }
  96.  
  97.     return ret;
  98. }
  99.  
  100. int ff_idet_filter_line_c_16bit(const uint16_t *a, const uint16_t *b, const uint16_t *c, int w)
  101. {
  102.     int x;
  103.     int ret=0;
  104.  
  105.     for(x=0; x<w; x++){
  106.         int v = (*a++ + *c++) - 2 * *b++;
  107.         ret += FFABS(v);
  108.     }
  109.  
  110.     return ret;
  111. }
  112.  
  113. static void filter(AVFilterContext *ctx)
  114. {
  115.     IDETContext *idet = ctx->priv;
  116.     int y, i;
  117.     int64_t alpha[2]={0};
  118.     int64_t delta=0;
  119.     int64_t gamma[2]={0};
  120.     Type type, best_type;
  121.     RepeatedField repeat;
  122.     int match = 0;
  123.     AVDictionary **metadata = avpriv_frame_get_metadatap(idet->cur);
  124.  
  125.     for (i = 0; i < idet->csp->nb_components; i++) {
  126.         int w = idet->cur->width;
  127.         int h = idet->cur->height;
  128.         int refs = idet->cur->linesize[i];
  129.  
  130.         if (i && i<3) {
  131.             w = FF_CEIL_RSHIFT(w, idet->csp->log2_chroma_w);
  132.             h = FF_CEIL_RSHIFT(h, idet->csp->log2_chroma_h);
  133.         }
  134.  
  135.         for (y = 2; y < h - 2; y++) {
  136.             uint8_t *prev = &idet->prev->data[i][y*refs];
  137.             uint8_t *cur  = &idet->cur ->data[i][y*refs];
  138.             uint8_t *next = &idet->next->data[i][y*refs];
  139.             alpha[ y   &1] += idet->filter_line(cur-refs, prev, cur+refs, w);
  140.             alpha[(y^1)&1] += idet->filter_line(cur-refs, next, cur+refs, w);
  141.             delta          += idet->filter_line(cur-refs,  cur, cur+refs, w);
  142.             gamma[(y^1)&1] += idet->filter_line(cur     , prev, cur     , w);
  143.         }
  144.     }
  145.  
  146.     if      (alpha[0] > idet->interlace_threshold * alpha[1]){
  147.         type = TFF;
  148.     }else if(alpha[1] > idet->interlace_threshold * alpha[0]){
  149.         type = BFF;
  150.     }else if(alpha[1] > idet->progressive_threshold * delta){
  151.         type = PROGRESSIVE;
  152.     }else{
  153.         type = UNDETERMINED;
  154.     }
  155.  
  156.     if ( gamma[0] > idet->repeat_threshold * gamma[1] ){
  157.         repeat = REPEAT_TOP;
  158.     } else if ( gamma[1] > idet->repeat_threshold * gamma[0] ){
  159.         repeat = REPEAT_BOTTOM;
  160.     } else {
  161.         repeat = REPEAT_NONE;
  162.     }
  163.  
  164.     memmove(idet->history+1, idet->history, HIST_SIZE-1);
  165.     idet->history[0] = type;
  166.     best_type = UNDETERMINED;
  167.     for(i=0; i<HIST_SIZE; i++){
  168.         if(idet->history[i] != UNDETERMINED){
  169.             if(best_type == UNDETERMINED)
  170.                 best_type = idet->history[i];
  171.  
  172.             if(idet->history[i] == best_type) {
  173.                 match++;
  174.             }else{
  175.                 match=0;
  176.                 break;
  177.             }
  178.         }
  179.     }
  180.     if(idet->last_type == UNDETERMINED){
  181.         if(match  ) idet->last_type = best_type;
  182.     }else{
  183.         if(match>2) idet->last_type = best_type;
  184.     }
  185.  
  186.     if      (idet->last_type == TFF){
  187.         idet->cur->top_field_first = 1;
  188.         idet->cur->interlaced_frame = 1;
  189.     }else if(idet->last_type == BFF){
  190.         idet->cur->top_field_first = 0;
  191.         idet->cur->interlaced_frame = 1;
  192.     }else if(idet->last_type == PROGRESSIVE){
  193.         idet->cur->interlaced_frame = 0;
  194.     }
  195.  
  196.     for(i=0; i<3; i++)
  197.         idet->repeats[i]  = av_rescale(idet->repeats [i], idet->decay_coefficient, PRECISION);
  198.  
  199.     for(i=0; i<4; i++){
  200.         idet->prestat [i] = av_rescale(idet->prestat [i], idet->decay_coefficient, PRECISION);
  201.         idet->poststat[i] = av_rescale(idet->poststat[i], idet->decay_coefficient, PRECISION);
  202.     }
  203.  
  204.     idet->total_repeats [         repeat] ++;
  205.     idet->repeats       [         repeat] += PRECISION;
  206.  
  207.     idet->total_prestat [           type] ++;
  208.     idet->prestat       [           type] += PRECISION;
  209.  
  210.     idet->total_poststat[idet->last_type] ++;
  211.     idet->poststat      [idet->last_type] += PRECISION;
  212.  
  213.     av_log(ctx, AV_LOG_DEBUG, "Repeated Field:%12s, Single frame:%12s, Multi frame:%12s\n",
  214.            rep2str(repeat), type2str(type), type2str(idet->last_type));
  215.  
  216.     av_dict_set    (metadata, "lavfi.idet.repeated.current_frame", rep2str(repeat), 0);
  217.     av_dict_set_fxp(metadata, "lavfi.idet.repeated.neither",       idet->repeats[REPEAT_NONE], 2, 0);
  218.     av_dict_set_fxp(metadata, "lavfi.idet.repeated.top",           idet->repeats[REPEAT_TOP], 2, 0);
  219.     av_dict_set_fxp(metadata, "lavfi.idet.repeated.bottom",        idet->repeats[REPEAT_BOTTOM], 2, 0);
  220.  
  221.     av_dict_set    (metadata, "lavfi.idet.single.current_frame",   type2str(type), 0);
  222.     av_dict_set_fxp(metadata, "lavfi.idet.single.tff",             idet->prestat[TFF], 2 , 0);
  223.     av_dict_set_fxp(metadata, "lavfi.idet.single.bff",             idet->prestat[BFF], 2, 0);
  224.     av_dict_set_fxp(metadata, "lavfi.idet.single.progressive",     idet->prestat[PROGRESSIVE], 2, 0);
  225.     av_dict_set_fxp(metadata, "lavfi.idet.single.undetermined",    idet->prestat[UNDETERMINED], 2, 0);
  226.  
  227.     av_dict_set    (metadata, "lavfi.idet.multiple.current_frame", type2str(idet->last_type), 0);
  228.     av_dict_set_fxp(metadata, "lavfi.idet.multiple.tff",           idet->poststat[TFF], 2, 0);
  229.     av_dict_set_fxp(metadata, "lavfi.idet.multiple.bff",           idet->poststat[BFF], 2, 0);
  230.     av_dict_set_fxp(metadata, "lavfi.idet.multiple.progressive",   idet->poststat[PROGRESSIVE], 2, 0);
  231.     av_dict_set_fxp(metadata, "lavfi.idet.multiple.undetermined",  idet->poststat[UNDETERMINED], 2, 0);
  232. }
  233.  
  234. static int filter_frame(AVFilterLink *link, AVFrame *picref)
  235. {
  236.     AVFilterContext *ctx = link->dst;
  237.     IDETContext *idet = ctx->priv;
  238.  
  239.     // initial frame(s) and not interlaced, just pass through for
  240.     // the analyze_interlaced_flag mode
  241.     if (idet->analyze_interlaced_flag &&
  242.         !picref->interlaced_frame &&
  243.         !idet->next) {
  244.         return ff_filter_frame(ctx->outputs[0], picref);
  245.     }
  246.     if (idet->analyze_interlaced_flag_done) {
  247.         if (picref->interlaced_frame && idet->interlaced_flag_accuracy < 0)
  248.             picref->interlaced_frame = 0;
  249.         return ff_filter_frame(ctx->outputs[0], picref);
  250.     }
  251.  
  252.     av_frame_free(&idet->prev);
  253.  
  254.     if(   picref->width  != link->w
  255.        || picref->height != link->h
  256.        || picref->format != link->format) {
  257.         link->dst->inputs[0]->format = picref->format;
  258.         link->dst->inputs[0]->w      = picref->width;
  259.         link->dst->inputs[0]->h      = picref->height;
  260.  
  261.         av_frame_free(&idet->cur );
  262.         av_frame_free(&idet->next);
  263.     }
  264.  
  265.     idet->prev = idet->cur;
  266.     idet->cur  = idet->next;
  267.     idet->next = picref;
  268.  
  269.     if (!idet->cur &&
  270.         !(idet->cur = av_frame_clone(idet->next)))
  271.         return AVERROR(ENOMEM);
  272.  
  273.     if (!idet->prev)
  274.         return 0;
  275.  
  276.     if (!idet->csp)
  277.         idet->csp = av_pix_fmt_desc_get(link->format);
  278.     if (idet->csp->comp[0].depth_minus1 / 8 == 1){
  279.         idet->filter_line = (ff_idet_filter_func)ff_idet_filter_line_c_16bit;
  280.         if (ARCH_X86)
  281.             ff_idet_init_x86(idet, 1);
  282.     }
  283.  
  284.     if (idet->analyze_interlaced_flag) {
  285.         if (idet->cur->interlaced_frame) {
  286.             idet->cur->interlaced_frame = 0;
  287.             filter(ctx);
  288.             if (idet->last_type == PROGRESSIVE) {
  289.                 idet->interlaced_flag_accuracy --;
  290.                 idet->analyze_interlaced_flag --;
  291.             } else if (idet->last_type != UNDETERMINED) {
  292.                 idet->interlaced_flag_accuracy ++;
  293.                 idet->analyze_interlaced_flag --;
  294.             }
  295.             if (idet->analyze_interlaced_flag == 1) {
  296.                 ff_filter_frame(ctx->outputs[0], av_frame_clone(idet->cur));
  297.  
  298.                 if (idet->next->interlaced_frame && idet->interlaced_flag_accuracy < 0)
  299.                     idet->next->interlaced_frame = 0;
  300.                 idet->analyze_interlaced_flag_done = 1;
  301.                 av_log(ctx, AV_LOG_INFO, "Final flag accuracy %d\n", idet->interlaced_flag_accuracy);
  302.                 return ff_filter_frame(ctx->outputs[0], av_frame_clone(idet->next));
  303.             }
  304.         }
  305.     } else {
  306.         filter(ctx);
  307.     }
  308.  
  309.     return ff_filter_frame(ctx->outputs[0], av_frame_clone(idet->cur));
  310. }
  311.  
  312. static int request_frame(AVFilterLink *link)
  313. {
  314.     AVFilterContext *ctx = link->src;
  315.     IDETContext *idet = ctx->priv;
  316.  
  317.     do {
  318.         int ret;
  319.  
  320.         if (idet->eof)
  321.             return AVERROR_EOF;
  322.  
  323.         ret = ff_request_frame(link->src->inputs[0]);
  324.  
  325.         if (ret == AVERROR_EOF && idet->cur && !idet->analyze_interlaced_flag_done) {
  326.             AVFrame *next = av_frame_clone(idet->next);
  327.  
  328.             if (!next)
  329.                 return AVERROR(ENOMEM);
  330.  
  331.             filter_frame(link->src->inputs[0], next);
  332.             idet->eof = 1;
  333.         } else if (ret < 0) {
  334.             return ret;
  335.         }
  336.     } while (link->frame_requested);
  337.  
  338.     return 0;
  339. }
  340.  
  341. static av_cold void uninit(AVFilterContext *ctx)
  342. {
  343.     IDETContext *idet = ctx->priv;
  344.     int level = strncmp(ctx->name, "auto-inserted", 13) ? AV_LOG_INFO : AV_LOG_DEBUG;
  345.  
  346.     av_log(ctx, level, "Repeated Fields: Neither:%6"PRId64" Top:%6"PRId64" Bottom:%6"PRId64"\n",
  347.            idet->total_repeats[REPEAT_NONE],
  348.            idet->total_repeats[REPEAT_TOP],
  349.            idet->total_repeats[REPEAT_BOTTOM]
  350.         );
  351.     av_log(ctx, level, "Single frame detection: TFF:%6"PRId64" BFF:%6"PRId64" Progressive:%6"PRId64" Undetermined:%6"PRId64"\n",
  352.            idet->total_prestat[TFF],
  353.            idet->total_prestat[BFF],
  354.            idet->total_prestat[PROGRESSIVE],
  355.            idet->total_prestat[UNDETERMINED]
  356.         );
  357.     av_log(ctx, level, "Multi frame detection: TFF:%6"PRId64" BFF:%6"PRId64" Progressive:%6"PRId64" Undetermined:%6"PRId64"\n",
  358.            idet->total_poststat[TFF],
  359.            idet->total_poststat[BFF],
  360.            idet->total_poststat[PROGRESSIVE],
  361.            idet->total_poststat[UNDETERMINED]
  362.         );
  363.  
  364.     av_frame_free(&idet->prev);
  365.     av_frame_free(&idet->cur );
  366.     av_frame_free(&idet->next);
  367. }
  368.  
  369. static int query_formats(AVFilterContext *ctx)
  370. {
  371.     static const enum AVPixelFormat pix_fmts[] = {
  372.         AV_PIX_FMT_YUV420P,
  373.         AV_PIX_FMT_YUV422P,
  374.         AV_PIX_FMT_YUV444P,
  375.         AV_PIX_FMT_YUV410P,
  376.         AV_PIX_FMT_YUV411P,
  377.         AV_PIX_FMT_GRAY8,
  378.         AV_PIX_FMT_YUVJ420P,
  379.         AV_PIX_FMT_YUVJ422P,
  380.         AV_PIX_FMT_YUVJ444P,
  381.         AV_PIX_FMT_GRAY16,
  382.         AV_PIX_FMT_YUV440P,
  383.         AV_PIX_FMT_YUVJ440P,
  384.         AV_PIX_FMT_YUV420P9,
  385.         AV_PIX_FMT_YUV422P9,
  386.         AV_PIX_FMT_YUV444P9,
  387.         AV_PIX_FMT_YUV420P10,
  388.         AV_PIX_FMT_YUV422P10,
  389.         AV_PIX_FMT_YUV444P10,
  390.         AV_PIX_FMT_YUV420P12,
  391.         AV_PIX_FMT_YUV422P12,
  392.         AV_PIX_FMT_YUV444P12,
  393.         AV_PIX_FMT_YUV420P14,
  394.         AV_PIX_FMT_YUV422P14,
  395.         AV_PIX_FMT_YUV444P14,
  396.         AV_PIX_FMT_YUV420P16,
  397.         AV_PIX_FMT_YUV422P16,
  398.         AV_PIX_FMT_YUV444P16,
  399.         AV_PIX_FMT_YUVA420P,
  400.         AV_PIX_FMT_NONE
  401.     };
  402.     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
  403.     if (!fmts_list)
  404.         return AVERROR(ENOMEM);
  405.     return ff_set_common_formats(ctx, fmts_list);
  406. }
  407.  
  408. static int config_output(AVFilterLink *outlink)
  409. {
  410.     outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
  411.     return 0;
  412. }
  413.  
  414. static av_cold int init(AVFilterContext *ctx)
  415. {
  416.     IDETContext *idet = ctx->priv;
  417.  
  418.     idet->eof = 0;
  419.     idet->last_type = UNDETERMINED;
  420.     memset(idet->history, UNDETERMINED, HIST_SIZE);
  421.  
  422.     if( idet->half_life > 0 )
  423.         idet->decay_coefficient = (uint64_t) round( PRECISION * exp2(-1.0 / idet->half_life) );
  424.     else
  425.         idet->decay_coefficient = PRECISION;
  426.  
  427.     idet->filter_line = ff_idet_filter_line_c;
  428.  
  429.     if (ARCH_X86)
  430.         ff_idet_init_x86(idet, 0);
  431.  
  432.     return 0;
  433. }
  434.  
  435. static const AVFilterPad idet_inputs[] = {
  436.     {
  437.         .name         = "default",
  438.         .type         = AVMEDIA_TYPE_VIDEO,
  439.         .filter_frame = filter_frame,
  440.     },
  441.     { NULL }
  442. };
  443.  
  444. static const AVFilterPad idet_outputs[] = {
  445.     {
  446.         .name         = "default",
  447.         .type         = AVMEDIA_TYPE_VIDEO,
  448.         .config_props = config_output,
  449.         .request_frame = request_frame
  450.     },
  451.     { NULL }
  452. };
  453.  
  454. AVFilter ff_vf_idet = {
  455.     .name          = "idet",
  456.     .description   = NULL_IF_CONFIG_SMALL("Interlace detect Filter."),
  457.     .priv_size     = sizeof(IDETContext),
  458.     .init          = init,
  459.     .uninit        = uninit,
  460.     .query_formats = query_formats,
  461.     .inputs        = idet_inputs,
  462.     .outputs       = idet_outputs,
  463.     .priv_class    = &idet_class,
  464. };
  465.