X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Ff_select.c;h=755e10a3992d6a34e0931c01d4f63dc1f25cc773;hb=715da295017e8060ded1e16ce995049ee38dae59;hp=b1b2cbc21a985860051a2d6f091750676c855e46;hpb=fb4a12cda4033f2f3d3d1039739f6e0e6f9afb82;p=ffmpeg diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c index b1b2cbc21a9..755e10a3992 100644 --- a/libavfilter/f_select.c +++ b/libavfilter/f_select.c @@ -26,14 +26,16 @@ #include "libavutil/avstring.h" #include "libavutil/eval.h" #include "libavutil/fifo.h" +#include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/opt.h" -#include "libavutil/pixelutils.h" +#include "libavutil/pixdesc.h" #include "avfilter.h" #include "audio.h" #include "formats.h" #include "internal.h" #include "video.h" +#include "scene_sad.h" static const char *const var_names[] = { "TB", ///< timebase @@ -144,8 +146,12 @@ typedef struct SelectContext { char *expr_str; AVExpr *expr; double var_values[VAR_VARS_NB]; + int bitdepth; + int nb_planes; + ptrdiff_t width[4]; + ptrdiff_t height[4]; int do_scene_detect; ///< 1 if the expression requires scene detection variables, 0 otherwise - av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) + ff_scene_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) double prev_mafd; ///< previous MAFD (scene detect only) AVFrame *prev_picref; ///< previous frame (scene detect only) double select; @@ -202,6 +208,21 @@ static av_cold int init(AVFilterContext *ctx) static int config_input(AVFilterLink *inlink) { SelectContext *select = inlink->dst->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + int is_yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB) && + (desc->flags & AV_PIX_FMT_FLAG_PLANAR) && + desc->nb_components >= 3; + + select->bitdepth = desc->comp[0].depth; + select->nb_planes = is_yuv ? 1 : av_pix_fmt_count_planes(inlink->format); + + for (int plane = 0; plane < select->nb_planes; plane++) { + ptrdiff_t line_size = av_image_get_linesize(inlink->format, inlink->w, plane); + int vsub = desc->log2_chroma_h; + + select->width[plane] = line_size >> (select->bitdepth > 8); + select->height[plane] = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(inlink->h, vsub) : inlink->h; + } select->var_values[VAR_N] = 0.0; select->var_values[VAR_SELECTED_N] = 0.0; @@ -241,8 +262,8 @@ static int config_input(AVFilterLink *inlink) select->var_values[VAR_SAMPLE_RATE] = inlink->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN; - if (select->do_scene_detect) { - select->sad = av_pixelutils_get_sad_fn(3, 3, 2, select); // 8x8 both sources aligned + if (CONFIG_SELECT_FILTER && select->do_scene_detect) { + select->sad = ff_scene_sad_get_fn(select->bitdepth == 8 ? 8 : 16); if (!select->sad) return AVERROR(EINVAL); } @@ -258,24 +279,21 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *frame) if (prev_picref && frame->height == prev_picref->height && frame->width == prev_picref->width) { - int x, y, nb_sad = 0; - int64_t sad = 0; + uint64_t sad = 0; double mafd, diff; - uint8_t *p1 = frame->data[0]; - uint8_t *p2 = prev_picref->data[0]; - const int p1_linesize = frame->linesize[0]; - const int p2_linesize = prev_picref->linesize[0]; - - for (y = 0; y < frame->height - 7; y += 8) { - for (x = 0; x < frame->width*3 - 7; x += 8) { - sad += select->sad(p1 + x, p1_linesize, p2 + x, p2_linesize); - nb_sad += 8 * 8; - } - p1 += 8 * p1_linesize; - p2 += 8 * p2_linesize; + uint64_t count = 0; + + for (int plane = 0; plane < select->nb_planes; plane++) { + uint64_t plane_sad; + select->sad(prev_picref->data[plane], prev_picref->linesize[plane], + frame->data[plane], frame->linesize[plane], + select->width[plane], select->height[plane], &plane_sad); + sad += plane_sad; + count += select->width[plane] * select->height[plane]; } + emms_c(); - mafd = nb_sad ? (double)sad / nb_sad : 0; + mafd = (double)sad / count / (1ULL << (select->bitdepth - 8)); diff = fabs(mafd - select->prev_mafd); ret = av_clipf(FFMIN(mafd, diff) / 100., 0, 1); select->prev_mafd = mafd; @@ -430,29 +448,6 @@ static av_cold void uninit(AVFilterContext *ctx) } } -static int query_formats(AVFilterContext *ctx) -{ - SelectContext *select = ctx->priv; - - if (!select->do_scene_detect) { - return ff_default_query_formats(ctx); - } else { - int ret; - static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, - AV_PIX_FMT_NONE - }; - AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); - - if (!fmts_list) - return AVERROR(ENOMEM); - ret = ff_set_common_formats(ctx, fmts_list); - if (ret < 0) - return ret; - } - return 0; -} - #if CONFIG_ASELECT_FILTER DEFINE_OPTIONS(aselect, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); @@ -498,6 +493,33 @@ AVFilter ff_af_aselect = { #if CONFIG_SELECT_FILTER +static int query_formats(AVFilterContext *ctx) +{ + SelectContext *select = ctx->priv; + + if (!select->do_scene_detect) { + return ff_default_query_formats(ctx); + } else { + int ret; + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, AV_PIX_FMT_RGBA, + AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA, AV_PIX_FMT_GRAY8, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_NONE + }; + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + + if (!fmts_list) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, fmts_list); + if (ret < 0) + return ret; + } + return 0; +} + DEFINE_OPTIONS(select, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); AVFILTER_DEFINE_CLASS(select);