diff options
author | XhmikosR <xhmikosr@users.sourceforge.net> | 2010-02-14 15:51:43 +0300 |
---|---|---|
committer | XhmikosR <xhmikosr@users.sourceforge.net> | 2010-02-14 15:51:43 +0300 |
commit | 5eb111b6b21b3d9ff568c345cfa9c2a1c6fd3c07 (patch) | |
tree | 44a5fedb86f9a965574cfc3fda65c78c0f541694 /src/filters/transform/vsfilter | |
parent | 7e956bb14bc7ee5499727fea101f91a3085d19ea (diff) |
-Added VFR support to the VSFilter AviSynth filter. Patch by nielsm.
-Fixed some warnings
git-svn-id: https://mpc-hc.svn.sourceforge.net/svnroot/mpc-hc/trunk@1659 10f7b99b-c216-0410-bff0-8a66a9350fd8
Diffstat (limited to 'src/filters/transform/vsfilter')
-rw-r--r-- | src/filters/transform/vsfilter/VSFilter.vcproj | 20 | ||||
-rw-r--r-- | src/filters/transform/vsfilter/plugins.cpp | 73 | ||||
-rw-r--r-- | src/filters/transform/vsfilter/vfr.cpp | 181 | ||||
-rw-r--r-- | src/filters/transform/vsfilter/vfr.h | 34 |
4 files changed, 279 insertions, 29 deletions
diff --git a/src/filters/transform/vsfilter/VSFilter.vcproj b/src/filters/transform/vsfilter/VSFilter.vcproj index 6446eb649..ff112ec0d 100644 --- a/src/filters/transform/vsfilter/VSFilter.vcproj +++ b/src/filters/transform/vsfilter/VSFilter.vcproj @@ -193,7 +193,7 @@ Name="VCCLCompilerTool"
AdditionalOptions="/MP"
AdditionalIncludeDirectories="..\..\..\..\include;..\..\..\..\include\virtualdub;..\..\BaseClasses"
- PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL;ISOLATION_AWARE_ENABLED;_WIN32_WINNT=0x0600"
+ PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL;ISOLATION_AWARE_ENABLED;_WIN32_WINNT=0x0600;_CRT_SECURE_NO_WARNINGS"
BufferSecurityCheck="true"
EnableEnhancedInstructionSet="1"
/>
@@ -275,7 +275,7 @@ Name="VCCLCompilerTool"
AdditionalOptions="/MP"
AdditionalIncludeDirectories="..\..\..\..\include;..\..\..\..\include\virtualdub;..\..\BaseClasses"
- PreprocessorDefinitions="WIN64;NDEBUG;_USRDLL;ISOLATION_AWARE_ENABLED;_WIN32_WINNT=0x0600"
+ PreprocessorDefinitions="WIN64;NDEBUG;_USRDLL;ISOLATION_AWARE_ENABLED;_WIN32_WINNT=0x0600;_CRT_SECURE_NO_WARNINGS"
BufferSecurityCheck="true"
Detect64BitPortabilityProblems="false"
/>
@@ -364,10 +364,6 @@ >
</File>
<File
- RelativePath=".\StdAfx.h"
- >
- </File>
- <File
RelativePath="StyleEditorDialog.cpp"
>
</File>
@@ -380,6 +376,10 @@ >
</File>
<File
+ RelativePath=".\vfr.cpp"
+ >
+ </File>
+ <File
RelativePath="VSFilter.cpp"
>
</File>
@@ -413,6 +413,10 @@ >
</File>
<File
+ RelativePath=".\StdAfx.h"
+ >
+ </File>
+ <File
RelativePath="StyleEditorDialog.h"
>
</File>
@@ -425,6 +429,10 @@ >
</File>
<File
+ RelativePath=".\vfr.h"
+ >
+ </File>
+ <File
RelativePath="VSFilter.h"
>
</File>
diff --git a/src/filters/transform/vsfilter/plugins.cpp b/src/filters/transform/vsfilter/plugins.cpp index 2ff493991..cfd52a769 100644 --- a/src/filters/transform/vsfilter/plugins.cpp +++ b/src/filters/transform/vsfilter/plugins.cpp @@ -27,6 +27,7 @@ #include "../../../subtitles/RTS.h"
#include "../../../subtitles/SSF.h"
#include "../../../SubPic/MemSubPic.h"
+#include "vfr.h"
//
// Generic interface
@@ -620,8 +621,10 @@ namespace AviSynth25 class CAvisynthFilter : public GenericVideoFilter, virtual public CFilter
{
+ VFRTranslator *vfr;
+
public:
- CAvisynthFilter(PClip c, IScriptEnvironment* env) : GenericVideoFilter(c) {}
+ CAvisynthFilter(PClip c, IScriptEnvironment* env, VFRTranslator *_vfr=0) : GenericVideoFilter(c), vfr(_vfr) {}
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env)
{
@@ -646,9 +649,14 @@ namespace AviSynth25 /*vi.IsIYUV()*/ vi.pixel_type == VideoInfo::CS_IYUV ? (s_fSwapUV?MSP_YV12:MSP_IYUV) :
-1;
+ REFERENCE_TIME timestamp;
float fps = m_fps > 0 ? m_fps : (float)vi.fps_numerator / vi.fps_denominator;
+ if (!vfr)
+ timestamp = (REFERENCE_TIME)(10000000i64 * n / fps);
+ else
+ timestamp = (REFERENCE_TIME)(10000000 * vfr->TimeStampFromFrameNumber(n));
- Render(dst, (REFERENCE_TIME)(10000000i64 * n / fps), fps);
+ Render(dst, timestamp, fps);
return(frame);
}
@@ -674,28 +682,31 @@ namespace AviSynth25 class CTextSubAvisynthFilter : public CTextSubFilter, public CAvisynthFilter
{
public:
- CTextSubAvisynthFilter(PClip c, IScriptEnvironment* env, const char* fn, int CharSet = DEFAULT_CHARSET, float fps = -1)
+ CTextSubAvisynthFilter(PClip c, IScriptEnvironment* env, const char* fn, int CharSet = DEFAULT_CHARSET, float fps = -1, VFRTranslator *vfr = 0)
: CTextSubFilter(CString(fn), CharSet, fps)
- , CAvisynthFilter(c, env)
+ , CAvisynthFilter(c, env, vfr)
{
if(!m_pSubPicProvider)
env->ThrowError("TextSub: Can't open \"%s\"", fn);
}
};
- AVSValue __cdecl TextSubCreateS(AVSValue args, void* user_data, IScriptEnvironment* env)
+ AVSValue __cdecl TextSubCreateGeneral(AVSValue args, void* user_data, IScriptEnvironment* env)
{
- return(new CTextSubAvisynthFilter(args[0].AsClip(), env, args[1].AsString()));
- }
+ if (!args[1].Defined())
+ env->ThrowError("TextSub: You must specify a subtitle file to use");
- AVSValue __cdecl TextSubCreateSI(AVSValue args, void* user_data, IScriptEnvironment* env)
- {
- return(new CTextSubAvisynthFilter(args[0].AsClip(), env, args[1].AsString(), args[2].AsInt()));
- }
+ VFRTranslator *vfr = 0;
+ if (args[4].Defined())
+ vfr = GetVFRTranslator(args[4].AsString());
- AVSValue __cdecl TextSubCreateSIF(AVSValue args, void* user_data, IScriptEnvironment* env)
- {
- return(new CTextSubAvisynthFilter(args[0].AsClip(), env, args[1].AsString(), args[2].AsInt(), args[3].AsFloat()));
+ return(new CTextSubAvisynthFilter(
+ args[0].AsClip(),
+ env,
+ args[1].AsString(),
+ args[2].AsInt(DEFAULT_CHARSET),
+ args[3].AsFloat(-1),
+ vfr));
}
AVSValue __cdecl TextSubSwapUV(AVSValue args, void* user_data, IScriptEnvironment* env)
@@ -704,13 +715,24 @@ namespace AviSynth25 return(AVSValue());
}
- AVSValue __cdecl MaskSubCreateSIIFI(AVSValue args, void* user_data, IScriptEnvironment* env)
+ AVSValue __cdecl MaskSubCreate(AVSValue args, void* user_data, IScriptEnvironment* env)
{
+ if (!args[0].Defined())
+ env->ThrowError("MaskSub: You must specify a subtitle file to use");
+
+ if (!args[3].Defined() && !args[6].Defined())
+ env->ThrowError("MaskSub: You must specify either FPS or a VFR timecodes file");
+
+ VFRTranslator *vfr = 0;
+ if (args[6].Defined())
+ vfr = GetVFRTranslator(args[6].AsString());
+
AVSValue rgb32("RGB32");
- AVSValue tab[5] = {
+ AVSValue fps(args[3].AsFloat(25));
+ AVSValue tab[6] = {
args[1],
args[2],
- args[3],
+ fps,
args[4],
rgb32
};
@@ -722,20 +744,25 @@ namespace AviSynth25 "length",
"pixel_type"
};
+
AVSValue clip(env->Invoke("Blackness",value,nom));
env->SetVar(env->SaveString("RGBA"),true);
- return(new CTextSubAvisynthFilter(clip.AsClip(), env, args[0].AsString()));
-
+
+ return(new CTextSubAvisynthFilter(
+ clip.AsClip(),
+ env,
+ args[0].AsString(),
+ args[5].AsInt(DEFAULT_CHARSET),
+ args[3].AsFloat(-1),
+ vfr));
}
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)
{
env->AddFunction("VobSub", "cs", VobSubCreateS, 0);
- env->AddFunction("TextSub", "cs", TextSubCreateS, 0);
- env->AddFunction("TextSub", "csi", TextSubCreateSI, 0);
- env->AddFunction("TextSub", "csif", TextSubCreateSIF, 0);
+ env->AddFunction("TextSub", "c[file]s[charset]i[fps]f[vfr]s", TextSubCreateGeneral, 0);
env->AddFunction("TextSubSwapUV", "b", TextSubSwapUV, 0);
- env->AddFunction("MaskSub", "siifi", MaskSubCreateSIIFI, 0);
+ env->AddFunction("MaskSub", "[file]s[width]i[height]i[fps]f[length]i[charset]i[vfr]s", MaskSubCreate, 0);
env->SetVar(env->SaveString("RGBA"),false);
return(NULL);
}
diff --git a/src/filters/transform/vsfilter/vfr.cpp b/src/filters/transform/vsfilter/vfr.cpp new file mode 100644 index 000000000..667351eb9 --- /dev/null +++ b/src/filters/transform/vsfilter/vfr.cpp @@ -0,0 +1,181 @@ +/*
+ * VFR translation functions for OverLua
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mplayerc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "vfr.h"
+#include <stdio.h>
+#include <string.h>
+#include <vector>
+
+
+// Work with seconds per frame (spf) here instead of fps since that's more natural for the translation we're doing
+
+
+class TimecodesV1 : public VFRTranslator {
+private:
+ // Used when sections run out
+ double default_spf;
+ double first_non_section_timestamp;
+ int first_non_section_frame;
+
+ // Also generate sections for unspecified ones
+ // (use the default framerate then)
+ struct FrameRateSection {
+ double start_time;
+ double spf;
+ int start_frame;
+ int end_frame;
+ };
+ std::vector<FrameRateSection> sections;
+
+public:
+ virtual double TimeStampFromFrameNumber(int n)
+ {
+ // Find correct section
+ for (size_t i = 0; i < sections.size(); i++) {
+ FrameRateSection § = sections[i];
+ if (n >= sect.start_frame && n <= sect.end_frame) {
+ return sect.start_time + (n - sect.start_frame) * sect.spf;
+ }
+ }
+ // Not in a section
+ if (n < 0) return 0.0;
+ return first_non_section_timestamp + (n - first_non_section_frame) * default_spf;
+ }
+
+ TimecodesV1(FILE *vfrfile)
+ {
+ char buf[100];
+
+ default_spf = -1;
+ double cur_time = 0.0;
+
+ FrameRateSection temp_section;
+ temp_section.start_time = 0.0;
+ temp_section.spf = -1;
+ temp_section.start_frame = 0;
+ temp_section.end_frame = 0;
+
+ while (fgets(buf, 100, vfrfile)) {
+ // Comment?
+ if (buf[0] == '#') continue;
+
+ if (_strnicmp(buf, "Assume ", 7) == 0 && default_spf < 0) {
+ char *num = buf+7;
+ default_spf = atof(num);
+ if (default_spf > 0)
+ default_spf = 1 / default_spf;
+ else
+ default_spf = -1;
+ temp_section.spf = default_spf;
+ continue;
+ }
+
+ int start_frame, end_frame;
+ float fps;
+ if (sscanf(buf, "%d,%d,%f", &start_frame, &end_frame, &fps) == 3) {
+ // Finish the current temp section
+ temp_section.end_frame = start_frame - 1;
+ if (temp_section.end_frame >= temp_section.start_frame) {
+ cur_time += (temp_section.end_frame - temp_section.start_frame + 1) * temp_section.spf;
+ sections.push_back(temp_section);
+ }
+ // Insert the section corresponding to this line
+ temp_section.spf = 1/fps;
+ temp_section.start_frame = start_frame;
+ temp_section.end_frame = end_frame;
+ temp_section.start_time = cur_time;
+ cur_time += (end_frame - start_frame + 1) / fps;
+ sections.push_back(temp_section);
+ // Begin new temp section
+ temp_section.spf = default_spf;
+ temp_section.start_frame = end_frame + 1;
+ temp_section.end_frame = end_frame; // yes, negative duration
+ temp_section.start_time = cur_time;
+ }
+ }
+
+ first_non_section_timestamp = cur_time;
+ first_non_section_frame = temp_section.start_frame;
+ }
+
+};
+
+
+class TimecodesV2 : public VFRTranslator {
+private:
+ // Main data
+ std::vector<double> timestamps;
+ // For when data are exhausted (well, they shouldn't, then the vfr file is bad)
+ int last_known_frame;
+ double last_known_timestamp;
+ double assumed_spf;
+
+public:
+ virtual double TimeStampFromFrameNumber(int n)
+ {
+ if (n < (int)timestamps.size() && n >= 0) {
+ return timestamps[n];
+ }
+ if (n < 0) return 0.0;
+ return last_known_timestamp + (n - last_known_frame) * assumed_spf;
+ }
+
+ TimecodesV2(FILE *vfrfile)
+ {
+ char buf[50];
+
+ timestamps.reserve(8192); // should be enough for most cases
+
+ while (fgets(buf, 50, vfrfile)) {
+ // Comment?
+ if (buf[0] == '#') continue;
+ // Otherwise assume it's a good timestamp
+ timestamps.push_back(atof(buf)/1000);
+ }
+
+ last_known_frame = (int)timestamps.size()-1;
+ last_known_timestamp = timestamps[last_known_frame];
+ assumed_spf = last_known_timestamp - timestamps[last_known_frame - 1];
+ }
+
+};
+
+
+VFRTranslator *GetVFRTranslator(const char *vfrfile)
+{
+ char buf[32];
+ buf[19] = 0; // In "# timecode format v1" the version number is character index 19
+ FILE *f = fopen(vfrfile, "r");
+ VFRTranslator *res = 0;
+ if (fgets(buf, 32, f) && buf[0] == '#') {
+ // So do some really shoddy parsing here, assume the file is good
+ if (buf[19] == '1') {
+ res = new TimecodesV1(f);
+ } else if (buf[19] == '2') {
+ res = new TimecodesV2(f);
+ }
+ }
+ fclose(f);
+ return res;
+}
+
diff --git a/src/filters/transform/vsfilter/vfr.h b/src/filters/transform/vsfilter/vfr.h new file mode 100644 index 000000000..61cb52546 --- /dev/null +++ b/src/filters/transform/vsfilter/vfr.h @@ -0,0 +1,34 @@ +/*
+ * VFR translation functions for OverLua
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mplayerc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VFR_H
+#define VFR_H
+
+class VFRTranslator {
+public:
+ virtual double TimeStampFromFrameNumber(int n) = 0;
+};
+
+VFRTranslator *GetVFRTranslator(const char *vfrfile);
+
+#endif
|