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.

 Doom9's Forum CutFrames: Opposite of Trim
 Register FAQ Calendar Search Today's Posts Mark Forums Read

 2nd March 2008, 00:29 #1  |  Link mikeytown2 Resize Abuser     Join Date: Apr 2005 Location: Seattle, WA Posts: 623 CutFrames: Opposite of Trim Code: # CutFrames() - March 9th, 2008 # Cut a range of frames from a single a/v clip. # # Parameters: # int start - start of cut # int end - end of cut # int duration - duration of fade between cuts # int fade_color - blank clip color (usually in Hex RGB) used at start or end of clip only # string transition - pass a function name, if user wants to use something other then Dissolve # val opt1 - pass a variable to the fade/transition function # val opt2 - pass a variable to the fade/transition function # val opt3 - pass a variable to the fade/transition function # # Preconditions: # start >= 0 ; start can not be a negative value # start-duration > 0 # start = 0 then a fade in is used # end = 0 cut till the end of the clip and a fade out is used # start != end ; mainly a condition to check for start == 0 and end == 0 function CutFrames(clip c, int start, int end, int "duration", int "fade_color", string "transition", val "opt1", val "opt2", val "opt3") { # Set Defaults duration = default(duration, 0) transition = default(transition, "Dissolve") fade_color = default(fade_color,$000000) opt1=(Defined(opt1) ? ", "+string(opt1): "") opt2=(Defined(opt2) ? ", "+string(opt2): "") opt3=(Defined(opt3) ? ", "+string(opt3): "") opts = opt1 + opt2 + opt3 end = c.Framecount()-1 == end ? 0: end d = c.BlankClip(duration, color=fade_color) # Check For Any Unreasonable Inputs Assert(start >= 0, "CutFrames: Starting Frame[" + String(start) + "] must be a positive value") Assert((start == 0) || (start-duration >= 0), "CutFrames: Starting Frame[" + String(start) + "] must be greater then or equal to" + Chr(10) + " inputed duration[" + String(duration) + "]") Assert(start <> end, "CutFrames: Start and End cannot both be the same") Assert(end <= c.Framecount()-1, "CutFrames: End[" + String(end) + "] is greater then " + Chr(10) + "clip length[" + String(c.Framecount()-1) + "]") Assert((end == 0) || (end+duration <= c.Framecount()-1), "CutFrames: Ending Frame[" + String(end) + "] must be less then or equal to" + Chr(10) + " last frame - duration [" + String(c.Framecount()-1-duration) + "]") # Select uncut frames (or blanks) as transition components: clip1 = (start == 0) ? d : c.trim(0, -start) clip2 = (end == 0) ? d : c.trim(end+1, 0) # Perform transition: Eval(transition + "(clip1, clip2," + string(duration) + opts + ")") } General Examples: - Assuming clip is 1000 frames in length CutFrames(200, 400) - Cut out frames 200-400 from the video. Resulting length: 799 CutFrames(200, 400, 20) - Cut out frames 200-400 using Dissolve() for a 20 frame fade. Transition starts on frame 180; Resulting length: 779 CutFrames(210, 390, 20) - Cut out frames 210-390 using Dissolve() for a 20 frame fade. Transition starts on frame 190; Resulting length: 799 CutFrames(400, 200, 20) - Replay frames 200-400 using Dissolve() with a 20 frame fade. Transition starts on frame 380; Resulting length: 1179 CutFrames(200, 400, 20,$000000, "TransSwing", false, 1, 1) - Cut out frames 200-400 using TransSwing() for a 20 frame fade, passing 3 additional arguments to TransSwing(). Transition starts on frame 180; Resulting length: 779 CutFrames(0, 400) - Cut out frames 0-400 from the video. Resulting length: 599 CutFrames(0, 400, 20) - Cut out frames 0-400 from the video using Dissolve() for a 20 frame fade from black (FadeIn). Resulting length: 599 CutFrames(200, 0) - Cut out frames 200-1000 from the video. Resulting length: 199 CutFrames(200, 0, 20) - Cut out frames 200-1000 from the video using Dissolve() for a 20 frame fade into black (FadeOut). Resulting length: 199 CutFrames(0, 400, 20, $FF0000) - Cut out frames 0-400 from the video using Dissolve() for a 20 frame fade from red (FadeIn). Resulting length: 599 Tips:When using this multiple times, work backwards. Cut frames from the end of the clip first. By doing this, your cuts will be independent from each other. Example: CutFrames(900, 950) CutFrames(800, 850) CutFrames(650, 700) Inserting ShowFrameNumber(x=10, y=30) before any cutframes() will show what frame you're currently on. If your looking for audio cuts add something like this before CutFrames() Code: Histogram("stereo") AddBorders(300, 0, 0, 0) Histogram("Audiolevels") ShowFrameNumber(x=width()-100, y=30) ShowSMPTE() Or a better way using AudioGraph(). Stickboy made a nice wrapper for stereo output. http://forum.doom9.org/showthread.php?s=&threadid=59412 Code: Grayscale() ConvertToRGB() AudioGraph(Width()/96) ShowFrameNumber(x=10, y=30) ShowSMPTE() You can place these after all your CutFrames() to see the resulting sound/waveform. Place your CutFrames() inside a function. This allows you to comment out all your cuts at once. Code: cut() Function Cut(clip c) { c CutFrames(254700, 0, 15) CutFrames(194974, 254027, 15) CutFrames(0, 189730, 15) } Taking this one step further, you can create multiple segments and order them in any way; selectively applying filters as well. Code: original = last segmentA(original) last + Grayscale(segmentB(original)) function segmentA(clip c) { c CutFrames(254700, 0, 15) CutFrames(194974, 254027, 15) CutFrames(0, 189730, 15) } function segmentB(clip c) { c CutFrames(3390, 0, 15) CutFrames(580, 2700, 15) CutFrames(0, 460, 15) } Footnotes: Loop() can delete frames as well. Second to last example on page. Future Ideas: This is a RFC (Request For Comments), your input is greatly appreciated. Edits: March 4th, 2008: Got rid of ugly logic - Thanks Gavino March 7th, 2008: Added error checking and FadeIn/FadeOut - Thanks stickboy for pointing out how this can fail and for header suggestions March 8th, 2008: Improved End error checking March 8th, 2008: Fixed cut points, now they are excluded - Thanks Gavino. Examples changed as a result. March 9th, 2008: More code cleanup, added color option to fadeI/O, fixed end boundary condition - Thanks Gavino. __________________ Mine: KenBurnsEffect/ZoomBox CutFrames Helped: DissolveAGG ColorBalance LQ Animation Fixer Last edited by mikeytown2; 15th March 2008 at 14:04.  2nd March 2008, 12:54 #2 | Link stickboy AviSynth Enthusiast Join Date: Jul 2002 Location: California, U.S. Posts: 1,268 Even your simple version is problematic. Be careful when using Trim with variable arguments.  2nd March 2008, 15:02 #3 | Link mikeytown2 Resize Abuser Join Date: Apr 2005 Location: Seattle, WA Posts: 623 Thanks for pointing this out! After looking at your functions and reading the headers, i think i will use Trim3. http://avisynth.org/stickboy/jdl-util.avsi You really like Assert, i had to go look it up. http://avisynth.org/mediawiki/Intern...trol_functions So reworking my first example it should be something like this Code: function CutFrames(clip c, int start, int end) { return c.trim3(0, start) + c.trim3(end, c.Framecount()) } __________________ Mine: KenBurnsEffect/ZoomBox CutFrames Helped: DissolveAGG ColorBalance LQ Animation Fixer 2nd March 2008, 21:16 #4 | Link Gavino Avisynth language lover Join Date: Dec 2007 Location: Spain Posts: 3,374 Quote:  Originally Posted by mikeytown2 This is a very simple script, but i would like it to be smart. Code: function CutFrames(clip c, int start, int end) { return c.trim(0, start) + c.trim(end, c.Framecount()) } I would like to make it aware of the other times it is called. So when i edit a video and call this function, multiple times, it knows. So if i remove the very first call to CutFrames i would not have to change all the other ones. The solution to your problem is much easier: simply apply your cuts in reverse order in your script, eg CutFrames(4444, 5555) CutFrames(2222, 3333) ... Then if you decide to remove any of the cuts, the frame numbers in the other ones will still be valid. Gavino  3rd March 2008, 08:08 #5 | Link Ebobtron Errant Knight Join Date: Oct 2004 Location: St Louis, M0 US Posts: 364 Hello, Lots of ways to skin this cat, here is one I use often, it is easier for me to understand weeks, maybe months, into something. Code: some source filter or filters # source filters return a clip "last" # which is equivalent to " last = source filter " # unless assigned to a clip variable, # (for example " source = source filter ") trim(framestart, frameend) + trim(fs, fe) + trim(fs, fe) + trim(fs, fe) # yep that sucks, and if there are a lot of them it really sucks aclip = trim(fs, fe) # aclip is assigned the clip returned by " trim(last, fs, fe) " aclip = aclip + trim(fs, fe) # The just keep doing it aclip = aclip + trim(fs, fe) aclip = aclip + trim(fs, fe) aclip = aclip + trim(fs, fe) aclip = aclip + trim(fs, fe) aclip = aclip + trim(fs, fe) aclip = aclip + trim(fs, fe) # want to comment one out #aclip = aclip + trim(fs, fe) aclip = aclip + trim(fs, fe) # at this point the script's output is still equal to " last ' # aclip # which is the same as last = aclip Code: # add dissolves between all clips aclip = trim(fs, fe) aclip = Dissolve(aclip, trim(fs, fe), 60) aclip = Dissolve(aclip, trim(fs, fe), 60) aclip = Dissolve(aclip, trim(fs, fe), 60) aclip = Dissolve(aclip, trim(fs, fe), 60) aclip have fun  3rd March 2008, 19:30 #6 | Link mikeytown2 Resize Abuser Join Date: Apr 2005 Location: Seattle, WA Posts: 623 @Gavino Thank you for the reverse order hint, that makes this a lot simpler to implement. @Ebobtron The option to dissolve/blend the clips would be a good thing. [http://avisynth.org/mediawiki/Dissolve] In the long run, i would like to be able to support any transition. [http://avisynth.org/vcmohan/TransAll/docs/index.html] I think i would have to use an eval statement in order to do it. [http://avisynth.org/mediawiki/Intern...trol_functions] In terms of the structure of the AddCutPoint function, i think it would look something like this AddCutPoint(clip c, int start, int end, string transition, int duration) where clip c is the a/v stream to cut up. int start is the starting frame to cut, int end would be the last or ending frame to cut. String transition would be the function name, and int duration is how long the transition will last. This function call would then store these 5 values into a 5 dim array. the only question i have is about storing a clip into an array; is this a bad idea? Int's and strings shouldn't be an issue but i'm not sure about the clip variable. The reason for storing the clip variable would be in the case of multiple a/v clips in a single script. Anyway here is the simple script with transitions added Code: function CutFrames(clip c, int start, int end, string "transition", int "duration") { duration = default(duration, 0) return Defined(transition) ? Eval(transition + "(c.trim(0, " + string(start) + "), c.trim(" + string(end) + ", c.Framecount()), " + string(duration) + ")") : c.trim(0, start) + c.trim(end, c.Framecount()) } CutFrames(200, 800, "Dissolve", 60) EDIT I think i like this function better Code: function CutFrames(clip c, int start, int end, int "duration", string "transition") { duration = default(duration, 0) transition = default(transition, "Dissolve") return Eval(transition + "(c.trim(0, " + string(start) + "), c.trim(" + string(end) + ", c.Framecount()), " + string(duration) + ")") } CutFrames(200, 800, 60) __________________ Mine: KenBurnsEffect/ZoomBox CutFrames Helped: DissolveAGG ColorBalance LQ Animation Fixer Last edited by mikeytown2; 3rd March 2008 at 22:28. 4th March 2008, 01:30 #7 | Link Gavino Avisynth language lover Join Date: Dec 2007 Location: Spain Posts: 3,374 Quote:  Originally Posted by mikeytown2 @Gavino Thank you for the reverse order hint, that makes this a lot simpler to implement. ... In terms of the structure of the AddCutPoint function, i think it would look something like this AddCutPoint(clip c, int start, int end, string transition, int duration) My point was that if you adopt the 'reverse order' strategy (ie put the cuts in reverse chronological order), you no longer need the AddCutPoint function. This approach will still work with your extended CutFrames function which supports transitions. Gavino  4th March 2008, 03:31 #8 | Link mikeytown2 Resize Abuser Join Date: Apr 2005 Location: Seattle, WA Posts: 623 @Gavion I was planing on using a sort array method, to order the array from largest to smallest, inside the ProcessCutPoints() function. Without your helpful input, i probably would have done it another way, with a lot of math calc involved. After looking at [http://avisynth.org/mediawiki/Arrays] and [http://avslib.sourceforge.net/functi...raycreate.html], i have decided to drop the idea of processing multiple clips simultaneously. The ProcessCutPoints() function should clear the arrays, so that it can still do cuts on multiple clips; just not all at the same time. Speaking of arrays i think 4 single dim arrays would be the easiest to do with the avisynth language. I just need a way to sort this, otherwise as Gavion has pointed out, my simple method is quite adequate. Any input would greatly be appreciated, should i go for the 2 step process or should i leave this as is? EDIT Multiple options can be passed to the blending function now Code: function CutFrames(clip c, int start, int end, int "duration", string "transition", string "opt1", string "opt2", string "opt3") { duration = default(duration, 0) transition = default(transition, "Dissolve") return \ Defined(opt3) ? Eval(transition + "(c.trim(0, " + string(start) + "), c.trim(" + string(end) + ", c.Framecount()), " + string(duration) + ", " + String(opt1) + ", " + String(opt2) + ", " + String(opt3) + ")") : \ Defined(opt2) ? Eval(transition + "(c.trim(0, " + string(start) + "), c.trim(" + string(end) + ", c.Framecount()), " + string(duration) + ", " + String(opt1) + ", " + String(opt2) + ")") : \ Defined(opt1) ? Eval(transition + "(c.trim(0, " + string(start) + "), c.trim(" + string(end) + ", c.Framecount()), " + string(duration) + ", " + String(opt1) + ")") : \ Eval(transition + "(c.trim(0, " + string(start) + "), c.trim(" + string(end) + ", c.Framecount()), " + string(duration) + ")") } CutFrames(200, 800, 60, "TransSwing", "false", "1", "1") http://avisynth.org/vcmohan/TransAll...ransSwing.html You can also use this as a quick, apply effect to range function, that takes 2 clips as input Code: CutFrames(200, 150, 50, "EffectName") Or instant replay Code: CutFrames(300, 150) Or "Drunk Effect" Code: CutFrames(800, 100, 695) __________________ Mine: KenBurnsEffect/ZoomBox CutFrames Helped: DissolveAGG ColorBalance LQ Animation Fixer Last edited by mikeytown2; 4th March 2008 at 04:39. 4th March 2008, 13:15 #9 | Link Gavino Avisynth language lover Join Date: Dec 2007 Location: Spain Posts: 3,374 Quote:  Originally Posted by mikeytown2 Any input would greatly be appreciated, should i go for the 2 step process or should i leave this as is? It's a matter of taste, but I think the introduction of AddCutPoint and ProcessCutPoints (if that's what you mean by the 2 step process) is overkill, and the CutFrames function is all you need. The 'reverse order' approach solves the problem you initially identified, of each cut potentially changing the frame numbers to be used in the others. Of course YMMV, and your time and effort are yours to spend as you wish. Incidentally, I suggest a modification to your enhanced CutFrames function: change the types of opt1, opt2 and opt3 from 'string' to 'val'. This would allow you to pass numerical parameters without quotes. Also (and again, it's a matter of personal taste), I would tidy up the last part as follows: Code:  opt1=(Defined(opt1) ? ", "+string(opt1): "") opt2=(Defined(opt2) ? ", "+string(opt2): "") opt3=(Defined(opt3) ? ", "+string(opt3): "") return Eval(transition + "(c.trim(0, " + string(start) + "), c.trim(" + string(end) + ", 0), " + string(duration) + opt1 + opt2 + opt3 + ")")  4th March 2008, 22:50 #10 | Link mikeytown2 Resize Abuser Join Date: Apr 2005 Location: Seattle, WA Posts: 623 Updated first post with latest function and put up examples as well as a very helpful tip. Thanks to Gavino for your help in cleaning up the code and the tip. Thanks to Ebobtron for pointing out transitions. Thanks to stickboy for directing me towards his other trim functions; i didn't use them because of dependency issues though. __________________ Mine: KenBurnsEffect/ZoomBox CutFrames Helped: DissolveAGG ColorBalance LQ Animation Fixer 5th March 2008, 20:37 #11 | Link stickboy AviSynth Enthusiast Join Date: Jul 2002 Location: California, U.S. Posts: 1,268 Quote:  Originally Posted by mikeytown2 Updated first post with latest Thanks to stickboy for directing me towards his other trim functions; i didn't use them because of dependency issues though. So you'd rather have functions that silently do the wrong thing when given certain inputs? You don't even bother using Assert() to validate them, nor do you describe in the comments which values to avoid. It's not as if they're unlikely inputs. You only need to call CutFrames(c, 0, ...) for it to be wrong. I've made my functions public domain for a reason. If you don't want to tell people to go download my scripts (and I don't think anyone actually has any problem with that), you're free to simply copy and paste the parts you need. 7th March 2008, 22:54 #12 | Link mikeytown2 Resize Abuser Join Date: Apr 2005 Location: Seattle, WA Posts: 623 Quote:  Originally Posted by stickboy So you'd rather have functions that silently do the wrong thing when given certain inputs? You don't even bother using Assert() to validate them, nor do you describe in the comments which values to avoid. It's not as if they're unlikely inputs. You only need to call CutFrames(c, 0, ...) for it to be wrong. I've made my functions public domain for a reason. If you don't want to tell people to go download my scripts (and I don't think anyone actually has any problem with that), you're free to simply copy and paste the parts you need. It's nothing against your scripts, just me personally, any time i have to download multiple files to get a function working, i find that annoying; trying to avoid that if i can. Thank you for the option to paste your script into this. I never considered 0 as an input for this function (was thinking they would use trim), now i think CutFrames handles this quite nicely. I also added Preconditions to the header. Where should i pass the BlankClip Color property into this function? i was thinking after int "duration". 9th March 2008, 02:37 #13 | Link Gavino Avisynth language lover Join Date: Dec 2007 Location: Spain Posts: 3,374 @mikeytown2: Looking at this again, I've just spotted something ... Quote:  Originally Posted by mikeytown2 General Examples: - Assuming clip is 1000 frames in length CutFrames(200, 400) - Cut out frames 200-400 from the video. Resulting length: 800 ... In fact, it cuts out frames 201-399, for a resulting length of 801. (and even if it did cut out 200-400, the length would then be 799) As the function is written, frames 'start' and 'end' are excluded from the cut, ie they appear in the output clip. I assume this is an oversight and you intended it to work as described in the example. Gavino 9th March 2008, 03:24 #14 | Link mikeytown2 Resize Abuser Join Date: Apr 2005 Location: Seattle, WA Posts: 623 Quote:  Originally Posted by Gavino @mikeytown2: Looking at this again, I've just spotted something ... In fact, it cuts out frames 201-399, for a resulting length of 801. (and even if it did cut out 200-400, the length would then be 799) As the function is written, frames 'start' and 'end' are excluded from the cut, ie they appear in the output clip. I assume this is an oversight and you intended it to work as described in the example. Gavino Thanks for pointing this out. I think i have it fixed now. Trim acts kinda odd when you just want the first frame [http://avisynth.org/mediawiki/Trim]. 9th March 2008, 17:05 #15 | Link Gavino Avisynth language lover Join Date: Dec 2007 Location: Spain Posts: 3,374 Quote:  Originally Posted by mikeytown2 I think i have it fixed now. Almost, but I think you've still got one of the boundary conditions wrong. Since the last frame of a clip is actually framecount-1, this value (rather than framecount) should be the max allowed for end (and mapped internally to 0). Also, it might be clearer to replace: Code: #Funkey Conditions start = (start == 0) ? -1 : start start = (start == 1) ? 0 : start #Perform Cut return start == -1 ? \Eval(transition + "(d, c.trim(" + string(end+1) + ", 0), " + string(duration) + opts + ")"): \end == 0 ? \Eval(transition + "(c.trim(0, " + string(start-1) + "), d, " + string(duration) + opts + ")"): \Eval(transition + "(c.trim(0, " + string(start-1) + "), c.trim(" + string(end+1) + ", 0), " + string(duration) + opts + ")") by Code: # Select uncut frames (or blanks) as transition components: clip1 = (start == 0) ? d : c.trim(0, -start) clip2 = (end == 0) ? d : c.trim(end+1, 0) # Perform transition: Eval(transition + "(clip1, clip2," + string(duration) + opts + ")") The effect is the same, but this way it seems clearer what the special cases are and how they are handled. (And by always using the negative Trim argument to select the first start frames, start=1 is no longer a special case) Gavino  9th March 2008, 23:25 #16 | Link mikeytown2 Resize Abuser Join Date: Apr 2005 Location: Seattle, WA Posts: 623 Gavino thank you for improving this function, it would be a lot uglier without your help! I was thinking about the fade color option, is there any way to test if an int is hex ($000000), if it has a "$" in it? If there is, then an idea i have is to get rid of the fade_color variable and use the start and end variables instead. Because the only time the blank clip is used is when start or end = 0; then if start or end is a color it would set the color with that value and then set start or end to 0. Example: CutFrames(0, 400, 20,$FF0000) would be CutFrames($FF0000, 400, 20) and CutFrames(400, 0, 20,$FF0000) would be CutFrames(400, $FF0000, 20). This would eliminate the unnecessary color variable in this example: CutFrames(200, 400, 20,$000000, "TransSwing", false, 1, 1) Good/Bad, is it even possible idea? __________________ Mine: KenBurnsEffect/ZoomBox CutFrames Helped: DissolveAGG ColorBalance LQ Animation Fixer
10th March 2008, 00:57   #17  |  Link
Gavino
Avisynth language lover

Join Date: Dec 2007
Location: Spain
Posts: 3,374
Quote:
 Originally Posted by mikeytown2 I was thinking about the fade color option, is there any way to test if an int is hex ($000000), if it has a "$" in it? If there is, then an idea i have is to get rid of the fade_color variable and use the start and end variables instead.
It's not possible to distinguish an int passed in hex from one passed in decimal; once you get your hands on it it's just an int value.

If passing an unnecessary color parameter bothers you, you could move fade_color to the end of the function parameter list, then pass it by name on the infrequent occasions that a non-default value is wanted.

There seems to be a typo in your latest edit:
Code:
bg_color = default(fade_color,$000000) should be Code: fade_color = default(fade_color,$000000)
(or maybe you meant to use bg_color as the parameter to BlankClip later?)

 10th March 2008, 01:05 #18  |  Link mikeytown2 Resize Abuser     Join Date: Apr 2005 Location: Seattle, WA Posts: 623 Thanks for the catching the typo! I originally called it background color, then i thought fade described it better. Thanks for looking into the int/hex issue, it's not a major issue, just thought it might be better if it was possible. I'll leave fade_color where it is. __________________ Mine: KenBurnsEffect/ZoomBox CutFrames Helped: DissolveAGG ColorBalance LQ Animation Fixer