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.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Development

Reply
 
Thread Tools Search this Thread Display Modes
Old 1st December 2010, 01:58   #1  |  Link
jmac698
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
We can also state the pattern as (0top, 0bot), (0top,1bot), (1top, 2bot), (2top, 2bot), (3top, 3bot), and repeating. This gives us our clean, interlaced, interlaced, clean, clean pattern, or in a more obvious way of counting things, 3 clean followed by 2 interlaced frames.

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
Here are the interlaced frames output at a laserdisc:
Code:
NTSC 0:  RRRR     (film 0)
           RRRR   (film 1)

NTSC 1:    RRRR   (film 1)
             RRRR (film 2)
However due to YV12 recording, this is what the tv card records:
Code:
NTSC 0:  rrRRrr   (film 0)
         rrRRrr   (film 1)

NTSC 1:    rrRRrr (film 1)
           rrRRrr (film 2)
The small r's represent a dulled red color; the average of grey and deep red. Even if I separate fields, the dull red color remains. If I use dgdecomb I get two frames with a kind of ghost color on them. Since I have a clean version of frames 0 and 2, I should be able to subtract lines of color to come up with a clean frame 1.

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.
jmac698 is offline   Reply With Quote
Old 1st December 2010, 03:02   #2  |  Link
jmac698
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
Step through this a field at a time; the problem first occurs on fields 4-7. AVSPmod is your friend!
jmac698 is offline   Reply With Quote
Old 1st December 2010, 08:35   #3  |  Link
jmac698
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
jmac698 is offline   Reply With Quote
Old 1st December 2010, 10:22   #4  |  Link
IanB
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.
IanB is offline   Reply With Quote
Old 1st December 2010, 14:31   #5  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by jmac698 View Post
Code:
  #unfortunately I have to make these global to work with scriptclip
  global square= ...
  global background= ...
  ScriptClip(background,"""
    overlay(background,square,x=103-25+current_frame*8,y=240-25)
""")
It doesn't much matter for a one-off demo function like this, but note that 'background' does not need to be global, since as the input to ScriptClip, it is available as 'last' inside the run-time script:
Code:
ScriptClip(background,"""
    overlay(square,x=103-25+current_frame*8,y=240-25)
""")
Further, using GRunT, you can also remove the need for 'square' to be global:
Code:
ScriptClip(background,"""
    overlay(square,x=103-25+current_frame*8,y=240-25)
  """, args="square")
__________________
GScript and GRunT - complex Avisynth scripting made easier
Gavino is offline   Reply With Quote
Old 1st December 2010, 17:40   #6  |  Link
jmac698
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.
jmac698 is offline   Reply With Quote
Old 1st December 2010, 20:56   #7  |  Link
jmac698
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" ?
jmac698 is offline   Reply With Quote
Old 2nd December 2010, 00:33   #8  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by jmac698 View Post
does frameevaluate appear after conditionalfilter and then pass the variables "backwards" ?
Yes, see here.

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:
  ...
""")
__________________
GScript and GRunT - complex Avisynth scripting made easier
Gavino is offline   Reply With Quote
Old 11th December 2010, 03:51   #9  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
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)
Here is your simpleivtc re-written:

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
}
as the 'd' clip in ShowFiveVersions.

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.
StainlessS is offline   Reply With Quote
Old 11th December 2010, 12:00   #10  |  Link
jmac698
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.
jmac698 is offline   Reply With Quote
Old 11th December 2010, 22:35   #11  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
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:
why do I have to use TFF? Because I was encoding to mpeg2
From Avisynth v2.8 Help (searchable ver$ chm via my sig)

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.
StainlessS is offline   Reply With Quote
Old 11th December 2010, 22:50   #12  |  Link
jmac698
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
jmac698 is offline   Reply With Quote
Old 11th December 2010, 23:20   #13  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
Quote:
avisynth.dll, version 2.6.0.2
By your own admission you are running some random wiley joe hackers version of avisynth.dll (maybe you built it yourself from CVS). If you have the matching Avisynth.map then you will be able to see what source code belongs to address 0x00073dc8 and address 0x00073e73 and then maybe get some idea what is actually happening. If you did build it yourself then just build a relsym or debug version and debug the fault.

P.S. It's pretty rude hijacking jmac698's thread with this off topic issue.
_
IanB is offline   Reply With Quote
Old 11th December 2010, 23:30   #14  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
Quote:
Went back to v2.8 (not sure which release) and getting message
about "ScriptClip does not have a named argument "font_width".
v2.8 is supposted to support that.
Well ScriptClip does not have a named argument "font_width".

ShowFrameNumber, ShowSMPTE, ShowTime and Subtitle are the only filter that have a "font_width" named argument. Seems the """ nesting is not quite right.
IanB is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 07:42.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.