mirror of https://github.com/odrling/Aegisub
Added VFR support. (Untested, as usual.)
Originally committed to SVN as r1477.
This commit is contained in:
parent
0a584a7cd4
commit
06452148d2
|
@ -31,6 +31,7 @@
|
|||
#include "avisynth.h"
|
||||
|
||||
#include "overlua.h"
|
||||
#include "vfr.h"
|
||||
|
||||
// Lots of code lifted from the CSRI avisynth.cpp
|
||||
|
||||
|
@ -38,6 +39,7 @@ class OverLuaAvisynth : public GenericVideoFilter {
|
|||
private:
|
||||
OverLuaScript *script;
|
||||
double spf; // seconds per frame - for frame/timestamp conversion
|
||||
VFRTranslator *vfr;
|
||||
|
||||
public:
|
||||
OverLuaAvisynth(PClip _child, IScriptEnvironment *env, const char *file, const char *datastring, const char *vfrfile)
|
||||
|
@ -55,6 +57,10 @@ public:
|
|||
try {
|
||||
script = new OverLuaScript(file, datastring);
|
||||
spf = (double)vi.fps_denominator / (double)vi.fps_numerator;
|
||||
if (vfrfile)
|
||||
vfr = GetVFRTranslator(vfrfile);
|
||||
else
|
||||
vfr = 0;
|
||||
}
|
||||
catch (const char *e) {
|
||||
env->ThrowError(e);
|
||||
|
@ -66,6 +72,8 @@ public:
|
|||
|
||||
~OverLuaAvisynth()
|
||||
{
|
||||
if (vfr)
|
||||
delete vfr;
|
||||
delete script;
|
||||
}
|
||||
|
||||
|
@ -76,6 +84,8 @@ public:
|
|||
env->MakeWritable(&avsframe);
|
||||
|
||||
double frametime = n * spf;
|
||||
if (vfr)
|
||||
frametime = vfr->TimeStampFromFrameNumber(n);
|
||||
ptrdiff_t stride = avsframe->GetPitch();
|
||||
unsigned char *plane = avsframe->GetWritePtr();
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ subtitles/karaoke.
|
|||
vfrfile is the path to a timecode file Matroska format 1 or 2. If supplied,
|
||||
it will be used to translate frame numbers to timestamps instead of relying
|
||||
on the frame rate provided by Avisynth.
|
||||
VFR support is not implemented yet.
|
||||
|
||||
|
||||
API the Lua script must implement
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* VFR translation functions for OverLua
|
||||
*
|
||||
|
||||
Copyright 2007 Niels Martin Hansen
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Contact:
|
||||
E-mail: <jiifurusu@gmail.com>
|
||||
IRC: jfs in #aegisub on irc.rizon.net
|
||||
|
||||
*/
|
||||
|
||||
#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 (strncmp(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;
|
||||
double fps;
|
||||
if (scanf("%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));
|
||||
}
|
||||
|
||||
last_known_frame = (int)timestamps.size()-1;
|
||||
last_known_timestamp = timestamps[last_known_frame];
|
||||
assumed_spf = 1/25.0; // yes, this is stupid - anyone got a better idea?
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* VFR translation functions for OverLua
|
||||
*
|
||||
|
||||
Copyright 2007 Niels Martin Hansen
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Contact:
|
||||
E-mail: <jiifurusu@gmail.com>
|
||||
IRC: jfs in #aegisub on irc.rizon.net
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VFR_H
|
||||
#define VFR_H
|
||||
|
||||
class VFRTranslator {
|
||||
public:
|
||||
virtual double TimeStampFromFrameNumber(int n) = 0;
|
||||
};
|
||||
|
||||
VFRTranslator *GetVFRTranslator(const char *vfrfile);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue