Difference between revisions of "Variable Frame Rate MP4"

From SDA Knowledge Base

Jump to: navigation, search
(Finding the frame ranges: v1.1 note about offset)
m (Understanding the VFR process)
 
(12 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
This guide assumes you're comfortable with AviSynth, MeGUI and batch files or working through the command line.
 
This guide assumes you're comfortable with AviSynth, MeGUI and batch files or working through the command line.
  
What is variable frame rate? You can probably guess that a constant frame rate is where the frame rate of a video stays the same throughout its whole length. In VFR you'll have sections that have a different framerate. VFR is useful when the game you've recorded has multiple in-game framerates. For example, God of War for the PS2 outputs gameplay at full framerate while its cinematics are half framerate. MvBob is best suited for F1 while Telecide is best suited for F2.
+
What is variable frame rate? You can probably guess that a constant frame rate is where the frame rate of a video stays the same throughout its whole length. In VFR you'll have sections that have a different framerate. VFR is useful when the game you've recorded has multiple in-game framerates. For example, God of War for the PS2 outputs gameplay at full framerate while its cinematics are half framerate.
 
+
Creating the actual VFR MP4 isn't so hard, the tedious part is setting up the AviSynth script and frame ranges. You have to look through your segment for changes in framerate and get the exact frame that this happens.
+
  
 
<br>
 
<br>
 +
===Understanding the VFR process===
  
==Files you'll need==
 
  
Download [[Media:tc2mp4_20060613_pom20061203.zip|tc2mp4]] and extract the contents to your working directory. Place mp4box.exe in the same directory. Mp4box can be found in "..\MeGUI\tools\mp4box\".
+
1. Normally, videos that have different framerates cannot be joined together.
  
<br>
+
[[Image:vfr1.png]]
  
==Encoding the AviSynth script==
 
  
To create a VFR video, you must first create the CFR version by matching the framerates. It's when you've encoded it to mp4 format that you'll use tc2mp4 to slow down or speed up specific sections in your video.
+
2. Using AviSynth, we can change the framerates of each video so that they match, and can thus be joined. Of course this will make parts of the video play faster or slower than it should. As you can see, changing the framerate from 60 to 30 has doubled the length of Video2.
  
<b>Example 1.</b>
+
[[Image:vfr2.png]]
<pre><nowiki>
+
a=avisource("my30fpsvid.avi")
+
b=avisource("my60fpsvid.avi")
+
  
### Match a's framerate to that of b. Avoid using numbers, if the
 
### framerates are even 0.000001 different, this will not work.
 
a=a.assumefps(b)
 
  
AlignedSplice(a,b)
+
3. Once joined, a temporary video is encoded with H.264.
ConvertToYV12()
+
</nowiki></pre>
+
  
Since this script didn't use any Trim commands, we have to find how many frames each video has. Load each into VirtualDub(Mod), go to File -> File Information. Look at the length and take note of how many frames there are. <b>Remember</b>, 0 counts as a frame. So if vdub reports 100 frames in total, the frames would be 0-99.
+
[[Image:vfr3.png]]
  
  
<b>Example 2.</b>
+
4. To get the video to play like normal again, we tell tc2mp4 which parts should be set to the original framerate. The result is a variable framerate video.
  
This example is more complex thanks to mvbob doubling the amount of frames.
+
[[Image:vfr4.png]]
<pre><nowiki>
+
Loadplugin("C:\Program Files\DGMPGDec\DGDecode.dll")
+
  
Ac3Source(MPEG2source("SEG7_5155.d2v"),"SEG7_5155_DELAY-73ms.ac3").DelayAudio(-0.073)
+
<br>
  
assumetff()
+
==Files you'll need==
  
a=last.Trim(0,1720).mvbob()
+
Download [[Media:tc2mp4_20060613_pom20061203.zip|tc2mp4]] and extract the contents to your working directory. Place mp4box.exe in the same directory. Mp4box can be found in "..\MeGUI\tools\mp4box\".
b=last.Trim(1721,4080).telecide().assumefps(a)
+
c=last.Trim(4081,11480).mvbob()
+
d=last.Trim(11481,12455).telecide().assumefps(a)
+
e=last.Trim(12456,13485).mvbob()
+
f=last.Trim(13486,16680).telecide().assumefps(a)
+
g=last.Trim(16681,17200).mvbob()
+
  
AlignedSplice(a,b,c,d,e,f,g)
+
<br>
Lanczos4Resize(640,480)
+
ConvertToYV12()
+
</nowiki></pre>
+
  
Encode it!
+
==Avisynth script==
  
<br>
+
The first step is to extract the audio stream before we do any kind of video stretching. Here's a simple AviSynth script, modify it to your liking.
  
==Finding the frame ranges==
+
<pre><nowiki>
 +
vid1=avisource("my30fpsvid.avi")
 +
vid2=avisource("my60fpsvid.avi")
  
To calculate the frame ranges from the AviSynth script above, first find out how many there are in each set.  
+
vid2=vid2.changefps(vid1)
  
From Example 1, if the 30 fps video had 23490 frames, and the 60 fps video had 25211 frames, then your timecode.txt file would be:
+
AlignedSplice(vid1,vid2)
 
+
ConvertToYV12()
<pre><nowiki>
+
# timecode format v1
+
Assume 30
+
0,23489,30
+
23490,48700
+
 
</nowiki></pre>
 
</nowiki></pre>
  
<font color="green"><b>Tip:</b> Write down the left hand side first by incrementing from the set above, then the end frame is just the one before.</font>
+
* Load the script into VirtualDub(Mod), go to File -> Information and write down the video length. For the sake of this guide, the length of the above script is 3:28.167.
 +
* Encode the audio.
  
  
From Example 2, since MvBob is a bobbing deinterlacer, it doubles the amount of frames. Don't forget that the first number in the trim command is inclusive. So the sets are 3442,2360,14800,975,2060,3195,1040, that's 27872 frames in total.
+
Once that's done it's time to prepare the real avisynth script. Simply change <b>changefps</b> to <b>assumefps</b>.
  
timecode.txt:
 
 
<pre><nowiki>
 
<pre><nowiki>
# timecode format v1
+
vid1=avisource("my30fpsvid.avi")
Assume 29.970030
+
vid2=avisource("my60fpsvid.avi")
0,3441,59.940060
+
 
3442,5801,29.970030
+
vid2=vid2.assumefps(vid1)
5802,20601,59.940060
+
 
20602,21576,29.970030
+
AlignedSplice(vid1,vid2)
21577,23636,59.940060
+
ConvertToYV12()
23637,26831,29.970030
+
26832,27871,59.940060
+
 
</nowiki></pre>
 
</nowiki></pre>
  
Here is a batch file that should help generate the timecode file. It is intended for scripts that use mvbob and telecide, and the code must be similar to that of example 2. You can run the batch file from the command line and also by dragging an AviSynth script onto it.
+
* Load the script into VirtualDub(Mod), go to File -> Information and write down the video length. For the sake of this guide, the length of the above script is 5:11.333.
 +
* Do not encode the video yet!
  
<b>calcframeranges.bat</b>
+
<br>
<pre><nowiki>
+
@echo off
+
REM Script written by Philip Cornell. Verion 1.1
+
  
REM If your video starts off with a statid, set the inc to however many frames it is.
+
==Calculating the correct video bitrates==
REM Once timecode.txt is generated, just change the first number back to 0.
+
set inc=0
+
  
REM ##### SET THE FRAMERATES! #####
+
Here's something you have to watch out for. Let's say that you're encoding a 10 minute long video at 2048 kbps that you plan to stretch to 20 minutes. What do you think would be the average bitrate for the new 20 minute vfr video? It wouldn't be 2048, it'd be 1024, since it's double the length.
set mrate=59.940060
+
set trate=29.970030
+
REM ##### SET THE PATH WHERE TIMECODE.TXT WILL BE SAVED ####
+
set mypath=C:\change this and keep the slash at the end\
+
  
echo # timecode format v1 > "%mypath%\timecode.txt"
+
A more extreme example: if a video is encoded at 2048 kbp/s and the video is 1 second long, the filesize will be 2048 kb.... right. What if it gets stretched out to 100 seconds? The filesize would still be 2048 kb, but the kbp/s will have changed to 20.48 kbp/s.
echo Assume %trate% >> "%mypath%\timecode.txt"
+
  
FOR /F "tokens=2,3,4 delims=(,)" %%A IN ('find "last.Trim(" %1') do call :calc %%A %%B %%C
+
The point is that if you encode a video at the usual SDA bitrates, you will find that once the final stretching/shrinking has taken place, the average bitrate will be something unexpected.
echo timecode.txt successfully generated in %mypath%
+
pause
+
GOTO :EOF
+
  
:calc
+
On with it then... All you really need to calculate is one number, the ratio between the real length of the video and the length of the stretched/shrunk video. Taking the example above:
if /I %3==.mvbob set /A num=(%2 - %1 + 1) *2 & set rate=%mrate%
+
if /I %3==.telecide set /A num=(%2 - %1 + 1) & set rate=%trate%
+
set start=%inc%
+
set /A inc=%inc% + %num%
+
set /A end=%inc% - 1
+
echo %start%,%end%,%rate% >> "%mypath%\timecode.txt"
+
GOTO :EOF
+
</nowiki></pre>
+
  
<br>
+
Real length = 3:28.167 = 208.167 seconds<br>
 +
Temporary length = 5:11.333 = 311.333 seconds
  
==Setting the VFR==
+
Ratio = 208.167 / 311.333 = 0.669
  
Your CFR encoding should be done now. Open a command line and use the following:
+
HQ 2048 * 0.669 = 1369 kbp/s<br>
 +
IQ 5000 * 0.669 = 3343 kbp/s
  
<pre><nowiki>
+
In the final stages when the temporary video gets stretched/shrunk back to the real length, the average bitrate will be the correct 2048/5000.
tc2mp4 -i myCFRvid.mp4 -t timecode.txt -o myVFRvid.mp4
+
</nowiki></pre>
+
  
tc2mp4 gets rid of any audio in your files, so keep reading..
+
Now that you know the correct bitrate, go ahead and encode the temporary video.
  
 
<br>
 
<br>
  
==Muxing the Audio==
+
==Timecodes, finding the frame ranges==
  
If you were to encode the audio based off the AviSynth scripts above, you'd get parts in the audio stream playing at an abnormal speed. Let's modify the above scripts solely to get the correct audio stream.
+
How difficult it is to find the frame ranges depends on the complexity of your AviSynth script. There's no easy way to do this, unless you're a scripting god, but you're already experienced enough that you should be able to figure it out.
  
 +
An example: if a 29.97 fps video has 1000 frames, and a 59.94 fps video has 2500 frames, timecode.txt file will be:
  
<b>Example 1.</b>
 
 
<pre><nowiki>
 
<pre><nowiki>
a=avisource("my30fpsvid.avi")
+
# timecode format v1
b=avisource("my60fpsvid.avi")
+
Assume 29.97
 
+
0,999,29.97
### Match a's framerate to that of b. Avoid using numbers, if the
+
1000,3499,59.94
### framerates are even 0.000001 different, this will not work.
+
#a=a.assumefps(b)
+
a=a.changefps(b)
+
 
+
AlignedSplice(a,b)
+
ConvertToYV12()
+
 
</nowiki></pre>
 
</nowiki></pre>
To splice the videos together, they need to have the same framerate. But how do we do that without speeding up the 30 fps vid? Use the changefps command this time to match the framerate by <i>duplicating</i> the frames but not actually changing the pace.
 
  
 +
<font color="red"><b>Remember:</b></font> 0 counts as a frame number.
  
<b>Example 2.</b>
+
<br>
<pre><nowiki>
+
Loadplugin("C:\Program Files\DGMPGDec\DGDecode.dll")
+
  
Ac3Source(MPEG2source("SEG7_5155.d2v"),"SEG7_5155_DELAY-73ms.ac3").DelayAudio(-0.073)
+
==Setting the VFR==
  
assumetff()
+
Your encoding should be done now. Open a command line and use the following:
  
a=last.Trim(0,1720).mvbob()
+
<pre><nowiki>
b=last.Trim(1721,4080).telecide().assumefps(a)
+
tc2mp4 -i myCFRvid.mp4 -t timecode.txt -o myVFRvid.mp4
c=last.Trim(4081,11480).mvbob()
+
d=last.Trim(11481,12455).telecide().assumefps(a)
+
e=last.Trim(12456,13485).mvbob()
+
f=last.Trim(13486,16680).telecide().assumefps(a)
+
g=last.Trim(16681,17200).mvbob()
+
 
+
#AlignedSplice(a,b,c,d,e,f,g)
+
Lanczos4Resize(640,480)
+
ConvertToYV12()
+
 
</nowiki></pre>
 
</nowiki></pre>
Simply comment out the AlignedSplice. What gets through is the original ac3source line.
 
  
 +
tc2mp4 gets rid of any audio in your files so mux the one you made at the beginning of the guide.
  
Encode the audio in MeGUI, and mux it with the vfr video. Et voilà, you're done.
+
And that's it! Now just make sure it plays correctly in Quicktime and you're good to go.
 +
<br>

Latest revision as of 02:00, 31 December 2007

Introduction

This guide assumes you're comfortable with AviSynth, MeGUI and batch files or working through the command line.

What is variable frame rate? You can probably guess that a constant frame rate is where the frame rate of a video stays the same throughout its whole length. In VFR you'll have sections that have a different framerate. VFR is useful when the game you've recorded has multiple in-game framerates. For example, God of War for the PS2 outputs gameplay at full framerate while its cinematics are half framerate.


Understanding the VFR process

1. Normally, videos that have different framerates cannot be joined together.

Vfr1.png


2. Using AviSynth, we can change the framerates of each video so that they match, and can thus be joined. Of course this will make parts of the video play faster or slower than it should. As you can see, changing the framerate from 60 to 30 has doubled the length of Video2.

Vfr2.png


3. Once joined, a temporary video is encoded with H.264.

Vfr3.png


4. To get the video to play like normal again, we tell tc2mp4 which parts should be set to the original framerate. The result is a variable framerate video.

Vfr4.png


Files you'll need

Download tc2mp4 and extract the contents to your working directory. Place mp4box.exe in the same directory. Mp4box can be found in "..\MeGUI\tools\mp4box\".


Avisynth script

The first step is to extract the audio stream before we do any kind of video stretching. Here's a simple AviSynth script, modify it to your liking.

vid1=avisource("my30fpsvid.avi")
vid2=avisource("my60fpsvid.avi")

vid2=vid2.changefps(vid1)

AlignedSplice(vid1,vid2)
ConvertToYV12()
  • Load the script into VirtualDub(Mod), go to File -> Information and write down the video length. For the sake of this guide, the length of the above script is 3:28.167.
  • Encode the audio.


Once that's done it's time to prepare the real avisynth script. Simply change changefps to assumefps.

vid1=avisource("my30fpsvid.avi")
vid2=avisource("my60fpsvid.avi")

vid2=vid2.assumefps(vid1)

AlignedSplice(vid1,vid2)
ConvertToYV12()
  • Load the script into VirtualDub(Mod), go to File -> Information and write down the video length. For the sake of this guide, the length of the above script is 5:11.333.
  • Do not encode the video yet!


Calculating the correct video bitrates

Here's something you have to watch out for. Let's say that you're encoding a 10 minute long video at 2048 kbps that you plan to stretch to 20 minutes. What do you think would be the average bitrate for the new 20 minute vfr video? It wouldn't be 2048, it'd be 1024, since it's double the length.

A more extreme example: if a video is encoded at 2048 kbp/s and the video is 1 second long, the filesize will be 2048 kb.... right. What if it gets stretched out to 100 seconds? The filesize would still be 2048 kb, but the kbp/s will have changed to 20.48 kbp/s.

The point is that if you encode a video at the usual SDA bitrates, you will find that once the final stretching/shrinking has taken place, the average bitrate will be something unexpected.

On with it then... All you really need to calculate is one number, the ratio between the real length of the video and the length of the stretched/shrunk video. Taking the example above:

Real length = 3:28.167 = 208.167 seconds
Temporary length = 5:11.333 = 311.333 seconds

Ratio = 208.167 / 311.333 = 0.669

HQ 2048 * 0.669 = 1369 kbp/s
IQ 5000 * 0.669 = 3343 kbp/s

In the final stages when the temporary video gets stretched/shrunk back to the real length, the average bitrate will be the correct 2048/5000.

Now that you know the correct bitrate, go ahead and encode the temporary video.


Timecodes, finding the frame ranges

How difficult it is to find the frame ranges depends on the complexity of your AviSynth script. There's no easy way to do this, unless you're a scripting god, but you're already experienced enough that you should be able to figure it out.

An example: if a 29.97 fps video has 1000 frames, and a 59.94 fps video has 2500 frames, timecode.txt file will be:

# timecode format v1
Assume 29.97
0,999,29.97
1000,3499,59.94

Remember: 0 counts as a frame number.


Setting the VFR

Your encoding should be done now. Open a command line and use the following:

tc2mp4 -i myCFRvid.mp4 -t timecode.txt -o myVFRvid.mp4

tc2mp4 gets rid of any audio in your files so mux the one you made at the beginning of the guide.

And that's it! Now just make sure it plays correctly in Quicktime and you're good to go.

Personal tools