View Full Version : Trim out Black Frames Automatically
FranceBB
17th September 2021, 10:37
Hi there,
my colleagues in another floor are capturing losslessly our whole archive using several VTRs and a BlackMagic DeckLink that saves the file as 4:2:2 10bit v210 lossless with PCM audio.
Unfortunately, timecode jumps so it's not possible to set TCin and TCout to make the recording stop automatically.
What they're doing is trying to set up alarm clocks in their phones and stop tapes manually, but since they have to do plenty of other things at the same time, sometimes they forget.
This leads to several minutes of black frames at the end of a tape recording and, sometimes, the tape goes back to the beginning.
Of course, I see everything that is recorded and I've been using Virtual Dub with Direct Stream Copy to trim out everything since v210 is lossless and all intra as every frame is a keyframe, so I can trim out easily without re-encoding, however we're getting to a point in which I can't trim out as many files.
The other day alone I've been trimming out 37 files...
The day before that it was 53 files...
I have other things to do in my job of course, I can't spend the whole day trimming out black frames in several files...
I can't go on like this and my boss response was: "Automatize it!"
so... here I am: is there a way (either in Avisynth or FFMpeg) to detect black frames at the end of a file and trim them out automatically?
(I know, I know, levels might come into play as tapes don't have a perfect black sitting at 64, so 0.0V, however is there anything that has a tweakable threshold and can do this?)
Frank62
17th September 2021, 11:08
Difficult without re-encoding...
Maybe something like:
-detect via avisynth (using a threshold, as you already thought, which might be quite difficult if blackness inside the video), log files, batch VirtualDub to let it all run
-write a small application to convert the cuts to vdscripts
-batch VirtualDub again with these
Dogway
17th September 2021, 11:32
Search AverageLuma backwards and when threshold is reached, send the framenumber to mkvtoolnix to split the file. Assuming the end of video is "black frame".
StainlessS
17th September 2021, 13:01
FaBB, can you come up with some command line (for ffmpeg or whatever), I can write a AVS script which can
fill in args for template command and save command wherever you like for later running, I guess could even auto run the command.
Anyway just supply template command line, with description of what and where to insert filenames and frame number or whatever.
EDIT:
I'll do a Vdub2 JOB script, then only need run Jobs in VD2.
I need you to run VD2,
Clear any jobs in VD2 job queue.
Set to Direct Stream Copy.
Load a clip into VDub2, manually trim off the black, Queue Batch operation / save Video.
Post VD2 job script.
FranceBB
17th September 2021, 14:53
Well right now I'm experimenting with:
for %%1 in ("*.avi") do ffmpeg.exe -i "%%1" -vf "blackdetect=d=0.1:pix_th=0.00" -an -f null - 2>&1 | findstr black_duration >> TMS.txt
to detect the black.
Then use them to trim in AVS or whatever even FFMpeg would be ok.
About re-encoding it's not a big deal, I could just go from v210 lossless to HuffYUV lossless 10bit like:
ffmpeg.exe -i "Test.avs" -pix_fmt yuv422p10 -vcodec ffvhuff -color_range 1 -color_primaries 1 -color_trc 1 -colorspace 1 -c:a pcm_s32le -ar 48000 -f avi -y "\\mibctvan000\Ingest\MEDIA\temp\output.avi"
pause
StainlessS
17th September 2021, 15:18
See EDIT:
Is that OK/better.
EDIT: I'll do the ffmpeg thingy 1st, looks easier, then if required VD2 whotsit.
StainlessS
17th September 2021, 20:14
Wanna give this a whirl FaBB. [Req AVS+, RT_Stats and CallCmd]
# FfMpeg_DeBlack.avs [Req AVS+, RT_Stats and CallCmd]
# Batch Process: Trim ALL Black frames from end of clip and call ffmpeg to re-encode.
###################################################
############## CONFIG #################
###################################################
TMPDIR = ".\TMP" # NO trailing backslash. MUST EXIST [CAN USE "" where system %TEMP% dir used instead].
INDIR = ".\IN" # NO trailing backslash. MUST EXIST
OUTDIR = ".\OUT" # NO trailing backslash. MUST EXIST
WILDCARD = "*.AVI"
NoiseTh = 0.4 # 0.4) As for YPlaneMax (% limit of of noise pixels to Ignore when finding YPlaneMax)
YMaxTh = 80 # 20*4) If YPlaneMax(threshold=NoiseTh) is above this, then is not black. In 10 bit Range (TV levels 64 -> 940) ]. [80 = 10 bit equivalent of 8 bit 20]
DEBUG = 1 # 1) 0 Off, 1 norm debug, 2 full debug
# If using AvsInit script, then as ffmpeg script uses Avisynth, so will clear DebugView window on each ffmpeg command and debugging will be cleared by AvsInit,
# If you need to see log, do test with either EXEC_CMD=False, or Log to file in DebugView.
# Suggest ALL below as in original script, as 1st value in comment. [Also, Use VDub2 and dont touch VDub2 or close it till shows "DONE"]
EXEC_CMD = True # True) Execute the ffmpeg Command file.
PAUSE = False # False) Pause before Close of ffmpeg console window when executing ffmpeg command file.
HIDE = False # False) Show ffmpeg command console window
SYNC = True # True) False return to opening app (eg Vdub2) immediately CMD file Executed, else Wait for command file to complete.
# If SYNC=True and you dont close the parent app, until Shows DONE, then will auto Delete the command file from TMPDIR.
DELINDEX = True # True) If True, and also using FfVideoSource in AVS_TEMPLATE, then will auto delete the ffindex files.
###################################################
/*
# If Can use FourCC 'FFVH" in AviSource when scan for black.
SOURCE_FILTER = """AviSource("__IN_FILENAME__")"""
*/
# If Can't use FourCC 'FFVH" in AviSource when scan for black, then use this.
SOURCE_FILTER = """FFVideoSource("__IN_FILENAME__")"""
FF_TEMPLATE = """ffmpeg.exe -i "__FF_AVSNAME__" -pix_fmt yuv422p10 -vcodec ffvhuff -color_range 1 -color_primaries 1 -color_trc 1 -colorspace 1 -c:a pcm_s32le -ar 48000 -f avi -y "__FF_OUTNAME__""""
###################################################
############## END CONFIG ################
###################################################
AVS_TEMPLATE = """
__SOURCE_FILTER__
Trim(0,__END_FRAME__)
Return Last
"""
myName = "FfMpeg_Deblack: "
TMPDIR = (TMPDIR=="") ? RT_GetSystemEnv("TEMP") : TMPDIR.RT_GetFullPathname
INDIR = INDIR.RT_GetFullPathname
OUTDIR = OUTDIR.RT_GetFullPathname
FILELIST = TMPDIR + "\~FileList_" + RT_LocalTimeString(True) + ".txt"
CMD_File = TMPDIR + "\FfMpeg_Deblack_" + RT_LocalTimeString(True) + ".CMD"
DBG = DEBUG>0
VERB = DEBUG>1
PAUSE = (HIDE) ? FALSE : PAUSE # Dont pause unless Hide = false
if(DBG) {
RT_DebugF("DBGVIEWCLEAR")
RT_DebugF("TMPDIR='%s'",TMPDIR,name=myName)
RT_DebugF("INDIR='%s'",INDIR,name=myName)
RT_DebugF("OUTDIR='%s'",OUTDIR,name=myName)
RT_DebugF("FILELIST='%s'",FILELIST,name=myName)
RT_DebugF("WILDCARD='%s'",WILDCARD,name=myName)
RT_DebugF("CMD_FILE='%s'",CMD_FILE,name=myName)
}
CMD_TEXT = ""
NFILES = RT_WriteFileList(INDIR + "\" + WILDCARD,FILELIST)
Assert(0 <= NFILES,myName+"Problem writing FileList")
Assert(0 != NFILES,myName+"Zero files matching Wildcard")
(DBG) ? RT_DebugF("Number of files detected = %d",NFILES,name=myName) : NOP
AVST_Find = RT_String("__SOURCE_FILTER__\n__END_FRAME__\n")
FFT_Find = RT_String("__FF_AVSNAME__\n__FF_OUTNAME__\n")
For(i=0,NFILES-1) {
in_filename = RT_ReadTxtFromFile(FILELIST ,Lines=1,Start=i).RT_TxtGetLine() # Read filename and remove trailing NewLine
TESTSOURCE = RT_StrReplace(SOURCE_FILTER,"__IN_FILENAME__",in_filename)
(DBG) ? RT_DebugF("\n%d) Loading ... %s",i+1,TESTSOURCE,name=myName) : NOP
c = Eval(TESTSOURCE) # Read source file for test
(DBG) ? RT_DebugF("Counting Black @ NoiseTh=%f YMaxTh=%d",NoiseTh,YMaxTh,name=myName) : NOP
NonBlkCnt = c.FindNonBlackFramesAtEnd(YMaxTh,NoiseTh,VERB) # good frame count
(DBG) ? RT_DebugF("Good Frames= %d : Black count = %d",NonBlkCnt,c.Framecount-NonBlkCnt,name=myName) : NOP
Assert(NonBlkCnt < c.framecount,myName+"NO BLACK END FRAMES FOUND\n"+in_filename)
Trim_End_frame = -NonBlkCnt # -ve version of end frame for trim
AVS_FileName = RT_FilenameSplit(in_filename,4) # Name node only, no drive/path/ext
AVS_FullName = TMPDIR + "\" + AVS_FileName + ".avs"
AVST_Repl = RT_String("%s\n%d\n",TESTSOURCE,Trim_End_frame)
AVS_TEXT = RT_StrReplaceMulti(AVS_TEMPLATE,AVST_Find,AVST_Repl,True)
RT_WriteFile(AVS_FullName,"%s",AVS_TEXT) # Write the avs file
(DBG) ? RT_DebugF("AVSFILE=%s\n%s",AVS_FullName,AVS_TEXT,name=myName) : NOP
FF_FullName = OUTDIR + "\" + AVS_FileName + ".avi"
FFT_Repl = RT_String("%s\n%s\n",AVS_FullName,FF_FullName)
CMD_LINE = RT_StrReplaceMulti(FF_TEMPLATE,FFT_Find,FFT_Repl,True) # ffmpeg command line
CMD_LINE = RT_String("""%s\nDEL /q "%s"""",CMD_LINE,AVS_FullName) # Add AVS Delete. "DEL /q AvsFileName" : Dont Ask for comfirmation # COMMENT OUT for no delete AVs files.
if(DELINDEX && RT_FindStr(SOURCE_FILTER,"FFVideoSource",sig=false)>0) { # If DELINDEX && SOURCE_FILTER uses FFVideoSource then delete the index file.
CMD_LINE=RT_String("""%s\nDEL /q "%s.ffindex"""",CMD_LINE,in_filename) # Add ffindex Deletion.
}
CMD_TEXT = RT_String("%s\n%s\n",CMD_TEXT,CMD_LINE) # add all to CMD_TEXT
(DBG) ? RT_DebugF("CMD_LINES=\n%s\n",CMD_LINE,name=myName) : NOP
}
CMD_TEXT = (PAUSE) ? RT_String("%s\n\nPAUSE\n",CMD_TEXT) : CMD_TEXT # Add 'pause' to command if required
(DBG) ? RT_DebugF("Deleting FILELIST",name=myName) : NOP
RT_FileDelete(FILELIST)
(DBG) ? RT_DebugF("\nCommand File::::",name=myName) : NOP
(DBG) ? RT_DebugF("%s",CMD_TEXT,name=myName) : NOP
RT_WriteFile(CMD_File,"%s",CMD_TEXT) # Write the cmd file
MessageClip("DONE " + String(NFILES)).Loop(99999,0,0) # lots of frames
(EXEC_CMD) ? CallCmd(open =RT_String("""CMD /C chcp 1252 && "%s" """,CMD_File), hide=HIDE, Synchronous=(SYNC)?7:0) : NOP # Exec Command file
(EXEC_CMD&&SYNC) ? CallCmd(close=RT_String("""CMD /C DEL /q "%s" """,CMD_File), hide=true, Synchronous=7,debug=true) : NOP # Delete Command file if EXEC_CMD && SYNC, on Messageclip Clip Closure.
Return Last
#####################
Function FindNonBlackFramesAtEnd(clip c,Int YMaxTh,Float "NoiseTh",bool "Debug") {
myName="FindNonBlackFramesAtEnd: "
c
Debug=Default(debug,False)
FC = FrameCount
result = 0
NoiseTh=Float(Default(NoiseTh,0.4))
for(n=FC-1,0,-1) {
current_frame = n
Y = YPlaneMax(Last,Threshold=NoiseTh)
(Debug) ? RT_DebugF("%d] Y=%f",n,Y,name=myName) : NOP
if(Y>YMaxTh) {result = n+1 n = -1 }
}
return result
}
Updated
StainlessS
18th September 2021, 16:52
Search AverageLuma backwards and when threshold is reached.
AverageLuma is the wrong metric for this job [EDIT: IMHO].
Y=YPlaneMax(threshold=THRESH) is a lot better, where it will ignore UP TO THRESH % of extreme noise pixels, and search till Y > YMax where my YMax is same as your "threshold".
Think I'll rename my THRESH to NoiseTh, and YMax to YTh.
Default NoiseTh I've used in FindNonBlackFramesAtEnd() is 0.4 %, which is about 1 noise pixel in every 256 pixels. [1/256 * 100 = 0.39... %]
I used
THRESH = 2.0 # As for YPlaneMax (% limit of of noise pixels to Ignore when finding YPlaneMax)
which is maybe a bit high but should work just fine, somewhere between 0.4 and 2.0 suggested.
OneInX = 100.0 / Percent, where Percent = 0.5 would be [100.0/0.5] up to 1 noise pixel in 200 pixels ignored.
FaBB, I only tested on 8 bit, and so originally set YMAX=28, I forgot yours is 10 bit so changed to 28*4,
Are you gonna ever use anything other than 10 bit ? [I could auto scale 8 bit YMAX to whatever bit depth used (could also edit "yuv422p10" or other args to ffmpeg cmd, say if is required)].
The settings THRESH=2.0 and YMAX = 28*4 may seem very 'loose' but should detect all black and be immune to very severe noise,
but you can alter as you see fit. [Maybe your blacks are known digital 16*4 or thereabouts where you can make more sensible adjustment].
(The values I used were originally used in some other black detector, where could be very noisy source VHS).
StainlessS
18th September 2021, 19:46
I've been trying to load FranceBB output files [-pix_fmt yuv422p10 -vcodec ffvhuff] via Avisource,
and get the avisource error about not having "FFVH" FourCC vfw codec.
On-line search suggests ffdshow for vfw avisource loading.
I installed x64 and x86 versions and both prevent me from viewing/setting vfw config, it just dont appear on W10 1909 x64.
Windows Application Event Log shows Access Violation (0xC0000005).
Faulting application name: rundll32.exe_ff_vfw.dll, version: 10.0.18362.1, time stamp: 0x8ceb427f
Faulting module name: ff_vfw.dll, version: 1.2.4475.0, time stamp: 0x4ffefccd
Exception code: 0xc0000005
Fault offset: 0x0000000000001616
Faulting process ID: 0x8f0
Faulting application start time: 0x01d7acb951f6fa04
Faulting application path: C:\Windows\system32\rundll32.exe
Faulting module path: C:\Windows\system32\ff_vfw.dll
Report ID: 9386c48b-8719-44ca-9f3e-948529f407a6
Faulting package full name:
Faulting package-relative application ID:
Tried versions of ffdshow, [ https://sourceforge.net/projects/ffdshow-tryout/files/ ]
SVN builds by XhmikosR, ICL builds from 2012 : x86 ffdshow_rev4475_20120712_xhmikosr_icl12.exe, AND ,x64 ffdshow_rev4475_20120712_xhmikosr_icl12_x64.exe
and
SVN builds by xxl, x86 (2011) ffdshow_rev4096_20111129.exe, AND, x64 (2009) ffdshow_rev3082_20090921_xxl_x64.exe
all fail the same.
Anybody any clues whats happening, or fix to load FFVH.
(I got recent lavfilters installed).
[I dont want to use ffmpegsource, or LSMash]
EDIT: Antivirus stuff all disabled.
EDIT: Re-installed in W7 compatability mode, run as Administrator.
Run vfw configuration with Run as administrator, same thing.
EDIT: Tried install CLSID version from 2014 [Is later than both above, despite higher level directory saying from 2011], and this time
it dont install vfw configuration shortcut at all, so still cant config it [dont know if its supposed to not install it].
FranceBB
18th September 2021, 21:27
First of all, thank you so much for coming up with the script, I'll test it on Monday when I'll be able to access the storage through a 10 Gbit/s ethernet cable rather than through a VPN via Internet eheheheh
About the codec, it's actually v210 and AviSource opens it just fine.
The whole "HuffYUV" thing is just for me to re-encode from lossless to lossless if I have to re-encode and you're right, HuffYUV can't be opened by AVISource(), only v210 can be opened by AviSource().
About the higher than 10bits, I don't think I'll ever make anything higher than 10bits 'cause those are really just old BetaCAM and Digital BetaCAM so 10bit 4:2:2 planar is already an overkill here ehehehehehe
StainlessS
19th September 2021, 01:14
OK, dedicated to 10 bit [I removed the upscale to 10 thingy, but could very easily put it back to specify YMaxTh in 0->255 range.]
Script in post #7 is updated.
And here little helper to maybe assist in choosing NoiseTh and YMaxTh for your sources,
dont try to get too near NoiseTh=0.0 and YMaxTh=64, even original severe noise settings would no doubt work fine [but I did mod them a little, assuming not total crap VHS src].
EDIT: SCRIPT REMOVED: see here Instead [use YPlaneOp=1.]:- https://forum.doom9.org/showthread.php?t=183236
EDIT: Test on black, ideally start where video ending has a natural black sequence, and then your 'added surplus' time-waster black stuff [and with at least a little leeway (higher) on YMaxTh].
Frank62
19th September 2021, 14:18
and you're right, HuffYUV can't be opened by AVISource(), only v210 can be opened by AviSource().
You just have to install the codec. We use it everyday.
StainlessS
19th September 2021, 18:19
Frank62, which codec do you use ? I have problems with ffdshow on W10 [access violation].
I know that DVDDecrypter has probs on my x64 W10 machine, tells me sometimes that I am Out-Of-Memory,
with ~3GB used and and 29GB free [???], maybe some problem related to that with ffdshow.
FranceBB
22nd September 2021, 13:34
Uhm... install the codec? That's gonna install the old HuffYUV 8bit; I don't think it's compatible with FFMpeg's ffvhuff which is the modern version of HuffYUV which goes to 10bit and above up to 16bit planar...
...or is it?
StainlessS
22nd September 2021, 13:45
So, does the ffmpeg thing work OK then ?
FranceBB
22nd September 2021, 15:45
So, does the ffmpeg thing work OK then ?
I've tested it and it seems to be working, however now I'm trying to include it in FFAStrans which is the automation software we use on a daily basis over here.
Of course, I can just put a command executor in there, but I'm trying to get a meaningful output in cmd out of it eheheheh.
But yeah, it seems to be doing what's supposed to do. :D
Well done.
StainlessS
22nd September 2021, 17:36
OK, thanks.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.