LCOV - code coverage report
Current view: top level - libavfilter - vf_pp7.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 177 0.0 %
Date: 2017-12-18 13:19:42 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
       3             :  * Copyright (c) 2014 Arwa Arif <arwaarif1994@gmail.com>
       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
      24             :  * Postprocessing filter - 7
      25             :  *
      26             :  * Originally written by Michael Niedermayer for the MPlayer
      27             :  * project, and ported by Arwa Arif for FFmpeg.
      28             :  */
      29             : 
      30             : #include "libavutil/avassert.h"
      31             : #include "libavutil/imgutils.h"
      32             : #include "libavutil/opt.h"
      33             : #include "libavutil/pixdesc.h"
      34             : #include "internal.h"
      35             : #include "vf_pp7.h"
      36             : 
      37             : enum mode {
      38             :     MODE_HARD,
      39             :     MODE_SOFT,
      40             :     MODE_MEDIUM
      41             : };
      42             : 
      43             : #define OFFSET(x) offsetof(PP7Context, x)
      44             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
      45             : static const AVOption pp7_options[] = {
      46             :     { "qp", "force a constant quantizer parameter", OFFSET(qp), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 64, FLAGS },
      47             :     { "mode", "set thresholding mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_MEDIUM}, 0, 2, FLAGS, "mode" },
      48             :         { "hard",   "hard thresholding",   0, AV_OPT_TYPE_CONST, {.i64 = MODE_HARD},   INT_MIN, INT_MAX, FLAGS, "mode" },
      49             :         { "soft",   "soft thresholding",   0, AV_OPT_TYPE_CONST, {.i64 = MODE_SOFT},   INT_MIN, INT_MAX, FLAGS, "mode" },
      50             :         { "medium", "medium thresholding", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_MEDIUM}, INT_MIN, INT_MAX, FLAGS, "mode" },
      51             :     { NULL }
      52             : };
      53             : 
      54             : AVFILTER_DEFINE_CLASS(pp7);
      55             : 
      56             : DECLARE_ALIGNED(8, static const uint8_t, dither)[8][8] = {
      57             :     {  0,  48,  12,  60,   3,  51,  15,  63, },
      58             :     { 32,  16,  44,  28,  35,  19,  47,  31, },
      59             :     {  8,  56,   4,  52,  11,  59,   7,  55, },
      60             :     { 40,  24,  36,  20,  43,  27,  39,  23, },
      61             :     {  2,  50,  14,  62,   1,  49,  13,  61, },
      62             :     { 34,  18,  46,  30,  33,  17,  45,  29, },
      63             :     { 10,  58,   6,  54,   9,  57,   5,  53, },
      64             :     { 42,  26,  38,  22,  41,  25,  37,  21, },
      65             : };
      66             : 
      67             : #define N0 4
      68             : #define N1 5
      69             : #define N2 10
      70             : #define SN0 2
      71             : #define SN1 2.2360679775
      72             : #define SN2 3.16227766017
      73             : #define N (1 << 16)
      74             : 
      75             : static const int factor[16] = {
      76             :     N / (N0 * N0), N / (N0 * N1), N / (N0 * N0), N / (N0 * N2),
      77             :     N / (N1 * N0), N / (N1 * N1), N / (N1 * N0), N / (N1 * N2),
      78             :     N / (N0 * N0), N / (N0 * N1), N / (N0 * N0), N / (N0 * N2),
      79             :     N / (N2 * N0), N / (N2 * N1), N / (N2 * N0), N / (N2 * N2),
      80             : };
      81             : 
      82           0 : static void init_thres2(PP7Context *p)
      83             : {
      84             :     int qp, i;
      85           0 :     int bias = 0; //FIXME
      86             : 
      87           0 :     for (qp = 0; qp < 99; qp++) {
      88           0 :         for (i = 0; i < 16; i++) {
      89           0 :             p->thres2[qp][i] = ((i&1) ? SN2 : SN0) * ((i&4) ? SN2 : SN0) * FFMAX(1, qp) * (1<<2) - 1 - bias;
      90             :         }
      91             :     }
      92           0 : }
      93             : 
      94           0 : static inline void dctA_c(int16_t *dst, uint8_t *src, int stride)
      95             : {
      96             :     int i;
      97             : 
      98           0 :     for (i = 0; i < 4; i++) {
      99           0 :         int s0 = src[0 * stride] + src[6 * stride];
     100           0 :         int s1 = src[1 * stride] + src[5 * stride];
     101           0 :         int s2 = src[2 * stride] + src[4 * stride];
     102           0 :         int s3 = src[3 * stride];
     103           0 :         int s = s3 + s3;
     104           0 :         s3 = s  - s0;
     105           0 :         s0 = s  + s0;
     106           0 :         s  = s2 + s1;
     107           0 :         s2 = s2 - s1;
     108           0 :         dst[0] = s0 + s;
     109           0 :         dst[2] = s0 - s;
     110           0 :         dst[1] = 2 * s3 +     s2;
     111           0 :         dst[3] =     s3 - 2 * s2;
     112           0 :         src++;
     113           0 :         dst += 4;
     114             :     }
     115           0 : }
     116             : 
     117           0 : static void dctB_c(int16_t *dst, int16_t *src)
     118             : {
     119             :     int i;
     120             : 
     121           0 :     for (i = 0; i < 4; i++) {
     122           0 :         int s0 = src[0 * 4] + src[6 * 4];
     123           0 :         int s1 = src[1 * 4] + src[5 * 4];
     124           0 :         int s2 = src[2 * 4] + src[4 * 4];
     125           0 :         int s3 = src[3 * 4];
     126           0 :         int s = s3 + s3;
     127           0 :         s3 = s  - s0;
     128           0 :         s0 = s  + s0;
     129           0 :         s  = s2 + s1;
     130           0 :         s2 = s2 - s1;
     131           0 :         dst[0 * 4] = s0 + s;
     132           0 :         dst[2 * 4] = s0 - s;
     133           0 :         dst[1 * 4] = 2 * s3 +     s2;
     134           0 :         dst[3 * 4] =     s3 - 2 * s2;
     135           0 :         src++;
     136           0 :         dst++;
     137             :     }
     138           0 : }
     139             : 
     140           0 : static int hardthresh_c(PP7Context *p, int16_t *src, int qp)
     141             : {
     142             :     int i;
     143             :     int a;
     144             : 
     145           0 :     a = src[0] * factor[0];
     146           0 :     for (i = 1; i < 16; i++) {
     147           0 :         unsigned int threshold1 = p->thres2[qp][i];
     148           0 :         unsigned int threshold2 = threshold1 << 1;
     149           0 :         int level = src[i];
     150           0 :         if (((unsigned)(level + threshold1)) > threshold2)
     151           0 :             a += level * factor[i];
     152             :     }
     153           0 :     return (a + (1 << 11)) >> 12;
     154             : }
     155             : 
     156           0 : static int mediumthresh_c(PP7Context *p, int16_t *src, int qp)
     157             : {
     158             :     int i;
     159             :     int a;
     160             : 
     161           0 :     a = src[0] * factor[0];
     162           0 :     for (i = 1; i < 16; i++) {
     163           0 :         unsigned int threshold1 = p->thres2[qp][i];
     164           0 :         unsigned int threshold2 = threshold1 << 1;
     165           0 :         int level = src[i];
     166           0 :         if (((unsigned)(level + threshold1)) > threshold2) {
     167           0 :             if (((unsigned)(level + 2 * threshold1)) > 2 * threshold2)
     168           0 :                 a += level * factor[i];
     169             :             else {
     170           0 :                 if (level > 0)
     171           0 :                     a += 2 * (level - (int)threshold1) * factor[i];
     172             :                 else
     173           0 :                     a += 2 * (level + (int)threshold1) * factor[i];
     174             :             }
     175             :         }
     176             :     }
     177           0 :     return (a + (1 << 11)) >> 12;
     178             : }
     179             : 
     180           0 : static int softthresh_c(PP7Context *p, int16_t *src, int qp)
     181             : {
     182             :     int i;
     183             :     int a;
     184             : 
     185           0 :     a = src[0] * factor[0];
     186           0 :     for (i = 1; i < 16; i++) {
     187           0 :         unsigned int threshold1 = p->thres2[qp][i];
     188           0 :         unsigned int threshold2 = threshold1 << 1;
     189           0 :         int level = src[i];
     190           0 :         if (((unsigned)(level + threshold1)) > threshold2) {
     191           0 :             if (level > 0)
     192           0 :                 a += (level - (int)threshold1) * factor[i];
     193             :             else
     194           0 :                 a += (level + (int)threshold1) * factor[i];
     195             :         }
     196             :     }
     197           0 :     return (a + (1 << 11)) >> 12;
     198             : }
     199             : 
     200           0 : static void filter(PP7Context *p, uint8_t *dst, uint8_t *src,
     201             :                    int dst_stride, int src_stride,
     202             :                    int width, int height,
     203             :                    uint8_t *qp_store, int qp_stride, int is_luma)
     204             : {
     205             :     int x, y;
     206           0 :     const int stride = is_luma ? p->temp_stride : ((width + 16 + 15) & (~15));
     207           0 :     uint8_t *p_src = p->src + 8 * stride;
     208           0 :     int16_t *block = (int16_t *)p->src;
     209           0 :     int16_t *temp  = (int16_t *)(p->src + 32);
     210             : 
     211           0 :     if (!src || !dst) return;
     212           0 :     for (y = 0; y < height; y++) {
     213           0 :         int index = 8 + 8 * stride + y * stride;
     214           0 :         memcpy(p_src + index, src + y * src_stride, width);
     215           0 :         for (x = 0; x < 8; x++) {
     216           0 :             p_src[index         - x - 1]= p_src[index +         x    ];
     217           0 :             p_src[index + width + x    ]= p_src[index + width - x - 1];
     218             :         }
     219             :     }
     220           0 :     for (y = 0; y < 8; y++) {
     221           0 :         memcpy(p_src + (    7 - y     ) * stride, p_src + (    y + 8     ) * stride, stride);
     222           0 :         memcpy(p_src + (height + 8 + y) * stride, p_src + (height - y + 7) * stride, stride);
     223             :     }
     224             :     //FIXME (try edge emu)
     225             : 
     226           0 :     for (y = 0; y < height; y++) {
     227           0 :         for (x = -8; x < 0; x += 4) {
     228           0 :             const int index = x + y * stride + (8 - 3) * (1 + stride) + 8; //FIXME silly offset
     229           0 :             uint8_t *src  = p_src + index;
     230           0 :             int16_t *tp   = temp + 4 * x;
     231             : 
     232           0 :             dctA_c(tp + 4 * 8, src, stride);
     233             :         }
     234           0 :         for (x = 0; x < width; ) {
     235           0 :             const int qps = 3 + is_luma;
     236             :             int qp;
     237           0 :             int end = FFMIN(x + 8, width);
     238             : 
     239           0 :             if (p->qp)
     240           0 :                 qp = p->qp;
     241             :             else {
     242           0 :                 qp = qp_store[ (FFMIN(x, width - 1) >> qps) + (FFMIN(y, height - 1) >> qps) * qp_stride];
     243           0 :                 qp = ff_norm_qscale(qp, p->qscale_type);
     244             :             }
     245           0 :             for (; x < end; x++) {
     246           0 :                 const int index = x + y * stride + (8 - 3) * (1 + stride) + 8; //FIXME silly offset
     247           0 :                 uint8_t *src = p_src + index;
     248           0 :                 int16_t *tp  = temp + 4 * x;
     249             :                 int v;
     250             : 
     251           0 :                 if ((x & 3) == 0)
     252           0 :                     dctA_c(tp + 4 * 8, src, stride);
     253             : 
     254           0 :                 p->dctB(block, tp);
     255             : 
     256           0 :                 v = p->requantize(p, block, qp);
     257           0 :                 v = (v + dither[y & 7][x & 7]) >> 6;
     258           0 :                 if ((unsigned)v > 255)
     259           0 :                     v = (-v) >> 31;
     260           0 :                 dst[x + y * dst_stride] = v;
     261             :             }
     262             :         }
     263             :     }
     264             : }
     265             : 
     266           0 : static int query_formats(AVFilterContext *ctx)
     267             : {
     268             :     static const enum AVPixelFormat pix_fmts[] = {
     269             :         AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV422P,
     270             :         AV_PIX_FMT_YUV420P,  AV_PIX_FMT_YUV411P,
     271             :         AV_PIX_FMT_YUV410P,  AV_PIX_FMT_YUV440P,
     272             :         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P,
     273             :         AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
     274             :         AV_PIX_FMT_GBRP,
     275             :         AV_PIX_FMT_GRAY8,    AV_PIX_FMT_NONE
     276             :     };
     277             : 
     278           0 :     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
     279           0 :     if (!fmts_list)
     280           0 :         return AVERROR(ENOMEM);
     281           0 :     return ff_set_common_formats(ctx, fmts_list);
     282             : }
     283             : 
     284           0 : static int config_input(AVFilterLink *inlink)
     285             : {
     286           0 :     AVFilterContext *ctx = inlink->dst;
     287           0 :     PP7Context *pp7 = ctx->priv;
     288           0 :     const int h = FFALIGN(inlink->h + 16, 16);
     289           0 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     290             : 
     291           0 :     pp7->hsub = desc->log2_chroma_w;
     292           0 :     pp7->vsub = desc->log2_chroma_h;
     293             : 
     294           0 :     pp7->temp_stride = FFALIGN(inlink->w + 16, 16);
     295           0 :     pp7->src = av_malloc_array(pp7->temp_stride,  (h + 8) * sizeof(uint8_t));
     296             : 
     297           0 :     if (!pp7->src)
     298           0 :         return AVERROR(ENOMEM);
     299             : 
     300           0 :     init_thres2(pp7);
     301             : 
     302           0 :     switch (pp7->mode) {
     303           0 :         case 0: pp7->requantize = hardthresh_c; break;
     304           0 :         case 1: pp7->requantize = softthresh_c; break;
     305           0 :         default:
     306           0 :         case 2: pp7->requantize = mediumthresh_c; break;
     307             :     }
     308             : 
     309           0 :     pp7->dctB = dctB_c;
     310             : 
     311             :     if (ARCH_X86)
     312           0 :         ff_pp7_init_x86(pp7);
     313             : 
     314           0 :     return 0;
     315             : }
     316             : 
     317           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     318             : {
     319           0 :     AVFilterContext *ctx = inlink->dst;
     320           0 :     PP7Context *pp7 = ctx->priv;
     321           0 :     AVFilterLink *outlink = ctx->outputs[0];
     322           0 :     AVFrame *out = in;
     323             : 
     324           0 :     int qp_stride = 0;
     325           0 :     uint8_t *qp_table = NULL;
     326             : 
     327           0 :     if (!pp7->qp)
     328           0 :         qp_table = av_frame_get_qp_table(in, &qp_stride, &pp7->qscale_type);
     329             : 
     330           0 :     if (!ctx->is_disabled) {
     331           0 :         const int cw = AV_CEIL_RSHIFT(inlink->w, pp7->hsub);
     332           0 :         const int ch = AV_CEIL_RSHIFT(inlink->h, pp7->vsub);
     333             : 
     334             :         /* get a new frame if in-place is not possible or if the dimensions
     335             :         * are not multiple of 8 */
     336           0 :         if (!av_frame_is_writable(in) || (inlink->w & 7) || (inlink->h & 7)) {
     337           0 :             const int aligned_w = FFALIGN(inlink->w, 8);
     338           0 :             const int aligned_h = FFALIGN(inlink->h, 8);
     339             : 
     340           0 :             out = ff_get_video_buffer(outlink, aligned_w, aligned_h);
     341           0 :             if (!out) {
     342           0 :                 av_frame_free(&in);
     343           0 :                 return AVERROR(ENOMEM);
     344             :             }
     345           0 :             av_frame_copy_props(out, in);
     346           0 :             out->width = in->width;
     347           0 :             out->height = in->height;
     348             :         }
     349             : 
     350           0 :         if (qp_table || pp7->qp) {
     351             : 
     352           0 :             filter(pp7, out->data[0], in->data[0], out->linesize[0], in->linesize[0],
     353             :                    inlink->w, inlink->h, qp_table, qp_stride, 1);
     354           0 :             filter(pp7, out->data[1], in->data[1], out->linesize[1], in->linesize[1],
     355             :                    cw,        ch,        qp_table, qp_stride, 0);
     356           0 :             filter(pp7, out->data[2], in->data[2], out->linesize[2], in->linesize[2],
     357             :                    cw,        ch,        qp_table, qp_stride, 0);
     358           0 :             emms_c();
     359             :         }
     360             :     }
     361             : 
     362           0 :     if (in != out) {
     363           0 :         if (in->data[3])
     364           0 :             av_image_copy_plane(out->data[3], out->linesize[3],
     365           0 :                                 in ->data[3], in ->linesize[3],
     366             :                                 inlink->w, inlink->h);
     367           0 :         av_frame_free(&in);
     368             :     }
     369           0 :     return ff_filter_frame(outlink, out);
     370             : }
     371             : 
     372           0 : static av_cold void uninit(AVFilterContext *ctx)
     373             : {
     374           0 :     PP7Context *pp7 = ctx->priv;
     375           0 :     av_freep(&pp7->src);
     376           0 : }
     377             : 
     378             : static const AVFilterPad pp7_inputs[] = {
     379             :     {
     380             :         .name         = "default",
     381             :         .type         = AVMEDIA_TYPE_VIDEO,
     382             :         .config_props = config_input,
     383             :         .filter_frame = filter_frame,
     384             :     },
     385             :     { NULL }
     386             : };
     387             : 
     388             : static const AVFilterPad pp7_outputs[] = {
     389             :     {
     390             :         .name = "default",
     391             :         .type = AVMEDIA_TYPE_VIDEO,
     392             :     },
     393             :     { NULL }
     394             : };
     395             : 
     396             : AVFilter ff_vf_pp7 = {
     397             :     .name            = "pp7",
     398             :     .description     = NULL_IF_CONFIG_SMALL("Apply Postprocessing 7 filter."),
     399             :     .priv_size       = sizeof(PP7Context),
     400             :     .uninit          = uninit,
     401             :     .query_formats   = query_formats,
     402             :     .inputs          = pp7_inputs,
     403             :     .outputs         = pp7_outputs,
     404             :     .priv_class      = &pp7_class,
     405             :     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     406             : };

Generated by: LCOV version 1.13