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. |
1st December 2010, 01:58 | #1 | Link |
Registered User
Join Date: Jan 2006
Posts: 1,867
|
New filter; Destruction of Chroma Interlacing
Hello, I'm working on a new script and am wondering if it's been solved before; if not if there's a better way to fix it.
Statement of the problem I have pulled-down NTSC video sampled in YV12/4:2:0. This destoys the chroma of interlaced frames, due to the vertical blending of the colors of line pairs. The result looks like blended frames. If the video is made greyscale, it will deinterlace properly with no problems. Review of pulldown process Film at 24fps has to be stetched by 5/4 to 30fps video. We do this by repeating some fields. This diagram shows the repetition. It is drawn in units of 1/120s; in this case a film frame lasts 5 units - 5/120=1/24, and a video field lasts 2 units, 2/120=1/60. This is shown as "0...." meaning film frame number 0 lasting for 5 units. The other lines are made by taking a snapshot of the film frame at that instant for the two fields of NTSC video. Code:
film 0....1....2....3....4....5.. top 0...0...1...2...3...4...4 bot ..0...1...2...2...3...4...5 fram cln lac lac cln cln|cln lac It's the two interlaced frames, (0top,1bot), (1top, 2bot), which cause the problem. First let me review color sampling. 4:2:2 YY with one C shared between them. This format can be recorded on VCR's, laserdisc, but not DVR's. 4:2:0 This records one common color for every 4 luma pixels; YY YY This format is recorded by hardware compression (mpeg) tv cards and is output by DVDs. Now imagine a red square moving right. Here are the original film frames 0-2: Code:
film 0: RRRR RRRR film 1: RRRR RRRR film 2: RRRR RRRR Code:
NTSC 0: RRRR (film 0) RRRR (film 1) NTSC 1: RRRR (film 1) RRRR (film 2) Code:
NTSC 0: rrRRrr (film 0) rrRRrr (film 1) NTSC 1: rrRRrr (film 1) rrRRrr (film 2) This is not CUE, DOI, or ICP - these all have to do with converting YV12 back to YUY2. Unless one exists, I'll call it a new term - Destruction of Chroma Interlacing, DOCI. I have no chance to re-cap in YUY2 since my card doesn't support this. I've also noticed that 3:2 pulldown presents a unique opportunity - perfect dot crawl removal for one field out of every 5. Dot crawl phase reverses every line and every two fields; the repeated NTSC film fields are two fields apart. I'll report back as I develop the filter. |
1st December 2010, 03:02 | #2 | Link |
Registered User
Join Date: Jan 2006
Posts: 1,867
|
Here's a script which generates the problem; now all I have to do is fix it
Code:
#Destruction of Chroma Interlacing filter #v0.1 #Capturing 3:2 pulled down material in YV12 leads to #frames with color ghosting when trying to deinterlace #This filter will correct the problem # #First create a test video with pulldown #Create a red square that moves red_yuv=$4164D4#in REC 601 square=blankclip(length=1,width=50,height=50,pixel_type="YUY2",fps=24000, fps_denominator=1001, color_yuv=red_yuv,sixteen_bit=true) background=colorbars(width=720,height=480,pixel_type="YUY2").assumefps("ntsc_film").converttomono.convertaudioto16bit.trim(0,16*10-1) #Make a moving red square ScriptClip(background,""" overlay(background,square,x=103-25+current_frame*4,y=240-25) """) #Pulldown to NTSC video AssumeFrameBased SeparateFields SelectEvery(8, 0,1, 2,3,2, 5,4, 7,6,7) Weave #This is the important part - reduce sampling to 4:2:0 to create the problem converttoyv12 separatefields |
1st December 2010, 08:35 | #3 | Link |
Registered User
Join Date: Jan 2006
Posts: 1,867
|
I've mostly solved it theoretically; this isn't optimized for real world video:
Code:
#Destruction of Chroma Interlacing filter by jmac698 #v0.5 #0.5: New method of calculation which hopefully will lead to setting the frame where the problem starts # for now, to use this on a real video you have to trim until the fix lines up with the problem. # GRunT is required now. #0.4: Include GRunT example, code improvements, used doubleweave. Planning to make dynamic. #Capturing 3:2 pulled down material in YV12 leads to #frames with color ghosting when trying to deinterlace #This filter will correct the problem #Known issues: still a bit of garbage left, non-adaptive - but can use editing to make it work for real, restored color has lost 1bit of accuracy, # may not preserve phase of rainbowing, restoration poor if video is not stable # #First create a test video with a moving red square #AVISource("C:\videos\test.avi") demo.pulldown32 LabelVideoWithCounts #This is the important part - reduce sampling to 4:2:0 to create the problem converttoyv12#our video is now destroyed! #change back to yuy2 so we can actually keep our reconstructed results converttoyuy2 destroyed=last #reconstruct chroma restored=doci #Show the ivtc'd video; compare against non-restored version stackvertical(destroyed.simpleivtc.subtitle("problem video",y=20),restored.simpleivtc.subtitle("restored video",y=20)) #This is working separatefields function demo() { #Create a red square that moves red_yuv=$4164D4#in REC 601 #Make a moving red square #unfortunately I have to make one of these global to work with scriptclip unless GRunT is installed global square=blankclip(length=1,width=50,height=50,pixel_type="YUY2",fps=24000, fps_denominator=1001, color_yuv=red_yuv,sixteen_bit=true) background=colorbars(width=720,height=480,pixel_type="YUY2").assumefps("ntsc_film").converttomono.convertaudioto16bit.trim(0,16*10-1) ScriptClip(background,""" overlay(square,x=103-25+current_frame*8,y=240-25) """) #If GRunT is installed, you can use this instead: #ScriptClip(background,""" # overlay(square,x=103-25+current_frame*8,y=240-25) #""", args="square") #add frame numbering assumetff separatefields top=last.selecteven bot=last.selectodd #all this is to remove color shadows; where the text overlays, color is desaturated, due to YV12 tu=top.utoy tv=top.vtoy bu=bot.utoy bv=bot.vtoy top1=top.ScriptClip("""subtitle("film frame on top field = " + string(current_frame),x=-1,y=20,size=20,text_color=$00FFFFFF,font_width=17)""") bot1=bot.ScriptClip("""subtitle("film frame on bot field = " + string(current_frame),x=-1,y=40,size=20,text_color=$00FFFFFF,font_width=17)""") top=ytouv(tu,tv,top1) bot=ytouv(bu,bv,bot1) interleave(top,bot) weave } function pulldown32(clip in) { #Expects and returns a frame based clip in AssumeFrameBased.AssumeTFF SeparateFields #8 progressive frames turn into 10 fields SelectEvery(8, 0,1,0, 3,2, 5,4,5, 6,7)# this is 3:2 pulldown unlike the example under SelectEvery which is 2:3 #this order is most accurate in time order; i.e. 3/60<2/24, though other orders may be preferred for other reasons Weave } function restorechroma(clip destroyed, clip clean) { #restores merged chroma from destoyed by subtracting clean, one of the mergee's #destroyed=(clean+unknown)/2, unkown=(destroyed-clean/2)*2 subtract(destroyed,clean.tweak(sat=.5)).tweak(sat=2) #now merge with existing luma #note: there is no precision loss compared with d*2-c because d and c are always even; # because the destruction was d=(c+unknown)/2 mergechroma(destroyed,last) } function doci(clip in) { #Expects and returns a frame based clip #Restore destroyed chroma; four fields out of 10 #note that if the pulldown pattern is distrupted, you may have to trim/edit the output #Extract all the fields #Need f1, f3, f4, f6 to reconstruct #Output 0,1,0,newf3,newf4,7,6,7,8,9 #Note: I considered using DoubleWeave, but that doesn't give me the combinations two fields apart which I need cycle=10 offset=0 in.assumetff.separatefields fr=last.framerate f0=selectevery(cycle,offset+0).changefps(fr)#you are decimating by 10, to change back to orignal framerate f1=selectevery(cycle,offset+1).changefps(fr) f3=selectevery(cycle,offset+3).changefps(fr) f4=selectevery(cycle,offset+4).changefps(fr) f6=selectevery(cycle,offset+6).changefps(fr) f7=selectevery(cycle,offset+7).changefps(fr) newf3=restorechroma(f3,f1).changefps(fr)#new 1bot newf4=restorechroma(f4,f6).changefps(fr)#new 1top conditionalfilter(last,f0,last,"current_frame % cycle", "equals", "offset+2",args="cycle, offset") conditionalfilter(last,newf3,last,"current_frame % cycle", "equals", "offset+3",args="cycle, offset") conditionalfilter(last,newf4,last,"current_frame % cycle", "equals", "offset+4",args="cycle, offset") conditionalfilter(last,f7,last,"current_frame % cycle", "equals", "offset+5",args="cycle, offset") #f0,f1,f0,newf3,newf4,f7,f6,f7,f8,f9 #0 1 2 1 weave } function simpleivtc(clip in) { #IVTC for a fixed 3:2 pulldown pattern, non-adaptive, returns 4/5 framerate clip (i.e. 24fps from 30fps) in.swapfields.doubleweave pulldown(0,3) } function LabelVideoWithCounts(clip v) { #Add framecount and field counts to a video v #add frame numbering assumetff separatefields top=last.selecteven bot=last.selectodd #all this is to remove color shadows; where the text overlays, color is desaturated, due to YV12 tu=top.utoy tv=top.vtoy bu=bot.utoy bv=bot.vtoy top1=top.ScriptClip("""subtitle("video field = " + string(current_frame*2),x=-1,y=60,size=20,text_color=$00FFFFFF,font_width=17)""") bot1=bot.ScriptClip("""subtitle("video field = " + string(current_frame*2+1),x=-1,y=80,size=20,text_color=$00FFFFFF,font_width=17)""") top=ytouv(tu,tv,top1) bot=ytouv(bu,bv,bot1) interleave(top,bot) weave assumefps("ntsc_video") } Last edited by jmac698; 31st July 2012 at 13:55. Reason: version 0.5 |
1st December 2010, 10:22 | #4 | Link |
Avisynth Developer
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
|
Hint:- For maximum performance have a look at DoubleWeave().SelectEvery(....) instead of SeperateFields().SelectEvery(...).Weave().
The former costs a single field blit for cross match frames and zero for original frames. The latter costs two field blits every frame. Unfortunately you will need to twist your brain inside out to come to terms with it's use. Also Neuron2 has an adaptive chroma interpolation filter, AutoYUY2, that you might find helpful in your reconstruction processing. |
1st December 2010, 14:31 | #5 | Link | |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
Quote:
Code:
ScriptClip(background,""" overlay(square,x=103-25+current_frame*8,y=240-25) """) Code:
ScriptClip(background,""" overlay(square,x=103-25+current_frame*8,y=240-25) """, args="square") |
|
1st December 2010, 17:40 | #6 | Link |
Registered User
Join Date: Jan 2006
Posts: 1,867
|
IanB: Wow, that was an insight - I'd always wondered what doubleweave was for. Great tip! I'll always use it And AutoYUY2 was the first thing I tried, didn't work.
Gavino: That was certainly a speedy intro to Grunt! Sounds quite useful, make sure you advertise it well! I do have a real question now, how to make this adaptive? I know I can borrow an IsCombed function from somewhere, but how do I tell where in the pulldown pattern I am? I need to find a string of two laced frames and two fields behind and ahead of them: f1 (clean, bot), f3 (bottom of laced frame), f4 (top of laced frame), f6 (clean, top) It's also possible to have this problem in one laced frame in 18fps (silent film, home 8mm) conversions. Anything slower has so many duplicated fields that you can discard to the bad frame. Btw, I tried it on real material and it does work, however I'm confused about my whole theory of it - I thought YV12 merged lines by field, not by frame, so it should preserve interlacing. I'm talking about my capture card here. Last edited by jmac698; 1st December 2010 at 17:42. |
1st December 2010, 20:56 | #7 | Link |
Registered User
Join Date: Jan 2006
Posts: 1,867
|
I've been looking at ConditionalFilter, FrameEvaluate and IsCombed (from dgdecomb). I need to operate per frame and track state between frames; how do I pass variables around in frame context?
I'm doing something like; if lastcombed and iscombed then restorewith=2 if not lastcombed and iscombed then restorewith=-2 if not iscombed then restorewith=0 lastcombed=iscombed --- conditionalfilter(source,"restorewith","=","2",restoredvid1,restorevid2) .. except I need to choose between 3 videos per frame does frameevaluate appear after conditionalfilter and then pass the variables "backwards" ? |
2nd December 2010, 00:33 | #8 | Link | |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
Quote:
However, in your case, the simplest thing is to do everything in a single call to ScriptClip (which can include a multi-line 'inner' script). Then things are done in a natural order and variables are preserved between frames. Code:
ScriptClip(""" iscombed = ... restorewith = (iscombed ? (lastcombed ? 2 : -2) : 0) lastcombed=iscombed #choose clip (for this frame) based on restorewith: ... """) |
|
11th December 2010, 03:51 | #9 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Have a look at ShowFiveVersions, here is an excerpt
Code:
# View all five pulldown patterns at once DoubleWeave() # put a resizing filter here if necessary (see below) a = Pulldown(0,2).Subtitle("0,2") b = Pulldown(1,3).Subtitle("1,3") c = Pulldown(2,4).Subtitle("2,4") d = Pulldown(0,3).Subtitle("0,3") e = Pulldown(1,4).Subtitle("1,4") ShowFiveVersions(a,b,c,d,e) Code:
function simpleivtc(clip in) { #IVTC for a fixed 3:2 pulldown pattern, non-adaptive, returns 4/5 framerate clip (i.e. 24fps from 30fps) # in.separatefields # f0=selectevery(10,0) # f1=selectevery(10,1) # f2=selectevery(10,2) # f3=selectevery(10,3) # f4=selectevery(10,4) # f5=selectevery(10,5) # f6=selectevery(10,6) # f7=selectevery(10,7) # f8=selectevery(10,8) # f9=selectevery(10,9) # interleave(f0,f1,f4,f3,f6,f5,f8,f9) # weave in.doubleWeave Pulldown(0,3) # selectevery(5,0,3).AssumeFrameBased # 0 1 2 3 4 5 6 7 8 # 01 12 23 34 45 56 67 78 89 } Also, can I ask you to update the full script as it changes.
__________________
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; 13th December 2010 at 21:20. |
11th December 2010, 12:00 | #10 | Link |
Registered User
Join Date: Jan 2006
Posts: 1,867
|
question
S,
I've updated my script with all suggestions, but didn't make it dynamic yet. There is also now nice labelling of frames/fields. Check out my huge comparison of lossless codecs under Capturing. FFV1 comes with FFDshow. ps I found I need a swapfields in order to use doubleweave, I'm sure that just killed the whole optimization. Doubleweave is in the wrong order. Instead of 0,0 1,0 1,1 I need 0,0 0,1 1,1. Now why do I have to use TFF? Because I was encoding to mpeg2, which is supposed to result in TFF. The encoding program might let you swap fields on input though. Any comments? Last edited by jmac698; 11th December 2010 at 19:40. |
11th December 2010, 22:35 | #11 | Link | |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
In dire straights right now, think my machine might be messed up.
Was getting problems with both MS Mplayer2 (via AvsEdit) and VirtualDubMod, crashing at the line "top=ytouv(tu,tv,top1)" in function demo(), in post#2. Error seems to disappear if everything is converted YV12. Am Using a v2.6 non-standard 2010 release. Tried with standard release 2.6 from 2009-09-27 nearly same error at same point in script. Think ytouv might be creating a double height clip as if input YUY2 were YV12. (perhaps unconnected but in non-standard release, was sometimes having media player trying to download a YV16 codec) Oh yes, what version AVS U using. Quote:
About DV / DVD in relation to field dominance DV to DVD : http://forum.doom9.org/showthread.ph...692#post410692 Fields: http://lurkertech.com/lg/fields/ HCEnc has an option to set TFF/BFF I'm using this little snippet to view before/after, at differing points in script. (Balanced points in script eg, 1st point after demo [before pulldown32], 2nd point after total recovery) Code:
Function Diff(clip c1,clip c2) { c1=subtract(c1,c2) levels(c1,127,1.0,129,0,255) } Function ShowDiff(clip c1, clip c2) { d=diff(c1,c2) StackHorizontal(StackVertical(c1,c2),Stackvertical(d,d)) }
__________________
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; 13th December 2010 at 21:13. |
|
11th December 2010, 22:50 | #12 | Link |
Registered User
Join Date: Jan 2006
Posts: 1,867
|
AviSynth 2.58. Man, that sucks, I have to deal with incompatibilities in 2.6! If anyone can figure out what's wrong, hopefully I can update it to work in both versions. I use AvsPmod 2.05 for development which has some crash protection. I'm only using an old version because it happened to be installed with some other packages, and I didn't really need anything speical in new version, just didn't think about it. If it's that buggy I see no need to upgrade
|
11th December 2010, 23:20 | #13 | Link | |
Avisynth Developer
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
|
Quote:
P.S. It's pretty rude hijacking jmac698's thread with this off topic issue. _ |
|
11th December 2010, 23:30 | #14 | Link | |
Avisynth Developer
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
|
Quote:
ShowFrameNumber, ShowSMPTE, ShowTime and Subtitle are the only filter that have a "font_width" named argument. Seems the """ nesting is not quite right. |
|
Thread Tools | Search this Thread |
Display Modes | |
|
|