I'm going to explain you how to make a picture in picture video. I found it hard to find resources or tutorials on the subject but I found out eventually, and some ModDB bar goers wanted to know to so here it is and all with free tools LET'S GO!
Firstly we are going to download all the programs we need. VirtualDubMod (VDM from now on) is a fork of VirtualDub. VDM is a collection of modifications to the original VirtualDub, one which is the key to solving our PiP problem.
NOTE! Do not forget to download the bugfix/cvs patch, you will be seeing VDM crash enough as it is (more on that later)
The other tool you will need is AviSynth. AviSynth is a script language that allows you to edit videos without modifying the source file. It does this by treating the script file as the actual movie, apply all the script actions and plays the modified movie. Download it (get version 2.5) and were on our way.
First we will be loading a movie and play it, I do have to say that I'm no expert myself but I dug in enough to solve problems on my own when they occur, but lets roll. I have put all the parts (main clip and pip clip) in C:\Movie, you will be typing paths, so a short path is handy. Generally the syntax of the filters (basically build-in functions in AviSynth) is as following.
There are some exception, like for loading where you don't need to supply the name of the parameter, but you will see later on.
First you should start up VDM and go to Tools > Script Editor (Ctrl+E). The reason VDM is a good choice together with AviSynth is that the scripts can be edited and be executed from there (video goes directly into VDM). First you should set the script type to AviSynth, this can be done with Edit > Script Handling > AviSynth. This will also provide you with auto-completion when you press ctrl+space.
A word of warning tough. The script editor has only 1 way of error reporting: crashing. When you mistype something, point to a non existing file, put ') instead of (),... it just crashes, VDM sometimes crashes on its own to, you can tell which one of the 2 crashed first by means of the type of error (they both completely crash VDM tough):
- A visual C++ runtime error = AviSynth error
- Dialog with crash report = VDM error
The VDM errors are sometimes random, so just try the action again. When you get a AviSynth error, then it means you have a error in your script and should check it. You will probably come across this quite often, but don't let it get to you, its kinda normal for AviSynth I guess. I will provide some alternative editors at the end of this article but I still prefer the VDM one, since you can directly load the movie in VDM by pressing F7.
There are 2 ways of opening clips: AviSource or DirectShowSource AviSource should be tried first. The syntax is as follows (# = comments):
AviSource("string path") # example AviSource("c:\Movie\clip.avi")
This loads a clip directly. When you need to enter a path to a file in AviSynth, you are required to include the extension of the file, ALWAYS. There are some parameters but I will only give the most important audio: This is a bool (true/false), if set to false, then AviSynth will discard all audio information. This can be useful for dubbing.
NOTE!: There is a limit on how many calls to AviSource you can make, this is usually around 50 but fluctuates sometimes.
I do have to say, using AviSource usually doesn't work for me, but its faster, if it doesn't work then you can try DirectShowSource with the following syntax:
DirectShowSource("string path") #example DirectShowSource("c:\Movie\clip.avi")
This loads the clip by using DirectShow. With DirectShowSource you have the advantage that if you can play it in windows media player (or any other video player that uses DirectShow to display the movie) then it can be loaded into AviSynth. This is slower then AviSource tough, so always try AviSource first, the results are the same in the end. DirectShowSource has some parameters to:
- path: string, same as AviSource
- audio: bool, if set to false then the audio information will be discarded
- video: bool, same for audio but with the video information, usefull if you only want to use the audio
- fps: float, sometimes the fps might be wrong (happens with mov and asf usually), you can correct it by setting this option to the correct fps.
- convertfps: bool, when set to true, AviSynth will convert a variable framerate clip to a constant framerate clip, shouldn't be used, but I included it just in case.
So by using either one of the 2 methods, load your main movie clip:
DirectShowSource("c:\Movie\main.gif") #Note1: I know i needed to use DirectShowSource, you should try with AviSource first #Note2: I'm loading a gif file because i had one laying around anyway and to show its possible to
Now press F7 or go to File > Save & Open as AVI. You will first have to save the file. VDM looks like it doesn't respond any more, this is normal, AviSynth is processing your script and is sending the data to VDM. After VDM responds again (or if you get an error, in which case you need to recheck your script) you can play the movie (I'm not going into VDM operation at this point, maybe later, if you need this, post it in the comments).
Now this is enough to know how AviSynth works, lets go on.
Start a new script (or clear your old one) first. The outline of what we need to dos is this:
- Load the 2 movies
- Resize the PiP window
- Overlay the PiP window on top of the main clips
Because we need to refer to the movies a couple of time we will need to give it a name using variables:
main = DirectShowSource("c:\Movie\main.gif") pipm = DirectShowSource("c:\Movie\pip.avi")
I loaded the same gif as before and I quickly modified it a bit and saved it as pip.avi to differentiate the 2 from each other. The pip screen is still equally as large as the main clip so we will need to resize it:
pipm = pipm.ReduceBy2().ReduceBy2() # applies the filter 2 times
The movie will now be at 25% of its original size, which should be good enough. ReduceBy2() is actually a alias for HorizontalReduceBy2() and VerticalReduceBy2() Executing these 2 filters provides the same result as ReduxeBy2() There are more of these but I am not going into details about those now. Check the reference links at the end of the article for more info.
Now we need to position it (lower left corner with a 10 pixel border in this case):
# The 10 is the offset of the pip screen xpos = Width(main) - Width(pipm) - 10 ypos = Height(main) - Height(pipm) - 10
This will do it exactly, it defines 2 variables and calculates the position. Now on to the final part: the overlay, also, if you tried running the script until this point, then it would have crashed, but after we have done the overlay, it won't do that any more.
Overlay(main, pipm, x=xpos, y=ypos)
This will set the main clip on the bottom with the PiP window on top with the x and y coordinates set previously. Now press F7 or use the menu, after a while you should see your movie in VDM with the PiP clip. You can now apply the editing functions of VDM on this movie since it is treated as a normal movie now (even tough you haven't loaded anything directly with VDM)
I will give one more thing, letting the PiP window fade in, as this is usually better looking. Remove the overlay line, it will come back later but modified. We first define a new variable for the fade effect, but we first have to convert the movie to RGB, then we have to apply the fade filter:
fade = pip.ConvertToRGB32() #time in number of frames fade = fade.FadeIn(50)
Now we need to include this into the overlay along with a blend mode:
Overlay(main, fade, mode="blend", mask=showalpha(fade), x=xpos, y=ypos)
That is it. In this case, the PiP window will fade in over the course of 50 frames. That is about all there is to it, I thank you for your attention and hope you will find it useful. If you want to know more about it you can post it in the comments and I will see what I can do about it. The link below is just some references which I mentioned in the article. When your script does not work and you have to post it in the comments, please include your script.