From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 0B0F74ABB1 for ; Thu, 13 Jun 2024 18:17:08 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B8B4C68DA2B; Thu, 13 Jun 2024 21:17:05 +0300 (EEST) Received: from mail-ed1-f50.google.com (mail-ed1-f50.google.com [209.85.208.50]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5EA8A6801AA for ; Thu, 13 Jun 2024 21:16:59 +0300 (EEST) Received: by mail-ed1-f50.google.com with SMTP id 4fb4d7f45d1cf-57c758b75c4so184537a12.2 for ; Thu, 13 Jun 2024 11:16:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718302618; x=1718907418; darn=ffmpeg.org; h=thread-index:content-language:mime-version:message-id:date:subject :in-reply-to:references:to:from:from:to:cc:subject:date:message-id :reply-to; bh=jUz75KifPo7OMf5KcBNJ/PSlR6BwJ9V34Wr8qBh4siE=; b=kzhubN7+B3VDWlqk0NCuv7TCw30zdeHVyQqTrNBZlDJkVrSJyxla7insTilXBeoi1p 800dWWW/+065+ohSUgTkekPdQMXBgrZHXpunPcvWn0e1GzrbLmEFbSiM2XXdag0xiphu 0zHmVkMDi5Bef4SqVaZ4FCTdAROhSQBE/Q1qbr+t01u/5hSo07aWCA56duw7DQJTG3Z1 IHB6yO3hWVg3AfxmIX47qKMw9swXws9EtfE+eV5i7FmRNSQ2U8J2WPceMFRv5yfAgjJZ YYHGqvZlws7BurxSjHw6ztsP+sdD3NiURMIeNqhByZT3yEUByMw11e8bos8gvKexa17m xMqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718302618; x=1718907418; h=thread-index:content-language:mime-version:message-id:date:subject :in-reply-to:references:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=jUz75KifPo7OMf5KcBNJ/PSlR6BwJ9V34Wr8qBh4siE=; b=oq+Ympxrs2EKwCV5QKctV/usVuJF79OqMraSeXz2srSnkx3xoeUjojoWu2t1KPcuE0 84BXVb43w0o776ScUTgNkgHgH3RtP3dlloy24mKxCglH3NbfOrzpQIXumriBmKFait6T trbtjvPLhmBVhKp6Xzsai7DgDqYA3sBvLqBfFEisVvZDgllMINvf0ot6OnvEZMQ/LvKb 7zcTYXOfKeEPyc0LBKiV8toRt1DLiW70ENpRug/HEphZWRwsWM6Fuv0wEcD2nlsYFDbj lfmifYKL2LCClyhFdIB0hpUNiP/SrojeMp2U3GbbEJ2j8bR7qMoJU7CIb0sHVKr5YyWI xjRw== X-Gm-Message-State: AOJu0YyvLqegyTnDJxrUJoW2zP+A5EYry0Uk/r3MsaJh304ASzw0TSv9 0/PRVSrq0vML+l2vH03II0Ty9G/sYjoeLcJWmMCCw6k0zuhSq6BOSJiqvQ== X-Google-Smtp-Source: AGHT+IEq0oj8m0poGcx9XAVM5Cn7p6rkKw+z+jXNx2v33t/3u49xbBG8csEX8h9Pg2zOCAEtZulraw== X-Received: by 2002:a17:907:da5:b0:a6f:5fc5:4596 with SMTP id a640c23a62f3a-a6f60e00b93mr35659866b.7.1718302618412; Thu, 13 Jun 2024 11:16:58 -0700 (PDT) Received: from Mishu ([2a02:2f0f:830c:c700:a4f7:3c24:5d9d:9f1e]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f56f40fd7sm97732466b.147.2024.06.13.11.16.57 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 13 Jun 2024 11:16:57 -0700 (PDT) From: To: "'FFmpeg development discussions and patches'" References: <000c01daa54d$8a0eedf0$9e2cc9d0$@gmail.com> <20240530213132.GE2821752@pb2> <008e01dab529$e5510630$aff31290$@gmail.com> <20240603224202.GD2821752@pb2> <001001dabbce$083f3c70$18bdb550$@gmail.com> <20240611171808.GP2821752@pb2> <005401dabd01$f66608f0$e3321ad0$@gmail.com> <1f77eae3-b3f2-477b-afe1-e31dc56917fa@noa-archive.com> <00c701dabd83$d33e1e80$79ba5b80$@gmail.com> <1fc50e5a-2400-40ff-92d9-b97889fd441e@noa-archive.com> <00c801dabd98$90dfb6b0$b29f2410$@gmail.com> In-Reply-To: <00c801dabd98$90dfb6b0$b29f2410$@gmail.com> Date: Thu, 13 Jun 2024 21:16:57 +0300 Message-ID: <00cf01dabdbd$e100de10$a3029a30$@gmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_00D0_01DABDD7.064E1610" X-Mailer: Microsoft Outlook 16.0 Content-Language: ro Thread-Index: Adq9va+ZE7GiupybSd2Qc5aqhtx/Jg== Subject: Re: [FFmpeg-devel] [PATCH v4] area changed: scdet filter X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: This is a multipart message in MIME format. ------=_NextPart_000_00D0_01DABDD7.064E1610 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Update as discussed ------=_NextPart_000_00D0_01DABDD7.064E1610 Content-Type: application/octet-stream; name="0001-area-changed-scdet-filter.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="0001-area-changed-scdet-filter.patch" >From 9cc9ecd9fe5df9b83251cfbd3fa1d5c94e1d4e86 Mon Sep 17 00:00:00 2001=0A= From: raduct =0A= Date: Wed, 8 May 2024 08:24:46 +0300=0A= Subject: [PATCH] area changed: scdet filter=0A= =0A= Improve scene detection accuracy by comparing frame with both previous = and next frame (creates one frame delay).=0A= Add new mode parameter and new method to compute the frame difference = using cubic square to increase the weight of small changes and new mean = formula. This improves accuracy significantly. Slightly improve = performance by not using frame clone.=0A= Add legacy mode for backward compatibility.=0A= =0A= Signed-off-by: raduct =0A= ---=0A= doc/filters.texi | 16 +++=0A= libavfilter/scene_sad.c | 153 ++++++++++++++++++++++++=0A= libavfilter/scene_sad.h | 20 ++++=0A= libavfilter/vf_scdet.c | 164 ++++++++++++++++++--------=0A= tests/fate/filter-video.mak | 3 +=0A= tests/ref/fate/filter-metadata-scdet1 | 13 ++=0A= 6 files changed, 321 insertions(+), 48 deletions(-)=0A= create mode 100644 tests/ref/fate/filter-metadata-scdet1=0A= =0A= diff --git a/doc/filters.texi b/doc/filters.texi=0A= index bfa8ccec8b..075fb5863a 100644=0A= --- a/doc/filters.texi=0A= +++ b/doc/filters.texi=0A= @@ -21797,6 +21797,22 @@ Default value is @code{10.}.=0A= @item sc_pass, s=0A= Set the flag to pass scene change frames to the next filter. Default = value is @code{0}=0A= You can enable it if you want to get snapshot of scene change frames = only.=0A= +=0A= +@item mode=0A= +Set the scene change detection method. Default value is @code{0}=0A= +Available values are:=0A= +=0A= +@table @samp=0A= +@item 0=0A= +No delay mode for sum of absolute linear differences. Compare frame = with previous only and no delay.=0A= +=0A= +@item 1=0A= +Sum of absolute linear differences. Compare frame with both previous = and next which introduces a 1 frame delay.=0A= +=0A= +@item 2=0A= +Sum of mean of cubic root differences. Compare frame with both previous = and next which introduces a 1 frame delay.=0A= +=0A= +@end table=0A= @end table=0A= =0A= @anchor{selectivecolor}=0A= diff --git a/libavfilter/scene_sad.c b/libavfilter/scene_sad.c=0A= index caf911eb5d..d7a11959b0 100644=0A= --- a/libavfilter/scene_sad.c=0A= +++ b/libavfilter/scene_sad.c=0A= @@ -21,6 +21,8 @@=0A= * Scene SAD functions=0A= */=0A= =0A= +#include "libavutil/mem.h"=0A= +#include "libavutil/thread.h"=0A= #include "scene_sad.h"=0A= =0A= void ff_scene_sad16_c(SCENE_SAD_PARAMS)=0A= @@ -71,3 +73,154 @@ ff_scene_sad_fn ff_scene_sad_get_fn(int depth)=0A= return sad;=0A= }=0A= =0A= +static AVMutex cbrt_mutex =3D AV_MUTEX_INITIALIZER;=0A= +static uint8_t *cbrt_table[16] =3D { NULL };=0A= +static int cbrt_table_ref[16] =3D { 0 };=0A= +=0A= +int ff_init_cbrt(int bitdepth)=0A= +{=0A= + uint8_t *table;=0A= + int size;=0A= +=0A= + if (bitdepth < 4 || bitdepth > 16)=0A= + return AVERROR(EINVAL);=0A= +=0A= + ff_mutex_lock(&cbrt_mutex);=0A= +=0A= + table =3D cbrt_table[bitdepth];=0A= + if (table) {=0A= + cbrt_table_ref[bitdepth]++;=0A= + goto end;=0A= + }=0A= +=0A= + table =3D av_malloc((1 << bitdepth) * (bitdepth > 8 ? 2 : 1));=0A= + if (!table)=0A= + goto end;=0A= + cbrt_table[bitdepth] =3D table;=0A= + cbrt_table_ref[bitdepth] =3D 1;=0A= +=0A= + size =3D 1 << bitdepth;=0A= + double factor =3D pow(size - 1, 2. / 3.);=0A= + if (bitdepth <=3D 8) {=0A= + for (int i =3D 0; i < size; i++)=0A= + table[i] =3D round(factor * pow(i, 1. / 3.));=0A= + } else {=0A= + uint16_t *tablew =3D (uint16_t*)table;=0A= + for (int i =3D 0; i < size; i++)=0A= + tablew[i] =3D round(factor * pow(i, 1. / 3.));=0A= + }=0A= +=0A= +end:=0A= + ff_mutex_unlock(&cbrt_mutex);=0A= + return table !=3D NULL;=0A= +}=0A= +=0A= +void ff_uninit_cbrt(int bitdepth)=0A= +{=0A= + if (bitdepth < 4 || bitdepth > 16)=0A= + return;=0A= + ff_mutex_lock(&cbrt_mutex);=0A= + if (!--cbrt_table_ref[bitdepth]) {=0A= + av_free(cbrt_table[bitdepth]);=0A= + cbrt_table[bitdepth] =3D NULL;=0A= + }=0A= + ff_mutex_unlock(&cbrt_mutex);=0A= +}=0A= +=0A= +void ff_scene_scrd_c(SCENE_SAD_PARAMS)=0A= +{=0A= + uint64_t scrdPlus =3D 0;=0A= + uint64_t scrdMinus =3D 0;=0A= + int x, y;=0A= + uint8_t *table =3D cbrt_table[8];=0A= +=0A= + if (!table) {=0A= + *sum =3D 0;=0A= + return;=0A= + }=0A= +=0A= + for (y =3D 0; y < height; y++) {=0A= + for (x =3D 0; x < width; x++)=0A= + if (src1[x] > src2[x])=0A= + scrdMinus +=3D table[src1[x] - src2[x]];=0A= + else=0A= + scrdPlus +=3D table[src2[x] - src1[x]];=0A= + src1 +=3D stride1;=0A= + src2 +=3D stride2;=0A= + }=0A= +=0A= + *sum =3D 0.5 * (scrdPlus + scrdMinus) + sqrt((double)scrdPlus * = scrdMinus);=0A= +}=0A= +=0A= +void ff_scene_scrd2B_c(SCENE_SAD_PARAMS, int bitdepth)=0A= +{=0A= + uint64_t scrdPlus =3D 0;=0A= + uint64_t scrdMinus =3D 0;=0A= + const uint16_t *src1w =3D (const uint16_t*)src1;=0A= + const uint16_t *src2w =3D (const uint16_t*)src2;=0A= + int x, y;=0A= + uint16_t *table =3D (uint16_t*)cbrt_table[bitdepth];=0A= +=0A= + if (!table) {=0A= + *sum =3D 0;=0A= + return;=0A= + }=0A= +=0A= + stride1 /=3D 2;=0A= + stride2 /=3D 2;=0A= +=0A= + for (y =3D 0; y < height; y++) {=0A= + for (x =3D 0; x < width; x++)=0A= + if (src1w[x] > src2w[x])=0A= + scrdMinus +=3D table[src1w[x] - src2w[x]];=0A= + else=0A= + scrdPlus +=3D table[src2w[x] - src1w[x]];=0A= + src1w +=3D stride1;=0A= + src2w +=3D stride2;=0A= + }=0A= +=0A= + *sum =3D 0.5 * (scrdPlus + scrdMinus) + sqrt((double)scrdPlus * = scrdMinus);=0A= +}=0A= +=0A= +void ff_scene_scrd9_c(SCENE_SAD_PARAMS)=0A= +{=0A= + ff_scene_scrd2B_c(src1, stride1, src2, stride2, width, height, sum, = 9);=0A= +}=0A= +=0A= +void ff_scene_scrd10_c(SCENE_SAD_PARAMS)=0A= +{=0A= + ff_scene_scrd2B_c(src1, stride1, src2, stride2, width, height, sum, = 10);=0A= +}=0A= +=0A= +void ff_scene_scrd12_c(SCENE_SAD_PARAMS)=0A= +{=0A= + ff_scene_scrd2B_c(src1, stride1, src2, stride2, width, height, sum, = 12);=0A= +}=0A= +=0A= +void ff_scene_scrd14_c(SCENE_SAD_PARAMS)=0A= +{=0A= + ff_scene_scrd2B_c(src1, stride1, src2, stride2, width, height, sum, = 14);=0A= +}=0A= +=0A= +void ff_scene_scrd16_c(SCENE_SAD_PARAMS)=0A= +{=0A= + ff_scene_scrd2B_c(src1, stride1, src2, stride2, width, height, sum, = 16);=0A= +}=0A= +=0A= +ff_scene_sad_fn ff_scene_scrd_get_fn(int depth)=0A= +{=0A= + ff_scene_sad_fn scrd =3D NULL;=0A= + if (depth =3D=3D 8)=0A= + scrd =3D ff_scene_scrd_c;=0A= + else if (depth =3D=3D 9)=0A= + scrd =3D ff_scene_scrd9_c;=0A= + else if (depth =3D=3D 10)=0A= + scrd =3D ff_scene_scrd10_c;=0A= + else if (depth =3D=3D 12)=0A= + scrd =3D ff_scene_scrd12_c;=0A= + else if (depth =3D=3D 14)=0A= + scrd =3D ff_scene_scrd14_c;=0A= + else if (depth =3D=3D 16)=0A= + scrd =3D ff_scene_scrd16_c;=0A= + return scrd;=0A= +}=0A= diff --git a/libavfilter/scene_sad.h b/libavfilter/scene_sad.h=0A= index 173a051f2b..dd20e1a259 100644=0A= --- a/libavfilter/scene_sad.h=0A= +++ b/libavfilter/scene_sad.h=0A= @@ -41,4 +41,24 @@ ff_scene_sad_fn ff_scene_sad_get_fn_x86(int depth);=0A= =0A= ff_scene_sad_fn ff_scene_sad_get_fn(int depth);=0A= =0A= +void ff_scene_scrd_c(SCENE_SAD_PARAMS);=0A= +=0A= +void ff_scene_scrd2B_c(SCENE_SAD_PARAMS, int bitdepth);=0A= +=0A= +void ff_scene_scrd9_c(SCENE_SAD_PARAMS);=0A= +=0A= +void ff_scene_scrd10_c(SCENE_SAD_PARAMS);=0A= +=0A= +void ff_scene_scrd12_c(SCENE_SAD_PARAMS);=0A= +=0A= +void ff_scene_scrd14_c(SCENE_SAD_PARAMS);=0A= +=0A= +void ff_scene_scrd16_c(SCENE_SAD_PARAMS);=0A= +=0A= +ff_scene_sad_fn ff_scene_scrd_get_fn(int depth);=0A= +=0A= +int ff_init_cbrt(int bitdepth);=0A= +=0A= +void ff_uninit_cbrt(int bitdepth);=0A= +=0A= #endif /* AVFILTER_SCENE_SAD_H */=0A= diff --git a/libavfilter/vf_scdet.c b/libavfilter/vf_scdet.c=0A= index 15399cfebf..1d3e932c55 100644=0A= --- a/libavfilter/vf_scdet.c=0A= +++ b/libavfilter/vf_scdet.c=0A= @@ -31,6 +31,18 @@=0A= #include "scene_sad.h"=0A= #include "video.h"=0A= =0A= +enum SCDETMode {=0A= + MODE_NODELAY =3D 0,=0A= + MODE_LINEAR =3D 1,=0A= + MODE_MEAN_CBRT =3D 2=0A= +};=0A= +=0A= +typedef struct SCDETFrameInfo {=0A= + AVFrame *picref;=0A= + double mafd;=0A= + double diff;=0A= +} SCDETFrameInfo;=0A= +=0A= typedef struct SCDetContext {=0A= const AVClass *class;=0A= =0A= @@ -39,11 +51,12 @@ typedef struct SCDetContext {=0A= int nb_planes;=0A= int bitdepth;=0A= ff_scene_sad_fn sad;=0A= - double prev_mafd;=0A= - double scene_score;=0A= - AVFrame *prev_picref;=0A= + SCDETFrameInfo curr_frame;=0A= + SCDETFrameInfo prev_frame;=0A= +=0A= double threshold;=0A= int sc_pass;=0A= + enum SCDETMode mode;=0A= } SCDetContext;=0A= =0A= #define OFFSET(x) offsetof(SCDetContext, x)=0A= @@ -55,6 +68,7 @@ static const AVOption scdet_options[] =3D {=0A= { "t", "set scene change detect threshold", = OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl =3D 10.}, 0, 100., = V|F },=0A= { "sc_pass", "Set the flag to pass scene change frames", = OFFSET(sc_pass), AV_OPT_TYPE_BOOL, {.dbl =3D 0 }, 0, 1, = V|F },=0A= { "s", "Set the flag to pass scene change frames", = OFFSET(sc_pass), AV_OPT_TYPE_BOOL, {.dbl =3D 0 }, 0, 1, = V|F },=0A= + { "mode", "scene change detection method", = OFFSET(mode), AV_OPT_TYPE_INT, {.i64 =3D MODE_NODELAY}, = MODE_NODELAY, MODE_MEAN_CBRT, V|F },=0A= {NULL}=0A= };=0A= =0A= @@ -91,7 +105,14 @@ static int config_input(AVFilterLink *inlink)=0A= s->height[plane] =3D inlink->h >> ((plane =3D=3D 1 || plane = =3D=3D 2) ? desc->log2_chroma_h : 0);=0A= }=0A= =0A= - s->sad =3D ff_scene_sad_get_fn(s->bitdepth =3D=3D 8 ? 8 : 16);=0A= + if (s->mode =3D=3D MODE_LINEAR || s->mode =3D=3D MODE_NODELAY)=0A= + s->sad =3D ff_scene_sad_get_fn(s->bitdepth =3D=3D 8 ? 8 : 16);=0A= + else if (s->mode =3D=3D MODE_MEAN_CBRT) {=0A= + int ret =3D ff_init_cbrt(s->bitdepth);=0A= + if (ret < 0)=0A= + return ret;=0A= + s->sad =3D ff_scene_scrd_get_fn(s->bitdepth);=0A= + }=0A= if (!s->sad)=0A= return AVERROR(EINVAL);=0A= =0A= @@ -101,46 +122,102 @@ static int config_input(AVFilterLink *inlink)=0A= static av_cold void uninit(AVFilterContext *ctx)=0A= {=0A= SCDetContext *s =3D ctx->priv;=0A= -=0A= - av_frame_free(&s->prev_picref);=0A= + if (s->mode =3D=3D MODE_NODELAY)=0A= + av_frame_free(&s->prev_frame.picref);=0A= + if (s->mode =3D=3D MODE_MEAN_CBRT)=0A= + ff_uninit_cbrt(s->bitdepth);=0A= }=0A= =0A= -static double get_scene_score(AVFilterContext *ctx, AVFrame *frame)=0A= +static void compute_diff(AVFilterContext *ctx)=0A= {=0A= - double ret =3D 0;=0A= SCDetContext *s =3D ctx->priv;=0A= - AVFrame *prev_picref =3D s->prev_picref;=0A= + AVFrame *prev_picref =3D s->prev_frame.picref;=0A= + AVFrame *curr_picref =3D s->curr_frame.picref;=0A= =0A= - if (prev_picref && frame->height =3D=3D prev_picref->height=0A= - && frame->width =3D=3D prev_picref->width) {=0A= - uint64_t sad =3D 0;=0A= - double mafd, diff;=0A= - uint64_t count =3D 0;=0A= + if (prev_picref && curr_picref=0A= + && curr_picref->height =3D=3D prev_picref->height=0A= + && curr_picref->width =3D=3D prev_picref->width) {=0A= =0A= + uint64_t sum =3D 0;=0A= + uint64_t count =3D 0;=0A= for (int plane =3D 0; plane < s->nb_planes; plane++) {=0A= - uint64_t plane_sad;=0A= + uint64_t plane_sum;=0A= s->sad(prev_picref->data[plane], = prev_picref->linesize[plane],=0A= - frame->data[plane], frame->linesize[plane],=0A= - s->width[plane], s->height[plane], &plane_sad);=0A= - sad +=3D plane_sad;=0A= + curr_picref->data[plane], = curr_picref->linesize[plane],=0A= + s->width[plane], s->height[plane], &plane_sum);=0A= + sum +=3D plane_sum;=0A= count +=3D s->width[plane] * s->height[plane];=0A= }=0A= =0A= - mafd =3D (double)sad * 100. / count / (1ULL << s->bitdepth);=0A= - diff =3D fabs(mafd - s->prev_mafd);=0A= - ret =3D av_clipf(FFMIN(mafd, diff), 0, 100.);=0A= - s->prev_mafd =3D mafd;=0A= - av_frame_free(&prev_picref);=0A= + s->curr_frame.mafd =3D (double)sum * 100. / count / (1ULL << = s->bitdepth);=0A= + s->curr_frame.diff =3D s->curr_frame.mafd - s->prev_frame.mafd;=0A= + if (s->mode =3D=3D MODE_NODELAY)=0A= + s->curr_frame.diff =3D fabs(s->curr_frame.diff);=0A= + } else {=0A= + s->curr_frame.mafd =3D 0;=0A= + s->curr_frame.diff =3D 0;=0A= }=0A= - s->prev_picref =3D av_frame_clone(frame);=0A= - return ret;=0A= }=0A= =0A= -static int set_meta(SCDetContext *s, AVFrame *frame, const char *key, = const char *value)=0A= +static int set_meta(AVFrame *frame, const char *key, const char *value)=0A= {=0A= return av_dict_set(&frame->metadata, key, value, 0);=0A= }=0A= =0A= +static int filter_frame(AVFilterContext *ctx, AVFrame *frame)=0A= +{=0A= + AVFilterLink *inlink =3D ctx->inputs[0];=0A= + AVFilterLink *outlink =3D ctx->outputs[0];=0A= + SCDetContext *s =3D ctx->priv;=0A= +=0A= + s->prev_frame =3D s->curr_frame;=0A= + s->curr_frame.picref =3D frame;=0A= +=0A= + if ((s->mode !=3D MODE_NODELAY && s->prev_frame.picref) || (s->mode = =3D=3D MODE_NODELAY && frame !=3D NULL)) {=0A= + SCDETFrameInfo fwd_frame;=0A= + double scene_score;=0A= + char buf[64];=0A= +=0A= + compute_diff(ctx);=0A= +=0A= + if (s->mode =3D=3D MODE_NODELAY) {=0A= + av_frame_free(&s->prev_frame.picref);=0A= + fwd_frame =3D s->curr_frame;=0A= + s->curr_frame.picref =3D = av_frame_clone(s->curr_frame.picref);=0A= + } else {=0A= + if (s->prev_frame.diff < -s->curr_frame.diff) {=0A= + s->prev_frame.diff =3D -s->curr_frame.diff;=0A= + s->prev_frame.mafd =3D s->curr_frame.mafd;=0A= + }=0A= + fwd_frame =3D s->prev_frame;=0A= + }=0A= + scene_score =3D av_clipf(s->mode =3D=3D MODE_NODELAY ? = FFMIN(fwd_frame.mafd, fwd_frame.diff) : FFMAX(fwd_frame.diff, 0), 0, = 100.);=0A= +=0A= + snprintf(buf, sizeof(buf), "%0.3f", fwd_frame.mafd);=0A= + set_meta(fwd_frame.picref, "lavfi.scd.mafd", buf);=0A= + snprintf(buf, sizeof(buf), "%0.3f", scene_score);=0A= + set_meta(fwd_frame.picref, "lavfi.scd.score", buf);=0A= +=0A= + if (scene_score >=3D s->threshold) {=0A= + av_log(s, AV_LOG_INFO, "lavfi.scd.score: %.3f, = lavfi.scd.time: %s\n",=0A= + scene_score, av_ts2timestr(fwd_frame.picref->pts, = &inlink->time_base));=0A= + set_meta(fwd_frame.picref, "lavfi.scd.time",=0A= + av_ts2timestr(fwd_frame.picref->pts, = &inlink->time_base));=0A= + }=0A= +=0A= + if (s->sc_pass) {=0A= + if (scene_score >=3D s->threshold)=0A= + return ff_filter_frame(outlink, fwd_frame.picref);=0A= + else=0A= + av_frame_free(&fwd_frame.picref);=0A= + }=0A= + else=0A= + return ff_filter_frame(outlink, fwd_frame.picref);=0A= + }=0A= +=0A= + return 0;=0A= +}=0A= +=0A= static int activate(AVFilterContext *ctx)=0A= {=0A= int ret;=0A= @@ -148,6 +225,8 @@ static int activate(AVFilterContext *ctx)=0A= AVFilterLink *outlink =3D ctx->outputs[0];=0A= SCDetContext *s =3D ctx->priv;=0A= AVFrame *frame;=0A= + int64_t pts;=0A= + int status;=0A= =0A= FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);=0A= =0A= @@ -155,31 +234,20 @@ static int activate(AVFilterContext *ctx)=0A= if (ret < 0)=0A= return ret;=0A= =0A= - if (frame) {=0A= - char buf[64];=0A= - s->scene_score =3D get_scene_score(ctx, frame);=0A= - snprintf(buf, sizeof(buf), "%0.3f", s->prev_mafd);=0A= - set_meta(s, frame, "lavfi.scd.mafd", buf);=0A= - snprintf(buf, sizeof(buf), "%0.3f", s->scene_score);=0A= - set_meta(s, frame, "lavfi.scd.score", buf);=0A= + if (ret > 0) {=0A= + ret =3D filter_frame(ctx, frame);=0A= + if (ret < 0)=0A= + return ret;=0A= + }=0A= =0A= - if (s->scene_score >=3D s->threshold) {=0A= - av_log(s, AV_LOG_INFO, "lavfi.scd.score: %.3f, = lavfi.scd.time: %s\n",=0A= - s->scene_score, av_ts2timestr(frame->pts, = &inlink->time_base));=0A= - set_meta(s, frame, "lavfi.scd.time",=0A= - av_ts2timestr(frame->pts, &inlink->time_base));=0A= - }=0A= - if (s->sc_pass) {=0A= - if (s->scene_score >=3D s->threshold)=0A= - return ff_filter_frame(outlink, frame);=0A= - else {=0A= - av_frame_free(&frame);=0A= - }=0A= - } else=0A= - return ff_filter_frame(outlink, frame);=0A= + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {=0A= + if (status =3D=3D AVERROR_EOF)=0A= + ret =3D filter_frame(ctx, NULL);=0A= +=0A= + ff_outlink_set_status(outlink, status, pts);=0A= + return ret;=0A= }=0A= =0A= - FF_FILTER_FORWARD_STATUS(inlink, outlink);=0A= FF_FILTER_FORWARD_WANTED(outlink, inlink);=0A= =0A= return FFERROR_NOT_READY;=0A= diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak=0A= index ee9f0f5e40..24d921153a 100644=0A= --- a/tests/fate/filter-video.mak=0A= +++ b/tests/fate/filter-video.mak=0A= @@ -672,6 +672,9 @@ SCDET_DEPS =3D LAVFI_INDEV FILE_PROTOCOL = MOVIE_FILTER SCDET_FILTER SCALE_FILTER \=0A= FATE_METADATA_FILTER-$(call ALLYES, $(SCDET_DEPS)) +=3D = fate-filter-metadata-scdet=0A= fate-filter-metadata-scdet: SRC =3D = $(TARGET_SAMPLES)/svq3/Vertical400kbit.sorenson3.mov=0A= fate-filter-metadata-scdet: CMD =3D run $(FILTER_METADATA_COMMAND) = "sws_flags=3D+accurate_rnd+bitexact;movie=3D'$(SRC)',scdet=3Ds=3D1"=0A= +FATE_METADATA_FILTER-$(call ALLYES, $(SCDET_DEPS)) +=3D = fate-filter-metadata-scdet1=0A= +fate-filter-metadata-scdet1: SRC =3D = $(TARGET_SAMPLES)/svq3/Vertical400kbit.sorenson3.mov=0A= +fate-filter-metadata-scdet1: CMD =3D run $(FILTER_METADATA_COMMAND) = "sws_flags=3D+accurate_rnd+bitexact;movie=3D'$(SRC)',scdet=3Ds=3D1:t=3D30= :mode=3D2"=0A= =0A= CROPDETECT_DEPS =3D LAVFI_INDEV FILE_PROTOCOL MOVIE_FILTER MOVIE_FILTER = MESTIMATE_FILTER CROPDETECT_FILTER \=0A= SCALE_FILTER MOV_DEMUXER H264_DECODER=0A= diff --git a/tests/ref/fate/filter-metadata-scdet1 = b/tests/ref/fate/filter-metadata-scdet1=0A= new file mode 100644=0A= index 0000000000..0c60b3fc80=0A= --- /dev/null=0A= +++ b/tests/ref/fate/filter-metadata-scdet1=0A= @@ -0,0 +1,13 @@=0A= +pts=3D1620|tag:lavfi.scd.score=3D41.567|tag:lavfi.scd.mafd=3D0.279|tag:l= avfi.scd.time=3D2.7=0A= +pts=3D4020|tag:lavfi.scd.score=3D31.824|tag:lavfi.scd.mafd=3D5.039|tag:l= avfi.scd.time=3D6.7=0A= +pts=3D4060|tag:lavfi.scd.score=3D32.793|tag:lavfi.scd.mafd=3D37.833|tag:= lavfi.scd.time=3D6.766667=0A= +pts=3D5800|tag:lavfi.scd.score=3D40.633|tag:lavfi.scd.mafd=3D40.633|tag:= lavfi.scd.time=3D9.666667=0A= +pts=3D6720|tag:lavfi.scd.score=3D57.019|tag:lavfi.scd.mafd=3D0.313|tag:l= avfi.scd.time=3D11.2=0A= +pts=3D8160|tag:lavfi.scd.score=3D34.500|tag:lavfi.scd.mafd=3D38.651|tag:= lavfi.scd.time=3D13.6=0A= +pts=3D9760|tag:lavfi.scd.score=3D31.848|tag:lavfi.scd.mafd=3D39.432|tag:= lavfi.scd.time=3D16.266667=0A= +pts=3D13740|tag:lavfi.scd.score=3D30.266|tag:lavfi.scd.mafd=3D2.976|tag:= lavfi.scd.time=3D22.9=0A= +pts=3D13780|tag:lavfi.scd.score=3D31.131|tag:lavfi.scd.mafd=3D34.106|tag= :lavfi.scd.time=3D22.966667=0A= +pts=3D14080|tag:lavfi.scd.score=3D31.244|tag:lavfi.scd.mafd=3D34.654|tag= :lavfi.scd.time=3D23.466667=0A= +pts=3D15700|tag:lavfi.scd.score=3D41.191|tag:lavfi.scd.mafd=3D41.292|tag= :lavfi.scd.time=3D26.166667=0A= +pts=3D18500|tag:lavfi.scd.score=3D48.512|tag:lavfi.scd.mafd=3D5.036|tag:= lavfi.scd.time=3D30.833333=0A= +pts=3D21760|tag:lavfi.scd.score=3D41.083|tag:lavfi.scd.mafd=3D42.842|tag= :lavfi.scd.time=3D36.266667=0A= -- =0A= 2.44.1.windows.1=0A= =0A= ------=_NextPart_000_00D0_01DABDD7.064E1610 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". ------=_NextPart_000_00D0_01DABDD7.064E1610--