diff --git a/FFmpegSource2/ffavisynth.cpp b/FFmpegSource2/ffavisynth.cpp
index 3c8eee11505b4cc0331b325ecfffc85f15cc69d0..ecf285a3baa8d339621278393747b0f6b4ff3173 100644
--- a/FFmpegSource2/ffavisynth.cpp
+++ b/FFmpegSource2/ffavisynth.cpp
@@ -21,10 +21,12 @@
 #include "ffavisynth.h"
 #include "utils.h"
 
-AvisynthVideoSource::AvisynthVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, int Threads, int SeekMode, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize) {
+AvisynthVideoSource::AvisynthVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, int FPSNum, int FPSDen, const char *PP, int Threads, int SeekMode, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize) {
 	memset(&VI, 0, sizeof(VI));
 	SWS = NULL;
 	ConvertToFormat = PIX_FMT_NONE;
+	this->FPSNum = FPSNum;
+	this->FPSDen = FPSDen;
 
 	VS = FFMS_CreateVideoSource(SourceFile, Track, TrackIndices, PP, Threads, SeekMode, ErrorMsg, MsgSize);
 	if (!VS)
@@ -35,9 +37,16 @@ AvisynthVideoSource::AvisynthVideoSource(const char *SourceFile, int Track, Fram
 	VI.image_type = VideoInfo::IT_TFF;
 	VI.width = VP.Width;
 	VI.height = VP.Height;
-	VI.fps_denominator = VP.FPSDenominator;
-	VI.fps_numerator = VP.FPSNumerator;
-	VI.num_frames = VP.NumFrames;
+
+	if (FPSNum > 0 && FPSDen > 0) {
+		VI.fps_denominator = FPSDen;
+		VI.fps_numerator = FPSNum;
+		VI.num_frames = ceil(((VP.LastTime - VP.FirstTime) * FPSNum) / FPSDen);
+	} else {
+		VI.fps_denominator = VP.FPSDenominator;
+		VI.fps_numerator = VP.FPSNumerator;
+		VI.num_frames = VP.NumFrames;
+	}
 
 	try {
 		InitOutputFormat(VP.PixelFormat, Env);
@@ -129,7 +138,13 @@ PVideoFrame AvisynthVideoSource::OutputFrame(const AVFrameLite *Frame, IScriptEn
 PVideoFrame AvisynthVideoSource::GetFrame(int n, IScriptEnvironment *Env) {
 	char ErrorMsg[1024];
 	unsigned MsgSize = sizeof(ErrorMsg);
-	const AVFrameLite *Frame = FFMS_GetFrame(VS, n, ErrorMsg, MsgSize);
+	const AVFrameLite *Frame;
+
+	if (FPSNum > 0 && FPSDen > 0)
+		Frame = FFMS_GetFrameByTime(VS, FFMS_GetVideoProperties(VS)->FirstTime + (double)(n * (int64_t)FPSDen) / FPSNum, ErrorMsg, MsgSize);
+	else
+		Frame = FFMS_GetFrame(VS, n, ErrorMsg, MsgSize);
+
 	if (Frame == NULL)
 		Env->ThrowError("FFVideoSource: %s", ErrorMsg);
 
@@ -137,7 +152,6 @@ PVideoFrame AvisynthVideoSource::GetFrame(int n, IScriptEnvironment *Env) {
 	return OutputFrame(Frame, Env);
 }
 
-
 AvisynthAudioSource::AvisynthAudioSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize) {
 	memset(&VI, 0, sizeof(VI));
 
@@ -147,7 +161,6 @@ AvisynthAudioSource::AvisynthAudioSource(const char *SourceFile, int Track, Fram
 
 	const AudioProperties AP = *FFMS_GetAudioProperties(AS);
 
-
 	VI.nchannels = AP.Channels;
 	VI.num_audio_samples = AP.NumSamples;
 	VI.audio_samples_per_second = AP.SampleRate;
diff --git a/FFmpegSource2/ffavisynth.h b/FFmpegSource2/ffavisynth.h
index 28d4afc7d59310ab0103eaa6a28bcdbd0d5a4ec9..1c3a94ad5ed86d2622938f487df217912c447267 100644
--- a/FFmpegSource2/ffavisynth.h
+++ b/FFmpegSource2/ffavisynth.h
@@ -38,11 +38,13 @@ private:
 	VideoBase *VS;
 	SwsContext *SWS;
 	int ConvertToFormat;
+	int FPSNum;
+	int FPSDen;
 
 	void InitOutputFormat(int CurrentFormat, IScriptEnvironment *Env);
 	PVideoFrame OutputFrame(const AVFrameLite *SrcPicture, IScriptEnvironment *Env);
 public:
-	AvisynthVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, int Threads, int SeekMode, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize);
+	AvisynthVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, int FPSNum, int FPSDen, const char *PP, int Threads, int SeekMode, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize);
 	~AvisynthVideoSource();
 	bool __stdcall GetParity(int n) { return false; }
 	void __stdcall SetCacheHints(int cachehints, int frame_range) { }
diff --git a/FFmpegSource2/ffavsfilters.cpp b/FFmpegSource2/ffavsfilters.cpp
index 1161a1dd53e294a10bde50d0c3efe3abc860c251..99b843c1da9b2af35dbe5d637e8384d051f41660 100644
--- a/FFmpegSource2/ffavsfilters.cpp
+++ b/FFmpegSource2/ffavsfilters.cpp
@@ -92,10 +92,12 @@ AVSValue __cdecl CreateFFVideoSource(AVSValue Args, void* UserData, IScriptEnvir
 	int Track = Args[1].AsInt(-1);
 	bool Cache = Args[2].AsBool(true);
 	const char *CacheFile = Args[3].AsString("");
-	const char *PP = Args[4].AsString("");
-	int Threads = Args[5].AsInt(-1);
-	const char *Timecodes = Args[6].AsString("");
-	int SeekMode = Args[7].AsInt(1);
+	int FPSNum = Args[4].AsInt(-1);
+	int FPSDen = Args[5].AsInt(1);
+	const char *PP = Args[6].AsString("");
+	int Threads = Args[7].AsInt(-1);
+	const char *Timecodes = Args[8].AsString("");
+	int SeekMode = Args[9].AsInt(1);
 
 	if (Track <= -2)
 		Env->ThrowError("FFVideoSource: No video track selected");
@@ -145,7 +147,7 @@ AVSValue __cdecl CreateFFVideoSource(AVSValue Args, void* UserData, IScriptEnvir
 	AvisynthVideoSource *Filter;
 
 	try {
-		Filter = new AvisynthVideoSource(Source, Track, Index, PP, Threads, SeekMode, Env, ErrorMsg, MsgSize);
+		Filter = new AvisynthVideoSource(Source, Track, Index, FPSNum, FPSDen, PP, Threads, SeekMode, Env, ErrorMsg, MsgSize);
 	} catch (...) {
 		FFMS_DestroyFrameIndex(Index);	
 		throw;
@@ -219,7 +221,7 @@ AVSValue __cdecl CreateSWScale(AVSValue Args, void* UserData, IScriptEnvironment
 
 extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* Env) {
     Env->AddFunction("FFIndex", "[source]s[cachefile]s[indexmask]i[dumpmask]i[audiofile]s[overwrite]b", CreateFFIndex, 0);
-    Env->AddFunction("FFVideoSource", "[source]s[track]i[cache]b[cachefile]s[pp]s[threads]i[timecodes]s[seekmode]i", CreateFFVideoSource, 0);
+	Env->AddFunction("FFVideoSource", "[source]s[track]i[cache]b[cachefile]s[fpsnum]i[fpsden]i[pp]s[threads]i[timecodes]s[seekmode]i", CreateFFVideoSource, 0);
     Env->AddFunction("FFAudioSource", "[source]s[track]i[cache]b[cachefile]s", CreateFFAudioSource, 0);
 	Env->AddFunction("FFPP", "c[pp]s", CreateFFPP, 0);
 	Env->AddFunction("SWScale", "c[width]i[height]i[resizer]s[colorspace]s", CreateSWScale, 0);
diff --git a/FFmpegSource2/ffms.cpp b/FFmpegSource2/ffms.cpp
index ff6fd2770f655ed43a93f503624a89cd4f384e56..c60634e3976f29d9ff4bb3c55200928fb520cbbc 100644
--- a/FFmpegSource2/ffms.cpp
+++ b/FFmpegSource2/ffms.cpp
@@ -110,8 +110,8 @@ FFMS_API(int) FFMS_GetAudio(AudioBase *AB, void *Buf, int64_t Start, int64_t Cou
 	return AB->GetAudio(Buf, Start, Count, ErrorMsg, MsgSize);
 }
 
-FFMS_API(int) FFMS_SetOutputFormat(VideoBase *VB, int TargetFormat, int Width, int Height) {
-	return VB->SetOutputFormat(TargetFormat, Width, Height);
+FFMS_API(int) FFMS_SetOutputFormat(VideoBase *VB, int TargetFormat, int Width, int Height, char *ErrorMsg, unsigned MsgSize) {
+	return VB->SetOutputFormat(TargetFormat, Width, Height, ErrorMsg, MsgSize);
 }
 
 FFMS_API(void) FFMS_ResetOutputFormat(VideoBase *VB) {
@@ -130,15 +130,15 @@ FFMS_API(int) FFMS_GetFirstTrackOfType(FrameIndex *TrackIndices, int TrackType,
 	return -1;
 }
 
-FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize) {
+FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices) {
 	return TrackIndices->size();
 }
 
-FFMS_API(int) FFMS_GetTrackType(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize) {
+FFMS_API(int) FFMS_GetTrackType(FrameInfoVector *FIV) {
 	return FIV->TT;
 }
 
-FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize) {
+FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV) {
 	return FIV->size();
 }
 
@@ -160,7 +160,7 @@ FFMS_API(FrameInfoVector *) FFMS_GetTITrackIndex(FrameIndex *TrackIndices, int T
 	}	
 }
 
-FFMS_API(FrameInfoVector *) FFMS_GetVSTrackIndex(VideoBase *VB, char *ErrorMsg, unsigned MsgSize) {
+FFMS_API(FrameInfoVector *) FFMS_GetVSTrackIndex(VideoBase *VB) {
 	return VB->GetFrameInfoVector();
 }
 
@@ -173,15 +173,15 @@ FFMS_API(int) FFMS_FindClosestKeyFrame(FrameInfoVector *FIV, int Frame, char *Er
 	}
 }
 
-FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize) {
+FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS) {
 	return FIV->FrameFromDTS(DTS);
 }
 
-FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize) {
+FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS) {
 	return FIV->ClosestFrameFromDTS(DTS);
 }
 
-FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize) {
+FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV) {
 	return &FIV->TB;
 }
 
diff --git a/FFmpegSource2/ffms.h b/FFmpegSource2/ffms.h
index 7c017c56915df98aea1cbad0d9a47c00905e4657..44b64c30d2c06361ed76a6f17d7389b7d263f783 100644
--- a/FFmpegSource2/ffms.h
+++ b/FFmpegSource2/ffms.h
@@ -157,6 +157,8 @@ struct AudioProperties {
 	int64_t NumSamples;
 };
 
+// Most functions return 0 on success
+// Functions without error message output can be assumed to never fail
 FFMS_API(void) FFMS_Init();
 FFMS_API(VideoBase *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, int Threads, int SeekMode, char *ErrorMsg, unsigned MsgSize);
 FFMS_API(AudioBase *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
@@ -167,21 +169,21 @@ FFMS_API(const AudioProperties *) FFMS_GetAudioProperties(AudioBase *AB);
 FFMS_API(const AVFrameLite *) FFMS_GetFrame(VideoBase *VB, int n, char *ErrorMsg, unsigned MsgSize);
 FFMS_API(const AVFrameLite *) FFMS_GetFrameByTime(VideoBase *VB, double Time, char *ErrorMsg, unsigned MsgSize);
 FFMS_API(int) FFMS_GetAudio(AudioBase *AB, void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(int) FFMS_SetOutputFormat(VideoBase *VB, int TargetFormat, int Width, int Height);
+FFMS_API(int) FFMS_SetOutputFormat(VideoBase *VB, int TargetFormat, int Width, int Height, char *ErrorMsg, unsigned MsgSize);
 FFMS_API(void) FFMS_ResetOutputFormat(VideoBase *VB);
 FFMS_API(void) FFMS_DestroyFrameIndex(FrameIndex *FI);
 FFMS_API(int) FFMS_GetFirstTrackOfType(FrameIndex *TrackIndices, int TrackType, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(int) FFMS_GetTrackType(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize);
+FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices);
+FFMS_API(int) FFMS_GetTrackType(FrameInfoVector *FIV);
+FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV);
 FFMS_API(const FrameInfo *) FFMS_GetFrameInfo(FrameInfoVector *FIV, int Frame, char *ErrorMsg, unsigned MsgSize);
 FFMS_API(FrameInfoVector *) FFMS_GetTITrackIndex(FrameIndex *TrackIndices, int Track, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(FrameInfoVector *) FFMS_GetVSTrackIndex(VideoBase *VB, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(FrameInfoVector *) FFMS_GetASTrackIndex(AudioBase *AB, char *ErrorMsg, unsigned MsgSize);
+FFMS_API(FrameInfoVector *) FFMS_GetVSTrackIndex(VideoBase *VB);
+FFMS_API(FrameInfoVector *) FFMS_GetASTrackIndex(AudioBase *AB);
 FFMS_API(int) FFMS_FindClosestKeyFrame(FrameInfoVector *FIV, int Frame, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize);
-FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize);
+FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS);
+FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS);
+FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV);
 FFMS_API(int) FFMS_WriteTimecodes(FrameInfoVector *FIV, const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize);
 FFMS_API(FrameIndex *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const char *AudioFile, bool IgnoreDecodeErrors, IndexCallback IP, void *Private, char *ErrorMsg, unsigned MsgSize);
 FFMS_API(FrameIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize);
diff --git a/FFmpegSource2/ffvideosource.cpp b/FFmpegSource2/ffvideosource.cpp
index 77f21bbb71e94e6b695a90322627c039cf05879c..f0ed36654466d2026228ad341eb9efea60f21abe 100644
--- a/FFmpegSource2/ffvideosource.cpp
+++ b/FFmpegSource2/ffvideosource.cpp
@@ -110,11 +110,11 @@ VideoBase::~VideoBase() {
 }
 
 AVFrameLite *VideoBase::GetFrameByTime(double Time, char *ErrorMsg, unsigned MsgSize) {
-	int Frame = Frames.ClosestFrameFromDTS(Time * Frames.TB.Den / Frames.TB.Num);
+	int Frame = Frames.ClosestFrameFromDTS((Time * Frames.TB.Num) / Frames.TB.Den);
 	return GetFrame(Frame, ErrorMsg, MsgSize);
 }
 
-int VideoBase::SetOutputFormat(int TargetFormats, int Width, int Height) {
+int VideoBase::SetOutputFormat(int TargetFormats, int Width, int Height, char *ErrorMsg, unsigned MsgSize) {
 //  FIXME: investigate the possible bug in avcodec_find_best_pix_fmt
 //	int Loss;
 //	int OutputFormat = avcodec_find_best_pix_fmt(TargetFormats,
@@ -128,8 +128,10 @@ int VideoBase::SetOutputFormat(int TargetFormats, int Width, int Height) {
 	if (CodecContext->pix_fmt != OutputFormat || Width != CodecContext->width || Height != CodecContext->height) {
 		NewSWS = sws_getContext(CodecContext->width, CodecContext->height, CodecContext->pix_fmt, Width, Height,
 			OutputFormat, GetCPUFlags() | SWS_BICUBIC, NULL, NULL, NULL);
-		if (NewSWS == NULL)
+		if (NewSWS == NULL) {
+			_snprintf(ErrorMsg, MsgSize, "Failed to allocate SWScale context");
 			return 1;
+		}
 	}
 
 	if (SWS)
@@ -234,6 +236,8 @@ FFVideoSource::FFVideoSource(const char *SourceFile, int Track, FrameIndex *Trac
 	VP.FPSNumerator = FormatContext->streams[VideoTrack]->time_base.den;
 	VP.NumFrames = Frames.size();
 	VP.PixelFormat = CodecContext->pix_fmt;
+	VP.FirstTime = (Frames.front().DTS * Frames.TB.Den) / (double)Frames.TB.Num;
+	VP.LastTime = (Frames.back().DTS * Frames.TB.Den) / (double)Frames.TB.Num;
 
 	if (VP.Width <= 0 || VP.Height <= 0) {
 		Free(true);
@@ -451,6 +455,8 @@ MatroskaVideoSource::MatroskaVideoSource(const char *SourceFile, int Track,
 	VP.FPSNumerator = 30;
 	VP.NumFrames = Frames.size();
 	VP.PixelFormat = CodecContext->pix_fmt;
+	VP.FirstTime = (Frames.front().DTS * Frames.TB.Den) / (double)Frames.TB.Num;
+	VP.LastTime = (Frames.back().DTS * Frames.TB.Den) / (double)Frames.TB.Num;
 
 	if (VP.Width <= 0 || VP.Height <= 0) {
 		Free(true);
diff --git a/FFmpegSource2/ffvideosource.h b/FFmpegSource2/ffvideosource.h
index dd97489ec67e9f5b3b28038c01a1aed77786934b..cbe870c15c7112edd1b45ee873e96478c8aaa1a1 100644
--- a/FFmpegSource2/ffvideosource.h
+++ b/FFmpegSource2/ffvideosource.h
@@ -58,7 +58,7 @@ public:
 	FrameInfoVector *GetFrameInfoVector() { return &Frames; }
 	virtual AVFrameLite *GetFrame(int n, char *ErrorMsg, unsigned MsgSize) = 0;
 	AVFrameLite *GetFrameByTime(double Time, char *ErrorMsg, unsigned MsgSize);
-	int SetOutputFormat(int TargetFormats, int Width, int Height);
+	int SetOutputFormat(int TargetFormats, int Width, int Height, char *ErrorMsg, unsigned MsgSize);
 	void ResetOutputFormat();
 };