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
|
/// @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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue