Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
2nd November 2014, 02:09 | #1 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
ApparentFPS v1.09
ApparentFPS v1.09.
Plugin, ApparentFPS dll's for Avisynth v2.58 and v2.6, and avs26+ x64. EDIT: zip includes full VS2008 Project files for easy re-build. NOW Requires VS 2008 CPP Runtimes. Code:
ApparentFPS: by StainlessS. Plugin dll's for Avisynth versions v2.58 and v2.6/+ (x86) and v2.6/+ x64. Shows underlying framerate where a clip has had many duplicates inserted, easier than counting unique frames. ApparentFPS(clip c,Float "DupeThresh"=0.5,Float "FrameRate"=clp.FrameRate,Int "Samples"=Int(Ceil(FrameRate)), \ Float "ChromaWeight"=1.0/3.0,String "Prefix"="", Bool "Show"=True,Bool "Verbose"=True, Bool "Debug"=False, \ Int "Mode"=0, \ Int "Matrix"=(c.Width>1100||c.Height>600)?3:2, # 2=Pc.601 : 3=PC.709 \ Int "BlkW"=64, Int "BlkH"=BlkW, Int "oLapX"=BlkW/2, Int "oLapY"=BlkH/2 \) DupeThresh, Float, Default 0.5 (Greater than 0.0), suggest 0.25 -> 1.0. FrameDifference below or equal to this is a dupe. FrameRate, Float, Default clp.FrameRate. # FrameRate of clp. Probably of no great use, just use default. Samples, Int, Default Int(Ceil(FrameRate)) # (1 or more). Min Frames to sample for underlying framerate detection. (>= FrameRate). ChromaWeight, Float, Default 1.0/3.0, (0.0 -> 1.0). # Suggest 1.0/3.0 -> 1.0/2.0. (Use 0.0 for GreyScale YUV). Prefix, String, Default "". # Prefix for returned Local vars, Default "" = None returned. Show, Bool, Default True. # Show Info Verbose, Bool, Default True. # Additional Info, Sequence as binary digits. Debug, Bool, Default False. # Not of any great use. ### Added v1.05 Mode Int, default 0. (0 -> 1). 0) Standard RT_FrameDifference mode. 1) FrameMovement mode, difference is greatest difference for any BlkWxBlkH block. Matrix, Default (c.Width>1100||c.Height>600)?3:2. 2)=PC.601 : 3=Pc.709. Used in Conversion of RGB to Luma-Y. BlkW Int, Default 64. (8 < BlkW, Even Only). Block Width for Mode 1 (not used for Mode=0). BlkH Int, Default BlkW. (8 < BlkH, Even Only). Block Height for Mode 1 (not used for Mode=0). oLapX Int, Default BlkW/2. (0 <= oLapX). Horizontal block Overlap for Mode = 1. oLapY Int, Default BlkH/2. (0 <= oLapY). Vertical block Overlap for Mode = 1. ### Function samples over Samples frames, and shows instantaneous ApparentFPS and MaxApparentFPS, the real and perhaps most useful result is MaxApparentFPS. If Prefix = "" (Default) then does not return any info Local vars. When set to eg "P_" will set Local P_ApparentFPS and P_MaxApparentFPS as Float. Also returns Locals P_MinAboveDupeDif, P_MaxBelowDupeDif and P_CurrentDif which may assist in choosing DupeThresh, they are min and max values so far, and difference between current and previous frame. P_MinAboveDupeDif is the difference to previous frame of the frame which has lowest difference that what considered NOT a dupe (above DupeThresh), MaxBelowDupeDif max difference of frame that WAS considered a dupe (below DupeThresh). Ideally in a clip containing duplicates, there would be a distinct gap between these two above/below dup dif values with DupeThresh somewhere in between. v1.07, Also sets P_Maxndl and P_Maxndl_Frm, Max Non dupe length (up to samples length) and frame number where first occurs. v1.08, Also sets P_MinAboveDupeDif_Frm and P_MaxBelowDupeDif_Frm. !!! NOTE !!!, It may be better to set DupeThresh a little too high rather than too low, (where some motion frames will be mistaken as dupes), as it is likely that there will be at least one sequence in clip where there is sufficient motion to accurately set MaxApparentFPS. Can switch Off metrics (Show=False), and set eg Prefix = "P_" to return Locals P_ApparentFPS and P_MaxApparentFPS with rough instantaneous estimate of current underlying framerate and maximum underlying framerate detected so far. NOTE, ApparentFPS can range from 0.0 in static scene (can be measure of how 'active' a scene is). 'Verbose' (Default True) shows additional info, a string of 1's and 0's showing duplicate and unique frames. Also shown in info is the Unique frame count for the current Sample spread (which will be reduced at either end of clip), current ApparentFPS is calculated as (FrameRate * UniqueFrameCount / CurrentSampleSpread), so where UniqueFrameCount == CurrentSampleSpread, the result is FrameRate, However, if CurrentSampleSpread is reduced due to being near clip ends, then current ApparentFPS will NOT be assigned to P_MaxApparentFPS even where greater than current P_MaxApparentFPS. The rest should be pretty straight forward. v1.01, Extended maximum samples from 256 to 1024 (silently limited to 1024). Maximum number of binary digit flags limited to 64 when Verbose=True. Max number of Debug Hex Values limited to 8 (ie 8 * 32 bits = 256 bit flags). v1.03, Added 'UniqMax' Verbose metrics indicator, maximum number of unique frames in Sample range, so far. NOTE, a clip that has been edited after dupe insertion may seem to jump up in MaxApparentFPS at edits, due to dupes being cut out. You can reduce this effect by setting eg Samples=Int(Ceil(FrameRate))*10, but it will not show any MaxApparentFPS until you have scanned forward Samples/2 frames (Samples are centered around current frame). It will also take a little time to start up as it has to sample a lot of frames at startup. NOTE, Samples is silently (no error) limited to 1024. v1.05. Added Some args, Matrix and Mode/blk args. Mode=1, ie RT_FrameMovement mode, measures frame differences using a Block mode, chops the frame into BlkWxBlkH blocks, and difference is the maximum difference for any one block. Blocks can also be OverLapping, by default block sizes / 2, so by default each frame is multiply sampled 4 times (ie is slower than Mode=0, but can set oLapX and oLapY to 0, for no overlaps). Mode=1, might be of use where there is very little movement in a sequence, but for most uses, probably best left at default Mode=0. Also Note, in v1.05, ChromaWeight also alters differencing method used for RGB. Where ChromaWeight=0.0, will use LumaDifferencing (via Matrix arg), and where ChromaWeight > 0.0, then will use (AveRedDif+AveGrnDif+AveBluDif)/3.0, for both Mode=0 and Mode=1. v1.07. Added Maxndl, Max Non dupe length and frame number where first occurs. v1.08. Added P_MinAboveDupeDif_Frm and P_MaxBelowDupeDif_Frm. StainlessS See post #23 for equivalent script with ALMOST identical functionality.[docs purposes only, dont use it] http://forum.doom9.org/showthread.ph...88#post1698788 Above image, 0's show dupes, 1's non dupes, middle 0 (a bit lighter) is current frame. Zip available via Mediafire (below this post).
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 10th October 2021 at 20:36. Reason: Update |
2nd November 2014, 02:12 | #2 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
EDIT: Below is early version in script, dont use it, use the plugin.
This was how v0.0 was implemented, left here in situ. See post #23 for current implementation in script. S_ApparentFPS.avs Code:
Function S_ApparentFPS(clip clp,Float "DupeThresh",Float "FrameRate",Int "HalfFrameRes",Float "ChromaWeight", \ String "Prefix", Bool "Show", Bool "Debug") { /* S_ApparentFPS: by StainlessS. Requires RT_Stats by StainlessS, GScript & Grunt Plugins (c) Gavino. Multi-Instance script version. Shows underlying framerate where a clip has had many duplicates inserted, easier than counting unique frames. S_ApparentFPS(clip clp,Float "DupeThresh"=0.75,Float "FrameRate"=clp.FrameRate,Int "HalfFrameRes"=ceil(FrameRate), \ Float "ChromaWeight"=1.0/3.0,String "Prefix"="", Bool "Show"=True, Bool "Debug"=False) DupeThresh, Float, Default 0.75 (Greater than 0.0), suggest 0.5 -> 1.0. FrameDifference below this is a dupe. FrameRate, Float, Default clp.FrameRate. # FrameRate of clp. Probably of no great use, just use default. HalfFrameRes, Int, Default Ceil(FrameRate) (1 or more). # Min Frames to sample for underlying framerate detection. Suggest FrameRate as min. ChromaWeight, Float, Default 1.0/3.0, (0.0 -> 1.0). # YUV Only. Suggest 1.0/3.0 -> 1.0/2.0. (Use 0.0 for GreyScale YUV). Prefix, String, Default "". # Prefix for returned Global vars, Default "" = None returned. Show, Bool, Default True. Debug, Bool, Default False. Function samples over 2*HalfFrameRes frames, but every HalfFrameRes frames it remembers frame position and Dupe Count and when it reaches 2*HalfFrameRes frames it swaps start position to use previous HalfFrameRes frames position and Dupe Count, this enables it to sample 2*HalfFrameRes frames starting with HalfFrameRes frames worth of data (See the code if that is as clear as mud). The function may tend to underestimate underlying framerate slightly where HalfFrameRes is at default of about FrameRate. If supplied with HalfFrameRes less than FrameRate, will tend to over-estimate underlying framerate. If Prefix = "" (Default) then does not return any info Global vars. When set to eg "S_" will set Global S_ApparentFPS and S_MaxApparentFPS as Float. If Multi-Instance then must give unique prefix for each instance returned Globals. Can switch Off metrics (Show=False), and set eg Prefix = "S_" to return Globals S_ApparentFPS and S_MaxApparentFPS with rough instantaneous estimate of current underlying framerate and maximum underlying framerate detected so far (perhaps of use for something). NOTE, ApparentFPS can range from 0.0 in static scene (can be measure of how 'active' a scene is). The rest should be pretty straight forward. */ myName="S_ApparentFPS: " Assert(RT_FunctionExist("GScriptClip"),myName+"Essential GRunT plugin installed, http://forum.doom9.org/showthread.php?t=139337") Assert(RT_FunctionExist("GScript"),myName+"Essential GScript plugin installed, http://forum.doom9.org/showthread.php?t=147846") DupeThresh=Default(DupeThresh,0.75) # (0.75) Suggest about 0.5 -> 1.0 Assert(DupeThresh>0.0,myName+"DupeThresh Must be greater than 0.0") FR=Float(Default(FrameRate,clp.FrameRate)) Assert(FR>0.0,myName+"FrameRate Must be greater than 0.0") HalfFrameRes=Default(HalfFrameRes,Ceil(FR)) # (Ceil(FrameRate)), suggest about int(1.0 * framerate) Assert(HalfFrameRes>0,myName+"HalfFrameRes Must be greater than 0") ChromaWeight=Float(Default(ChromaWeight,1.0/3.0)) # (1.0/3.0) YUV Only, suggest 1.0/3.0 -> 1.0/2.0 Assert(ChromaWeight>=0.0 && ChromaWeight<=1.0,myName+"ChromaWeight 0.0 -> 1.0") Prefix=Default(Prefix,"") # ("") Prefix for returned Global vars ("" = None returned) Show=Default(Show,True) # (True) Show on frame Debug=Default(Debug,False) # (False) Extra debug info, not terribly useful FuncS=""" Function s_ApparentFPS@@@(clip clp,DupeThresh,Float FR,Int HalfFrameRes,Float ChromaWeight,bool Show,bool Debug) { clp n = current_frame # Local var if(Prev@@@ != n-1 || n==0) { # Start/Reset timer start_n = (n==0) ? n : n-1 Global StartFrame@@@ = start_n Global StartFrame2@@@ = start_n Global StartTime@@@ = start_n/FR Global StartTime2@@@ = start_n/FR Global DupeCnt@@@ = 0 Global DupeCnt2@@@ = 0 } Diff = RT_FrameDifference(clp,clp,n2=n-1,ChromaWeight=ChromaWeight) if(Diff < DupeThresh && n > 0) { Global DupeCnt@@@ = DupeCnt@@@ + 1 Global DupeCnt2@@@ = DupeCnt2@@@ + 1 } CurrTime = n / FR FrameCnt = n-StartFrame@@@ Tog1 = (FrameCnt==HalfFrameRes) Tog2 = (FrameCnt>=HalfFrameRes*2) UniqueFrameCnt = FrameCnt - DupeCnt@@@ TimeExpired = Max(CurrTime-StartTime@@@,0.000001) # Kick in only after HalfFrameRes frames done ApparentFPS = (FrameCnt<HalfFrameRes) ? 0.0 : UniqueFrameCnt/TimeExpired Global MaxApparentFPS@@@ = ApparentFPS>MaxApparentFPS@@@ ? ApparentFPS : MaxApparentFPS@@@ if(Show || Debug) { if(!Debug) { RT_Subtitle("%6.3f MaxFPS=%6.3f\nDif=%.3f",ApparentFPS,MaxApparentFPS@@@,Diff) } Else { RT_Subtitle("%d] AppFPS=%6.3f (Max=%6.3f)" + \ "\nFPS=%6.3f Dif=%.3f" + \ "\nStartFrm =%d StartT =%.3f\nStartFrm2=%d StartT2=%.3f" + \ "\nFrameCnt =%d ExpiredT=%.3f\nDupeCnt =%2d DupeCnt2=%d\nUniqueFrameCnt=%d\nTog1=%.1s Tog2=%.1s", \ n,ApparentFPS,MaxApparentFPS@@@, \ FrameCnt/TimeExpired,Diff, \ StartFrame@@@,StartTime@@@,StartFrame2@@@,StartTime2@@@,FrameCnt,TimeExpired, \ DupeCnt@@@,DupeCnt2@@@,UniqueFrameCnt,Tog1,Tog2) } } if(Tog2 || Tog1) { if(Tog2) { Global StartFrame@@@ = StartFrame2@@@ Global StartTime@@@ = StartTime2@@@ Global DupeCnt@@@ = DupeCnt2@@@ } Global StartFrame2@@@ = n Global StartTime2@@@ = CurrTime Global DupeCnt2@@@ = 0 } ### Insert returned Global Vars Below if required @@@@ ### Global Prev@@@ = n Return Last } Global MaxApparentFPS@@@ = 0.0 Global Prev@@@ = -666 # Init ARGS = "Dupethresh,FR,HalfFrameRes,ChromaWeight,Show,Debug" clp.GScriptClip("s_ApparentFPS@@@(last, "+ARGS+")", local=true, args=ARGS) """ RT_IncrGlobal("AFPS_InstanceNumber") # Are return Globals required IG_S = (Prefix=="") ? "" : RT_String("Global %sApparentFPS=ApparentFPS Global %sMaxApparentFPS=MaxApparentFPS@@@",Prefix,Prefix) Fnd_S = RT_String("@@@@\n@@@\n") Rep_S = RT_String("%s\n_AFPS_%d\n",IG_S,AFPS_InstanceNumber) InstS = RT_StrReplaceMulti(FuncS,Fnd_S,Rep_S) # RT_WriteFile(RT_String("DEBUG_AFPS_%d.txt",AFPS_InstanceNumber),"%s",InstS) # Debug script listing Return GScript(InstS) } Code:
Import("S_ApparentFPS.avs") #Avisource("D:\AVS\Test2.avi") Avisource("D:\SCDump\CAP1.avi") #Avisource("WebCam.avi") KillAudio DUPTHRESH_S = 1.0 # Script version DUPTHRESH_P = 1.0 # Plug version A = s_ApparentFPS(Dupethresh=DUPTHRESH_S,Prefix="S_",Show=false) B = ApparentFPS(Dupethresh=DUPTHRESH_P,Prefix="P_",Show=false) RT_Graphlink(A,B) # Ensure both clips processed [about same as Echo() in v2.6Alpha5] ScriptClip(""" RT_SubTitle("%d] %6.3f : Max=%6.3f (Script)",current_frame,S_ApparentFPS,S_MaxApparentFPS,align=0) RT_SubTitle("%d] %6.3f : Max=%6.3f (Plug)" ,current_frame,P_ApparentFPS,P_MaxApparentFPS,align=1) """,After_Frame=True) Assumefps(250.0)
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 6th May 2019 at 16:11. |
2nd November 2014, 06:59 | #3 | Link |
Registered User
Join Date: May 2008
Posts: 1,840
|
This seems interesting, I'll give it a try, it would be awesome if it performed ivtc. Is this a step towards auto ivtc? MadVR has had this for awhile now and it's pretty accurate.
__________________
PC: FX-8320 GTS250 HTPC: G1610 GTX650 PotPlayer/MPC-BE LAVFilters MadVR-Bicubic75AR/Lanczos4AR/Lanczos4AR LumaSharpen -Strength0.9-Pattern3-Clamp0.1-OffsetBias2.0 Last edited by turbojet; 2nd November 2014 at 07:02. |
2nd November 2014, 11:43 | #4 | Link | ||
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Quote:
The script version is exactly how it is implemented. EDIT: Globals are returned for whatever use people can make of them (Locals for the plug version). (I live in PAL land and have little need for anything NTSC related). I guess with a bit of bobbing it might be used to detect if IVTC were required, I look forward to seeing what use you can make of it. EDIT: Quote:
Code:
PVideoFrame __stdcall ApparentFPS::GetFrame(int n, IScriptEnvironment* env) { n = (n<0) ? 0 : (n>= num_frames) ? num_frames - 1 : n; // Range limit n PVideoFrame dst = child->GetFrame(n, env); if(Show||Debug) env->MakeWritable(&dst); if(Prev_n != n-1 || n==0) { // Start/Reset const int start_n = (n == 0) ? 0 : n-1; StartFrame2 = StartFrame = start_n; StartTime2 = StartTime = start_n/FrameRate; DupeCnt2 = DupeCnt = 0; } AVSValue aFpsArgs[5]={child,child,n,n-1,ChromaWeight}; double Diff = RT_FrameDifference_Lo(AVSValue(aFpsArgs,5),env); if(Diff < DupeThresh && n > 0) { ++DupeCnt; ++DupeCnt2; } const double CurrTime = n / FrameRate; const int FrameCnt = n-StartFrame; const bool Tog1 = (FrameCnt==HalfFrameRes); const bool Tog2 = (FrameCnt>=HalfFrameRes*2); const int UniqueFrameCnt= FrameCnt - DupeCnt; const double TimeExpired= max(CurrTime-StartTime,0.000001); // Only kick in after HalfFrameRes frames done const double ApparentFPS = (FrameCnt<HalfFrameRes) ? 0.0 : UniqueFrameCnt/TimeExpired; MaxApparentFPS = (ApparentFPS>MaxApparentFPS) ? ApparentFPS : MaxApparentFPS; if(Show || Debug) { if(!Debug) { DrawFStr(dst,0,0,"%d] %6.3f MaxFPS=%6.3f\nDif=%.3f",n,ApparentFPS,MaxApparentFPS,Diff); } else { DrawFStr(dst,0,0, "%d] AppFPS=%6.3f (Max=%6.3f)" "\nFPS=%6.3f Dif=%.3f" "\nStartFrm =%d StartT =%.3f\nStartFrm2=%d StartT2=%.3f" "\nFrameCnt =%d ExpiredT=%.3f\nDupeCnt =%2d DupeCnt2=%d\nUniqueFrmCnt=%d\nTog1=%s Tog2=%s", n,ApparentFPS,MaxApparentFPS, FrameCnt/TimeExpired,Diff, StartFrame,StartTime,StartFrame2,StartTime2,FrameCnt,TimeExpired, DupeCnt,DupeCnt2,UniqueFrameCnt,Tog1?"T":"F",Tog2?"T":"F"); } } if(Tog2||Tog1) { // FrameCnt cannot be 0 if(Tog2) { StartFrame = StartFrame2; StartTime = StartTime2; DupeCnt = DupeCnt2; } StartFrame2 = n; StartTime2 = CurrTime; DupeCnt2 = 0; } if(*Prefix != '\0') { // Most of this could have been prepped in the constructor :( int pfixlen=strlen(Prefix); if(pfixlen>128) pfixlen=128; char bf[128+32]; memcpy(bf,Prefix,pfixlen); char *d=bf+pfixlen; const char *p,*afps="ApparentFPS"; for(p=afps;*d++=*p++;); // strcat variable name part AVSValue var = GetVar(env,bf); env->SetVar(var.Defined() ? bf : env->SaveString(bf),ApparentFPS); d = bf+pfixlen; const char *afpsmx="MaxApparentFPS"; for(p=afpsmx;*d++=*p++;); // strcat variable name part var = GetVar(env,bf); env->SetVar(var.Defined() ? bf : env->SaveString(bf),MaxApparentFPS); } Prev_n=n; return dst; }
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 2nd November 2014 at 14:43. |
||
2nd November 2014, 14:14 | #5 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
turboJet,
I only have a single (good quality) NTSC FILM sample (about 16 mins rescued from a now totally corrupt DVD), tried this: (EDIT: With 'Honour Pulldown Flags' in DGIndex, ie Not 'Forced Film'). Code:
MPeg2Source("NTSC_Top_FORCEFILM-ReturnOfTheKing_NTSC_FORCEFILM.d2v") Robocrop(WMod=4) Bob ApparentFPS(Dupethresh=2.5) Assumefps(250.0) (after full 16min scan, initial 23.976FPS detected at frame 121 of 57668 bobbed frames, ie 2* HalfFrameRes + 1 frames, frame 0 does not count [EDIT: we count frame 0 as neither a dupe not unique]). EDIT: Fairly high Dupethresh to see both bobbed frames belonging to single progressive frame as same, detects bobbed output @ 59.94FPS as 23.976 MaxApparentFPS. EDIT: Script version detects as 23.977FPS, probably due to lower precision Float, I'm guessin at this line: Code:
CurrTime = n / FR
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 2nd November 2014 at 23:13. |
2nd November 2014, 22:58 | #6 | Link | |
Registered User
Join Date: Feb 2002
Location: California
Posts: 2,695
|
Quote:
Now, if I can just remember that it exists the next time I need it ... Thanks!! |
|
2nd November 2014, 22:59 | #7 | Link |
Registered User
Join Date: May 2008
Posts: 1,840
|
I tried it on a few and it detected 23.976 at 24.0*, 25 at 26.* and 29.97 30.0 fps on limited testing. Which is accurate enough for scanning like autocrop/robocrop to determine what it should be ivtc'd to. It's not possible currently to get this info to pass on to call an ivtc filter, is it something that might be considered in the future?
__________________
PC: FX-8320 GTS250 HTPC: G1610 GTX650 PotPlayer/MPC-BE LAVFilters MadVR-Bicubic75AR/Lanczos4AR/Lanczos4AR LumaSharpen -Strength0.9-Pattern3-Clamp0.1-OffsetBias2.0 |
2nd November 2014, 23:48 | #8 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
So far as I know, TFM uses 'd2v' file to auto fix IVTC on MPEG2. (think it also outputs some kind of logfile, dont know if any
decimation info in there). EDIT: d2v has line at end eg something like "100% FILM", can use RT_Stats to get that line of text. EDIT: Is eg "FINISHED 100.00% FILM". From RT_Stats doc: Code:
RT_ReadTxtFromFile(String ,Int "Lines"=0,Int "Start"=0) Non-clip function. String Filename, Name of text file to load into a string. Lines=0=unlimited. Set to number of leading lines in text file to load, eg 1 = load only the first line of text file. The return string is n/l ie Chr(10) separated, and carriage returns are removed from the returned string. If source file was missing newline on very last line, it will append a newline so that all lines are similarly formatted. v1.03, Added Start arg default=0=very first line (relative 0). Would have been nice to have start and lines in reverse order but implemented as above to not break scripts. Throws an error if your requested Start is >= to the number of lines in the file, or zero len file. To fetch the last line of a text file, use eg Start = RT_FileQueryLines(Filename) - 1 (Start is zero relative). You could eg get the last line of a d2v file which might look like this:- "FINISHED 100.00% VIDEO" I dont have that much/many samples, knowledge nor inclination to do so myself, GScript could come in handy here. something like: Code:
Function fn(clip c) { c GSCript(""" z = bob.ApparentFPS(Dupethresh=2.5,Prefix="P_",Show=False) FC=z.FrameCount cnt=min(FC,1000) for(i=0,cnt-1) { RT_YankChain(z,n=i) # force process frame i } return P_MaxApparentFPS """) } on both original framerate and apparent framerate). EDIT: I used RoboCrop(), just to remove any borders that may 'water down' metrics and possibly necessitate adjustment of DupeThresh.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 3rd November 2014 at 00:35. |
3rd November 2014, 00:23 | #9 | Link |
Registered User
Join Date: Feb 2002
Location: California
Posts: 2,695
|
TDecimate doc is here:
TDecimate Documenation Decimation is set using two parameters: cycle This is the group of frames, prior to decimation, which contain the duplicates. If you have a complicated decimation pattern, you need to specify a large enough "cycle" number so that you include all the pattern variations, but only until those patterns repeat. For instance, if the video has one repeat in the first group of five frames, but then has one repeat in the next four, and then this same thing happens with the next group of five, and the following group of four, you need to specify a "cycle" of nine frames. For me, this is always the most difficult parameter to determine. cycleR This is how many frames you want to decimate in every "cycle." In my example above, this would be 2. So, the challenge would be to be able to determine what "cycle" to use. Once that is determined, I think it should be easy to compute CycleR, using this new function, and pass that to TDecimate. |
3rd November 2014, 00:55 | #10 | Link |
Registered User
Join Date: May 2008
Posts: 1,840
|
d2v parameter only helps when pulldown is used, which is common in big studio dvd's but not all that common in tv, it's only for 29 -> 23 too.
On a 23.976 telecined source: The script's return value was not a video clip, (Is a float, 24.169378). On a 25 fps telecined source that's time compressed: The script's return value was not a video clip, (Is a float, 33.300034). The latter is concerning, this same file when scrubbing is around 26-28. How to take this info and apply these rules to TDecimate(cycle=n) if fps 22-24.5 n = 5 if fps 24.5-28 n = 6 else omit TDecimate
__________________
PC: FX-8320 GTS250 HTPC: G1610 GTX650 PotPlayer/MPC-BE LAVFilters MadVR-Bicubic75AR/Lanczos4AR/Lanczos4AR LumaSharpen -Strength0.9-Pattern3-Clamp0.1-OffsetBias2.0 Last edited by turbojet; 3rd November 2014 at 01:09. |
3rd November 2014, 01:10 | #11 | Link | ||
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
As I said, I dont know that much about it.
Quote:
to judge whether we hit maximum (eg ApparentFPS varied much below MaxApparentFPS but then hit exact MaxApparentFPS, AGAIN, if so exit loop early, probably need a bit more thought). EDIT: Quote:
Think I've gotta bow out soon, before I fall down, exhausted.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 3rd November 2014 at 01:14. |
||
3rd November 2014, 01:31 | #12 | Link |
Registered User
Join Date: May 2008
Posts: 1,840
|
Ya I never expected it to output video and it doesn't matter if it does. I can send you some samples if you want to work with this more.
Those will all report 29.97 which is the source fps. I'm trying to get apparentFPS into a text file to determine what to put in TDecimate, if any. Or better yet calling the correct TDecimate in the script, which would make it an auto ivtc function. However with significant blending srestore usually performs better. Sleep well, this can wait. It's something I've been waiting for years for and I was shocked when it was mostly realized in MadVR.
__________________
PC: FX-8320 GTS250 HTPC: G1610 GTX650 PotPlayer/MPC-BE LAVFilters MadVR-Bicubic75AR/Lanczos4AR/Lanczos4AR LumaSharpen -Strength0.9-Pattern3-Clamp0.1-OffsetBias2.0 |
3rd November 2014, 02:01 | #13 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Quote:
You can output whatever you wish using eg Code:
RT_WriteFile(Filename,"Int=%d Float=%f String=%s NewLine=\nI'm On a New Line",42,42.0,"42") (I think currently something like 150 functions) You could also use a temp RT_Stats DBase file to return multiple info from a function, caller supplies DB name, function creates and fills DB and returns a status code with existing DB. [caller deals with results and then RT_FileDelete(DB)]. Some stuff MediaInfo related: Code:
RT_Call(String Cmd,bool "Hide"=false,bool "Debug"=false) Run an external program using supplied cmd command line, hiding the console window if Hide==True. Debug, If true, send some debug info to debugview including return code from called process. DOS Filenames should be enclosed in quotes to avoid the system misinterpreting spaces in filenamess, see RT_QuoteStr(). Returns 0 if process successfully started, otherwise non zero (ie 1). Example to write Aspect Ratio in form "1.333" to file D:\OUT\MEDINFO.TXT using command line version of MediaInfo. RT_Call(RT_QuoteStr("D:\TEST\MediaInfo.Exe") + " --LogFile=" + RT_Quotestr("D:\OUT\MEDINFO.TXT") + \ " --Inform=Video;%DisplayAspectRatio% " + RT_Quotestr("D:\VID\1.mpg")) demo: http://forum.doom9.org/showthread.ph...47#post1589747 EDIT: And CallCmd() plug here: http://forum.doom9.org/showthread.ph...hlight=callcmd
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 3rd November 2014 at 02:09. |
|
3rd November 2014, 17:47 | #14 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Turbo,
Here, output from the NTSC FILM VOB, via MediaInfo NTSC.VOB > NTSC.txt Code:
General Complete name : ntsc.vob Format : MPEG-PS File size : 320 MiB Duration : 16mn 2s Overall bit rate mode : Variable Overall bit rate : 2 789 Kbps Video ID : 224 (0xE0) Format : MPEG Video Format version : Version 2 Format profile : Main@Main Format settings, BVOP : Yes Format settings, Matrix : Custom Format settings, GOP : M=3, N=12 Duration : 16mn 2s Bit rate mode : Variable Bit rate : 2 286 Kbps Maximum bit rate : 9 802 Kbps Width : 720 pixels Height : 480 pixels Display aspect ratio : 16:9 Frame rate : 23.976 fps Standard : NTSC Color space : YUV Chroma subsampling : 4:2:0 Bit depth : 8 bits Scan type : Progressive Scan order : 2:3 Pulldown Compression mode : Lossy Bits/(Pixel*Frame) : 0.276 Stream size : 262 MiB (82%) Audio ID : 189 (0xBD)-128 (0x80) Format : AC-3 Format/Info : Audio Coding 3 Mode extension : CM (complete main) Format settings, Endianness : Big Muxing mode : DVD-Video Duration : 16mn 2s Bit rate mode : Constant Bit rate : 448 Kbps Channel(s) : 6 channels Channel positions : Front: L C R, Side: L R, LFE Sampling rate : 48.0 KHz Bit depth : 16 bits Compression mode : Lossy Delay relative to video : -717ms Stream size : 51.4 MiB (16%) Text #1 ID : 189 (0xBD)-32 (0x20) Format : RLE Format/Info : Run-length encoding Muxing mode : DVD-Video Duration : 15mn 50s Delay relative to video : 2s 269ms Text #2 ID : 189 (0xBD)-33 (0x21) Format : RLE Format/Info : Run-length encoding Muxing mode : DVD-Video Duration : 15mn 50s Delay relative to video : 2s 269ms Text #3 ID : 189 (0xBD)-34 (0x22) Format : RLE Format/Info : Run-length encoding Muxing mode : DVD-Video Duration : 15mn 35s Delay relative to video : 2s 302ms Text #4 ID : 189 (0xBD)-35 (0x23) Format : RLE Format/Info : Run-length encoding Muxing mode : DVD-Video Duration : 15mn 35s Delay relative to video : 2s 302ms Text #5 ID : 189 (0xBD)-36 (0x24) Format : RLE Format/Info : Run-length encoding Muxing mode : DVD-Video Duration : 15mn 35s Delay relative to video : 2s 302ms Text #6 ID : 224 (0xE0)-CC3 Format : EIA-608 Muxing mode : DVD-Video Muxing mode, more info : Muxed in Video #1 Bit rate mode : Constant Stream size : 0.00 Byte (0%) Menu (I think Mediainfo gives more detail if given an IFO rather than VOB, I dont have the IFO, DVD corrupt). EDIT: Output from ffprobe Code:
[mpeg2video @ 032b0760] Invalid frame dimensions 0x0. Last message repeated 10 times Input #0, mpeg, from 'ntsc.vob': Duration: 00:16:02.68, start: 1758.473567, bitrate: 2788 kb/s Stream #0:0[0x1e0]: Video: mpeg2video (Main), yuv420p(tv), 720x480 [SAR 32:7 DAR 16:9], max. 9801 kb/s, 29.83 fps, 59.94 tbr, 90k tbn, 59.94 tbc Stream #0:1[0x80]: Audio: ac3, 48000 Hz, 5.1(side), fltp, 448 kb/s Stream #0:2[0x1bf]: Data: dvd_nav_packet Stream #0:3[0x20]: Subtitle: dvd_subtitle Stream #0:4[0x21]: Subtitle: dvd_subtitle Stream #0:5[0x22]: Subtitle: dvd_subtitle Stream #0:6[0x23]: Subtitle: dvd_subtitle Stream #0:7[0x24]: Subtitle: dvd_subtitle EDIT: VOB probably went through DVD shrink without compression but with some streams removed.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 3rd November 2014 at 17:58. |
3rd November 2014, 20:25 | #15 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Treat ApparentFPS() definition as currently transient, just had a daft idea and want to try it out.
May drop HalfFrameRes arg altogether. Gonna try scan ahead(& behind) a number of frames to get better current estimate, maybe about 15 ahead,+ 15 behind + current.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? |
3rd November 2014, 22:54 | #16 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
OK, got this, need some guinea pigs (or a few small hamsters will do I suppose).
Code:
Function Test(clip clp,Float "DupeThresh",Float "FrameRate",Float "ChromaWeight", String "Prefix", Bool "Show", Bool "Debug") { myName="s_ApparentFPS: " Assert(RT_FunctionExist("GScriptClip"),myName+"Essential GRunT plugin installed, http://forum.doom9.org/showthread.php?t=139337") Assert(RT_FunctionExist("GScript"),myName+"Essential GScript plugin installed, http://forum.doom9.org/showthread.php?t=147846") DupeThresh=Default(DupeThresh,0.5) # (1.0) Suggest 1.0 (clean) down to 0.5 (lossy compressed) Assert(DupeThresh>0.0,myName+"DupeThresh Must be greater than 0.0") FR=Float(Default(FrameRate,clp.FrameRate)) Assert(FR>0,myName+"FrameRate Must be greater than 0.0") ChromaWeight=Float(Default(ChromaWeight,1.0/3.0)) # (1.0/3.0) YUV Only, suggest 1.0/3.0 -> 1.0/2.0 Assert(ChromaWeight>=0.0 && ChromaWeight<=1.0,myName+"ChromaWeight 0.0 -> 1.0") Prefix=Default(Prefix,"") Show=Default(Show,True) Debug=Default(Debug,False) FuncS=""" Function ApparentFPS@@@(clip clp,DupeThresh,Float FR,Float ChromaWeight,bool Show,bool Debug) { clp n = current_frame # Local var LastFrame = FrameCount - 1 if(Prev@@@ != n-1 || n==0) { # Start/Reset timer Prior_n = n - 1 # As if at previous n position (ie pretend previous iteration) BITS = 0 SFrm = max(Prior_n - 15,1) # Frame 0 has no prior frame to compare with EFrm = min(Prior_n + 15,LastFrame) for(i= SFrm,EFrm) { Dif = RT_FrameDifference(clp,clp,n=i,n2=i-1,ChromaWeight=ChromaWeight) if(Dif >= Dupethresh) { BITS = RT_BitSet(BITS,15-(i-Prior_n)) } } Global BITS@@@ = BITS } BITS=BITS@@@ # Local var, from previous iteration BITS=BitAnd(RT_BitLSL(BITS,1),$7FFFFFFE) # shift over and discard oldest bit (and clear bit zero new bit) if(n + 15 <= LastFrame) { Dif = RT_FrameDifference(clp,clp,n=n+15,n2=n+15-1,ChromaWeight=ChromaWeight) if(Dif >= Dupethresh) { BITS = BITS + 1 # Bit zero was clear } } SFrm = max(n - 15,1) EFrm = min(n + 15,LastFrame) Samples = EFrm - SFrm + 1 # Valid samples Unique = RT_BitSetCount(BITS) ApparentFPS = Unique * FR / Samples Global MaxApparentFPS@@@ = (Samples!=31) ? MaxApparentFPS@@@ : max(ApparentFPS,MaxApparentFPS@@@) if(Debug || Show) { Dif = (n==0) ? 0.0 : RT_FrameDifference(clp,clp,n2=n-1,ChromaWeight=ChromaWeight) LS=RT_NumberString(RT_BitLSR(BITS,16),2,15) MS=RT_BitTst(BITS,15) ? "1":"0" RS=RT_NumberString(RT_BitAnd(BITS,$7FFF),2,15) RT_Subtitle("AppFPS=%6.3f MaxFPS=%6.3f\nDif=%.3f (Set=%2d Samples=%2d)\n\aR%s\a-%s\aR%s\a-", \ ApparentFPS,MaxApparentFPS@@@,Dif,Unique,Samples,LS,MS,RS) } ### Insert returned Global Vars Below if required @@@@ ### Global BITS@@@ = BITS Global Prev@@@ = n Return Last } Global BITS@@@=0 Global MaxApparentFPS@@@ = 0.0 Global Prev@@@ = -666 ARGS = "Dupethresh,FR,ChromaWeight,Show,Debug" clp.GScriptClip("ApparentFPS@@@(last, "+ARGS+")", local=true, args=ARGS) """ RT_IncrGlobal("AFPS_InstanceNumber") # Are return Globals required IG_S = (Prefix=="") ? "" : RT_String("Global %sApparentFPS=ApparentFPS Global %sMaxApparentFPS=MaxApparentFPS@@@",Prefix,Prefix) Fnd_S = RT_String("@@@@\n@@@\n") Rep_S = RT_String("%s\n_AFPS_%d\n",IG_S,AFPS_InstanceNumber) InstS = RT_StrReplaceMulti(FuncS,Fnd_S,Rep_S) RT_WriteFile(RT_String("DEBUG_AFPS_%d.txt",AFPS_InstanceNumber),"%s",InstS) Return GScript(InstS) } #Avisource("D:\AVS\Test2.avi") #Avisource("D:\SCDump\CAP1.avi") Avisource("WebCam.avi") KillAudio #StackHorizontal(Last,Last) Test() AssumeFPS(250.0)
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? |
4th November 2014, 00:47 | #17 | Link |
Registered User
Join Date: May 2008
Posts: 1,840
|
Mediainfo reads 29.97i or 59.94p on all tv I just checked, the rare one that uses pulldown may state 23.976p but I don't have one at the moment. I don't think it will be any help.
Is the latest function relevant to what I'm trying to do?
__________________
PC: FX-8320 GTS250 HTPC: G1610 GTX650 PotPlayer/MPC-BE LAVFilters MadVR-Bicubic75AR/Lanczos4AR/Lanczos4AR LumaSharpen -Strength0.9-Pattern3-Clamp0.1-OffsetBias2.0 |
4th November 2014, 01:35 | #18 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Quote:
The one I posted said: Code:
Frame rate : 23.976 fps Scan type : Progressive Scan order : 2:3 Pulldown Hope so. Is replacement for previous [just different name ie Test()]. BUT, currently trying to make it sample up to 64 frames, even numbers probably better for 30fps (eg 30 or 60) and 25 or 50 for PAL. If even then will sample 1 less after current frame than before current frame. Do you see yourself more as a large guinea pig, or a small hamster ? (stay away from Peru either way).
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 4th November 2014 at 01:39. |
|
4th November 2014, 06:56 | #19 | Link |
Registered User
Join Date: May 2008
Posts: 1,840
|
Tried test() on a 23.976 telecined source and it bounce around between 22 and 27 while scrubbing, max fps was 29. How can I get an average fps of the file after quick scanning?
__________________
PC: FX-8320 GTS250 HTPC: G1610 GTX650 PotPlayer/MPC-BE LAVFilters MadVR-Bicubic75AR/Lanczos4AR/Lanczos4AR LumaSharpen -Strength0.9-Pattern3-Clamp0.1-OffsetBias2.0 |
4th November 2014, 10:55 | #20 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
OK, thanks.
Probably need to do more samples, only doing 31 samples with that try (current + 15 either side, [limited 32 bits in Int]). Not suitable for use with the bob function thing, not enough samples (old version did 2*framerate samples (2*2*framerate for bob thing). The hi-lited binary digit is the current frame, is it showing the sequence you expect ? (if not, adjust Dupethresh) I'll try to get 64 sample script going today (forget bob thing for now), and if I get it working OK, will attempt plug at 128 sample max using 64 bit int's. It's not intended for scrubbing around, continuous play only, and the only numeric of real value is the MaxApparentFPS. OK, I give in, can you up a sample of about 30-60 secs compressed (Not HD), with varying motion would be ok, at least 2 seconds of continuous motion at some point. EDIT: And can you say what sequence I should expect from the sample, ta.
__________________
I sometimes post sober. StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace "Some infinities are bigger than other infinities", but how many of them are infinitely bigger ??? Last edited by StainlessS; 4th November 2014 at 11:54. |
|
|