#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
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;
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;
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);
}
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;
return NAN;
}
-#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
-#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
-
static void select_frame(AVFilterContext *ctx, AVFrame *frame)
{
SelectContext *select = ctx->priv;
}
}
-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);
{ NULL }
};
-AVFilter ff_af_aselect = {
+const AVFilter ff_af_aselect = {
.name = "aselect",
.description = NULL_IF_CONFIG_SMALL("Select audio frames to pass in output."),
.init = aselect_init,
#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);
{ NULL }
};
-AVFilter ff_vf_select = {
+const AVFilter ff_vf_select = {
.name = "select",
.description = NULL_IF_CONFIG_SMALL("Select video frames to pass in output."),
.init = select_init,