plugh
24th May 2007, 14:54
I'm new to this, but it seems like properly decimating transport stream caps can be, shall we say, interesting :rolleyes:
My second oddball - a cap of a 720p ABC-HD animated movie.
My manual analysis seems to indicate they sped the film up a little bit (I calculate 24.52fps). After a SelectEven (59.94->29.97) I'm seeing a basic cycle of 22 frames with 4 telecining dups. But of course there is a twist :( Example:'|'= new frame '-'=duplicate
|-|-|-- |-|-- |-|-- |-|--
|-|-|-- |-|-- |-|-- |-|--
|-|-|-- |-|-- |-|-- |-|--
|-|-|-- |-|-- |-|-- |-|--
|-|-|-- ||||- |-||- ||||-
||||||- ||||- ||||- ||||-
||||-|- ||||- ||||- ||||-
||||-|| ||||- ||||- ||||-
|||--|| ||||- ||||- ||||-
|||--|- |-|-- |-|-- |-|--
You will note I've broken the cycle of 22 into four groups, of 7,5,5,5 frames. This makes 3 of the telecine dups obvious.
The 'twist' is that in low motion sequences the original animation already has dups. Removing one of these instead of a telecine dup will yeild jerky motion.
My last oddball framerate cap I was able to handle with tdecimate (removed 7 of 29), but it didn't have intentional dups in the source like this one does.
Any of the gurus out there have a suggestion?
Thanks!
plugh
25th May 2007, 06:17
I don't understand your diagram. There are more duplicates there than you say. You shouldn't be trying to figure out the cycle pattern/frame rate in low motion scenes if that's why...
That is a single continuous sequence of frames, broken into 22 frames per line (and the sub-groups). It illustrates the fact that in the initial low motion section there are dupes in the original film in addition to the dups due to telecine. When the sequence gets to a high motion segment there are fewer filmed dupes (to make motion smoother I assume). I guess this cuts down on the number of cel's they had to create.
If there is a repeating pattern it may be more obvious looking at the 59.94 fps clip instead of the halved one.If you think of a typical cycle=5 telecine, you would see "||||-" (four frames and a dup) repeated over and over. You can see this in a portion of the high motion segment above. Once you 'see' that pattern, you can see that the telecine dup is present at the same position in the low motion segment as well. However, since this is at an oddball framerate, I've also got that funky group of seven frames. But the basic cycle appears to be 18 movie frames (some of which are dups sometimes) with 4 telecine dups.
TDecimate's mode 1 is supposed to be for animation and deletes from the longest string of duplicates. I've never quite understood how it works, myself, though. Certainly finding a dup pattern and applying it manually with an ovr file (or even SelectEvery) would produce superior results. Of course you'd have to adjust it at every commercial break (or pad black frames to re-align the video to the pattern).
Yeah, I'm trying to use mode 1 at the moment. It is doing a pretty fair job, but I'm running into another 'gotcha' that is throwing off its dup detection - film jitter. In the (low motion) segments where the film has its own dups, a frame and its dup are not always perfectly aligned vertically. The dup is sometimes shifted higher, sometimes lower. You can tell the dup was made from the same animation cel as the preceding frame, but the shift causes tdecimate to calculate a larger factor and not always recognize it as a dup. I'm playing with the dupThresh parameter now, but the jitter seems to be causing problems when I try to process the full 59.94fps stream. I'm having much better luck with the halved stream.
This is a real pain in the ass; probably part of the reason why they do it :mad: Anyway, figured I wasn't the first person to encounter this situation. I may end up just leaving the telecine dups in it and encode at 29.97fps...
plugh
2nd June 2007, 01:25
Wheh! That was 'fun' :rolleyes:
As mentioned earlier, one of the problems I was having with
this HD cap was vertical jitter. After searching for solutions,
I 'Read The Fine Manual' and wrote the following scripts.
This is my first attempt at some "serious" avisynth scripting.
I'm posting it in the hope that it will provide a useful starting
point for someone else with a similar problem, as well as to get
feedback on how it might be better implimented.
Basically what it does is compare the previous frame to vertically
shifted versions of the current frame. If it finds a local minima
at an offset then the frame is 'de-jittered' - a shifted version is
created by discarding a scan line on one side and duplicating one
on the other (one scan line is the limit in this version). As this
can be time-consuming to process, I also record the results so they
can be re-used in subsequent passes. The second script is an example.
Frankly I am amazed at how well it works on my animated film capture.
It isn't perfect, but nearly all the jitter is eliminated, tdecimate
does a MUCH better job at detecting dups, and the resulting constant
quant xvid avi is significantly smaller to boot.
Enjoy!
tag="-try5"
base="lk2"
sep=" "
timer=0 #in case we miss a shift
offset=0 #state tracking variable (random access NOT supported)
s=mpeg2source(base+".d2v",cpu=2) # 59.94fps 720p source
s=converttoyuy2(s).crop(40,0,1200,720) # remove the curtains
c=FrameEvaluate(s, "offset = (current_frame == 0) ? 0 : offset" ,after_frame=true) #re-set on
c=FrameEvaluate(c, "timer = (current_frame == 0) ? 0 : timer" ,after_frame=true) #first frame
# vertically offset metrics (grumble - YDiff won't accept yuy2, but I have to use yuy2 for the crops! - grumble)
c=frameevaluate(c, "d2=YDifferenceFromPrevious(converttoyv12(crop(0,2,0,-2).trim(0,current_frame-1)+crop(0,0,0,-4).trim(current_frame,0)))", after_frame=true)
c=frameevaluate(c, "d1=YDifferenceFromPrevious(converttoyv12(crop(0,2,0,-2).trim(0,current_frame-1)+crop(0,1,0,-3).trim(current_frame,0)))", after_frame=true)
c=frameevaluate(c, "at=YDifferenceFromPrevious(converttoyv12( crop(0,2,0,-2) ))", after_frame=true)
c=frameevaluate(c, "u1=YDifferenceFromPrevious(converttoyv12(crop(0,2,0,-2).trim(0,current_frame-1)+crop(0,3,0,-1).trim(current_frame,0)))", after_frame=true)
c=frameevaluate(c, "u2=YDifferenceFromPrevious(converttoyv12(crop(0,2,0,-2).trim(0,current_frame-1)+crop(0,4,0, 0).trim(current_frame,0)))", after_frame=true)
# unidirectional strategy - displacenent down a scan line and back
#c=FrameEvaluate(c, "delta=(d1*1.2 < d2 && d1*(1.2-(offset*.1)) < at) ? -1 : 0" ,after_frame=true)
#c=FrameEvaluate(c, "delta=(u1*1.2 < u2 && u1*(1.2+(offset*.1)) < at) ? +1 : delta" ,after_frame=true)
#c=FrameEvaluate(c, "timer= (delta == 0) ? timer+1 : 0" ,after_frame=true)
#c=FrameEvaluate(c, "offset = (timer == 31) ? 0 : ((delta < 0) ? 0 : offset)" ,after_frame=true)
#c=FrameEvaluate(c, "offset = (timer == 31) ? 0 : ((delta > 0) ? 1 : offset)" ,after_frame=true)
# bidirectional strategy - displacement up/down a line about center
c=FrameEvaluate(c, "delta= (d1*(1.25-(offset*.24)) < d2 && d1*(1.25-(offset*.24)) < at) ? -1 : 0" ,after_frame=true)
c=FrameEvaluate(c, "delta= (u1*(1.25+(offset*.24)) < u2 && u1*(1.25+(offset*.24)) < at) ? +1 : delta" ,after_frame=true)
c=FrameEvaluate(c, "timer= (delta == 0) ? timer+1 : 0" ,after_frame=true)
c=FrameEvaluate(c, "offset= (timer == 62) ? 0 : ((delta == offset) ? offset : offset+delta)" ,after_frame=true)
# debug log AND 2nd pass info file
c=WriteFile(c, base+tag+"-jitter.log", "current_frame","sep","offset","sep","u2","sep","u1","sep","at","sep","d1","sep","d2","sep","delta")
c=WriteFileStart(c, base+tag+"-jitter.log", """ "TYPE int" """)
# now do something useful
d=scriptclip(crop(c,0,1,0,-1),"trim(0,current_frame-1)+crop(c,0,offset+1,0,offset-1).trim(current_frame,0)",after_frame=true)
d=tdecimate(d, mode=4,hint=false,output=base+tag+"-tdout.txt",blockx=64,blocky=64,nt=1) #pre-calc metrics for two pass decimate
# or perhaps (very slow)
#d=scriptclip(c, "trim(0,current_frame-1)+overlay(c,0,-offset).trim(current_frame,0)",after_frame=true)
#d=tdecimate(d, mode=7,hint=false,rate=24.5,blockx=64,blocky=64,nt=1) #try a one-pass decimate
# or just a visualization
#d=scriptclip(c, "trim(0,current_frame-1)+overlay(c,0,-offset).trim(current_frame,0)",after_frame=true)
#d=ScriptClip(d, "subtitle(string(timer),size=48,x=600,y=offset*150+360)",after_frame=true)
#d=stackhorizontal(crop(s,0,0,600,0),crop(d,600,0,0,0))
return(d)
tag="-f1"
base="lk2"
mpeg2source(base+".d2v",cpu=0) # 59.94fps 720p source
converttoyuy2().crop(40,0,1200,720) # remove the curtains
# apply de-jitter to the frame
scriptclip("(offset < 0) ? stackvertical(crop(0,0,0,1),crop(0,0,0,-1)) : last")
scriptclip("(offset > 0) ? stackvertical(crop(0,1,0,0),crop(0,height()-1,0,0)) : last")
#ScriptClip("subtitle(string(offset),size=48)") #debug - show offset on frame
ConditionalReader(base+tag+"-jitter.log", "offset") #random access IS supported
#note: tdecimate metrics were computed on a cropped yuy2 clip; must disable the crc32 check
tdecimate(mode=2,rate=24.5,hint=false,input=base+tag+"-tdout.txt",blockx=64,blocky=64,nt=1,batch=true)
ColorMatrix(mode="Rec.709->Rec.601")
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.