lecapitan
7th July 2011, 02:33
Hey everyone.
I was really bothered that I couldn't find a decent free/cheap alternative to Adobe's Time Remapping, so I decided to take a stab at it using Avisynth and MVTools. I'm posting my script here to share and also get some feedback on ways to improve it. As of right now I am happy with the results I get but I have to imagine it can be improved.
I make use of GScript as well since it's easier for me to use standard control statements and loops.
For the noob's: (myself included)
LoadPlugin("mvtools2.dll")
LoadPlugin("GScript.dll")
Here are the functions: (the good stuff)
# Gradually slows a clip down
function Slowmoe(clip source, float startFrame, float endFrame, float startRatio, float endRatio)
{
# Get the clip's original framerate
mfpsn = FramerateNumerator(source)
mfpsd = FramerateDenominator(source)
# Convert and trim clip
mclip = Trim(source, startFrame, endFrame)
# Flip frames
GScript("""
if (endFrame < startFrame) {
temp = endFrame
endFrame = startFrame
startFrame = temp
}
""")
# Do the MVTools SlowMotion
super = MSuper(mclip, pel=2)
backward_vec = MAnalyse(super, overlap=4, isb = true, truemotion=true, search=3)
forward_vec = MAnalyse(super, overlap=4, isb = false, truemotion=true, search=3)
slowdown = MFlowFPS(mclip, super, backward_vec, forward_vec, Round(mfpsn * 1.0/endRatio), mfpsd)
slowdown = AssumeFPS(slowdown, mfpsn, mfpsd)
# Initialize values
startFrames = (mfpsn * 1.0/startRatio)/mfpsd # Starting frames in a second
endFrames = (mfpsn * 1.0/endRatio)/mfpsd # Ending frames in a second
framesRange = endFrames - startFrames # Difference in frames
currentFrame = 0 # The current frame in the final clip
counter = 0 # The total frame counter
lastFrame = Framecount(slowdown) # The total frames in the slow mo clip
desiredFrames = 0 # The current desired frames
removeFrameCounter = 0 # The frame removal counter
removeFrameThreshold = Float(endFrames)/Float(startFrames) # The number of frames to remove
overflow = 0 # Overflow from the frame threshold
GScript("""
while (counter < lastFrame) {
# Increment the frame removal counter
removeFrameCounter = removeFrameCounter + 1
# Check if the frame removal counter is over the threshold
if (removeFrameCounter >= Floor(removeFrameThreshold + overflow)) {
# Store the overflow
if (overflow > 1) {
overflow = overflow - 1.0
}
else {
overflow = overflow + removeFrameThreshold - Floor(removeFrameThreshold)
}
# Calculate the desired frames. You could use a higher power to make the transition even smoother.
desiredFrames = startFrames + Pow(Float(counter)/Float(lastFrame), 4) * framesRange
removeFrameThreshold = Float(endFrames)/Float(desiredFrames)
# Stop the threshold if it gets too low
if (removeFrameThreshold < 1.1) {
removeFrameThreshold = 1.0
overflow = 0
}
# Reset the counter
removeFrameCounter = 0
}
# Delete or Keep frame
if (removeFrameCounter == 0) {
currentFrame = currentFrame + 1
}
else {
slowdown = DeleteFrame(slowdown, currentFrame)
}
# Increment the counter
counter = counter + 1
}
""")
# Delete the last frame
slowdown = DeleteFrame(slowdown, Framecount(slowdown))
# Return the clip
return slowdown
}
# Gradually speeds a clip up
function Speedmoe(clip source, float startFrame, float endFrame, float startRatio, float endRatio)
{
# Get the clip's original framerate
mfpsn = FramerateNumerator(source)
mfpsd = FramerateDenominator(source)
# Convert and trim clip
mclip = Trim(source, startFrame, endFrame)
# Flip frames
GScript("""
if (endFrame < startFrame) {
temp = endFrame
endFrame = startFrame
startFrame = temp
}
""")
# Do the MVTools SlowMotion
super = MSuper(mclip, pel=2)
backward_vec = MAnalyse(super, overlap=4, isb = true, truemotion=true, search=3)
forward_vec = MAnalyse(super, overlap=4, isb = false, truemotion=true, search=3)
slowdown = MFlowFPS(mclip, super, backward_vec, forward_vec, Round(mfpsn * 1.0/startRatio), mfpsd)
slowdown = AssumeFPS(slowdown, mfpsn, mfpsd)
# Initialize values
startFrames = (mfpsn * 1.0/startRatio)/mfpsd # Starting frames in a second
endFrames = (mfpsn * 1.0/endRatio)/mfpsd # Ending frames in a second
framesRange = startFrames - endFrames # Difference in frames
currentFrame = Framecount(slowdown) # The current frame in the final clip
counter = 0 # The total frame counter
lastFrame = Framecount(slowdown) # The total frames in the slow mo clip
desiredFrames = 0 # The current desired frames
removeFrameCounter = 0 # The frame removal counter
removeFrameThreshold = Float(startFrames)/Float(endFrames) # The number of frames to remove
overflow = 0 # Overflow from the frame threshold
GScript("""
while (counter < lastFrame) {
# Increment the frame removal counter
removeFrameCounter = removeFrameCounter + 1
# Check if the frame removal counter is over the threshold
if (removeFrameCounter >= Floor(removeFrameThreshold + overflow)) {
# Store the overflow
if (overflow > 1) {
overflow = overflow - 1.0
}
else {
overflow = overflow + removeFrameThreshold - Floor(removeFrameThreshold)
}
# Calculate the desired frames. You could use a higher root to make the transition even smoother.
desiredFrames = endFrames + Pow(Float(counter)/Float(lastFrame), 4) * framesRange
removeFrameThreshold = Float(startFrames)/Float(desiredFrames)
# Stop the threshold if it gets too low
if (removeFrameThreshold < 1.1) {
removeFrameThreshold = 1.0
overflow = 0
}
# Reset the counter
removeFrameCounter = 0
}
# Keep or Delete frame
if (removeFrameCounter == 0) {
currentFrame = currentFrame - 1
}
else {
slowdown = DeleteFrame(slowdown, currentFrame)
currentFrame = currentFrame - 1
}
# Increment the counter
counter = counter + 1
}
""")
# Return the clip
return slowdown
}
Here's an example of using them:
source = AVISource("stock.avi")
return Slowmoe(source, 0, 18, 1.0, 1.0) ++ Slowmoe(source, 18, 26, 1.0, 0.10) ++ Slowmoe(source, 26, 30, 0.10, 0.10) ++ Speedmoe(source, 30, Framecount(source), 0.10, 1.0)
I thought up the algorithm to do this on my own. I have no idea if it's even close to the real way to do it.
Anyways, it works like so:
First I take the slowest percentage you want the clip at and use MVTools to do the nice frame interpolation and slow the clip down to that speed. Then I loop through the clip and gradually remove frames to speed the clip back up. I start with looking at the clip's original fps. If the clip was originally 30 fps, and I've slowed it down to 120 fps, I would need to cut 75% of the frames out to get back to the original speed. In other words, I need to save every 4th frame and remove the rest. Then it's just a matter of ramping that down using some math.
Example:
I've got a 10 frame clip @ 30fps and I want to gradually slow it from 100% to 25%
Slow to 25%
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF (40 frames)
I start saving the first frame then removing the next 3
F---FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Eventually I get to a point where I save one frame and remove the next 2
F---F---F--FFFFFFFFFFFFFFFFFFFFFFFFFFFFF
And later, I get to a point where I save one frame and remove the adjacent frame
F---F---F--F--F--F--F-FFFFFFFFFFFFFFFFFF
Finally, I'm down to where all the frames are saved
F---F---F--F--F--F--F-F-F-F-F-F-FFFFFFFF
The overflow calculation helps to smooth the transitions out. It won't always be remove 3, then remove 2, then remove 1. It should look more like (removing frames) 33323232222121211110101010000.
That's all there is to it!
Thanks for looking :cool:
I was really bothered that I couldn't find a decent free/cheap alternative to Adobe's Time Remapping, so I decided to take a stab at it using Avisynth and MVTools. I'm posting my script here to share and also get some feedback on ways to improve it. As of right now I am happy with the results I get but I have to imagine it can be improved.
I make use of GScript as well since it's easier for me to use standard control statements and loops.
For the noob's: (myself included)
LoadPlugin("mvtools2.dll")
LoadPlugin("GScript.dll")
Here are the functions: (the good stuff)
# Gradually slows a clip down
function Slowmoe(clip source, float startFrame, float endFrame, float startRatio, float endRatio)
{
# Get the clip's original framerate
mfpsn = FramerateNumerator(source)
mfpsd = FramerateDenominator(source)
# Convert and trim clip
mclip = Trim(source, startFrame, endFrame)
# Flip frames
GScript("""
if (endFrame < startFrame) {
temp = endFrame
endFrame = startFrame
startFrame = temp
}
""")
# Do the MVTools SlowMotion
super = MSuper(mclip, pel=2)
backward_vec = MAnalyse(super, overlap=4, isb = true, truemotion=true, search=3)
forward_vec = MAnalyse(super, overlap=4, isb = false, truemotion=true, search=3)
slowdown = MFlowFPS(mclip, super, backward_vec, forward_vec, Round(mfpsn * 1.0/endRatio), mfpsd)
slowdown = AssumeFPS(slowdown, mfpsn, mfpsd)
# Initialize values
startFrames = (mfpsn * 1.0/startRatio)/mfpsd # Starting frames in a second
endFrames = (mfpsn * 1.0/endRatio)/mfpsd # Ending frames in a second
framesRange = endFrames - startFrames # Difference in frames
currentFrame = 0 # The current frame in the final clip
counter = 0 # The total frame counter
lastFrame = Framecount(slowdown) # The total frames in the slow mo clip
desiredFrames = 0 # The current desired frames
removeFrameCounter = 0 # The frame removal counter
removeFrameThreshold = Float(endFrames)/Float(startFrames) # The number of frames to remove
overflow = 0 # Overflow from the frame threshold
GScript("""
while (counter < lastFrame) {
# Increment the frame removal counter
removeFrameCounter = removeFrameCounter + 1
# Check if the frame removal counter is over the threshold
if (removeFrameCounter >= Floor(removeFrameThreshold + overflow)) {
# Store the overflow
if (overflow > 1) {
overflow = overflow - 1.0
}
else {
overflow = overflow + removeFrameThreshold - Floor(removeFrameThreshold)
}
# Calculate the desired frames. You could use a higher power to make the transition even smoother.
desiredFrames = startFrames + Pow(Float(counter)/Float(lastFrame), 4) * framesRange
removeFrameThreshold = Float(endFrames)/Float(desiredFrames)
# Stop the threshold if it gets too low
if (removeFrameThreshold < 1.1) {
removeFrameThreshold = 1.0
overflow = 0
}
# Reset the counter
removeFrameCounter = 0
}
# Delete or Keep frame
if (removeFrameCounter == 0) {
currentFrame = currentFrame + 1
}
else {
slowdown = DeleteFrame(slowdown, currentFrame)
}
# Increment the counter
counter = counter + 1
}
""")
# Delete the last frame
slowdown = DeleteFrame(slowdown, Framecount(slowdown))
# Return the clip
return slowdown
}
# Gradually speeds a clip up
function Speedmoe(clip source, float startFrame, float endFrame, float startRatio, float endRatio)
{
# Get the clip's original framerate
mfpsn = FramerateNumerator(source)
mfpsd = FramerateDenominator(source)
# Convert and trim clip
mclip = Trim(source, startFrame, endFrame)
# Flip frames
GScript("""
if (endFrame < startFrame) {
temp = endFrame
endFrame = startFrame
startFrame = temp
}
""")
# Do the MVTools SlowMotion
super = MSuper(mclip, pel=2)
backward_vec = MAnalyse(super, overlap=4, isb = true, truemotion=true, search=3)
forward_vec = MAnalyse(super, overlap=4, isb = false, truemotion=true, search=3)
slowdown = MFlowFPS(mclip, super, backward_vec, forward_vec, Round(mfpsn * 1.0/startRatio), mfpsd)
slowdown = AssumeFPS(slowdown, mfpsn, mfpsd)
# Initialize values
startFrames = (mfpsn * 1.0/startRatio)/mfpsd # Starting frames in a second
endFrames = (mfpsn * 1.0/endRatio)/mfpsd # Ending frames in a second
framesRange = startFrames - endFrames # Difference in frames
currentFrame = Framecount(slowdown) # The current frame in the final clip
counter = 0 # The total frame counter
lastFrame = Framecount(slowdown) # The total frames in the slow mo clip
desiredFrames = 0 # The current desired frames
removeFrameCounter = 0 # The frame removal counter
removeFrameThreshold = Float(startFrames)/Float(endFrames) # The number of frames to remove
overflow = 0 # Overflow from the frame threshold
GScript("""
while (counter < lastFrame) {
# Increment the frame removal counter
removeFrameCounter = removeFrameCounter + 1
# Check if the frame removal counter is over the threshold
if (removeFrameCounter >= Floor(removeFrameThreshold + overflow)) {
# Store the overflow
if (overflow > 1) {
overflow = overflow - 1.0
}
else {
overflow = overflow + removeFrameThreshold - Floor(removeFrameThreshold)
}
# Calculate the desired frames. You could use a higher root to make the transition even smoother.
desiredFrames = endFrames + Pow(Float(counter)/Float(lastFrame), 4) * framesRange
removeFrameThreshold = Float(startFrames)/Float(desiredFrames)
# Stop the threshold if it gets too low
if (removeFrameThreshold < 1.1) {
removeFrameThreshold = 1.0
overflow = 0
}
# Reset the counter
removeFrameCounter = 0
}
# Keep or Delete frame
if (removeFrameCounter == 0) {
currentFrame = currentFrame - 1
}
else {
slowdown = DeleteFrame(slowdown, currentFrame)
currentFrame = currentFrame - 1
}
# Increment the counter
counter = counter + 1
}
""")
# Return the clip
return slowdown
}
Here's an example of using them:
source = AVISource("stock.avi")
return Slowmoe(source, 0, 18, 1.0, 1.0) ++ Slowmoe(source, 18, 26, 1.0, 0.10) ++ Slowmoe(source, 26, 30, 0.10, 0.10) ++ Speedmoe(source, 30, Framecount(source), 0.10, 1.0)
I thought up the algorithm to do this on my own. I have no idea if it's even close to the real way to do it.
Anyways, it works like so:
First I take the slowest percentage you want the clip at and use MVTools to do the nice frame interpolation and slow the clip down to that speed. Then I loop through the clip and gradually remove frames to speed the clip back up. I start with looking at the clip's original fps. If the clip was originally 30 fps, and I've slowed it down to 120 fps, I would need to cut 75% of the frames out to get back to the original speed. In other words, I need to save every 4th frame and remove the rest. Then it's just a matter of ramping that down using some math.
Example:
I've got a 10 frame clip @ 30fps and I want to gradually slow it from 100% to 25%
Slow to 25%
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF (40 frames)
I start saving the first frame then removing the next 3
F---FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Eventually I get to a point where I save one frame and remove the next 2
F---F---F--FFFFFFFFFFFFFFFFFFFFFFFFFFFFF
And later, I get to a point where I save one frame and remove the adjacent frame
F---F---F--F--F--F--F-FFFFFFFFFFFFFFFFFF
Finally, I'm down to where all the frames are saved
F---F---F--F--F--F--F-F-F-F-F-F-FFFFFFFF
The overflow calculation helps to smooth the transitions out. It won't always be remove 3, then remove 2, then remove 1. It should look more like (removing frames) 33323232222121211110101010000.
That's all there is to it!
Thanks for looking :cool: