Log in

View Full Version : Multiple, sequenced .jpg's one timeline


Starduster
27th August 2013, 15:00
I've been combining jpg's with .flv videos for a while with great results. However, I need to combine multiple .jpg images with a single .flv file so the images play throughout the entire file.

To make this a little more difficult, I need to be able to time the appearance of each .jpg at specific, but irregular, points in the video timeline. I'll have say 10 .jpg's, and want the first one to come up immediately, the 2nd at 12 seconds in, the 3rd at 33 seconds, etc.

I was thinking I could join each .jpg with a "cropped" segment of the .flv but it seems that would produce a coppy result. If cropping the video is the way to go, what's the best technique for doing that?

Is there a better way to do this?

Starduster
27th August 2013, 16:37
BTW, I've used "Trim" and it gets me close, but there's a small break in the audio that I'd like to get rid of. I'm using:

...
s=e
e=round(frm*9.781)
vd = DirectShowSource("MOB_102_0_1.flv", fps = 27.97, convertfps = True).trim(s,e)
fv=ImageSource("slide1_2.jpg",fps=27.97,start=1,end=ceil(frm*AudioLengthF(vd)/AudioRate(vd))).AssumeFPS(stdVid).ConvertToRGB32().Spline36Resize(640,480)
sld2 = AudioDub(fv, vd)

s=e
e=round(frm*13.937)
vd = DirectShowSource("MOB_102_0_1.flv", fps = 27.97, convertfps = True).trim(s,e)
fv=ImageSource("slide1_3.jpg",fps=27.97,start=1,end=ceil(frm*AudioLengthF(vd)/AudioRate(vd))).AssumeFPS(stdVid).ConvertToRGB32().Spline36Resize(640,480)
sld3 = AudioDub(fv, vd)
...
sld1 ++ sld2 ++ sld3 ++ sld4

creaothceann
27th August 2013, 19:19
This is entirely duration-based:

f = "MOB_102_0_1.flv"
v = FFVideoSource(f).ConvertFPS(28000, 1001).ConvertToRGB32.Spline36Resize(640, 480)
a = FFAudioSource(f)
AudioDub(v, a)

global InsertionTime = 0

Section("slide1_2.jpg", 9.781)
Section("slide1_3.jpg", 13.937)




function Section(clip c, string FileName, float Duration) {
c
Start = round(InsertionTime * FrameRate) global InsertionTime = InsertionTime + Duration
End = round(InsertionTime * FrameRate)
Image = ImageSource(FileName, 0, 0, pixel_type="RGB32").Spline36Resize(640, 480)
Replace(Start, End, Layer(Image))
}


function Replace(clip c, int Start, int End, clip Replacement) {
End = (End == 0) || (End >= c.FrameCount) ? c.FrameCount - 1 : End
Replacement.Trim(Start, End)
(Start > 0) ? c.Trim(0, -Start) + last : last
(End < c.FrameCount - 1) ? last + c.Trim(End + 1, 0) : last
(c.HasAudio) ? last.AudioDub(c) : last
}

Starduster
29th August 2013, 21:39
That looks great... lots of new concepts for me. I'll plug that in a give it a go. Thanks so much for the response.

Starduster
29th August 2013, 22:12
I ran a few of the files through the code and a couple of things... (1) the timing looked off and (2) there was no audio. I noticed that you had set the convertFPS(28000, 1001). These .flv's are encoded at 15 fps so I thought that might be the issue (still do). So I changed the convertFPS(15) and tried that... didn't work. I noticed you had set InsertionTime * FrameRate but I didn't know where FrameRate came from so I set a global FrameRate = 15. All I managed to do was make a cool machine-gun sound but that's only fun for so long. I'm sure the frame rate is part of my problem but apparently I don't know how to fix it. Where have I messed up?

IanB
29th August 2013, 23:40
Framerate is function and resolves to Framerate(last), where in the context of the example above last is the clip C.

And yes you need to define the right frame rate for the original source clip.

And the audio is not handled, if you want the original audio as is then do the AudioDub after all the "Section" calls.

creaothceann
30th August 2013, 00:01
The "28000, 1001" was because you used 27.97fps in your code. If the .FLVs are encoded with a constant frame rate (i.e. there's only one 'global' framerate in the video) instead of a variable framerate (frames can have their own duration) then the ConvertFPS call probably isn't needed at all.

"FrameRate" is a clip property (http://avisynth.org/mediawiki/Clip_properties) (a special group of functions) and in the script it acts on the special implicit variable "last". Why? Well, in a traditional language you'd have to type a lot more:

video = AVISource(...)
video = PointResize(video, Width(video) * 2, Height(video) * 2)
return video

The 'dot syntax'

video = AVISource(...)
video = video.PointResize(video.Width * 2, video.Height * 2)
return video

is equivalent to it since the part in front of the dot is simply used as the first parameter of the function. Avisynth has the variable "last" for each namespace (global and in functions) that receives the result of a function if you don't assign that result to another variable, so you can write

AVISource(...)
PointResize(Width * 2, Height * 2)

and the "return" statement can be omitted because "last" is automatically returned if you don't use "return". (And if you don't return a video clip in the global namespace you get the "not a clip" error message.)


EDIT1: What IanB said. I don't know why audio is misbehaving; it should work...
EDIT2: Fixed script to handle audio.

Gavino
30th August 2013, 00:34
Avisynth has the variable "last" for each namespace (global and in functions) that receives the result of a function if you don't assign that result to another variable
only if that result is a clip (not for other types).

... "last" is automatically returned if you don't use "return".
Not strictly accurate, although in practice the effect is often the same.
From The full Avisynth grammar (http://avisynth.nl/index.php/The_full_AviSynth_grammar#Closing_Remarks):

As a shorthand, a bare expression as the final statement is treated as if the keyword 'return' was present.
If there is no (explicit or implicit) return, a void value (ie a value of the 'undefined' type) is returned. For example, this will happen if the last statement is an assignment.
So, if a function or script ends with a non-clip expression or an assignment, 'last' is not returned.

Seedmanc
30th August 2013, 11:40
Maybe ConditionalReader function can help, make a file with something like "<Number of frame for JPG to start> (space) <Amount of frames it is supposed to last>" and then use said function to overlay images on video.
http://avisynth.nl/index.php/ConditionalReader

Starduster
30th August 2013, 16:27
You all are amazing and so helpful... tremendous resourse this!! Thanks so much.