Log in

View Full Version : Detect black borders


Hotte
6th May 2018, 11:08
Hi,

how can I find out and react if a video source contains black borders above or below ?

I have 1920x1080 video scources which sometimes contain 720x576 or 640x480 scenes with black borders. Sometimes they come in upscaled (e.g. 576 > 1080, black borders only left and right), sometimes not.

I am looking for avisynth statement(s) which check if there is a black area above or below the known format, so that I can crop and upscale the source.

I know the real size of the source by the time I process i.e. I know which pixel area to check for a black border. But I do not know, if the source comes in upscaled or not.

I have very limited knowledge of avisynth programming.

Could anyone experienced help ?

Groucho2004
6th May 2018, 11:13
Have a look at StainlessS' RoboCrop (https://forum.doom9.org/showthread.php?t=168053&highlight=robocrop).

Hotte
6th May 2018, 21:20
Thanks Groucho, I looked into this before I started this thread. I am not sure, if/how this can help.
I do not need a cropping tool.
I just need a simple check, if there are borders or not.
If no I will do nothing, if yes I will use standard avisynth crop (because I know the format) and upscale with LanczosResize.
I do not know how such a condition can be created.

manolito
6th May 2018, 21:32
The old and trusted Autocrop by Glenn Bussell can create a log file in mode=2. You could evaluate the log file to check if any cropping is required and act accordingly. When using a value for "samples" of about 20 the results are quite accurate.

Cheers
manolito

manono
6th May 2018, 22:15
Why not just look at the thing?

Hotte
7th May 2018, 20:20
Thanks Manolito. I saw this filter before and I thought there might a way 'round writing a log file and getting the data back.

Now I understood that this ist the way to go.

The issue is: I fear I do not know how to read the log file within avisynth and to do this in a one-pass script.

So maybe I will be looking for an outside solution.

Thanks so far for your support.

StainlessS
8th May 2018, 01:52
Its a real bad idea to try do that kind of thing based on single frame samples, many frames may simply be black/dark near edges.
I remember scanning a 10 minute section of Cabaret (Minnelli/York, from ~10 mins in @ Toothpaste flavoured Prairie Oysters), where AutoCrop
cropped off more good frame than it kept, (on default settings), and that was with (default) 5 frames sampled, I think (evenly spread across the 10 mins section).
Sampling & cropping & resizing @ every single frame would likely be chopping off good image in lots of cases, if you want to totally mess up a clip, then that is a good way to do it.
RoboCrop is no better than AutoCrop ie can only crop off outmost border, [but current ver$ default 40 frames sampled], but roboCrop did
not chew off vaste swathes of image and nailed it just exactly right (Cabaret) after about 8 frames sampled I think. (think autocrop still got it quite wrong even if upping the sampled frames to about 32).
I believe that ffmpeg has some kind of border cropping filter, but that it likely no better than making a decision to crop by sampling every frame.
(unless it does a complete scan of clip first where will be similar-ish output to RoboCrop, or if detecting scene cuts as well as borders, then maybe better).

The only thing that I'm aware of that may be persuaded to assist, is DBSC:- https://forum.doom9.org/showthread.php?t=171624
Splits clip into scenes/cuts, and then process those individually, less likely to make disastrous mistakes.
However, DBSC, does not do as required in this case, but who knows, maybe could be persuaded somehow.

Here, is the latest version that I was playing at least 12 months ago:- http://www.mediafire.com/file/3z94zf7i2gmy7vx/DBSC_Temp_v0.08.zip
requires RT_Stats v2.0Beta and RoboCrop latest, maybe some other stuff, dont know.
(take any comments with a pinch of salt, Best have DebugView [google], as makes extensive use of debugging).

DBSC can call 'User Routines', perhaps something could be written to function as required.

I have my own problems at the moment which dont seem to be going away any time soon, and so cannot help.

It would likely be a lot less work to crop / resize manually, and certainly a lot less likely to make spectacularly bad choices.

EDIT: The main script of DBSC.avsi, is 1800+ lines of script, + several client scripts. (latest as posted above).


EDIT:
I fear I do not know how to read the log file
Probably just the crop size at a particular frame (by default only samples 5 frames), my guess is that it is described somewhere in the Autocrop docs.

Hotte
9th May 2018, 18:59
Thanks, StainlessS. As always highly informative!
Sophicsticated cropping detection is not my issue. The original format of the input avi is known exactly in this use case since it is dedicated output from an NLE. It is only unknown if the clip had been upscaled or not. So a simple check if there is something black at rectangle x,y,a,b right on the first frame would be sufficient for 99,5% of the cases.
Anyway, I do not want to use your time any longer: I will not be able to read a log file, my avisynth knowledge is too little. And I did not find any help in the Autocrop docs.
So thanks all, I will be looking for a workaround.

StainlessS
10th May 2018, 09:58
Sorry Hotte, I think I may misunderstand requirements.

Are you saying that you have multiple sources, each of which DO NOT CHANGE border format within those single sources ?
(I thought you were saying that you had sources, which each contain multiple border formats [dynamically changing borders]).

Can you be more specific as to content to process, I dont care whether it was upscaled from original or not, only what is in current sources.

Do you know precise border locations already (what are they, list all current crop coords, whether was upscaled or otherwise) ?

If you want to provide samples, I can pick them up tomorrow.

Also, yes, probably a lot easier than I thought you were asking for.

EDIT: Incidentally, RoboCrop provides a log which can be interrogated


LogFn: Default "" (unset). Filename of Log file.
Will output crop coords, crop coords will be output whether cropping or not (Blank/Show), format as within quotes below.

'28 92 668 392 2 4 2 4 720 576 27 89 696 484 2 27 89 696 484 '

Where in order:
CropX CropY CropW CropH : Crop coords mod XMod, YMod, WMod, HMod.
XMod YMod WMod HMod : As used for above crop coords
Width Height : Original frame width and height
ORG_X1 ORG_Y1 ORG_X2 ORG_Y2 : Exact coords of found image, not rounded according to x/y/w/h mod (Before User Adjust)
CropMode : 1 = CropLess, 2 = CropMore(default)
X1 Y1 X2 Y2 : Coords after any User adjustments eg ORG_X1+LeftAdd etc and before applying XMod etc.
All values output are single SPACE separated.


EDIT: Also, RT_Stats has RT_QueryBorderCrop() which is a sort of cut down RoboCrop(). [Does not crop, just provides crop info]

EDIT:
But I do not know, if the source comes in upscaled or not.

Me neither, but I'm guessin' that is easy to just guess from current cropping coords. (would be your decision what to do with the
upscaled ones, we would simply provide crop coords [EDIT: or a 'crop type' index number, eg -1 = indiscernible, 0 = 1920x1080, etc]).

EDIT:
Provide list of crop coords, I'll try make func to return crop type index, or -1 (unknown), and write functions so that you can
add addional coords to list without my assistance.
It will be your job to figure out what to with with upscaled clip, when you give crop coords, can also provide optional original size,
and I will incorporate that data and allow you to retrieve if is upscaled, and original coords (if provided).

Q) Is border color fixed known value, ie set in NLE and never compressed ? (if so, what is it, also what colorspace, always same ?).

EDIT:
Will provide something like:-

CODS="""
0,0,1920,1080 # index 0, 1920,1080 without upscale coords
x,y,w,h # index 1, x,y,w,h, source coords, without upscale
x,y,w,h,x2,y2,w2,h2 # index 2, x,y,w,h, source coords, with upscale from x2,y2,w2,h2
... # additional, optionally added to by you, at your leasure.
"""

Will provide Functions to create a DBase of coords from CODS string, and also functions to scan and return
Index,
Src_Coord(Index, CoordIx ie 0-> 3), ie X to H,
IsUpScale(Index), ie True to False
Org_Coord(Index, CoordIx ie 0-> 3), ie X2 to H2.

Is that of use to you ?

EDIT: You could either create DBase for every file (every avs script accessing DBase), or create fixed DBase only once,
and use that until adding more crop formats to the CODS string.

EDIT: This is what I'm starting with.

CODS="""
0,0,1920,1080 # index 0, 1920,1080 without upscale coords
600,252,720,576 # index 1, 600,252,720,576, source coords, without upscale
285,0,1350,1080,600,252,720,576 # index 2, 285,0,1350,1080, source coords, with upscale from 600,252,720,576
640,300,640,480 # index 3, x,y,w,h, source coords, without upscale
240,0,1440,1080,640,300,640,480 # index 4, 240,0,1440,1080, source coords, with upscale from 640,300,640,480
# ... # additional, optionally added to by you, at your leasure.
"""

Would above be correct, especially the 285,0,1350,1080 in red ?
There is no Aspect ratio whatsit applied to the red numbers, what should they be, I'll go ahead as is above for the time being,
you can supply appropriate numbers at some point.
I will for now assume fixed border color is EXACTLY 16.

EDIT: Above X2,Y2 are nonsense, will only have W2,H2.

StainlessS
11th May 2018, 02:40
You wanna give this a whirl,

Firstly, script to make a coords DBase from coordinates definition string.

# Hot_MkDBase.avs

GImport(".\Hot_DBase.avs")

DB=RT_GetFullPathName("Hot_DBase.DB")

/*
Hotte_MkDBase(String Coords,String DB)
*/

HOT_CODS="""
0,0,1920,1080 # index 0, 1920,1080 without upscale coords
600,252,720,576 # index 1, 600,252,720,576, source coords, without upscale
285,0,1350,1080, 720,576 # index 2, 285,0,1350,1080, source coords, with upscale from 720,576
640,300,640,480 # index 3, x,y,w,h, source coords, without upscale
240,0,1440,1080, 640,480 # index 4, 240,0,1440,1080, source coords, with upscale from 640,480
# ... # additional, optionally added to by you, at your leasure.
"""

Records=Hotte_MkDBase(HOT_CODS,DB)
MessageClip(String(records,"Records=%.0f"))


Script to Show the created DBase.

# Hot_ShowDBase.avs

GImport(".\Hot_DBase.avs")

DB=RT_GetFullPathName("Hot_DBase.DB")

/*
Hotte_Coord_X ( String DB,Int Index) Hotte_Coord_Y ( String DB,Int Index)
Hotte_Coord_W ( String DB,Int Index) Hotte_Coord_H ( String DB,Int Index)
Hotte_Coord_W2 ( String DB,Int Index) Hotte_Coord_H2 ( String DB,Int Index)
Hotte_IsUpScale(String DB,Int Index)
*/

Records=RT_DBaseRecords(DB)
S=""
for(i=0,Records-1) {
X=Hotte_Coord_X(DB,i) Y=Hotte_Coord_Y(DB,i) W=Hotte_Coord_W(DB,i) H=Hotte_Coord_H(DB,i)
W2=Hotte_Coord_W2(DB,i) H2=Hotte_Coord_H2(DB,i)
IsUpScale=Hotte_IsUpScale(DB,i)
S=S+RT_String("%d] %4d,%-4d %4dx%-4d : %4dx%-4d : %s\n",i,X,Y,W,H,W2,H2,IsUpScale?"T":"F")
}
ColorBars.KillAudio
RT_Subtitle("%s",S)

https://s20.postimg.cc/qa0oswbih/Hot_Show_DBase.jpg (https://postimg.cc/image/qa0oswbih/)

A test Script

# Hot_Client.avs

GImport(".\Hot_DBase.avs")

DB=RT_GetFullPathName("Hot_DBase.DB")

/* # Available Functions
Hotte_MkDBase(String Coords,String DB) # Make the DBase, can do this only once and use that DB, or create for each and every script.

# Find border coords and return DB Index/RecordNumber for that data, else if Show=True, returns the detect clip for perusal.
# If returning clip for perusal, shows Index, coords, associated coords and whether upscaled or not (T/F).
# YV24 or RGB ONLY.
Hotte_ScanClip(clip c,String DB,Bool "Show",Int "Samples",Int "BordCol",Float "Ignore")

# Return X,Y,W,H coords for DB Index entry returned from Hotte_ScanClip().
Hotte_Coord_X(String DB,Int Index) Hotte_Coord_Y(String DB,Int Index)
Hotte_Coord_W(String DB,Int Index) Hotte_Coord_H(String DB,Int Index)

# Return True for DB Index (found by Hotte_ScanClip) if that DB entry has original coords associated with it.
Hotte_IsUpScale(String DB,Int Index)

# Returns the associated pre upscale coords (not same as Hotte_Coord_W and Hotte_Coord_H if Hotte_IsUpScale==True).
Hotte_Coord_W2(String DB,Int Index) Hotte_Coord_H2(String DB,Int Index)

# Returns a string of coords given an index returned by Hotte_ScanClip.
Hotte_InfoStr(String DB,Int Index)
*/

### TEST CONFIG ###
UPSCALE = False ### Test is Upscaled
### END TEST CONFIG ###

ORG=Colorbars.KillAudio #.ConvertToYV24
C = (!UPSCALE) ? ORG : ORG.BicubicResize(1440,1080)
BORDL=(1920-C.Width) /2 BORDT=(1080-C.Height)/2 BORDR=1920-C.Width-BORDL BORDB=1080-C.Height-BORDT

C.AddBorders(BORDL,BORDT,BORDR,BORDB)

#return Hotte_ScanClip(Last,DB,Show=true) # Un-Comment to Return detect Clip for perusal.

Index = Hotte_ScanClip(Last,DB) # Get ScanClip, OR DB Record/coord Index number

Return MessageClip(Index<0 ? "-1] Coord NOT FOUND" : Hotte_InfoStr(DB,Index))

Upscale=True
https://s20.postimg.cc/ivbczz7h5/Hot_Client.jpg (https://postimg.cc/image/ivbczz7h5/)
Upscale=False
https://s20.postimg.cc/jm435xx1l/Hot_Client_False.jpg (https://postimg.cc/image/jm435xx1l/)

Finally, the Library routines used by other scripts.

# Hot_DBase.avs # Use GImport in either AVS+, or AVS with GScript

### START OF PRIVATE FUNCTIONS #######
Function Hotte_GetField_LO(String DB,Int Index,Int Field,String "name") { # Private Function, Do NOT use
myName=Default(name,"Hotte_GetField_LO: ")
Assert(DB!="",RT_String("%sDBase Name required",myName))
DBase=RT_GetFullPathName(DB) Assert(Exist(DB),RT_String("%sDBase Does Not exist",myName)) Records=RT_DBaseRecords(DB)
Assert(Index>=0 && Index<Records,RT_String("%sDBase[%d] Invalid Record/Index (0->%d)",myName,Index,Records-1))
Assert(Field>=0 && Field<=6,RT_String("%sDBase[%d] Invalid Source CoordIx[%d] (0->5)",myName,Index,Field))
Return RT_DBaseGetField(DB,Index,Field)
}
Function ChrIsDigit(String S) {C=RT_Ord(S) return C>=48&&C<=57}
Function ChrIsComma(String S) {return RT_Ord(S)==44}
Function ChrEatWhite(String S) {i=1 C=RT_Ord(S,i) While(C==32||C>=8&&C<=13) {i=i+1 C=RT_Ord(S,i)} return i>1?MidStr(S,i):S}
Function ChrEatDigits(String S) {i=1 C=RT_Ord(S,i) While(C>=48&&C<=57) {i=i+1 C=RT_Ord(S,i)} return i>1?MidStr(S,i):S}
### END OF PRIVATE FUNCTIONS #########

Function Hotte_Coord_X( String DB,Int Index) {Return Hotte_GetField_LO(DB,Index,0,"Hotte_Coord_X: ")}
Function Hotte_Coord_Y( String DB,Int Index) {Return Hotte_GetField_LO(DB,Index,1,"Hotte_Coord_Y: ")}
Function Hotte_Coord_W( String DB,Int Index) {Return Hotte_GetField_LO(DB,Index,2,"Hotte_Coord_W: ")}
Function Hotte_Coord_H( String DB,Int Index) {Return Hotte_GetField_LO(DB,Index,3,"Hotte_Coord_H: ")}
Function Hotte_Coord_W2( String DB,Int Index) {Return Hotte_GetField_LO(DB,Index,4,"Hotte_Coord_W2: ")}
Function Hotte_Coord_H2( String DB,Int Index) {Return Hotte_GetField_LO(DB,Index,5,"Hotte_Coord_H2: ")}
Function Hotte_IsUpScale(String DB,Int Index) {Return Hotte_GetField_LO(DB,Index,6,"Hotte_IsUpScale: ")}

Function Hotte_MkDBase(String Coords,String DB) {
myName="Hotte_MkDBase: "
Assert(Coords!="",RT_String("%sCoords string required",myName))
Assert(DB!="",RT_String("%sDBase Name required",myName)) DBase=RT_GetFullPathName(DB)
Lines = RT_TxtQueryLines(Coords)
RT_DBaseAlloc(DB,0,"iiiiiib")
rec=-1
For(i=0,Lines-1) {
SSS=RT_TxtGetLine(Coords,i).ChrEatWhite
if(SSS!="" && RT_Ord(SSS)!=35) { # NOT Empty line or Hash (#) ALL Comment
S=SSS
Assert(ChrIsDigit(S),RT_String("%sLINE_%d Expecting X Coord\n'%s'",myName,i+1,SSS))
X=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite
if(S.ChrIsComma) {S=MidStr(S,2).ChrEatWhite}
Assert(ChrIsDigit(S),RT_String("%sLINE_%d Expecting Y Coord\n'%s'",myName,i+1,SSS))
Y=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite
if(S.ChrIsComma) {S=MidStr(S,2).ChrEatWhite}
Assert(ChrIsDigit(S),RT_String("%sLINE_%d Expecting W Coord\n'%s'",myName,i+1,SSS))
W=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite
if(S.ChrIsComma) {S=MidStr(S,2).ChrEatWhite}
Assert(ChrIsDigit(S),RT_String("%sLINE_%d Expecting H Coord\n'%s'",myName,i+1,SSS))
H=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite
W2=W H2=H
if(S!="" && RT_Ord(S)!=35) { # NOT Empty line or Hash (#)
if(S.ChrIsComma) {S=MidStr(S,2).ChrEatWhite}
Assert(ChrIsDigit(S),RT_String("%sLINE_%d Expecting W2 Coord\n'%s'",myName,i+1,SSS))
W2=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite
if(S.ChrIsComma) {S=MidStr(S,2).ChrEatWhite}
Assert(ChrIsDigit(S),RT_String("%sLINE_%d Expecting H2 Coord\n'%s'",myName,i+1,SSS))
H2=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite
Assert(S=="" || RT_Ord(S)==35,RT_String("%sLINE_%d UnExpected character '%c'\n'%s'",myName,i+1,RT_Ord(S),SSS))
}
for(j=0,rec) {
if(X==RT_DBaseGetField(DB,j,0)&&Y==RT_DBaseGetField(DB,j,1)&&W==RT_DBaseGetField(DB,j,2)&&H==RT_DBaseGetField(DB,j,3)) {
Assert(False,RT_String("%sLine_%d Coords Already Exists (%d,%d,%d,%d)\n'%s'",myName,i+1,X,Y,W,H,SSS))
}
}
Assert(W2<=W && H2<=H,RT_String("%sLine_%d Current Coords %dx%d DownScaled from %dx%d\n'%s'",myName,i+1,W,H,W2,H2,SSS))
IsUpScale=(W>W2||H>H2)
rec=rec+1
RT_DBaseAppend(DB,X,Y,W,H, W2,H2, IsUpScale)
RT_DebugF("%d] %4d,%4d,%4d,%4d : %4d,%4d : %s",rec,X,Y,W,H, W2,H2, IsUpScale?"T":"F", name=myName)
} # End SSS!="" && RT_Ord(SSS)!=35
} # End For i
Return RT_DBaseRecords(DB)
}

Function Hotte_InfoStr(String DB,Int Index) {
myName="Hotte_InfoStr: "
Assert(DB!="",RT_String("%sDBase Name required",myName)) Assert(Exist(DB),RT_String("%sDBase Does Not exist",myName))
DBase=RT_GetFullPathName(DB) Assert(Exist(DB),RT_String("%sDBase Does Not exist",myName)) Records=RT_DBaseRecords(DB)
Assert(Index>=0 && Index<Records,RT_String("%sInvalid Index(%d) for DBase (0->%d)",myName,Index,Records-1))
Return RT_string("%d] %d,%d %dx%d : %dx%d : UpScaled=%s",Index,
\ RT_DBaseGetField(DB,Index,0),RT_DBaseGetField(DB,Index,1), RT_DBaseGetField(DB,Index,2),RT_DBaseGetField(DB,Index,3),
\ RT_DBaseGetField(DB,Index,4),RT_DBaseGetField(DB,Index,5), RT_DBaseGetField(DB,Index,6)?"T":"F")
}

Function Hotte_ScanClip(clip c,String DB,Bool "Show",Int "Samples",Int "BordCol",Float "Ignore") {
# Returns Clip if SHOW=True, Else Int DBase Record Number/Coord_Index.
c myName="Hotte_ScanClip: "
Assert(IsRGB24 || IsRGB32 || IsYV24,RT_String("%sRGB24 or RGB32 or YV24 ONLY Please",myName))
Assert(DB!="",RT_String("%sDBase Name required",myName)) Assert(Exist(DB),RT_String("%sDBase Does Not exist",myName))
Records=RT_DBaseRecords(DB) Assert(Records>0,RT_String("%sDBase NO Records",myName))
Show=Default(Show,False) Samples=Default(Samples,40)
BordCol=Default(BordCol,IsYV24?16:0) Ignore=Default(Ignore,0.0)
LogFn=RT_GetFullPathName("~Hotte_ScanClip_"+RT_LocalTimeString(File=True))
RoboCrop(Samples=Samples,Laced=False,WMod=1,HMod=1,Debug=True,Ignore=Ignore,Thresh=BordCol,Start=0,End=0,Show=True,Align=true,LogFN=LOGFN)
Assert(Exist(LogFN),RT_String("%sCannot Read LogFN",myName))
S=RT_ReadTxtFromFile(LogFN) RT_FileDelete(LogFn)
Crop_X=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite Crop_Y=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite
Crop_W=RT_NumberValue(S) S=ChrEatDigits(S).ChrEatWhite Crop_H=RT_NumberValue(S)
GotIx = -1
for(i=0,Records-1) {
X=RT_DBaseGetField(DB,i,0) Y=RT_DBaseGetField(DB,i,1) W=RT_DBaseGetField(DB,i,2) H=RT_DBaseGetField(DB,i,3)
if(X==Crop_X && Y==Crop_Y && W==Crop_W && H==Crop_H) {
GotIx=i
i=Records # Break with i=records+1
}
}
if(GotIx>=0) {
W2=RT_DBaseGetField(DB,GotIx,4) H2=RT_DBaseGetField(DB,GotIx,5) US=RT_DBaseGetField(DB,GotIx,6)
S=RT_string("%d] %d,%d %dx%d : %dx%d : UpScaled=%s",GotIx,CROP_X,CROP_Y,CROP_W,CROP_H,W2,H2,US?"T":"F")
Subtitle(S,Size=40,Align=5)
} else {
S=RT_string("%d] %d %d %d %d : NOT FOUND",GotIx,CROP_X,CROP_Y,CROP_W,CROP_H)
Subtitle(S,Size=40,Align=5,Text_Color=$FF0000)
}
RT_DebugF("%s",S,name=myName)
return (SHOW) ? Last : GotIx
}

EDIT: Hot_Client and Hot_DBase updated.

Blue_MiSfit
11th May 2018, 03:41
If you're not married to avisynth, ffmpeg has the cropdetect filter that works pretty well :)

StainlessS
11th May 2018, 12:57
If you're not married to avisynth, ffmpeg has the cropdetect filter that works pretty well :)

He wants to know the coords of crop, not do crop itself, if only crop required then RoboCrop would perform that quite nicely.
Also seems to want to have some related coordinates found to decide whether or not it was upscaled from some other original size.

Thanks Groucho, I looked into this before I started this thread. I am not sure, if/how this can help.
I do not need a cropping tool.
I just need a simple check, if there are borders or not.
If no I will do nothing, if yes I will use standard avisynth crop (because I know the format) and upscale with LanczosResize.
I do not know how such a condition can be created.

richardpl
11th May 2018, 13:34
cropdetect filter does not crop....

StainlessS
11th May 2018, 14:04
I stand corrected, thank you :)

Blue_MiSfit
11th May 2018, 19:37
Right, I've implemented this filter to gather the coordinates to use in optional downstream processing in a player before ;)

Hotte
14th May 2018, 21:56
Wow, StainlessS is the man...really, really impressive.

Sorry I wasn't in for a couple of days so I had not noticed, that this thread sort of exploded.

Mmmmhhh, I am a bit confused now where to start.....

OK, prerequisites are: Each avisynth script only takes in one single clip whose original format is known to me since the avisynth script is being created automatically and individually by Autohotkey, but due to my requirements. Two formats are typical: One is 720x576, the other is 640x480. Typical target format is 1920x1080.

If NLE upscaled its avi-output - to let's say 720x576 - I am getting frames 1350 x 1080 with black borders left and right to fill 1920 x 1080 and no borders above and below. If this is the case i will code:


clp = BlackmanResize(clp,1024,576)
#....apply some filters...
clp = BlackmanResize(clp,1920,1080)


This is done due to the fact, that some filters only work right if being applied to the original format rather than upscaled stuff.

If NLE did not upscale, there will be total black borders (RGB-Color 0x000000) above and below in the incoming AVIs. In this case I will do the same but leave away the first resize statement.

That's about it.

I am just simply looking for the "if-then" statement to tell avisynth to leave away the first clp = BlackmanResize(clp,1024,576) statement. This will deliver better quality, more sharpness, less blocking and is recommended to the NLE-user, but unfortunately is not always done by the user and canīt sufficiently be monitored.

A simple rectangle check for blackness on given coords will work perfectly for me in 99,5% of the cases.

So which part of you suggested code would you recommend to implant into my script ? Crop coords can be delivered and do need to be calculated or estimated.

Thanks so much for your time and effort, guys!

StainlessS
14th May 2018, 23:32
Post #10 client and library funcs scripts updated. [EDIT: Allowed RGB24/32 as well as YV24, in library funcs]

nuther client, as per request.

# Hot_Client2.avs

GImport(".\Hot_DBase.avs")
DB=RT_GetFullPathName("Hot_DBase.DB")

################
UPSCALE = False ## Test is Upscaled, set either True or False
ORG=Colorbars.KillAudio ##.ConvertToYV24
C = (!UPSCALE) ? ORG : ORG.BicubicResize(1440,1080)
BORDL=(1920-C.Width) /2 BORDT=(1080-C.Height)/2 BORDR=1920-C.Width-BORDL BORDB=1080-C.Height-BORDT
C.AddBorders(BORDL,BORDT,BORDR,BORDB)
# Above, whatever your clip source is (I only have test func).
################
#Return Hotte_ScanClip(Last,DB,SHOW=TRUE) # UnComment, shows detect index, coords, associated coords & if Upscaled or not.

Index = Hotte_ScanClip(Last,DB) # Get DB Record/coord_Index_number.
if(Index<0) { Assert(False,"Hotte_ScanClip, Coords NOT FOUND in DBase") } # Show Not Found Error

### Get, Coords ##################################
X=Hotte_Coord_X(DB,Index) Y=Hotte_Coord_Y(DB,Index)
W=Hotte_Coord_W(DB,Index) H=Hotte_Coord_H(DB,Index)
# Get, Associated Coords
W2=Hotte_Coord_W2(DB,Index) H2=Hotte_Coord_H2(DB,Index) # ie pre-upscale width and height (same as W,H if not upscaled)
# Get, Was Upscaled Status
WasUpscaled=Hotte_IsUpScale(DB,Index)

if (WasUpscaled) {
# Do whatever you want to clip that WAS previously upscaled
} else {
# Do whatever you want to clip that was NOT previously upscaled
}

# Do whatever else you want to do.

return last


EDIT: Of course you need to supply your complete list of coords in the HOT_CODS string in post #10, and create DBASE, either create
DB once and always use that [EDIT: as we did here], or create in every script, your choice.

EDIT: Above assumes Avs+ with builtin GSCript, wrap script in GScript(""" ... """) if avs standard.

EDIT: Above in red fixed (was W2=Hotte_Coord_W and H2=Hotte_Coord_H instead of W2=Hotte_Coord_W2 and H2=Hotte_Coord_H2)

Hotte
15th May 2018, 01:03
Thank you very much for your kind and intense help, StainlessS.

I will test this coding as soon as I can. There are a number of commands in it I have never used before, but I will fight my way through....I am happy to come back with feedback soon.

I have always admired the guys here in this forum playing around with highly complex code that turned avisynth into that gold bar it is today.

Just a little slightly off-topic question - so only a small hint please: Starting off with more and more 4K footage I am sometimes running out-of-memory (some message like "I think we ran out of mem, folks") already with small filter-stacks (mdegrain is a hard consumer here). Are we touching the ultimate limits here ?

Hotte

StainlessS
15th May 2018, 07:13
Oops, sorry. Couple of faux pas fixed in prev post (marked in red).

I dont play with 4K.

Hotte
18th May 2018, 11:06
I will be travelling for 2 weeks. I will look into the code later. Thanks so far.