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 5064D4AA95 for ; Tue, 11 Jun 2024 07:07:46 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 1310368D7AF; Tue, 11 Jun 2024 10:07:44 +0300 (EEST) Received: from mail-ej1-f45.google.com (mail-ej1-f45.google.com [209.85.218.45]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E281768D789 for ; Tue, 11 Jun 2024 10:07:36 +0300 (EEST) Received: by mail-ej1-f45.google.com with SMTP id a640c23a62f3a-a6f0d8f7794so23969066b.1 for ; Tue, 11 Jun 2024 00:07:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718089656; x=1718694456; 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=52PdOo2CN6amdD6xHy4kb6ZI0+0sN4vEM1r6ylQlrlw=; b=Biu/Td92VSsmt5roQR4woncxJuEv6vNtPaJaPBR3m6EFqjfEFPmuSKSTbnf40JhgUp X8JU7tNQxJw+QC7ThldMupBanFGREd3N23biYshem/djTJzHChLQe8lunoJnbgOVFmhp HEFnWKgnVdvX5qsQtTbcDBnxYKEhuHWrTpiUqsdXHmvtTDcCdfi6zmRF6AyHq2D9F3kO 61VH1PQ64VAl7092hQVEIsBeyKfiP1HGe87D+1CQR7eqoJM/lxJ2J/ZcIazhdHeChyRn ceIhOIsCnjFA/ozTEzgrKcafAsR8U2Aq1q0W+AcJgytULcYYUDDArfcJf98vTrDcfFOs ok4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718089656; x=1718694456; 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=52PdOo2CN6amdD6xHy4kb6ZI0+0sN4vEM1r6ylQlrlw=; b=FajwXcUz9nnlZZZY+KAz3/0wyRKgV8LB9fozAXxBle4croQQTrM4g+lq48KyTlwxUv tJ72IeV51NOuhZD4Zz75ksqMF9dMvVCxIOIeXfA5jDTKpTyKEzvqSB+2OGQQEXvzDV3Z QDbtin/pCeTIY2BR/Ok6EF/MskFwiEzMJ76h6eXCiKBGbZRzbtvwHFJNCYOV9StGesAA UPueeTa1cbDcLRqfO3u3PgXiGHITm144YhhO75HV61/yUlkw5mk2sBZZAGIiFfWz13KG r2oOWTnPRNh/JubfCaSjVvbW612w8jmu59vRmZ42YdKewFAlG3kZlMEbB9QGxzcsiIuY KPRQ== X-Gm-Message-State: AOJu0YwqP3870tt5V9Z8Z2UW3cFC88ORNm1E8LwOXeFgmRNRaNMNLP0a /aZv9gs1nnYt5wgMQR2bQbeUY3vs+edL6+Jp0ha19Ike0cDzh7kkszTZAw== X-Google-Smtp-Source: AGHT+IEoubFxxJRrYx+0W/KVcJ9UOlndJNS2k6hzTTK9c0UaOlOnEEUtNWB5vp2sgcakDWj467Yi8g== X-Received: by 2002:a17:907:1006:b0:a6e:f52a:c355 with SMTP id a640c23a62f3a-a6ef52ac426mr645769166b.7.1718089655802; Tue, 11 Jun 2024 00:07:35 -0700 (PDT) Received: from Mishu ([2a02:2f0f:830c:c700:c53c:1493:3200:5ac6]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a6f34591542sm74997866b.55.2024.06.11.00.07.33 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 11 Jun 2024 00:07:34 -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> In-Reply-To: <20240603224202.GD2821752@pb2> Date: Tue, 11 Jun 2024 10:07:32 +0300 Message-ID: <001001dabbce$083f3c70$18bdb550$@gmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0011_01DABBE7.2D8DFB10" X-Mailer: Microsoft Outlook 16.0 Content-Language: ro Thread-Index: Adq7zb1wZDOgLX4YRIWSUOKiW4IEdg== Subject: Re: [FFmpeg-devel] [PATCH v2] 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_0011_01DABBE7.2D8DFB10 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable > -----Original Message----- > From: ffmpeg-devel On Behalf Of > Michael Niedermayer > Sent: mar=C8=9Bi, 4 iunie 2024 01:42 > To: FFmpeg development discussions and patches = > Subject: Re: [FFmpeg-devel] [PATCH] area changed: scdet filter >=20 > On Sun, Jun 02, 2024 at 11:17:29PM +0300, radu.taraibuta@gmail.com = wrote: > > > > > > > -----Original Message----- > > > From: ffmpeg-devel On Behalf Of > > > Michael Niedermayer > > > Sent: vineri, 31 mai 2024 00:32 > > > To: FFmpeg development discussions and patches > > > > > > Subject: Re: [FFmpeg-devel] [PATCH] area changed: scdet filter > > > > > > On Mon, May 13, 2024 at 06:52:19PM +0300, radu.taraibuta@gmail.com > > > wrote: > > > > Previous observations: > > > > > > > > - Inconsistent code style with other filters. (Mostly using > > > > AVFilterLink* link instead of AVFilterLink *link). > > > > I hope it's fine now. > > > > > > > > - Unrelated changes, please split trivial unrelated changes = into > > > > separate patches. > > > > Removed trivial changes from this patch. > > > > > > > > - Can't tables be generated at .init/.config_props time? No = point > > > > in storing them into binary. > > > > Done. > > > > > > > > - Adding extra delay is not backward compatible change, it = should > > > > be implemented properly by adding option for users to select = mode: > > > > next & prev frame or just next or prev frame. > > > > Added legacy option to the mode parameter. > > > > > > > > - Could split frame clone change into earlier separate patch. > > > > Cannot be done. It's either frame clone or 1 frame delay. > > > > > > > > - Where are results of improvements with accuracy so it can be > > confirmed? > > > > Here are my test results with manual labeling of scene changes: > > > > 2379 Full length movie > > > > > > > > Method Threshold TP FP FN Precision > > > > Recall F > > > > Cubic 7 2357 423 22 0.847841727 > > 0.990752417 > > > > 0.913742973 > > > > Cubic 10 2297 200 82 0.919903885 > > 0.965531736 > > > > 0.94216571 > > > > Cubic 12 2217 146 162 0.938214135 > > 0.931904161 > > > > 0.935048503 > > > > Cubic 15 2049 101 330 0.953023256 > > 0.861286255 > > > > 0.904835505 > > > > Linear 2.8 2357 1060 22 0.689786362 > > 0.990752417 > > > > 0.813319531 > > > > Linear 8 2099 236 280 0.898929336 > > 0.882303489 > > > > 0.890538821 > > > > Linear 10 1886 173 493 0.91597863 > > 0.792770071 > > > > 0.849932402 > > > > Legacy 5 2235 1260 144 0.639484979 > > > 0.939470366 > > > > 0.760980592 > > > > Legacy 8 1998 414 381 0.828358209 > > > 0.839848676 > > > > 0.83406387 > > > > Legacy 10 1743 193 636 0.900309917 > > > 0.732660782 > > > > 0.80787949 > > > > > > > > 15 HDR10Plus_PB_EAC3JOC > > > > https://mega.nz/file/nehDka6Z#C5_OPbSZkONdOp1jRmc09C9- > > > viDc3zMj8ZHruHcW > > > > KyA > > > > > > > > Method Threshold TP FP FN Precision > > > > Recall F > > > > Cubic 10 15 0 0 1 1 1 > > > > Linear 5 13 1 2 0.928571429 > > 0.866666667 > > > > 0.896551724 > > > > Legacy 5 12 2 3 0.857142857 0.8 > > > > 0.827586207 > > > > > > > > 21 (HDR HEVC 10-bit BT.2020 24fps) Exodus Sample > > > > > > > > https://mega.nz/file/Sfw1hDpK#ErxCOpQDVjcI1gq6ZbX3vIfdtXZompkFe0jq47 > > > E > > > h > > > > R2o > > > > > > > > Method Threshold TP FP FN Precision > > > > Recall F > > > > Cubic 10 21 0 0 1 1 1 > > > > Linear 4 20 0 1 1 0.952380952 > > > > 0.975609756 > > > > Legacy 4 19 0 2 1 0.904761905 > > > 0.95 > > > > > > > > 94 Bieber Grammys > > > > https://mega.nz/#!c9dhAaKA!MG5Yi- > > > MJNATE2_KqcnNJZCRKtTWvdjJP1NwG8Ggdw3E > > > > > > > > Method Threshold TP FP FN Precision > > > > Recall F > > > > Cubic 15 91 23 3 0.798245614 > > 0.968085106 > > > > 0.875 > > > > Cubic 18 85 9 9 0.904255319 > > 0.904255319 > > > > 0.904255319 > > > > Linear 7 79 49 15 0.6171875 > > 0.840425532 > > > > 0.711711712 > > > > Linear 8 74 28 20 0.725490196 > > 0.787234043 > > > > 0.755102041 > > > > Legacy 7 74 40 20 0.649122807 > > > 0.787234043 > > > > 0.711538462 > > > > Legacy 8 71 26 23 0.731958763 > > > 0.755319149 > > > > 0.743455497 > > > > > > > > > > > > Improve scene detection accuracy by comparing frame with both > > > > previous and next frame (creates one frame delay). > > > > 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. > > > > Add legacy mode for backward compatibility. > > > > > > > > Signed-off-by: raduct > > > > --- > > > > doc/filters.texi | 16 ++++ > > > > libavfilter/scene_sad.c | 151 = ++++++++++++++++++++++++++++++++++ > > > > libavfilter/scene_sad.h | 6 ++ > > > > libavfilter/vf_scdet.c | 156 = +++++++++++++++++++++++++----------- > > > > tests/fate/filter-video.mak | 3 + > > > > 5 files changed, 284 insertions(+), 48 deletions(-) > > > > > > > > diff --git a/doc/filters.texi b/doc/filters.texi index > > > > bfa8ccec8b..53814e003b 100644 > > > > --- a/doc/filters.texi > > > > +++ b/doc/filters.texi > > > > @@ -21797,6 +21797,22 @@ Default value is @code{10.}. > > > > @item sc_pass, s > > > > Set the flag to pass scene change frames to the next filter. > > > > Default value is @code{0} > > > > > > The patch is corrupted by linebreaks: > > > > > > Applying: area changed: scdet filter > > > error: corrupt patch at line 16 > > > Patch failed at 0001 area changed: scdet filter > > > > > > please check the linebreak settings or attach the patch or use git > > send-email > > > > > > thx > > > > > > [...] > > > -- > > > Michael GnuPG fingerprint: > > > 9FF2128B147EF6730BADF133611EC787040B0FAB > > > > > > Homeopathy is like voting while filling the ballot out with > > > transparent > > ink. > > > Sometimes the outcome one wanted occurs. Rarely its worse than > > > filling out > > a > > > ballot properly. > > > > Please find attached the patch. > > >=20 > > doc/filters.texi | 16 ++++ > > libavfilter/scene_sad.c | 151 > ++++++++++++++++++++++++++++++++++++++++++ > > libavfilter/scene_sad.h | 6 + > > libavfilter/vf_scdet.c | 156 = ++++++++++++++++++++++++++++++-------------- > > tests/fate/filter-video.mak | 3 > > 5 files changed, 284 insertions(+), 48 deletions(-) > > 8f29f2e1c202ab283a9ca0f5d9599de6ab534d7a > > 0001-area-changed-scdet-filter.patch > > From 6d55c65d92376b0ab6e3bb2439af30fbcc430d0b Mon Sep 17 00:00:00 > 2001 > > From: raduct > > Date: Wed, 8 May 2024 08:24:46 +0300 > > Subject: [PATCH] area changed: scdet filter > > > > Improve scene detection accuracy by comparing frame with both = previous > and next frame (creates one frame delay). > > 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. > > Add legacy mode for backward compatibility. > > > > Signed-off-by: raduct > > --- > > doc/filters.texi | 16 ++++ > > libavfilter/scene_sad.c | 151 = ++++++++++++++++++++++++++++++++++ > > libavfilter/scene_sad.h | 6 ++ > > libavfilter/vf_scdet.c | 156 = +++++++++++++++++++++++++----------- > > tests/fate/filter-video.mak | 3 + > > 5 files changed, 284 insertions(+), 48 deletions(-) >=20 > fails to build >=20 > libavfilter/scene_sad.c: In function =E2=80=98ff_init_cbrt=E2=80=99: > libavfilter/scene_sad.c:86:5: warning: ISO C90 forbids mixed = declarations and > code [-Wdeclaration-after-statement] > 86 | uint8_t *table =3D cbrt_table[bitdepth]; > | ^~~~~~~ > libavfilter/scene_sad.c:92:13: error: implicit declaration of function = =E2=80=98av_malloc=E2=80=99; > did you mean =E2=80=98malloc=E2=80=99? = [-Werror=3Dimplicit-function-declaration] > 92 | table =3D av_malloc((1 << bitdepth) * (bitdepth > 8 ? 2 : = 1)); > | ^~~~~~~~~ > | malloc > libavfilter/scene_sad.c:92:11: warning: assignment to =E2=80=98uint8_t = *=E2=80=99 {aka =E2=80=98unsigned > char *=E2=80=99} from =E2=80=98int=E2=80=99 makes pointer from integer = without a cast [-Wint-conversion] > 92 | table =3D av_malloc((1 << bitdepth) * (bitdepth > 8 ? 2 : = 1)); > | ^ > libavfilter/scene_sad.c:98:5: warning: ISO C90 forbids mixed = declarations and > code [-Wdeclaration-after-statement] > 98 | int size =3D 1 << bitdepth; > | ^~~ > libavfilter/scene_sad.c: In function =E2=80=98ff_uninit_cbrt=E2=80=99: > libavfilter/scene_sad.c:120:9: error: implicit declaration of function = =E2=80=98av_free=E2=80=99; > did you mean =E2=80=98free=E2=80=99? = [-Werror=3Dimplicit-function-declaration] > 120 | av_free(cbrt_table[bitdepth]); > | ^~~~~~~ > | free > libavfilter/scene_sad.c: At top level: > libavfilter/scene_sad.c:126:6: error: no previous prototype for > =E2=80=98ff_scene_scrd_c=E2=80=99 [-Werror=3Dmissing-prototypes] > 126 | void ff_scene_scrd_c(SCENE_SAD_PARAMS) > | ^~~~~~~~~~~~~~~ > libavfilter/scene_sad.c: In function = =E2=80=98ff_scene_scrd_c=E2=80=99: > libavfilter/scene_sad.c:148:5: warning: ISO C90 forbids mixed = declarations and > code [-Wdeclaration-after-statement] > 148 | double mean =3D (sqrt(scrdPlus) + sqrt(scrdMinus)) / 2.0; > | ^~~~~~ > libavfilter/scene_sad.c: At top level: > libavfilter/scene_sad.c:152:6: error: no previous prototype for > =E2=80=98ff_scene_scrd2B_c=E2=80=99 [-Werror=3Dmissing-prototypes] > 152 | void ff_scene_scrd2B_c(SCENE_SAD_PARAMS, int bitdepth) > | ^~~~~~~~~~~~~~~~~ > libavfilter/scene_sad.c: In function = =E2=80=98ff_scene_scrd2B_c=E2=80=99: > libavfilter/scene_sad.c:179:5: warning: ISO C90 forbids mixed = declarations and > code [-Wdeclaration-after-statement] > 179 | double mean =3D (sqrt(scrdPlus) + sqrt(scrdMinus)) / 2.0; > | ^~~~~~ > libavfilter/scene_sad.c: At top level: > libavfilter/scene_sad.c:183:6: error: no previous prototype for > =E2=80=98ff_scene_scrd9_c=E2=80=99 [-Werror=3Dmissing-prototypes] > 183 | void ff_scene_scrd9_c(SCENE_SAD_PARAMS) > | ^~~~~~~~~~~~~~~~ > libavfilter/scene_sad.c:188:6: error: no previous prototype for > =E2=80=98ff_scene_scrd10_c=E2=80=99 [-Werror=3Dmissing-prototypes] > 188 | void ff_scene_scrd10_c(SCENE_SAD_PARAMS) > | ^~~~~~~~~~~~~~~~~ > libavfilter/scene_sad.c:193:6: error: no previous prototype for > =E2=80=98ff_scene_scrd12_c=E2=80=99 [-Werror=3Dmissing-prototypes] > 193 | void ff_scene_scrd12_c(SCENE_SAD_PARAMS) > | ^~~~~~~~~~~~~~~~~ > libavfilter/scene_sad.c:198:6: error: no previous prototype for > =E2=80=98ff_scene_scrd14_c=E2=80=99 [-Werror=3Dmissing-prototypes] > 198 | void ff_scene_scrd14_c(SCENE_SAD_PARAMS) > | ^~~~~~~~~~~~~~~~~ > libavfilter/scene_sad.c:203:6: error: no previous prototype for > =E2=80=98ff_scene_scrd16_c=E2=80=99 [-Werror=3Dmissing-prototypes] > 203 | void ff_scene_scrd16_c(SCENE_SAD_PARAMS) > | ^~~~~~~~~~~~~~~~~ > cc1: some warnings being treated as errors > make: *** [ffbuild/common.mak:81: libavfilter/scene_sad.o] Error 1 > make: *** Waiting for unfinished jobs.... >=20 >=20 > [...] >=20 > -- > Michael GnuPG fingerprint: > 9FF2128B147EF6730BADF133611EC787040B0FAB >=20 > Frequently ignored answer#1 FFmpeg bugs should be sent to our = bugtracker. > User questions about the command line tools should be sent to the = ffmpeg- > user ML. > And questions about how to use libav* should be sent to the libav-user = ML. Please find attached a new version of the patch. I'm building using msvc and I don't get these warnings. ------=_NextPart_000_0011_01DABBE7.2D8DFB10 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 0a6963360076213d30b70f8297eae3d44a638dab 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 | 157 +++++++++++++++++++++++++++++++++++=0A= libavfilter/scene_sad.h | 20 +++++=0A= libavfilter/vf_scdet.c | 161 +++++++++++++++++++++++++-----------=0A= tests/fate/filter-video.mak | 3 +=0A= 5 files changed, 309 insertions(+), 48 deletions(-)=0A= =0A= diff --git a/doc/filters.texi b/doc/filters.texi=0A= index bfa8ccec8b..53814e003b 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{-1}=0A= +Available values are:=0A= +=0A= +@table @samp=0A= +@item -1=0A= +Legacy mode for sum of absolute linear differences. Compare frame with = previous only and no delay.=0A= +=0A= +@item 0=0A= +Sum of absolute linear differences. Compare frame with both previous = and next which introduces a 1 frame delay.=0A= +=0A= +@item 1=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..1585d0a522 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,158 @@ 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= + double mean;=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= + mean =3D (sqrt(scrdPlus) + sqrt(scrdMinus)) / 2.0;=0A= + *sum =3D 2.0 * mean * mean;=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= + double mean;=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= + mean =3D (sqrt(scrdPlus) + sqrt(scrdMinus)) / 2.0;=0A= + *sum =3D 2.0 * mean * mean;=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..48692f8c29 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_LEGACY =3D -1,=0A= + MODE_LINEAR =3D 0,=0A= + MODE_MEAN_CBRT =3D 1=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_LEGACY}, = MODE_LEGACY, 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_LEGACY)=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_LEGACY)=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_LEGACY)=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_LEGACY && s->prev_frame.picref) || (s->mode = =3D=3D MODE_LEGACY && 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_LEGACY) {=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_LEGACY ? = 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,17 @@ 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= + return filter_frame(ctx, frame);=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..cff48e33d9 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=3D6.= 5:mode=3D1"=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= -- =0A= 2.44.1.windows.1=0A= =0A= ------=_NextPart_000_0011_01DABBE7.2D8DFB10 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_0011_01DABBE7.2D8DFB10--