Variable Frame Rate MP4

From SDA Knowledge Base

Revision as of 21:21, 26 December 2007 by Ballofsnow (Talk | contribs)

Jump to: navigation, search

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.

This guide will not work with DivX / Xvid.


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 / AAC in the MP4 container.

Vfr3.png


4. Now to get the video to play like normal again, we tell tc2mp4 which parts should be set to the orignal 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

As you saw in the pictures above, changing the framerate can change the video duration. Doing so also changes the duration of the audio which affects the pitch; not a good thing. So, the first goal is to create an audio file that sounds normal. Here's a simple AviSynth script:

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

vid2=vid2.changefps(vid1)

AlignedSplice(a,b)
ConvertToYV12()

Modify it to your liking and encode the audio only. Once that's done it's time to prepare the real avisynth script. Simply change changefps to assumefps and encode the video.

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

vid2=vid2.assumefps(vid1)

AlignedSplice(a,b)
ConvertToYV12()


Finding the frame ranges

To calculate the frame ranges from the AviSynth script above, first find out how many there are in each set.

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:

# timecode format v1
Assume 30
0,23489,30
23490,48700,60

Tip: Write down the left hand side first by incrementing from the set above, then the end frame is just the one before.


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.

timecode.txt:

# timecode format v1
Assume 29.970030
0,3441,59.940060
3442,5801,29.970030
5802,20601,59.940060
20602,21576,29.970030
21577,23636,59.940060
23637,26831,29.970030
26832,27871,59.940060

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.

calcframeranges.bat

@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.
REM Once timecode.txt is generated, just change the first number back to 0.
set inc=0

REM ##### SET THE FRAMERATES! #####
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"
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
echo timecode.txt successfully generated in %mypath%
pause
GOTO :EOF

:calc
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


Setting the VFR

Your CFR 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 keep reading..


Muxing the Audio

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.


Example 1.

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)
a=a.changefps(b)

AlignedSplice(a,b)
ConvertToYV12()

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 duplicating the frames but not actually changing the pace.


Example 2.

Loadplugin("C:\Program Files\DGMPGDec\DGDecode.dll")

Ac3Source(MPEG2source("SEG7_5155.d2v"),"SEG7_5155_DELAY-73ms.ac3").DelayAudio(-0.073)

assumetff()

a=last.Trim(0,1720).mvbob()
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)
Lanczos4Resize(640,480)
ConvertToYV12()

Simply comment out the AlignedSplice. What gets through is the original ac3source line.


Encode the audio in MeGUI, and mux it with the vfr video. Et voilà, you're done.

Personal tools