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 "avisynth.h"
|
||||||
|
|
||||||
#include "overlua.h"
|
#include "overlua.h"
|
||||||
|
#include "vfr.h"
|
||||||
|
|
||||||
// Lots of code lifted from the CSRI avisynth.cpp
|
// Lots of code lifted from the CSRI avisynth.cpp
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ class OverLuaAvisynth : public GenericVideoFilter {
|
||||||
private:
|
private:
|
||||||
OverLuaScript *script;
|
OverLuaScript *script;
|
||||||
double spf; // seconds per frame - for frame/timestamp conversion
|
double spf; // seconds per frame - for frame/timestamp conversion
|
||||||
|
VFRTranslator *vfr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OverLuaAvisynth(PClip _child, IScriptEnvironment *env, const char *file, const char *datastring, const char *vfrfile)
|
OverLuaAvisynth(PClip _child, IScriptEnvironment *env, const char *file, const char *datastring, const char *vfrfile)
|
||||||
|
@ -55,6 +57,10 @@ public:
|
||||||
try {
|
try {
|
||||||
script = new OverLuaScript(file, datastring);
|
script = new OverLuaScript(file, datastring);
|
||||||
spf = (double)vi.fps_denominator / (double)vi.fps_numerator;
|
spf = (double)vi.fps_denominator / (double)vi.fps_numerator;
|
||||||
|
if (vfrfile)
|
||||||
|
vfr = GetVFRTranslator(vfrfile);
|
||||||
|
else
|
||||||
|
vfr = 0;
|
||||||
}
|
}
|
||||||
catch (const char *e) {
|
catch (const char *e) {
|
||||||
env->ThrowError(e);
|
env->ThrowError(e);
|
||||||
|
@ -66,6 +72,8 @@ public:
|
||||||
|
|
||||||
~OverLuaAvisynth()
|
~OverLuaAvisynth()
|
||||||
{
|
{
|
||||||
|
if (vfr)
|
||||||
|
delete vfr;
|
||||||
delete script;
|
delete script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +84,8 @@ public:
|
||||||
env->MakeWritable(&avsframe);
|
env->MakeWritable(&avsframe);
|
||||||
|
|
||||||
double frametime = n * spf;
|
double frametime = n * spf;
|
||||||
|
if (vfr)
|
||||||
|
frametime = vfr->TimeStampFromFrameNumber(n);
|
||||||
ptrdiff_t stride = avsframe->GetPitch();
|
ptrdiff_t stride = avsframe->GetPitch();
|
||||||
unsigned char *plane = avsframe->GetWritePtr();
|
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,
|
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
|
it will be used to translate frame numbers to timestamps instead of relying
|
||||||
on the frame rate provided by Avisynth.
|
on the frame rate provided by Avisynth.
|
||||||
VFR support is not implemented yet.
|
|
||||||
|
|
||||||
|
|
||||||
API the Lua script must implement
|
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