View Full Version : New Function Request - Telecine()
zettai
12th August 2003, 08:24
Hi All,
Currently it is very simple to do a 23,976fps to 29.97fps conversion using seperatefields, selectevery and weave.
24 FPS with the field shuffle will make a 30 FPS video...
However, what if we want 29.97 but don't want to touch our audio stream and don't want a desynch?
every 100 seconds there is 2997 frames (29.97fps)
or every 100 seconds there is 3000 frames (30fps)
so... every 3000 frames, we have to remove 3... or in 1000 remove 1
so we have a 999 frame block of stuff... or a 995 + 4 block (this will be important in a second)
when we go from 24-30 we are going from 4-5 (995 is devisable by 5 ^_^)
so if we Telecine 796 frames, and leave 4 frames alone... 800 frames, which normally would translate to 1000 frames, instead translates to 999 frames... perfect....
now how to do this smoothly (the easy method would just to Telecine the first 796, then copy the last 4)
the longer than you can smooth over the frame transitions... the better the Telecine process is going to be
(which is why AA AB BC CD DD is better than AA BB BC CD DD )
So... what if the "solid" frames were 197, 398, 599, 800 out of every 800 frame block...?
So, in short the idea is to telecine every 196 frames, then copy one, then telecine 196, then copy one, then telecine 196, then copy one... etc...
the "solid" frames as i refered to them are the copied frames...
so technically this could be accomplished with
AssumeFrameBased()
SeparateFields()
a very long SelectEvery command ^_^ with 246 field settings
Weave()
AssumeFPS(29.97) [not sure if it would be required with selectevery]
However, a selectevery that big will get thrown out by avisynth.
A better option would be to have a plugin such as
Telecine(clip,fieldorder,outputframerate)
where possible output framerates are 25, 29.97 and 30 [and have a conditional telecine pattern for each common mapping]
Thoughts?
stickboy
12th August 2003, 09:10
Is ChangeFPS insufficient for duplicating frames as needed to adjust the framerate?
zettai
12th August 2003, 09:19
ChangeFPS isn't what we want here.
The aim is to telecine the footage so that it ends up being 29.97fps - ChangeFPS would reduce 30fps to 29.97fps by removing frames which is what we want to avoid.... especially with telecinied footage. You could change to 23.976 at the beginning but again that's losing a frame where you honestly don't need to.
We're not doing any frame duplication either, we're just choosing to NOT telecine 4 frames in every 800.
It's a pretty simple idea but can't be done as far as I can tell with avisynth scripting at the moment (or at least, can't be done with one script that will work for every video file... you can do it with trim but it's nasty).
stickboy
12th August 2003, 10:24
Ah, sorry, I misread. I think I see what you mean now.
How did you come up with the 197, 398, 500, and 800 values? (Is that right? If you're counting from 0, frame 800 is the 801st frame and isn't part of the 800-frame block...)
Hmm... if only there were an ApplyRangeEvery function...
zettai
12th August 2003, 10:43
Now it's morning I'm not sure how I came to that number.
Maybe it's 199 frames not 196.... why would I think it was 196?
Hmm, way to confuse myself :)
zettai
12th August 2003, 10:52
AH! Yes, I know where I got 196.
It's because you generally take 4 frames and make them into 5 when you telecine, so you have to work in 4 frame sections.
199 isn't divisable by 4.
so you do
1-4 Telecine to 1-5
4-8 Telecine to 6-10
9-12.....
192-196 Telecine to 240-245
197 copy to 246
you repeat this 4 times. When you've done it 4 times you get to frame 985. You then add on the next 3 sequences of 5 telecined frames to get to 999.
Then you reset and start again.
So, yeah, complicated ^_^
stickboy
12th August 2003, 12:12
I believe your math is a little off... if you remove every 196th frame, you'll remove 5 frames of every 800. (If you neglect to remove the fifth frame, one of the segments will not be a multiple of 4.)
I think it should be:keep telecine
0 [ 1, 200]
201 [202, 401]
402 [403, 602]
603 [604, 799]Anyhow, here's a function I whipped up that I believe does what you want (24 -> 29.97). I'm really sleepy, so the code is rather crude, isn't well-tested, and doesn't perform any error-checking:
function min(int m, int n)
{
return (m < n) ? m : n
}
function Telecine(clip c)
{
assert(c.IsFrameBased(), "Telecine: clip must be frame-based")
# we need to handle the case of a null-clip manually;
# otherwise, SelectEvery(...) will generate unwanted blank frames
return (c.FrameCount() == 0)
\ ? c.AssumeFPS(c.FrameRate() * 5.0 / 4.0)
\ : c.ComplementParity().DoubleWeave().SelectEvery(8, 0, 2, 3, 5, 6)
}
function NewTelecineHelper(clip c, int iterLeft)
{
assert(iterLeft > 0, "NewTelecineHelper: invalid <iterLeft> value")
iterLeft = iterLeft - 1
start = iterLeft * 800
end = min(c.FrameCount(), (iterLeft + 1) * 800)
seg = c.Trim2(start, length=800)
seg1 = seg.Trim2( 0, length=1) + seg.Trim2( 1, 201).Telecine()
seg2 = seg.Trim2(201, length=1) + seg.Trim2(202, 402).Telecine()
seg3 = seg.Trim2(402, length=1) + seg.Trim2(403, 603).Telecine()
seg4 = seg.Trim2(603, length=1) + seg.Trim2(604 ).Telecine()
c = c.Trim2(0, start) + seg1 + seg2 + seg3 + seg4 + c.Trim2(end)
return (iterLeft == 0)
\ ? c
\ : NewTelecineHelper(c, iterLeft)
}
function NewTelecine(clip c)
{
assert(c.FrameCount() > 0, "NewTelecine: input clip must have at least one frame")
c.NewTelecineHelper(Ceil(c.FrameCount() / 800.0)).AssumeFPS(29.97)
return AudioDub(last, c)
}(See also: Trim2 (http://forum.doom9.org/showthread.php?s=&threadid=58358))
Edit:
The code should no longer add blank frames to the end when the framecount of the input clip is not a multiple of 800.
zettai
12th August 2003, 13:45
I believe your math is a little off... if you remove every 196th frame, you'll remove 5 frames of every 800. (If you neglect to remove the fifth frame, one of the segments will not be a multiple of 4.)
But I'm not removing any frames... nor do I want to. It's a case of some frames are telecinied and some frames are copied directly from the source to the "telecined" version.
You telecine 196 frames and then copy fram 197 and then telecine the next 196 frames until you've reached frame 800 then you start the cycle again.
196*4 = 784
1*4 = 4
total 788, continue cycles of 4 until frame 800.
If you do things your way (from what I can understand of your code) then you will have frame 200 being the 199th frame being telecinied which would happen in the middle of a normal telecine pattern and that wouldn't be a good thing, I don't think, as you really want to keep the cycle of 4 frames being telecinied at once.
However, I think I can adapt your script to what I need it to do. Please check my reasoning behind 196 again and how it would work. It's the same principle but it's making sure that you are always doing telecine on sections of 4 frames with the last frames being the exception.
EDIT: OK, yes, I see the flaw in the 196 model now.
I would prefer to not have to have telecine stop mid sequence (as it could end on one frame being represented by only one field.
Perhaps then I could telecine 196 frames then just copy the other 4 directly and then repeat.
Hmm, not sure... I want this telecine process to be as smooth as possible, you see.
stickboy
12th August 2003, 17:24
Originally posted by zettai
But I'm not removing any frames... nor do I want to. It's a case of some frames are telecinied and some frames are copied directly from the source to the "telecined" version.Er, I didn't mean "remove". I meant to say "not telecined".
If you do things your way (from what I can understand of your code) then you will have frame 200 being the 199th frameFrame number 200 is the 201st frame in the clip, since frame numbers start at 0.
I would prefer to not have to have telecine stop mid sequence (as it could end on one frame being represented by only one field.
In my code, Telecine() is always called on a range of frames that's a multiple of 4 (except at very end of the original clip); in every 800 frames, it leaves one frame alone, telecines 200 frames, leaves one alone, telecines another 200, leaves one alone, telecines another 200, leaves one alone, and then telecines the remaining 196. That's 200 + 200 + 200 + 196 = 796 frames telecined and 4 left alone, which is what you wanted, right?
zettai
12th August 2003, 18:54
Yes, sorry - I've had a good chance to really play around with it and it's perfect! Sorry for doubting you :)
Thank you ever so much for working out how to use trim like that and helping me with the script. It's exactly what I need!
stickboy
12th August 2003, 19:20
BTW, the code above is sort of meant as proof-of-concept, not for production use or anything...
If the framecount of the original clip is not a multiple of 800, you might end up with some extra frames at the very end, because if you call Trim with a start frame past the end of the clip, it returns the last frame of the clip instead of a 0-frame clip.
I really should use my Trim2 function instead, but currently its bounds-checking is too strict to be used in this case easily. I will relax the checks and post an updated version later today.
Originally posted by stickboy:
I believe your math is a little off... if you remove every 196th frame, you'll remove 5 frames of every 800. (If you neglect to remove the fifth frame, one of the segments will not be a multiple of 4.)Ack, I must have been really sleepy when I wrote that. You're right, leaving every 196th frame untelecined works too. I don't know why I thought the last segment (196 + 12 = 208 frames) would not be a multiple of 4.
OTOH, using intervals of 200 should be a little bit smoother, since the discrepancy at the end is smaller.
stickboy
13th August 2003, 09:55
I made some minor edits to the code above. Extra blank frames no longer should be appended to the end...
(Requires an updated version of Trim2 (http://forum.doom9.org/showthread.php?s=&threadid=58358).)
zettai
13th August 2003, 10:33
Sounds great - one question though... what is your max function? I've put in what I think it probably is but I thought I'd ask just to be sure :)
stickboy
13th August 2003, 10:41
Whoops again. Fixed now. :)
Xesdeeni
13th August 2003, 16:50
A question: Where did you get actual 24 fps content? PAL is 25 fps, so if you convert to 24 fps, then why not just convert to 23.976 fps? IVTC'd NTSC is 23.976.
Anyway, you can always just:ChangeFPS(59.94)
SeparateFields()
SelectEvery(4,0,3)
Weave() # or notIf your input is a progressive 24 fps, then ChangeFPS(59.94) will replicate frames to give you a progressive sequence that does a frame-based 3:2 pulldown (that's what 720p HDTV does), with the rounding when necessary. If the input is a progressive 23.976 fps, then ChangeFPS(59.94) will give you a pure frame-based 3:2 pulldown. In either case, you just pick off one field from each frame and voila!
Xesdeeni
zettai
13th August 2003, 17:38
Well, it's a long story :)
One of the annoying bugs of Adobe Premiere is that it can't deal with 23.976fps footage. Upon export it will make it 23.98fps which is no use to man nor beast.
What I used to do to get around this was to:
a) take my audio stream and do a rate change on it
b) assuemfps(24) on all 23.976 source footage
c) edit at 24fps, export at 24fps
d) Assumefps(23.976) on exported video
e) Re-attach original unchanged audio stream.
But once upon a time, I didn't think about doing things this way - I just edited at 24fps so I wouldnt have frame drift because of premiere being dumb. Then I realised that to make things 29.97fps I'd have to either change the audio stream or remove frames... neither of which I wanted to do. This is where the idea came from.
I'll look into changefps, but I figured doing it in the telecine would smooth out the transition as much as possible.
jmac698
15th October 2006, 21:42
Stickboy, thanks a lot! I've wanted this exact function for a while. Changefps(), has a phase problem. Example, 24p->30i starting at 0 you get clean, laced, laced, clean, clean but changefps() gives me laced,laced,laced,clean,clean... I wanted precise control to be able to label each field and frame for a test video, one counter runs at 24fps, another at 60i, another at 30p, so I could see the exact effects of doubleweave, deint, pulldown, and other functions.
Thanks stickboy again, for explaining doubleweave on your page!
My other problem has been deint's picking the wrong duplicate because of B frame causing a ghosting with the next frame, but that's another topic...
Trixter
18th October 2006, 02:40
One of the annoying bugs of Adobe Premiere is that it can't deal with 23.976fps footage. Upon export it will make it 23.98fps which is no use to man nor beast.
Hate to break this to you, but Premiere Pro (I tested 1.5, 2.0 is now the current version) works with it just fine. It only rounds to 23.98 when *displaying* the framerate -- internally, it is properly represented at 23.976 and I've never had a frame drop/desynch when working with 23.976p footage.
Zarxrax
18th October 2006, 19:33
Hate to break this to you, but Premiere Pro (I tested 1.5, 2.0 is now the current version) works with it just fine. It only rounds to 23.98 when *displaying* the framerate -- internally, it is properly represented at 23.976 and I've never had a frame drop/desynch when working with 23.976p footage.
You realize the post you replied to was written 3 years ago? :D
On that note though, I think I have seen premiere pro (1.5 at least, maybe 2.0 as well) drop a frame or 2 with 23.976 footage. I believe it relates to the rational framerate value that is stored in the avi.
Trixter
19th October 2006, 04:37
You realize the post you replied to was written 3 years ago? :D
Would I have replied if I had realized that? :o
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.