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:
parent
627d423017
commit
53fb43c7e6
5 changed files with 138 additions and 414 deletions
|
@ -34,29 +34,48 @@
|
|||
/// @ingroup export
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#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_file.h"
|
||||
#include "ass_override.h"
|
||||
#include "export_framerate.h"
|
||||
#include "vfr.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
/// @brief Constructor
|
||||
/// DOCME
|
||||
/// @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() {
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Init
|
||||
/// @return
|
||||
///
|
||||
void AssTransformFramerateFilter::Init() {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
@ -67,27 +86,10 @@ void AssTransformFramerateFilter::Init() {
|
|||
Output = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Process
|
||||
/// @param subs
|
||||
/// @param export_dialog
|
||||
///
|
||||
void AssTransformFramerateFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) {
|
||||
// Transform frame rate
|
||||
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 *base = new wxPanel(parent, -1);
|
||||
|
||||
|
@ -146,11 +148,6 @@ wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent) {
|
|||
return base;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Load settings
|
||||
/// @param IsDefault
|
||||
///
|
||||
void AssTransformFramerateFilter::LoadSettings(bool IsDefault) {
|
||||
if (IsDefault) {
|
||||
Input = &VFR_Input;
|
||||
|
@ -168,149 +165,91 @@ void AssTransformFramerateFilter::LoadSettings(bool IsDefault) {
|
|||
}
|
||||
else Output = &VFR_Output;
|
||||
|
||||
// Reverse
|
||||
if (Reverse->IsChecked()) {
|
||||
FrameRate *temp = Output;
|
||||
Output = Input;
|
||||
Input = temp;
|
||||
std::swap(Input, Output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
// Only modify anything if this is a number
|
||||
VariableDataType type = curParam->GetType();
|
||||
if (type != VARDATA_INT && type != VARDATA_FLOAT) return;
|
||||
|
||||
// Setup
|
||||
LineData *lineData = (LineData*) curData;
|
||||
AssDialogue *curDiag = lineData->line;;
|
||||
bool start = true;
|
||||
bool karaoke = false;
|
||||
int mult = 1;
|
||||
int value;
|
||||
LineData *lineData = static_cast<LineData*>(curData);
|
||||
AssDialogue *curDiag = lineData->line;
|
||||
|
||||
int parVal = curParam->Get<int>();
|
||||
|
||||
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;
|
||||
}
|
||||
case PARCLASS_RELATIVE_TIME_END:
|
||||
start = false;
|
||||
curParam->Set(lineData->newEnd - instance.ConvertTime(trunc_cs(curDiag->End.GetMS()) - parVal));
|
||||
break;
|
||||
case PARCLASS_KARAOKE:
|
||||
karaoke = true;
|
||||
mult = 10;
|
||||
case PARCLASS_KARAOKE: {
|
||||
int start = curDiag->Start.GetMS() / 10 + lineData->oldK + parVal;
|
||||
int value = (instance.ConvertTime(start * 10) - lineData->newStart) / 10 - lineData->newK;
|
||||
lineData->oldK += parVal;
|
||||
lineData->newK += value;
|
||||
curParam->Set(value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
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) {
|
||||
int n=0;
|
||||
|
||||
// Run through
|
||||
using std::list;
|
||||
AssEntry *curEntry;
|
||||
AssDialogue *curDialogue;
|
||||
if (!Input->IsLoaded() || !Output->IsLoaded() || Input == Output || *Input == *Output) return;
|
||||
for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) {
|
||||
curEntry = *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);
|
||||
AssDialogue *curDialogue = dynamic_cast<AssDialogue*>(*cur);
|
||||
|
||||
// Update dialogue entries
|
||||
if (curDialogue) {
|
||||
// Line data
|
||||
LineData data;
|
||||
data.line = curDialogue;
|
||||
data.k = 0;
|
||||
data.kf = 0;
|
||||
data.ko = 0;
|
||||
data.newK = 0;
|
||||
data.oldK = 0;
|
||||
data.newStart = trunc_cs(ConvertTime(curDialogue->Start.GetMS()));
|
||||
data.newEnd = trunc_cs(ConvertTime(curDialogue->End.GetMS()));
|
||||
|
||||
// Process stuff
|
||||
curDialogue->ParseASSTags();
|
||||
curDialogue->ProcessParameters(TransformTimeTags,&data);
|
||||
curDialogue->Start.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curDialogue->Start.GetMS(),true),true));
|
||||
curDialogue->End.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curDialogue->End.GetMS(),false),false));
|
||||
curDialogue->Start.SetMS(data.newStart);
|
||||
curDialogue->End.SetMS(data.newEnd);
|
||||
curDialogue->UpdateText();
|
||||
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;
|
||||
|
||||
|
||||
|
|
|
@ -34,110 +34,61 @@
|
|||
/// @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 "vfr.h"
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class AssOverrideParameter;
|
||||
class AssDialogue;
|
||||
|
||||
|
||||
class AssOverrideParameter;
|
||||
class wxCheckBox;
|
||||
class wxRadioButton;
|
||||
class wxTextCtrl;
|
||||
|
||||
/// DOCME
|
||||
/// @class AssTransformFramerateFilter
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class AssTransformFramerateFilter : public AssExportFilter {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
/// The singleton instance of this filter
|
||||
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;
|
||||
|
||||
wxTextCtrl *InputFramerate; /// Input frame rate text box
|
||||
wxTextCtrl *OutputFramerate; /// Output frame rate text box
|
||||
|
||||
/// DOCME
|
||||
wxTextCtrl *InputFramerate;
|
||||
wxRadioButton *RadioOutputCFR; /// CFR radio control
|
||||
wxRadioButton *RadioOutputVFR; /// VFR radio control
|
||||
|
||||
/// DOCME
|
||||
wxTextCtrl *OutputFramerate;
|
||||
|
||||
/// DOCME
|
||||
wxRadioButton *RadioOutputCFR;
|
||||
|
||||
/// DOCME
|
||||
wxRadioButton *RadioOutputVFR;
|
||||
|
||||
/// DOCME
|
||||
wxCheckBox *Reverse;
|
||||
wxCheckBox *Reverse; /// Switch input and output
|
||||
|
||||
/// Constructor
|
||||
AssTransformFramerateFilter();
|
||||
|
||||
/// @brief Apply the transformation to a file
|
||||
/// @param subs File to process
|
||||
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();
|
||||
|
||||
/// @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:
|
||||
void ProcessSubs(AssFile *subs, wxWindow *export_dialog);
|
||||
wxWindow *GetConfigDialogWindow(wxWindow *parent);
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -53,53 +50,36 @@
|
|||
|
||||
|
||||
/// @brief V2 Clear function
|
||||
///
|
||||
void FrameRate::Clear () {
|
||||
Frame.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief V2 Add frame
|
||||
/// @param ms
|
||||
///
|
||||
void FrameRate::AddFrame(int ms) {
|
||||
Frame.push_back(ms);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief V2 Get Average
|
||||
///
|
||||
void FrameRate::CalcAverage() {
|
||||
|
||||
if (Frame.size() <= 1)
|
||||
throw _("No timecodes to average");
|
||||
|
||||
AverageFrameRate = double(Frame.back()) / (Frame.size()-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Constructor FrameRate //////////////////////
|
||||
///
|
||||
/// @brief Constructor
|
||||
FrameRate::FrameRate() {
|
||||
Unload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
FrameRate::~FrameRate() {
|
||||
Unload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Loads VFR file
|
||||
/// @param filename
|
||||
///
|
||||
void FrameRate::Load(wxString filename) {
|
||||
using namespace std;
|
||||
|
||||
|
@ -241,11 +221,8 @@ void FrameRate::Load(wxString filename) {
|
|||
config::mru->Add("Timecodes", STD_STR(filename));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Save
|
||||
/// @param filename
|
||||
///
|
||||
void FrameRate::Save(wxString filename) {
|
||||
TextFileWriter file(filename,_T("ASCII"));
|
||||
file.WriteLineToFile(_T("# timecode format v2"));
|
||||
|
@ -254,10 +231,7 @@ void FrameRate::Save(wxString filename) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Unload
|
||||
///
|
||||
void FrameRate::Unload () {
|
||||
FrameRateType = NONE;
|
||||
AverageFrameRate = 0;
|
||||
|
@ -268,11 +242,8 @@ void FrameRate::Unload () {
|
|||
vfrFile = _T("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Sets to CFR
|
||||
/// @param fps
|
||||
///
|
||||
void FrameRate::SetCFR(double fps) {
|
||||
Unload();
|
||||
loaded = true;
|
||||
|
@ -280,13 +251,9 @@ void FrameRate::SetCFR(double fps) {
|
|||
AverageFrameRate = fps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Sets to VFR
|
||||
/// @param newTimes
|
||||
///
|
||||
void FrameRate::SetVFR(std::vector<int> newTimes) {
|
||||
// Prepare
|
||||
Unload();
|
||||
|
||||
loaded = true;
|
||||
|
@ -299,22 +266,16 @@ void FrameRate::SetVFR(std::vector<int> newTimes) {
|
|||
last_frame = (int)newTimes.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Gets frame number at time
|
||||
/// @param ms
|
||||
/// @param useceil
|
||||
/// @return
|
||||
///
|
||||
int FrameRate::PFrameAtTime(int ms,bool useceil) {
|
||||
int FrameRate::PFrameAtTime(int ms,bool useceil) const {
|
||||
// Check if it's loaded
|
||||
if (!loaded) return -1;
|
||||
|
||||
// Normalize miliseconds
|
||||
ms = MAX(ms,0);
|
||||
|
||||
// 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;
|
||||
if (useceil) return (int)ceil(value);
|
||||
else return (int)floor(value);
|
||||
|
@ -366,13 +327,10 @@ int FrameRate::PFrameAtTime(int ms,bool useceil) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Gets time at frame
|
||||
/// @param frame
|
||||
/// @return
|
||||
///
|
||||
int FrameRate::PTimeAtFrame(int frame) {
|
||||
int FrameRate::PTimeAtFrame(int frame) const {
|
||||
// Not loaded
|
||||
if (!loaded) return -1;
|
||||
|
||||
|
@ -397,26 +355,20 @@ int FrameRate::PTimeAtFrame(int frame) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief otherwise for start frames returns the adjusted time for end frames when start=false Get correct frame at time
|
||||
/// @param ms
|
||||
/// @param start
|
||||
/// @return
|
||||
///
|
||||
int FrameRate::GetFrameAtTime(int ms,bool start) {
|
||||
int FrameRate::GetFrameAtTime(int ms,bool start) const {
|
||||
return PFrameAtTime(ms,start);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief compensates and returns an end time when start=false Get correct time at frame
|
||||
/// @param frame
|
||||
/// @param start
|
||||
/// @param exact
|
||||
/// @param frame Frame number
|
||||
/// @param start Adjust for start time
|
||||
/// @param exact Don't do awful things to avoid rounding errors
|
||||
/// @return
|
||||
///
|
||||
int FrameRate::GetTimeAtFrame(int frame,bool start,bool exact) {
|
||||
int FrameRate::GetTimeAtFrame(int frame,bool start,bool exact) const {
|
||||
int finalTime;
|
||||
|
||||
// Exact, for display
|
||||
|
@ -439,121 +391,21 @@ int FrameRate::GetTimeAtFrame(int frame,bool start,bool exact) {
|
|||
return finalTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get the current list of frames/times
|
||||
/// @return
|
||||
///
|
||||
std::vector<int> FrameRate::GetFrameTimeList() {
|
||||
std::vector<int> FrameRate::GetFrameTimeList() const {
|
||||
return Frame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief e.g., in a mix of 24fps and 30fps, returns 120fps Calculate the common FPS for evil stuff
|
||||
/// @return
|
||||
///
|
||||
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();
|
||||
bool FrameRate::operator==(FrameRate const& rgt) {
|
||||
if (FrameRateType != rgt.FrameRateType) return false;
|
||||
if (FrameRateType == NONE) return true;
|
||||
if (FrameRateType == CFR) return AverageFrameRate == rgt.AverageFrameRate;
|
||||
return Frame == rgt.Frame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
FrameRate VFR_Output;
|
||||
|
||||
/// DOCME
|
||||
FrameRate VFR_Input;
|
||||
|
||||
|
||||
|
|
|
@ -42,9 +42,6 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
@ -53,19 +50,10 @@
|
|||
#include <wx/string.h>
|
||||
#endif
|
||||
|
||||
#include "include/aegisub/aegisub.h"
|
||||
|
||||
|
||||
/// DOCME
|
||||
enum ASS_FrameRateType {
|
||||
|
||||
/// DOCME
|
||||
NONE,
|
||||
|
||||
/// DOCME
|
||||
CFR,
|
||||
|
||||
/// DOCME
|
||||
VFR
|
||||
};
|
||||
|
||||
|
@ -97,8 +85,8 @@ private:
|
|||
void Clear();
|
||||
|
||||
void CalcAverage();
|
||||
int PFrameAtTime(int ms,bool useCeil=false);
|
||||
int PTimeAtFrame(int frame);
|
||||
int PFrameAtTime(int ms,bool useCeil=false) const;
|
||||
int PTimeAtFrame(int frame) const;
|
||||
|
||||
|
||||
/// DOCME
|
||||
|
@ -122,37 +110,33 @@ public:
|
|||
void Save(wxString file);
|
||||
void Unload();
|
||||
|
||||
int GetFrameAtTime(int ms,bool start=true);
|
||||
int GetTimeAtFrame(int frame,bool start=true,bool exact=false);
|
||||
int GetFrameAtTime(int ms,bool start=true) const;
|
||||
int GetTimeAtFrame(int frame,bool start=true,bool exact=false) const;
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
double GetAverage() { return AverageFrameRate; };
|
||||
double GetAverage() const { return AverageFrameRate; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool IsLoaded() { return loaded; };
|
||||
bool IsLoaded() const { return loaded; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
ASS_FrameRateType GetFrameRateType() { return FrameRateType; };
|
||||
ASS_FrameRateType GetFrameRateType() const { return FrameRateType; };
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
wxString GetFilename() { return vfrFile; };
|
||||
wxString GetFilename() const { return vfrFile; };
|
||||
|
||||
std::vector<int> GetFrameTimeList();
|
||||
double GetCommonFPS();
|
||||
std::vector<int> GetFrameTimeList() const;
|
||||
|
||||
bool operator==(FrameRate const& rgt);
|
||||
};
|
||||
|
||||
|
||||
///////////
|
||||
// Globals
|
||||
extern FrameRate VFR_Output;
|
||||
extern FrameRate VFR_Input;
|
||||
|
||||
|
||||
|
|
|
@ -255,7 +255,6 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
// Read keyframes and timecodes from MKV file
|
||||
isVfr = false;
|
||||
FrameRate temp;
|
||||
double overFps = 0;
|
||||
bool mkvOpen = MatroskaWrapper::wrapper.IsOpen();
|
||||
KeyFrames.Clear();
|
||||
if (extension == _T(".mkv") || mkvOpen) {
|
||||
|
@ -273,7 +272,6 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
MatroskaWrapper::wrapper.SetToTimecodes(temp);
|
||||
isVfr = temp.GetFrameRateType() == VFR;
|
||||
if (isVfr) {
|
||||
overFps = temp.GetCommonFPS();
|
||||
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Input);
|
||||
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Output);
|
||||
trueFrameRate = temp;
|
||||
|
|
Loading…
Reference in a new issue