View Full Version : Trouble converting 720p60 to 29.97fps
cayblood
25th November 2009, 05:21
I'm having trouble with a framerate mismatch between two videos. I want to put a slide presentation next to a video of the presenter. The slide files are recorded in 720p60 MJPEGs and the video files are in NTSC firewire dv (29.97fps).
I'm using DirectShowSource to read in the slide files, since this seems to be the only thing that recognizes the files. However, it doesn't really allow me fine grained adjustments when I call ConvertFPS. It seems to get close but not quite in sync with the presenter video, and it either doesn't change when I do small adjustments or it overcorrects when I make large adjustments.
Anyone have any suggestions for how I can get around this?
Thanks,
Carl Youngblood
IanB
25th November 2009, 07:35
Assuming OtherClip is your NTSC firewire dv (29.97fps) clip.
Use the DirectShowSource() options ConvertFPS=True and FPS=FrameRate(OtherClip)
Then use AssumeFPS(OtherClip) on the DSS clip to get the framerate numerator and denominator exactly right.
Do any framerate manipulation (i.e. IVTC, Bob, etc) on the DV clip before you load the MJPEG clip.
cayblood
25th November 2009, 08:13
I have done this and the result still ends up being off by about 300 frames after about 1/2 hr.
IanB
25th November 2009, 13:21
Perhaps you had better confess a bit more information. ;)
i.e. 30 minutes of NTSC DV will be 53946 frames.
The unconverted 720p60 MJPEG should be 107892 frames in 30 minutes.
Now a 300 frame difference implies either 60.27 or 59.61 fps or perhaps the capture system has dropped 300 frames over 30 minutes or maybe one clip is 30 minutes and the other is 30 minutes and 10 seconds (or 29:50) or ....
DirectShowSource("720p60 MJPEG", ConvertFPS=True, FPS=FrameRate(OtherClip)) by definition will force the result to be time period identical, if the framecounts are different then the durations simply are different. In which case do you want to adjust the durations to match?
cayblood
25th November 2009, 15:56
Forgive me Ian, I wasn't sure how precisely avisynth was adhering to my instructions. What I basically know is that when we have done this in the past at 720p50 on the slides and NSTC on the video they have lined up perfectly. Now that we are using 720p60 (it was recorded this way by accident) it is no longer lining up as we expect it to.
Here is my code in full detail. The following file (main.avsi) gets included by another file (listed below it):
LoadPlugin("N:\scripts\rubyconf2009\scripts\include\LeakKernelDeint.dll")
##################################################################################
### Helper functions
##################################################################################
Function PadNumber_(int num, int num_digits, bool first_time) {
return first_time ? PadNumber_(num, num_digits - StrLen(String(num)), false) : \
num_digits > 0 ? "0" + PadNumber_(num, num_digits - 1, false) : String(num)
}
Function PadNumber(int num, int num_digits) {
return PadNumber_(num, num_digits, true)
}
Function ConcatenateDShow(string prefix, int start, int stop, int padby) {
return start > stop - 1 ? DirectShowSource(prefix + PadNumber(stop, padby) + ".avi") : \
DirectShowSource(prefix + PadNumber(start, padby) + ".avi") + \
ConcatenateDShow(prefix, start + 1, stop, padby)
}
Function ConcatenateAVIs(string prefix, int start, int stop, int padby) {
return start > stop - 1 ? AVISource(prefix + PadNumber(stop, padby) + ".avi") : \
AVISource(prefix + PadNumber(start, padby) + ".avi") + \
ConcatenateAVIs(prefix, start + 1, stop, padby)
}
# read video
video = videostartnum == -1 ? DirectShowSource(videoprefix) : ConcatenateDShow(videoprefix, videostartnum, videoendnum, zeropadcount)
video = LeakKernelDeint(video, 0)
fr = Framerate(video)
video = format == "wide" ? BilinearResize(video, 426, 320, videox1, videoy1, videox2, videoy2) : BilinearResize(video, 480, 360, videox1, videoy1, videox2, videoy2)
video = format == "wide" ? Crop(video, 52, 0, -54, 0) : video
video = Levels(video, levels1, levels2, levels3, levels4, levels5)
# stack and resize video with ads
above = BlankClip(video, length=200, color=$ff0000)
above = ImageSource("N:\scripts\rubyconf2009\ads\video-top.png", \
pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
below = ImageSource("N:\scripts\rubyconf2009\ads\video-bottom-alt.png", \
pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
video = format != "wide" ? video : AudioDub(StackVertical(StackVertical(above, video), below), video)
# balance audio
left_channel = GetChannel(video, 1)
right_channel = GetChannel(video, 2)
audio = audiochannel == "right" ? right_channel : left_channel
video = AudioDub(video, audio)
# Read slides in.
slides = StrLen(slidefile) > 0 ? DirectShowSource(slidefile, ConvertFPS=true, FPS=FrameRate(video)) : BlankClip(video, length=200, color=$ff0000)
slides = Levels(slides, slidelevels1, slidelevels2, slidelevels3, slidelevels4, slidelevels5)
slides = slides.AssumeFPS(video).ConvertToYV12
slides = BilinearResize(slides, 960, 720, slidesx1, slidesy1, slidesx2, slidesy2)
fr = Framerate(video)
slidesduration = FrameCount(slides) / fr
videoduration = FrameCount(video) / fr
difference = slidesmtime - videomtime
adjusted_duration = difference + videoduration
slideoffset = Round(fr * (slidesduration - adjusted_duration))
slideoffset = slideoffset + slideadjustment
# trim video and slides
Eval(trimcode)
# stack video and slides
combined = format == "wide" ? StackHorizontal(trimmed_slides, trimmed_video) : trimmed_video
logo = ImageSource("N:\scripts\rubyconf2009\ads\confreaks_overlay_new.png", \
end=1000, pixel_type="rgb32", fps=FrameRate(video))
logo = logo.BilinearResize(100, 16)
combined = format != "wide" ? Overlay(combined, logo, x=373, y=337, mask=ShowAlpha(logo)) : combined
combined = AudioDub(combined, trimmed_video)
# dissolve to title image
blank = BlankClip(combined, length=200, color=$000000)
title = ImageSource(titleimagepath, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
title = AudioDub(title, blank)
title = BilinearResize(title, combined.width, combined.height)
titled_video = Dissolve(FadeIn(title, 30), combined, 30)
# prepend ads
platinum_ad_image_path = format == "wide" ? "N:\scripts\rubyconf2009\ads\platinum-sponsor.png" : "N:\scripts\rubyconf2009\ads\platinum-sponsor-small.png"
platinum_sponsor = ImageSource(platinum_ad_image_path, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
platinum_sponsor = AudioDub(platinum_sponsor, blank)
gold_ad_image_path = format == "wide" ? "N:\scripts\rubyconf2009\ads\gold-sponsors.png" : "N:\scripts\rubyconf2009\ads\gold-sponsors-small.png"
gold_sponsors = ImageSource(gold_ad_image_path, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
gold_sponsors = AudioDub(gold_sponsors, blank)
titled_video_with_ads = Dissolve(Dissolve(FadeIn(platinum_sponsor, 30), gold_sponsors, 30), titled_video, 30)
width = format == "wide" ? 1280 : 480
height = format == "wide" ? 720 : 360
final = BilinearResize(titled_video_with_ads, width, height)
final = FadeOut(final, 30)
final = size == "small" ? final.ReduceBy2 : final
final = StrLen(audiofile) > 0 ? AudioDub(final, WAVSource(audiofile)) : final
final
The above file gets included by the following file (whose contents are auto-generated from our database):
videoprefix = "O:\rubyconf2009\day1\room1\camera."
zeropadcount = 2
videomtime = 1258653716
slidefile = "O:\rubyconf2009\day1\room1\data.avi"
audiofile = ""
audiochannel = "left"
slidesmtime = 1258653715
slideadjustment = 0
videostartnum = 2
videoendnum = 5
filterslides = "no"
filtervideo = "no"
trimcode = """
start_frame = Round((0 * fr) + (540 * fr) + (52.0 * fr))
end_frame = Round((0 * fr) + (2700 * fr) + (46.25 * fr))
temp_slides = slideoffset + start_frame < 0 ? UnalignedSplice(BlankClip(slides, length=Abs(slideoffset + start_frame), color=$000000), slides) : slides
trimmed_video = video.Trim(start_frame, end_frame)
trimmed_slides = temp_slides.Trim(slideoffset + start_frame, slideoffset + start_frame + (end_frame - start_frame))
"""
videox1 = 10
videox2 = -14
videoy1 = 4
videoy2 = -4
slidesx1 = 180
slidesx2 = -220
slidesy1 = 29
slidesy2 = -32
levels1 = 0
levels2 = 1
levels3 = 255
levels4 = 0
levels5 = 255
slidelevels1 = 0
slidelevels2 = 1
slidelevels3 = 255
slidelevels4 = 0
slidelevels5 = 255
title = """Keynote"""
presenter = """Yukuhiro "Matz" Matsumoto"""
format = "wide"
sponsorad = ""
sponsorintro = 0
size = "small"
titleimagepath = "N:\scripts\rubyconf2009\ads\day1-room1-01.png"
Import("N:\scripts\rubyconf2009\scripts\include\main.avsi")
This file is basically trimming or padding the slides to be the same size as the video. However, what happens is that by the end of the video (the point they were synchronized from) the slides and video are in sync, but at the beginning they are off by roughly ~250 frames. The same thing seems to have happened with all our slides (about 30 different presentations) by roughly the same amount depending on the presentation length, so I don't think this can all be explained by dropped frames.
The reason I thought it was a granularity problem in ConvertFPS is that I have tried manually adjusting the framerate of the slides by a slight amount, and contrary to what you would expect, reloading the script in virtualdub did not cause the frame synchronization to advance or retreat by a few frames. Instead, what I saw was that small adjustments in the framerate resulted in NO difference in synchronization until they got larger, and then suddenly the frame synchronization did change, but it overshot by a significant amount. In other words, avisynth didn't seem to be allowing me to make fine-grained adjustments in the frame rate. My guess was that the two sticking points for the slides were either too slow or too fast compared to the video.
Honestly I'm not sure what the answer is. I'm just grasping at straws. Let me say, though, that I REALLY APPRECIATE your help and will be happy to pay you if you can help us figure out this synchronization problem.
Thanks a ton,
Carl
IanB
25th November 2009, 23:11
Add a ShowFrameNumber() to both video and slides clips before the Eval(trimcode) to help you debug your script, the arithmetic is somewhat confusing without context. What is slideoffset trying to achieve?
I am not so sure if the DSS convertfps option is appropriate here. Are you trying to match frames or match durations? If matching frames then no. Maybe starting again with a very simple script just stacking raw video and slides can illuminate the issue and help define the correction needed.
Default ImageSource returns 1001 frames.
Stacks returned properties are taken from clip1 with the framecount from the longest clip.
And you can stack more than 2 clips in 1 stack statement.
The levels filter will still fully process with args (0, 1, 255, 0, 255) even though it is a nop.
cayblood
27th November 2009, 05:22
Thanks Ian. Here is a simpler example that reproduces the issue:
LoadPlugin("N:\scripts\rubyconf2009\scripts\include\LeakKernelDeint.dll")
Function PadNumber_(int num, int num_digits, bool first_time) {
return first_time ? PadNumber_(num, num_digits - StrLen(String(num)), false) : \
num_digits > 0 ? "0" + PadNumber_(num, num_digits - 1, false) : String(num)
}
Function PadNumber(int num, int num_digits) {
return PadNumber_(num, num_digits, true)
}
Function ConcatenateDShow(string prefix, int start, int stop, int padby) {
return start > stop - 1 ? DirectShowSource(prefix + PadNumber(stop, padby) + ".avi") : \
DirectShowSource(prefix + PadNumber(start, padby) + ".avi") + \
ConcatenateDShow(prefix, start + 1, stop, padby)
}
# read video
video = ConcatenateDShow("O:\rubyconf2009\day1\room1\camera.", 2, 5, 2)
video = LeakKernelDeint(video, 0)
fr = Framerate(video)
video = BilinearResize(video, 480, 360, 10, 4, -14, -4)
# use left channel for audio
audio = GetChannel(video, 1)
video = AudioDub(video, audio)
# read slides
slides = DirectShowSource("O:\rubyconf2009\day1\room1\data.avi", ConvertFPS=true, FPS=FrameRate(video))
slides = slides.AssumeFPS(video).ConvertToYV12
slides = BilinearResize(slides, 480, 360, 180, 29, -220, -32)
# trim video
video_start = 17780
video_stop = 82280
video_duration = video_stop - video_start
trimmed_video = video.Trim(video_start, video_stop).ShowFrameNumber
# trim slides
slide_syncronization_offset = 25892
trimmed_slides = slides.Trim(video_start + slide_syncronization_offset, video_stop + slide_syncronization_offset).ShowFrameNumber
StackHorizontal(trimmed_video, trimmed_slides).ReduceBy2
This example results in the following video:
http://youngbloods.org/video/test.mp4
At the beginning of the video the presenter's clicks are in sync with the slide changes. But by the end of the video they are about 5 seconds off. As you can see, ShowFrameNumber shows synchronized frames throughout, despite the fact that the video and slides got increasingly out of sync.
Any further ideas? I really think that ConvertFPS is doing something wrong.
As I stated earlier, this problem did not seem to occur for some reason when we captured slides at 720p50.
Thanks,
Carl
IanB
28th November 2009, 23:18
I am not so sure if the DSS convertfps option is appropriate here. Are you trying to match frames or match durations? If matching frames then no.
Seems No! is the case here.
The ConvertFPS option makes the delivered FPS match the internal DirectShow clock. Obviously the DS Clock is running 5 seconds out.
So you need to match the frames instead :- ...
# read video
video = ConcatenateDShow("O:\rubyconf2009\day1\room1\camera.", 2, 5, 2)
video = LeakKernelDeint(video, 0)
video = BilinearResize(video, 480, 360, 10, 4, -14, -4).ShowFrameNumber()
...
# read slides
slides = DirectShowSource("O:\rubyconf2009\day1\room1\data.avi")
slides = slides.AssumeFPS(video).ConvertToYV12() # Start with matching Framerates
slides = BilinearResize(slides, 480, 360, 180, 29, -220, -32).ShowFrameNumber()
# trim video
video_start = 17780
video_stop = 82280
video_duration = video_stop - video_start
trimmed_video = video.Trim(video_start, video_stop)
# trim slides and time align
slide_start = 43672 # Slide frame number corresponding to video_start event
slide_stop = 108322 # Slide frame number corresponding to video_stop event
slide_duration = slide_stop - slide_start
trimmed_slides = slides.Trim(slide_start, slide_stop)
trimmed_slides = trimmed_slides.AssumeScaledFPS(slide_duration, video_duration) # Force the 2 durations to match
trimmed_slides = trimmed_slides.ChangeFPS(video) # Force the 2 framerates to match
StackHorizontal(trimmed_video, trimmed_slides)Obviously you need to find your correct numbers for 43672 and 108322.
cayblood
6th December 2009, 13:58
Thanks for your help. I was offline for a few days there while moving to Oslo. Now that I'm back, I wanted to add one other thing that I'm noticing. I'm not absolutely sure yet, but I think that virtualdub (the tool I'm using to sync these clips) is showing different behavior than the process I'm using to transcode my final videos (x264). It seems like the slides are advancing too fast in the final transcoded output even though virtualdub seems to show them in sync. Have you seen anything like this before?
IanB
6th December 2009, 22:16
It could be a DirectShow seeking issue. Various encoders have non-linear frame request patterns which can cause problems.
You could try abusing ChangeFPS(Last, Last, True) as a limited linear access filter. Put it at the end of your script and/or after any affected *Source() statements. It only has a 10 frame window, but this is often enough to compensate for any 0, 3, 1,2, 6, 4,5, ... access pattern problems.
And of course you should confirm all this by doing a pass with the ShowFrameNumber's in the script to check what is really going on.
cayblood
7th December 2009, 00:23
When you say Last in the args to ChangeFPS, do you mean the framerate of the most recent clip?
IanB
7th December 2009, 06:50
Yes, well the framerate of the same clip, or more explicitly :-...
V = ChangeFPS(V, V, True) # Apparent NOP, Side effect 10 frame limited linear access filter.
...
cayblood
9th December 2009, 13:40
OK, so here is the result of doing this with my video:
http://youngbloods.org/video/test.mp4
You'll notice that at the end, the slides still finish before the video. I believe this is because there were some frames dropped in the slides.
I have a couple of questions:
1) Is there a good way to detect where a frame drop occurred and add frames back in? With this clip there is no continuous movement, so I can't visually observe it. I'm wondering if there might be some data analysis method for this.
2) Barring that, do you have a recommendation for what I would use to evenly duplicate frames throughout the clip in order to make the durations match? I understand that this would cause the sync to be slightly off, but I think it would still be close enough, in this context.
Thanks,
Carl
IanB
9th December 2009, 22:25
You have obviously not correctly implemented my algorithm from post 8 above.
If you have correctly set the frame numbers slide_start and slide_stop to correspond with video_start and video_stop then by definition after the AssumeScaledFPS and ChangeFPS the 2 clips will have the same framerate and the same duration.
This algorithm effectively does "evenly duplicate frames throughout the clip"....
slides = slides.AssumeFPS(video).ConvertToYV12() # Start with matching Framerates
...
# trim slides and time align
slide_start = ?????? # Slide clip frame number corresponding to video_start event
slide_stop = ?????? # Slide clip frame number corresponding to video_stop event
slide_duration = slide_stop - slide_start
trimmed_slides = slides.Trim(slide_start, slide_stop)
trimmed_slides = trimmed_slides.AssumeScaledFPS(slide_duration, video_duration) # Force the 2 durations to match
trimmed_slides = trimmed_slides.ChangeFPS(video) # Force the 2 framerates to match
For example assume the video clip of interest starts at frame 1000 and stops frame 11000 and the corresponding slide clip starts at frame 3000 and stops at frame 28000.
We have with a 10000 frame video sub-clip and a 25000 frame slide sub-clip. With both running at the same framerate, say 29.97 fps, the slide sub-clip runs 2.5 longer than the video sub-clip.
After the AssumeScaledFPS the slide sub-clip runs at 2.5 times the framerate, say 74.925 fps, but now the total duration of both clips match.
And after the ChangeFPS both the duration and the framerate of the slide sub-clip are the same as the video sub-clip.
So when frame 1000 of the video plays, frame 3000 of the slide plays. When frame 11000 of the video plays, frame 28000 of the slide plays. In this example the ChangeFPS will evenly select 2 frames of every 5 input frames of the slide clip. Thus in the middle video frame 6000 will correspond with slide frame 15500 (+/-1).
This implementation does not care about the original frame rate of the slide clip, all that matters are that the slide_start and slide_stop frame numbers correctly correspond with the video_start and video_stop frame numbers.
cayblood
10th December 2009, 00:08
I really thought that your suggestion was going to work also, but I think there is something wrong with the precision of these two functions. Here is the exact code I'm using to produce that video I linked to above:
Import("N:\scripts\rubyconf2009\scripts\include\plugins_and_functions.avsi")
# read video
video = video_start_num == -1 ? DirectShowSource(video_prefix) : ConcatenateDShow(video_prefix, video_start_num, video_end_num, zero_pad_count)
# no-op for editor sync
video = video.ChangeFPS(video, true)
video = LeakKernelDeint(video, 0)
frvideo = Framerate(video)
video = format == "wide" ? BilinearResize(video, 426, 320, videox1, videoy1, videox2, videoy2) : BilinearResize(video, 480, 360, videox1, videoy1, videox2, videoy2)
video = format == "wide" ? Crop(video, 52, 0, -54, 0) : video
video = Levels(video, levels1, levels2, levels3, levels4, levels5)
video = video.ShowFrameNumber
# stack and resize video with ads
above = BlankClip(video, length=200, color=$ff0000)
above = ImageSource("N:\scripts\rubyconf2009\ads\video-top.png", \
pixel_type="rgb32", fps=frvideo).ConvertToYV12
below = ImageSource("N:\scripts\rubyconf2009\ads\video-bottom-alt.png", \
pixel_type="rgb32", fps=frvideo).ConvertToYV12
video = format != "wide" ? video : AudioDub(StackVertical(StackVertical(above, video), below), video)
# balance audio
left_channel = GetChannel(video, 1)
right_channel = GetChannel(video, 2)
audio = audio_channel == "right" ? right_channel : left_channel
video = AudioDub(video, audio)
# Read slides in.
slides = StrLen(slide_file) > 0 ? DirectShowSource(slide_file).ConvertToYV12 : BlankClip(video, length=200, color=$ff0000)
# no-op for editor sync
slides = slides.ChangeFPS(slides, true)
slides = Levels(slides, slide_levels1, slide_levels2, slide_levels3, slide_levels4, slide_levels5)
slides = BilinearResize(slides, 960, 720, slidesx1, slidesy1, slidesx2, slidesy2)
slides = slides.ShowFrameNumber
video_duration = video_stop_frame - video_start_frame
trimmed_video = video.Trim(video_start_frame, video_stop_frame)
slide_duration = slide_stop_frame - slide_start_frame
trimmed_slides = slides.Trim(slide_start_frame, slide_stop_frame)
# force framerates to match
trimmed_slides = trimmed_slides.ChangeFPS(video)
# force durations to match
trimmed_slides = trimmed_slides.AssumeScaledFPS(slide_duration, video_duration)
# stack video and slides
combined = format == "wide" ? (slide_position == "right" ? StackHorizontal(trimmed_video, trimmed_slides) : StackHorizontal(trimmed_slides, trimmed_video)) : trimmed_video
logo = ImageSource("N:\scripts\rubyconf2009\ads\confreaks_overlay_new.png", \
end=1000, pixel_type="rgb32", fps=FrameRate(video))
logo = logo.BilinearResize(100, 16)
combined = format != "wide" ? Overlay(combined, logo, x=373, y=337, mask=ShowAlpha(logo)) : combined
combined = AudioDub(combined, trimmed_video)
# dissolve to title image
blank = BlankClip(combined, length=200, color=$000000)
title = ImageSource(title_image_path, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
title = AudioDub(title, blank)
title = BilinearResize(title, combined.width, combined.height)
titled_video = Dissolve(FadeIn(title, 30), combined, 30)
# prepend ads
platinum_ad_image_path = format == "wide" ? "N:\scripts\rubyconf2009\ads\platinum-sponsor.png" : "N:\scripts\rubyconf2009\ads\platinum-sponsor-small.png"
platinum_sponsor = ImageSource(platinum_ad_image_path, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
platinum_sponsor = AudioDub(platinum_sponsor, blank)
gold_ad_image_path = format == "wide" ? "N:\scripts\rubyconf2009\ads\gold-sponsors.png" : "N:\scripts\rubyconf2009\ads\gold-sponsors-small.png"
gold_sponsors = ImageSource(gold_ad_image_path, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
gold_sponsors = AudioDub(gold_sponsors, blank)
titled_video_with_ads = Dissolve(Dissolve(FadeIn(platinum_sponsor, 30), gold_sponsors, 30), titled_video, 30)
width = format == "wide" ? 1280 : 480
height = format == "wide" ? 720 : 360
final = BilinearResize(titled_video_with_ads, width, height)
final = FadeOut(final, 30)
final = size == "small" ? final.ReduceBy2 : final
final = StrLen(audio_file) > 0 ? AudioDub(final, WAVSource(audio_file)) : final
# no-op for editor sync
final = final.ChangeFPS(final, true)
final
If you look at the video, you can clearly see that the slide frames stop advancing right near the end of the video while the video is still going. I really think I'm following your directions exactly yet they aren't perfectly matching.
IanB
10th December 2009, 02:01
Order matters! Rounding error!...
# force framerates to match
trimmed_slides = trimmed_slides.ChangeFPS(video)
# force durations to match
trimmed_slides = trimmed_slides.AssumeScaledFPS(slide_duration, video_duration)
...
cayblood
10th December 2009, 07:58
Are you saying that the order of these two commands should be reversed? When I had it that way, only the first few minutes of the slides were displayed and then frozen for the entire duration of the video. Please clarify.
IanB
10th December 2009, 13:58
Yes, the order need to be as I originally specified it. And sorry you are also missing this :-...
slides = slides.AssumeFPS(video).ConvertToYV12() # Start with matching Framerates
...Please re-read my Post #14 above. The 3 relevant elements are all marked in red, and the example I hope indicates what is needed. You are obviously not a beginner, your level of scripting is advanced. Sorry if I am taking to much for granted.
cayblood
10th December 2009, 14:12
Thanks, I will try that and get back to you later on tonight.
cayblood
10th December 2009, 22:58
Putting in your changes as follows causes the slides to be stuck on frame 88100 (near the beginning of the slides) for the entire video, never changing. Reversing the order of the two commands again (but keeping in the initial AssumeFPS on the slides) causes the total clip to be twice as long with the video finishing halfway through and the slides going till the end.
Thanks for all your help.
Import("N:\scripts\rubyconf2009\scripts\include\plugins_and_functions.avsi")
# read video
video = video_start_num == -1 ? DirectShowSource(video_prefix) : ConcatenateDShow(video_prefix, video_start_num, video_end_num, zero_pad_count)
# no-op for editor sync
video = video.ChangeFPS(video, true)
video = video.ShowFrameNumber
video = LeakKernelDeint(video, 0)
frvideo = Framerate(video)
video = format == "wide" ? BilinearResize(video, 426, 320, videox1, videoy1, videox2, videoy2) : BilinearResize(video, 480, 360, videox1, videoy1, videox2, videoy2)
video = format == "wide" ? Crop(video, 52, 0, -54, 0) : video
video = Levels(video, levels1, levels2, levels3, levels4, levels5)
video = video.ShowFrameNumber
# stack and resize video with ads
above = BlankClip(video, length=200, color=$ff0000)
above = ImageSource("N:\scripts\rubyconf2009\ads\video-top.png", \
pixel_type="rgb32", fps=frvideo).ConvertToYV12
below = ImageSource("N:\scripts\rubyconf2009\ads\video-bottom-alt.png", \
pixel_type="rgb32", fps=frvideo).ConvertToYV12
video = format != "wide" ? video : AudioDub(StackVertical(StackVertical(above, video), below), video)
# balance audio
left_channel = GetChannel(video, 1)
right_channel = GetChannel(video, 2)
audio = audio_channel == "right" ? right_channel : left_channel
video = AudioDub(video, audio)
# Read slides in.
slides = StrLen(slide_file) > 0 ? DirectShowSource(slide_file).AssumeFPS(video).ConvertToYV12 : BlankClip(video, length=200, color=$ff0000)
# no-op for editor sync
slides = slides.ChangeFPS(slides, true)
slides = Levels(slides, slide_levels1, slide_levels2, slide_levels3, slide_levels4, slide_levels5)
slides = BilinearResize(slides, 960, 720, slidesx1, slidesy1, slidesx2, slidesy2)
slides = slides.ShowFrameNumber
video_duration = video_stop_frame - video_start_frame
trimmed_video = video.Trim(video_start_frame, video_stop_frame)
slide_duration = slide_stop_frame - slide_start_frame
trimmed_slides = slides.Trim(slide_start_frame, slide_stop_frame)
# force durations to match
trimmed_slides = trimmed_slides.AssumeScaledFPS(slide_duration, video_duration)
# force framerates to match
trimmed_slides = trimmed_slides.ChangeFPS(video)
# stack video and slides
combined = format == "wide" ? (slide_position == "right" ? StackHorizontal(trimmed_video, trimmed_slides) : StackHorizontal(trimmed_slides, trimmed_video)) : trimmed_video
logo = ImageSource("N:\scripts\rubyconf2009\ads\confreaks_overlay_new.png", \
end=1000, pixel_type="rgb32", fps=FrameRate(video))
logo = logo.BilinearResize(100, 16)
combined = format != "wide" ? Overlay(combined, logo, x=373, y=337, mask=ShowAlpha(logo)) : combined
combined = AudioDub(combined, trimmed_video)
# dissolve to title image
blank = BlankClip(combined, length=200, color=$000000)
title = ImageSource(title_image_path, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
title = AudioDub(title, blank)
title = BilinearResize(title, combined.width, combined.height)
titled_video = Dissolve(FadeIn(title, 30), combined, 30)
# prepend ads
platinum_ad_image_path = format == "wide" ? "N:\scripts\rubyconf2009\ads\platinum-sponsor.png" : "N:\scripts\rubyconf2009\ads\platinum-sponsor-small.png"
platinum_sponsor = ImageSource(platinum_ad_image_path, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
platinum_sponsor = AudioDub(platinum_sponsor, blank)
gold_ad_image_path = format == "wide" ? "N:\scripts\rubyconf2009\ads\gold-sponsors.png" : "N:\scripts\rubyconf2009\ads\gold-sponsors-small.png"
gold_sponsors = ImageSource(gold_ad_image_path, start=0, end=200, pixel_type="rgb32", fps=FrameRate(video)).ConvertToYV12
gold_sponsors = AudioDub(gold_sponsors, blank)
titled_video_with_ads = Dissolve(Dissolve(FadeIn(platinum_sponsor, 30), gold_sponsors, 30), titled_video, 30)
width = format == "wide" ? 1280 : 480
height = format == "wide" ? 720 : 360
final = BilinearResize(titled_video_with_ads, width, height)
final = FadeOut(final, 30)
final = size == "small" ? final.ReduceBy2 : final
final = StrLen(audio_file) > 0 ? AudioDub(final, WAVSource(audio_file)) : final
# no-op for editor sync
final = final.ChangeFPS(final, true)
final
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.