Fix significantly incorrect handling of pretty much everything in AssTransformFramerateFilter and make it better at deciding when it actually needs to do anything.

Originally committed to SVN as r4578.
This commit is contained in:
Thomas Goyne 2010-06-24 01:24:26 +00:00
parent 627d423017
commit 53fb43c7e6
5 changed files with 138 additions and 414 deletions

View file

@ -34,29 +34,48 @@
/// @ingroup export /// @ingroup export
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#ifndef AGI_PRE
#include <utility>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/panel.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#endif
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "ass_override.h" #include "ass_override.h"
#include "export_framerate.h" #include "export_framerate.h"
#include "vfr.h" #include "utils.h"
/// DOCME
/// @brief Constructor /// @class LineData
/// @brief DOCME
/// ///
/// DOCME
struct LineData {
AssDialogue *line;
int newStart;
int newEnd;
int newK;
int oldK;
};
/// IDs
enum {
Get_Input_From_Video = 2000
};
AssTransformFramerateFilter::AssTransformFramerateFilter() { AssTransformFramerateFilter::AssTransformFramerateFilter() {
initialized = false; initialized = false;
} }
/// @brief Init
/// @return
///
void AssTransformFramerateFilter::Init() { void AssTransformFramerateFilter::Init() {
if (initialized) return; if (initialized) return;
initialized = true; initialized = true;
@ -67,27 +86,10 @@ void AssTransformFramerateFilter::Init() {
Output = NULL; Output = NULL;
} }
/// @brief Process
/// @param subs
/// @param export_dialog
///
void AssTransformFramerateFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) { void AssTransformFramerateFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) {
// Transform frame rate TransformFrameRate(subs);
if (Input->IsLoaded() && Output->IsLoaded()) {
if (Input->GetFrameRateType() == VFR || Output->GetFrameRateType() == VFR || Output->GetAverage() != Input->GetAverage()) {
TransformFrameRate(subs);
}
}
} }
/// @brief Get dialog
/// @param parent
/// @return
///
wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent) { wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent) {
wxWindow *base = new wxPanel(parent, -1); wxWindow *base = new wxPanel(parent, -1);
@ -146,11 +148,6 @@ wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent) {
return base; return base;
} }
/// @brief Load settings
/// @param IsDefault
///
void AssTransformFramerateFilter::LoadSettings(bool IsDefault) { void AssTransformFramerateFilter::LoadSettings(bool IsDefault) {
if (IsDefault) { if (IsDefault) {
Input = &VFR_Input; Input = &VFR_Input;
@ -168,149 +165,91 @@ void AssTransformFramerateFilter::LoadSettings(bool IsDefault) {
} }
else Output = &VFR_Output; else Output = &VFR_Output;
// Reverse
if (Reverse->IsChecked()) { if (Reverse->IsChecked()) {
FrameRate *temp = Output; std::swap(Input, Output);
Output = Input;
Input = temp;
} }
} }
} }
/// Truncate a time to centisecond precision
int FORCEINLINE trunc_cs(int time) {
return (time / 10) * 10;
}
/// @brief Transform framerate in tags
/// @param name
/// @param n
/// @param curParam
/// @param curData
/// @return
///
void AssTransformFramerateFilter::TransformTimeTags (wxString name,int n,AssOverrideParameter *curParam,void *curData) { void AssTransformFramerateFilter::TransformTimeTags (wxString name,int n,AssOverrideParameter *curParam,void *curData) {
// Only modify anything if this is a number
VariableDataType type = curParam->GetType(); VariableDataType type = curParam->GetType();
if (type != VARDATA_INT && type != VARDATA_FLOAT) return; if (type != VARDATA_INT && type != VARDATA_FLOAT) return;
// Setup LineData *lineData = static_cast<LineData*>(curData);
LineData *lineData = (LineData*) curData; AssDialogue *curDiag = lineData->line;
AssDialogue *curDiag = lineData->line;;
bool start = true; int parVal = curParam->Get<int>();
bool karaoke = false;
int mult = 1;
int value;
switch (curParam->classification) { switch (curParam->classification) {
case PARCLASS_RELATIVE_TIME_START: case PARCLASS_RELATIVE_TIME_START: {
int value = instance.ConvertTime(trunc_cs(curDiag->Start.GetMS()) + parVal) - lineData->newStart;
// An end time of 0 is actually the end time of the line, so ensure
// nonzero is never converted to 0
// Needed here rather than the end case because start/end here mean
// which end of the line the time is relative to, not whether it's
// the start or end time (compare \move and \fad)
if (value == 0 && parVal != 0) value = 1;
curParam->Set(value);
break; break;
}
case PARCLASS_RELATIVE_TIME_END: case PARCLASS_RELATIVE_TIME_END:
start = false; curParam->Set(lineData->newEnd - instance.ConvertTime(trunc_cs(curDiag->End.GetMS()) - parVal));
break; break;
case PARCLASS_KARAOKE: case PARCLASS_KARAOKE: {
karaoke = true; int start = curDiag->Start.GetMS() / 10 + lineData->oldK + parVal;
mult = 10; int value = (instance.ConvertTime(start * 10) - lineData->newStart) / 10 - lineData->newK;
lineData->oldK += parVal;
lineData->newK += value;
curParam->Set(value);
break; break;
}
default: default:
return; return;
} }
// Parameter value
int parVal = curParam->Get<int>() * mult;
// Karaoke preprocess
int curKarPos = 0;
if (karaoke) {
if (name == _T("\\k")) {
curKarPos = lineData->k;
lineData->k += parVal/10;
}
else if (name == _T("\\K") || name == _T("\\kf")) {
curKarPos = lineData->kf;
lineData->kf += parVal/10;
}
else if (name == _T("\\ko")) {
curKarPos = lineData->ko;
lineData->ko += parVal/10;
}
else throw wxString::Format(_T("Unknown karaoke tag! '%s'"), name.c_str());
curKarPos *= 10;
parVal += curKarPos;
}
// Start time
if (start) {
int newStart = instance.Input->GetTimeAtFrame(instance.Output->GetFrameAtTime(curDiag->Start.GetMS()));
int absTime = curDiag->Start.GetMS() + parVal;
value = instance.Input->GetTimeAtFrame(instance.Output->GetFrameAtTime(absTime)) - newStart;
// An end time of 0 is actually the end time of the line, so ensure nonzero is never converted to 0
// Needed in the start case as well as the end one due to \t, whose end time needs the start time
// behavior
if (value == 0 && parVal != 0) value = 1;
}
// End time
else {
int newEnd = instance.Input->GetTimeAtFrame(instance.Output->GetFrameAtTime(curDiag->End.GetMS()));
int absTime = curDiag->End.GetMS() - parVal;
value = newEnd - instance.Input->GetTimeAtFrame(instance.Output->GetFrameAtTime(absTime));
if (value == 0 && parVal != 0) value = 1;
}
// Karaoke postprocess
if (karaoke) {
int post = instance.Input->GetTimeAtFrame(instance.Output->GetFrameAtTime(curDiag->Start.GetMS() + curKarPos));
int start = instance.Input->GetTimeAtFrame(instance.Output->GetFrameAtTime(curDiag->Start.GetMS()));
curKarPos = post-start;
value -= curKarPos;
}
curParam->Set<int>(value/mult);
} }
/// @brief Transform framerate
/// @param subs
///
void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) { void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
int n=0; if (!Input->IsLoaded() || !Output->IsLoaded() || Input == Output || *Input == *Output) return;
// Run through
using std::list;
AssEntry *curEntry;
AssDialogue *curDialogue;
for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) {
curEntry = *cur; AssDialogue *curDialogue = dynamic_cast<AssDialogue*>(*cur);
// why the christ was this ever done to begin with?
// yes, let's framerate compensate the start timestamp and then use the changed value to
// compensate it AGAIN 20 lines down? I DO NOT GET IT
// -Fluff
//curEntry->Start.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curEntry->GetStartMS(),true),true));
curDialogue = dynamic_cast<AssDialogue*>(curEntry);
// Update dialogue entries
if (curDialogue) { if (curDialogue) {
// Line data
LineData data; LineData data;
data.line = curDialogue; data.line = curDialogue;
data.k = 0; data.newK = 0;
data.kf = 0; data.oldK = 0;
data.ko = 0; data.newStart = trunc_cs(ConvertTime(curDialogue->Start.GetMS()));
data.newEnd = trunc_cs(ConvertTime(curDialogue->End.GetMS()));
// Process stuff // Process stuff
curDialogue->ParseASSTags(); curDialogue->ParseASSTags();
curDialogue->ProcessParameters(TransformTimeTags,&data); curDialogue->ProcessParameters(TransformTimeTags,&data);
curDialogue->Start.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curDialogue->Start.GetMS(),true),true)); curDialogue->Start.SetMS(data.newStart);
curDialogue->End.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curDialogue->End.GetMS(),false),false)); curDialogue->End.SetMS(data.newEnd);
curDialogue->UpdateText(); curDialogue->UpdateText();
curDialogue->ClearBlocks(); curDialogue->ClearBlocks();
n++;
} }
} }
} }
int AssTransformFramerateFilter::ConvertTime(int time) {
int frame = Output->GetFrameAtTime(time, false);
int frameStart = Output->GetTimeAtFrame(frame, false, true);
int frameEnd = Output->GetTimeAtFrame(frame + 1, false, true);
int frameDur = frameEnd - frameStart;
double dist = double(time - frameStart) / frameDur;
int newStart = Input->GetTimeAtFrame(frame, false, true);
int newEnd = Input->GetTimeAtFrame(frame + 1, false, true);
int newDur = newEnd - newStart;
return newStart + newDur * dist;
}
/// DOCME
AssTransformFramerateFilter AssTransformFramerateFilter::instance; AssTransformFramerateFilter AssTransformFramerateFilter::instance;

View file

@ -34,110 +34,61 @@
/// @ingroup export /// @ingroup export
/// ///
///////////
// Headers
#ifndef AGI_PRE
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/panel.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#endif
#include "ass_export_filter.h" #include "ass_export_filter.h"
#include "vfr.h" #include "vfr.h"
//////////////
// Prototypes
class AssOverrideParameter;
class AssDialogue; class AssDialogue;
class AssOverrideParameter;
class wxCheckBox;
class wxRadioButton;
class wxTextCtrl;
/// DOCME /// DOCME
/// @class AssTransformFramerateFilter /// @class AssTransformFramerateFilter
/// @brief DOCME /// @brief DOCME
///
/// DOCME
class AssTransformFramerateFilter : public AssExportFilter { class AssTransformFramerateFilter : public AssExportFilter {
private: /// The singleton instance of this filter
/// DOCME
static AssTransformFramerateFilter instance; static AssTransformFramerateFilter instance;
/// DOCME // Yes, these are backwards
FrameRate *Input; /// Destination frame rate
FrameRate *Output; /// Source frame rate
/// DOCME
FrameRate *Input,*Output;
/// DOCME
/// DOCME
FrameRate t1,t2; FrameRate t1,t2;
wxTextCtrl *InputFramerate; /// Input frame rate text box
wxTextCtrl *OutputFramerate; /// Output frame rate text box
/// DOCME wxRadioButton *RadioOutputCFR; /// CFR radio control
wxTextCtrl *InputFramerate; wxRadioButton *RadioOutputVFR; /// VFR radio control
/// DOCME wxCheckBox *Reverse; /// Switch input and output
wxTextCtrl *OutputFramerate;
/// DOCME
wxRadioButton *RadioOutputCFR;
/// DOCME
wxRadioButton *RadioOutputVFR;
/// DOCME
wxCheckBox *Reverse;
/// Constructor
AssTransformFramerateFilter(); AssTransformFramerateFilter();
/// @brief Apply the transformation to a file
/// @param subs File to process
void TransformFrameRate(AssFile *subs); void TransformFrameRate(AssFile *subs);
static void TransformTimeTags(wxString name,int n,AssOverrideParameter *curParam,void *_curDiag); /// @brief Transform a single tag
/// @param name Name of the tag
/// @param curParam Current parameter being processed
/// @param userdata LineData passed
static void TransformTimeTags(wxString name,int,AssOverrideParameter *curParam,void *userdata);
/// Initialize the singleton instance
void Init(); void Init();
/// @brief Convert a time from the input frame rate to the output frame rate
/// @param time Time in ms to convert
/// @return Time in ms
///
/// This preserves two things:
/// 1. The frame number
/// 2. The relative distance between the beginning of the frame which time
/// is in and the beginning of the next frame
int ConvertTime(int time);
public: public:
void ProcessSubs(AssFile *subs, wxWindow *export_dialog); void ProcessSubs(AssFile *subs, wxWindow *export_dialog);
wxWindow *GetConfigDialogWindow(wxWindow *parent); wxWindow *GetConfigDialogWindow(wxWindow *parent);
void LoadSettings(bool IsDefault); void LoadSettings(bool IsDefault);
}; };
/// DOCME
/// @class LineData
/// @brief DOCME
///
/// DOCME
class LineData {
public:
/// DOCME
AssDialogue *line;
/// DOCME
int k;
/// DOCME
int kf;
/// DOCME
int ko;
};
///////
// IDs
enum {
/// DOCME
Get_Input_From_Video = 2000
};

View file

@ -34,9 +34,6 @@
/// @ingroup video_input /// @ingroup video_input
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#ifndef AGI_PRE #ifndef AGI_PRE
@ -53,53 +50,36 @@
/// @brief V2 Clear function /// @brief V2 Clear function
///
void FrameRate::Clear () { void FrameRate::Clear () {
Frame.clear(); Frame.clear();
} }
/// @brief V2 Add frame /// @brief V2 Add frame
/// @param ms /// @param ms
///
void FrameRate::AddFrame(int ms) { void FrameRate::AddFrame(int ms) {
Frame.push_back(ms); Frame.push_back(ms);
} }
/// @brief V2 Get Average /// @brief V2 Get Average
///
void FrameRate::CalcAverage() { void FrameRate::CalcAverage() {
if (Frame.size() <= 1) if (Frame.size() <= 1)
throw _("No timecodes to average"); throw _("No timecodes to average");
AverageFrameRate = double(Frame.back()) / (Frame.size()-1); AverageFrameRate = double(Frame.back()) / (Frame.size()-1);
} }
/// @brief Constructor
/// @brief Constructor FrameRate //////////////////////
///
FrameRate::FrameRate() { FrameRate::FrameRate() {
Unload(); Unload();
} }
/// @brief Destructor /// @brief Destructor
///
FrameRate::~FrameRate() { FrameRate::~FrameRate() {
Unload(); Unload();
} }
/// @brief Loads VFR file /// @brief Loads VFR file
/// @param filename /// @param filename
///
void FrameRate::Load(wxString filename) { void FrameRate::Load(wxString filename) {
using namespace std; using namespace std;
@ -241,11 +221,8 @@ void FrameRate::Load(wxString filename) {
config::mru->Add("Timecodes", STD_STR(filename)); config::mru->Add("Timecodes", STD_STR(filename));
} }
/// @brief Save /// @brief Save
/// @param filename /// @param filename
///
void FrameRate::Save(wxString filename) { void FrameRate::Save(wxString filename) {
TextFileWriter file(filename,_T("ASCII")); TextFileWriter file(filename,_T("ASCII"));
file.WriteLineToFile(_T("# timecode format v2")); file.WriteLineToFile(_T("# timecode format v2"));
@ -254,10 +231,7 @@ void FrameRate::Save(wxString filename) {
} }
} }
/// @brief Unload /// @brief Unload
///
void FrameRate::Unload () { void FrameRate::Unload () {
FrameRateType = NONE; FrameRateType = NONE;
AverageFrameRate = 0; AverageFrameRate = 0;
@ -268,11 +242,8 @@ void FrameRate::Unload () {
vfrFile = _T(""); vfrFile = _T("");
} }
/// @brief Sets to CFR /// @brief Sets to CFR
/// @param fps /// @param fps
///
void FrameRate::SetCFR(double fps) { void FrameRate::SetCFR(double fps) {
Unload(); Unload();
loaded = true; loaded = true;
@ -280,13 +251,9 @@ void FrameRate::SetCFR(double fps) {
AverageFrameRate = fps; AverageFrameRate = fps;
} }
/// @brief Sets to VFR /// @brief Sets to VFR
/// @param newTimes /// @param newTimes
///
void FrameRate::SetVFR(std::vector<int> newTimes) { void FrameRate::SetVFR(std::vector<int> newTimes) {
// Prepare
Unload(); Unload();
loaded = true; loaded = true;
@ -299,22 +266,16 @@ void FrameRate::SetVFR(std::vector<int> newTimes) {
last_frame = (int)newTimes.size(); last_frame = (int)newTimes.size();
} }
/// @brief Gets frame number at time /// @brief Gets frame number at time
/// @param ms /// @param ms
/// @param useceil /// @param useceil
/// @return /// @return
/// int FrameRate::PFrameAtTime(int ms,bool useceil) const {
int FrameRate::PFrameAtTime(int ms,bool useceil) {
// Check if it's loaded // Check if it's loaded
if (!loaded) return -1; if (!loaded) return -1;
// Normalize miliseconds
ms = MAX(ms,0);
// Get for constant frame rate // Get for constant frame rate
if (FrameRateType == CFR || Frame.size() == 0) { if (FrameRateType == CFR || Frame.size() == 0 || ms < 0) {
double value = double(ms) * AverageFrameRate / 1000.0; double value = double(ms) * AverageFrameRate / 1000.0;
if (useceil) return (int)ceil(value); if (useceil) return (int)ceil(value);
else return (int)floor(value); else return (int)floor(value);
@ -366,13 +327,10 @@ int FrameRate::PFrameAtTime(int ms,bool useceil) {
return -1; return -1;
} }
/// @brief Gets time at frame /// @brief Gets time at frame
/// @param frame /// @param frame
/// @return /// @return
/// int FrameRate::PTimeAtFrame(int frame) const {
int FrameRate::PTimeAtFrame(int frame) {
// Not loaded // Not loaded
if (!loaded) return -1; if (!loaded) return -1;
@ -397,26 +355,20 @@ int FrameRate::PTimeAtFrame(int frame) {
return -1; return -1;
} }
/// @brief otherwise for start frames returns the adjusted time for end frames when start=false Get correct frame at time /// @brief otherwise for start frames returns the adjusted time for end frames when start=false Get correct frame at time
/// @param ms /// @param ms
/// @param start /// @param start
/// @return /// @return
/// int FrameRate::GetFrameAtTime(int ms,bool start) const {
int FrameRate::GetFrameAtTime(int ms,bool start) {
return PFrameAtTime(ms,start); return PFrameAtTime(ms,start);
} }
/// @brief compensates and returns an end time when start=false Get correct time at frame /// @brief compensates and returns an end time when start=false Get correct time at frame
/// @param frame /// @param frame Frame number
/// @param start /// @param start Adjust for start time
/// @param exact /// @param exact Don't do awful things to avoid rounding errors
/// @return /// @return
/// int FrameRate::GetTimeAtFrame(int frame,bool start,bool exact) const {
int FrameRate::GetTimeAtFrame(int frame,bool start,bool exact) {
int finalTime; int finalTime;
// Exact, for display // Exact, for display
@ -439,121 +391,21 @@ int FrameRate::GetTimeAtFrame(int frame,bool start,bool exact) {
return finalTime; return finalTime;
} }
/// @brief Get the current list of frames/times /// @brief Get the current list of frames/times
/// @return /// @return
/// std::vector<int> FrameRate::GetFrameTimeList() const {
std::vector<int> FrameRate::GetFrameTimeList() {
return Frame; return Frame;
} }
bool FrameRate::operator==(FrameRate const& rgt) {
if (FrameRateType != rgt.FrameRateType) return false;
/// @brief e.g., in a mix of 24fps and 30fps, returns 120fps Calculate the common FPS for evil stuff if (FrameRateType == NONE) return true;
/// @return if (FrameRateType == CFR) return AverageFrameRate == rgt.AverageFrameRate;
/// return Frame == rgt.Frame;
double FrameRate::GetCommonFPS() {
// Variables
int curDist;
int lastDist = 0;
int sectionStart = 0;
double curFps;
// List of likely frame rates
std::vector<double> frameRates;
frameRates.push_back(15.0 / 1.001);
frameRates.push_back(15);
frameRates.push_back(24.0 / 1.001);
frameRates.push_back(24);
frameRates.push_back(30.0 / 1.001);
frameRates.push_back(30);
frameRates.push_back(120.0 / 1.001);
frameRates.push_back(120);
// List of rates found
std::vector<double> found;
// Find the relative fps of each area
for (unsigned int i=1;i<Frame.size();i++) {
// Find the current frame distance
curDist = Frame[i]-Frame[i-1];
// See if it's close enough to the last
if ((abs(curDist - lastDist) < 2 || i-1 == (unsigned) sectionStart) && i != Frame.size()-1) {
lastDist = curDist;
continue;
}
// Calculate section fps
curFps = (i - sectionStart - 1) * 1000.0 / double(Frame[i-1]-Frame[sectionStart]);
sectionStart = i;
lastDist = curDist;
// See if it's close enough to one of the likely rates
for (unsigned int j=0;j<frameRates.size();j++) {
if (curFps-0.01 <= frameRates[j] && curFps+0.01 >= frameRates[j]) {
curFps = frameRates[j];
break;
}
}
// See if it's on list
bool onList = false;
for (unsigned int j=0;j<found.size();j++) {
if (found[j] == curFps) {
onList = true;
break;
}
}
// If not, add it
if (!onList) found.push_back(curFps);
}
// Find common between them
double v1,v2,minInt,tempd;
int tempi1,tempi2;
while (found.size() > 1) {
// Extract last two values
v1 = found.back();
found.pop_back();
v2 = found.back();
found.pop_back();
// Divide them
v2 = v1/v2;
// Find what it takes to make it an integer
for (minInt = 1;minInt<20;minInt++) {
tempd = v2 * minInt;
tempi1 = (int)(tempd-0.001);
tempi2 = (int)(tempd+0.001);
if (tempi1 != tempi2) break;
}
if (minInt != 20) v1 = v1*minInt;
// See if it's close enough to one of the likely rates
for (unsigned int j=0;j<frameRates.size();j++) {
if (v1-0.01 <= frameRates[j] && v1+0.01 >= frameRates[j]) {
v1 = frameRates[j];
break;
}
}
// Re-insert obtained result
found.push_back(v1);
}
return found.back();
} }
/// DOCME /// DOCME
FrameRate VFR_Output; FrameRate VFR_Output;
/// DOCME /// DOCME
FrameRate VFR_Input; FrameRate VFR_Input;

View file

@ -42,9 +42,6 @@
#pragma once #pragma once
///////////
// Headers
#ifndef AGI_PRE #ifndef AGI_PRE
#include <list> #include <list>
#include <vector> #include <vector>
@ -53,19 +50,10 @@
#include <wx/string.h> #include <wx/string.h>
#endif #endif
#include "include/aegisub/aegisub.h"
/// DOCME /// DOCME
enum ASS_FrameRateType { enum ASS_FrameRateType {
/// DOCME
NONE, NONE,
/// DOCME
CFR, CFR,
/// DOCME
VFR VFR
}; };
@ -97,8 +85,8 @@ private:
void Clear(); void Clear();
void CalcAverage(); void CalcAverage();
int PFrameAtTime(int ms,bool useCeil=false); int PFrameAtTime(int ms,bool useCeil=false) const;
int PTimeAtFrame(int frame); int PTimeAtFrame(int frame) const;
/// DOCME /// DOCME
@ -122,37 +110,33 @@ public:
void Save(wxString file); void Save(wxString file);
void Unload(); void Unload();
int GetFrameAtTime(int ms,bool start=true); int GetFrameAtTime(int ms,bool start=true) const;
int GetTimeAtFrame(int frame,bool start=true,bool exact=false); int GetTimeAtFrame(int frame,bool start=true,bool exact=false) const;
/// @brief DOCME /// @brief DOCME
/// @return /// @return
/// ///
double GetAverage() { return AverageFrameRate; }; double GetAverage() const { return AverageFrameRate; };
/// @brief DOCME /// @brief DOCME
/// @return /// @return
/// ///
bool IsLoaded() { return loaded; }; bool IsLoaded() const { return loaded; };
/// @brief DOCME /// @brief DOCME
/// @return /// @return
/// ///
ASS_FrameRateType GetFrameRateType() { return FrameRateType; }; ASS_FrameRateType GetFrameRateType() const { return FrameRateType; };
/// @brief DOCME /// @brief DOCME
/// ///
wxString GetFilename() { return vfrFile; }; wxString GetFilename() const { return vfrFile; };
std::vector<int> GetFrameTimeList(); std::vector<int> GetFrameTimeList() const;
double GetCommonFPS();
bool operator==(FrameRate const& rgt);
}; };
///////////
// Globals
extern FrameRate VFR_Output; extern FrameRate VFR_Output;
extern FrameRate VFR_Input; extern FrameRate VFR_Input;

View file

@ -255,7 +255,6 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
// Read keyframes and timecodes from MKV file // Read keyframes and timecodes from MKV file
isVfr = false; isVfr = false;
FrameRate temp; FrameRate temp;
double overFps = 0;
bool mkvOpen = MatroskaWrapper::wrapper.IsOpen(); bool mkvOpen = MatroskaWrapper::wrapper.IsOpen();
KeyFrames.Clear(); KeyFrames.Clear();
if (extension == _T(".mkv") || mkvOpen) { if (extension == _T(".mkv") || mkvOpen) {
@ -273,7 +272,6 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
MatroskaWrapper::wrapper.SetToTimecodes(temp); MatroskaWrapper::wrapper.SetToTimecodes(temp);
isVfr = temp.GetFrameRateType() == VFR; isVfr = temp.GetFrameRateType() == VFR;
if (isVfr) { if (isVfr) {
overFps = temp.GetCommonFPS();
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Input); MatroskaWrapper::wrapper.SetToTimecodes(VFR_Input);
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Output); MatroskaWrapper::wrapper.SetToTimecodes(VFR_Output);
trueFrameRate = temp; trueFrameRate = temp;