Redesign export filters to not be static singletons, removing the need to jump through hoops to avoid static initialization order issues

Originally committed to SVN as r5258.
This commit is contained in:
Thomas Goyne 2011-01-21 06:09:04 +00:00
parent 83a461ca63
commit af92002d8c
11 changed files with 131 additions and 378 deletions

View file

@ -39,178 +39,53 @@
#include "ass_export_filter.h" #include "ass_export_filter.h"
#include "ass_file.h" #include "ass_file.h"
AssExportFilter::AssExportFilter(wxString const& name, wxString const& description, int priority)
/// @brief Constructor : name(name)
/// , priority(priority)
AssExportFilter::AssExportFilter() { , autoExporter(false)
hidden = false; , hidden(false)
autoExporter = false; , description(description)
initialized = false; {
FilterList *fil = AssExportFilterChain::GetUnpreparedFilterList();
fil->push_back(this);
} }
void AssExportFilterChain::Register(AssExportFilter *filter) {
/// @brief Destructor
///
AssExportFilter::~AssExportFilter() {
try {
Unregister();
}
catch (...) {
// Ignore error
}
}
/// @brief Register
/// @param name
/// @param priority
///
void AssExportFilter::Register (wxString name,int priority) {
// Check if it's registered
// Changed this to an assert, since this kind of error should really only happen during dev. -jfs
// (Actually the list of regged filters should rather be looped through and check that this object isn't in.)
assert(RegisterName == _T(""));
// Remove pipes from name // Remove pipes from name
name.Replace(_T("|"),_T("")); filter->name.Replace("|", "");
FilterList::iterator begin = GetFilterList()->begin();
FilterList::iterator end = GetFilterList()->end();
int filter_copy = 0; int filter_copy = 0;
wxString tmpnam; wxString tmpnam = filter->name;
if (filter_copy == 0) { if (false) {
tmpnam = name;
} else {
try_new_name: try_new_name:
tmpnam = wxString::Format(_T("%s (%d)"), name.c_str(), filter_copy); tmpnam = wxString::Format("%s (%d)", filter->name, filter_copy);
} }
// Check if name exists // Check if name exists
FilterList::iterator begin = AssExportFilterChain::GetFilterList()->begin();
FilterList::iterator end = AssExportFilterChain::GetFilterList()->end();
for (FilterList::iterator cur=begin;cur!=end;cur++) { for (FilterList::iterator cur=begin;cur!=end;cur++) {
if ((*cur)->RegisterName == tmpnam) { if ((*cur)->name == tmpnam) {
// Instead of just failing and making a big noise about it, let multiple filters share name, but append something to the later arrivals -jfs // Instead of just failing and making a big noise about it, let multiple filters share name, but append something to the later arrivals -jfs
filter_copy++; filter_copy++;
goto try_new_name; goto try_new_name;
} }
} }
// Set name filter->name = tmpnam;
RegisterName = tmpnam;
Priority = priority;
// Look for place to insert // Look for place to insert
bool inserted = false; while (begin != end && (*begin)->priority >= filter->priority) ++begin;
for (FilterList::iterator cur=begin;cur!=end;cur++) { GetFilterList()->insert(begin, filter);
if ((*cur)->Priority < Priority) {
AssExportFilterChain::GetFilterList()->insert(cur,this);
inserted = true;
break;
}
}
if (!inserted) AssExportFilterChain::GetFilterList()->push_back(this);
} }
void AssExportFilterChain::Unregister(AssExportFilter *filter) {
if (find(GetFilterList()->begin(), GetFilterList()->end(), filter) == GetFilterList()->end())
throw wxString::Format("Unregister export filter: name \"%s\" is not registered.", filter->name);
GetFilterList()->remove(filter);
/// @brief Unregister
///
void AssExportFilter::Unregister () {
// Check if it's registered
if (!IsRegistered()) throw wxString::Format(_T("Unregister export filter: name \"%s\" is not registered."), RegisterName.c_str());
// Unregister
RegisterName = _T("");
AssExportFilterChain::GetFilterList()->remove(this);
} }
/// @brief Checks if it's registered
/// @return
///
bool AssExportFilter::IsRegistered() {
// Check name
if (RegisterName.IsEmpty()) {
return false;
}
// Check list
bool found = false;
FilterList::iterator begin = AssExportFilterChain::GetFilterList()->begin();
FilterList::iterator end = AssExportFilterChain::GetFilterList()->end();
for (FilterList::iterator cur=begin;cur!=end;cur++) {
if ((*cur) == this) {
found = true;
break;
}
}
return found;
}
/// @brief Get sizer
/// @param parent
/// @return
///
wxWindow *AssExportFilter::GetConfigDialogWindow(wxWindow *parent) {
return NULL;
}
/// @brief Config dialog OK
/// @param IsDefault
///
void AssExportFilter::LoadSettings(bool IsDefault) {
}
/// @brief Description reader
/// @return
///
const wxString& AssExportFilter::GetDescription() const {
return description;
}
/// DOCME
std::auto_ptr<AssExportFilterChain> AssExportFilterChain::instance;
/// @brief Get list
/// @return
///
FilterList *AssExportFilterChain::GetFilterList() { FilterList *AssExportFilterChain::GetFilterList() {
if (!instance.get()) instance.reset(new AssExportFilterChain()); static FilterList instance;
return &(instance->Filters); return &instance;
}
/// @brief Get unprepared list
/// @return
///
FilterList *AssExportFilterChain::GetUnpreparedFilterList() {
if (!instance.get()) instance.reset(new AssExportFilterChain());
return &(instance->Unprepared);
}
/// @brief Prepare filters
///
void AssExportFilterChain::PrepareFilters() {
if (!instance.get()) instance.reset(new AssExportFilterChain());
for (FilterList::iterator cur=instance->Unprepared.begin();cur!=instance->Unprepared.end();cur++) {
(*cur)->Init();
}
instance->Unprepared.clear();
} }

View file

@ -58,24 +58,19 @@ typedef std::list<AssExportFilter*> FilterList;
/// ///
/// DOCME /// DOCME
class AssExportFilterChain { class AssExportFilterChain {
friend class AssExportFilter;
friend class AssExporter; friend class AssExporter;
private: /// The list of registered filters
/// DOCME
FilterList Filters; FilterList Filters;
/// DOCME /// Get the singleton instance
FilterList Unprepared;
/// DOCME
static std::auto_ptr<AssExportFilterChain> instance;
static FilterList *GetFilterList(); static FilterList *GetFilterList();
static FilterList *GetUnpreparedFilterList(); AssExportFilterChain() { }
public: public:
static void PrepareFilters(); /// Register an export filter
static void Register(AssExportFilter *filter);
/// Unregister an export filter; must have been registered
static void Unregister(AssExportFilter *filter);
}; };
/// DOCME /// DOCME
@ -87,41 +82,33 @@ class AssExportFilter {
friend class AssExporter; friend class AssExporter;
friend class AssExportFilterChain; friend class AssExportFilterChain;
private: /// This filter's name
wxString name;
/// DOCME /// Higher priority = run earlier
wxString RegisterName; int priority;
/// DOCME
int Priority;
protected: protected:
/// Should this filter be used when sending subtitles to the subtitle provider
/// DOCME
bool autoExporter; bool autoExporter;
/// DOCME /// Should this filter be hidden from the user
bool hidden; bool hidden;
/// DOCME /// User-visible description of this filter
bool initialized;
/// DOCME
wxString description; wxString description;
void Register(wxString name,int priority=0); // Register the filter with specific name. Higher priority filters get the file to process first.
void Unregister(); // Unregister the filter instance
bool IsRegistered(); // Is this instance registered as a filter?
virtual void Init()=0; // Tell it to initialize itself
public: public:
AssExportFilter(); AssExportFilter(wxString const& name, wxString const& description, int priority = 0);
virtual ~AssExportFilter(); virtual ~AssExportFilter() { };
const wxString& GetDescription() const; const wxString& GetDescription() const { return description; }
virtual void ProcessSubs(AssFile *subs, wxWindow *export_dialog=0)=0; // Process subtitles - this function must be overriden. /// Process subtitles
virtual wxWindow *GetConfigDialogWindow(wxWindow *parent); // Draw setup controls - this function may optionally be overridden. virtual void ProcessSubs(AssFile *subs, wxWindow *export_dialog=0)=0;
virtual void LoadSettings(bool IsDefault); // Config dialog is done - extract data now. /// Draw setup controls
virtual wxWindow *GetConfigDialogWindow(wxWindow *parent) { return 0; }
/// Config dialog is done - extract data now.
virtual void LoadSettings(bool IsDefault) { }
}; };

View file

@ -67,13 +67,13 @@ void AssExporter::DrawSettings(wxWindow *parent,wxSizer *AddTo) {
for (FilterList::iterator cur=begin;cur!=end;cur++) { for (FilterList::iterator cur=begin;cur!=end;cur++) {
// Make sure to construct static box sizer first, so it won't overlap // Make sure to construct static box sizer first, so it won't overlap
// the controls on wxMac. // the controls on wxMac.
box = new wxStaticBoxSizer(wxVERTICAL,parent,(*cur)->RegisterName); box = new wxStaticBoxSizer(wxVERTICAL,parent,(*cur)->name);
window = (*cur)->GetConfigDialogWindow(parent); window = (*cur)->GetConfigDialogWindow(parent);
if (window) { if (window) {
box->Add(window,0,wxEXPAND,0); box->Add(window,0,wxEXPAND,0);
AddTo->Add(box,0,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,5); AddTo->Add(box,0,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,5);
AddTo->Show(box,false); AddTo->Show(box,false);
Sizers[(*cur)->RegisterName] = box; Sizers[(*cur)->name] = box;
} }
else { else {
delete box; delete box;
@ -90,13 +90,14 @@ void AssExporter::AddFilter(wxString name) {
FilterList::iterator begin = AssExportFilterChain::GetFilterList()->begin(); FilterList::iterator begin = AssExportFilterChain::GetFilterList()->begin();
FilterList::iterator end = AssExportFilterChain::GetFilterList()->end(); FilterList::iterator end = AssExportFilterChain::GetFilterList()->end();
for (FilterList::iterator cur=begin;cur!=end;cur++) { for (FilterList::iterator cur=begin;cur!=end;cur++) {
if ((*cur)->RegisterName == name) { if ((*cur)->name == name) {
filter = *cur; filter = *cur;
break;
} }
} }
// Check // Check
if (!filter) throw wxString::Format(_T("Filter not found: %s"), name.c_str()); if (!filter) throw wxString::Format("Filter not found: %s", name.c_str());
// Add to list // Add to list
Filters.push_back(filter); Filters.push_back(filter);
@ -122,7 +123,7 @@ wxArrayString AssExporter::GetAllFilterNames() {
FilterList::iterator begin = AssExportFilterChain::GetFilterList()->begin(); FilterList::iterator begin = AssExportFilterChain::GetFilterList()->begin();
FilterList::iterator end = AssExportFilterChain::GetFilterList()->end(); FilterList::iterator end = AssExportFilterChain::GetFilterList()->end();
for (FilterList::iterator cur=begin;cur!=end;cur++) { for (FilterList::iterator cur=begin;cur!=end;cur++) {
if (!(*cur)->hidden) names.Add((*cur)->RegisterName); if (!(*cur)->hidden) names.Add((*cur)->name);
} }
return names; return names;
} }
@ -172,9 +173,9 @@ wxString AssExporter::GetDescription(wxString name) {
FilterList::iterator begin = AssExportFilterChain::GetFilterList()->begin(); FilterList::iterator begin = AssExportFilterChain::GetFilterList()->begin();
FilterList::iterator end = AssExportFilterChain::GetFilterList()->end(); FilterList::iterator end = AssExportFilterChain::GetFilterList()->end();
for (FilterList::iterator cur=begin;cur!=end;cur++) { for (FilterList::iterator cur=begin;cur!=end;cur++) {
if ((*cur)->RegisterName == name) { if ((*cur)->name == name) {
return (*cur)->GetDescription(); return (*cur)->GetDescription();
} }
} }
throw wxString::Format(_T("Filter not found: %s"), name.c_str()); throw wxString::Format("Filter not found: %s", name.c_str());
} }

View file

@ -291,11 +291,10 @@ namespace Automation4 {
/// ///
FeatureFilter::FeatureFilter(const wxString &_name, const wxString &_description, int _priority) FeatureFilter::FeatureFilter(const wxString &_name, const wxString &_description, int _priority)
: Feature(SCRIPTFEATURE_FILTER, _name) : Feature(SCRIPTFEATURE_FILTER, _name)
, AssExportFilter() , AssExportFilter(_name, _description, _priority)
, config_dialog(0) , config_dialog(0)
{ {
description = _description; // from AssExportFilter AssExportFilterChain::Register(this);
Register(_name, _priority);
} }
@ -303,7 +302,7 @@ namespace Automation4 {
/// ///
FeatureFilter::~FeatureFilter() FeatureFilter::~FeatureFilter()
{ {
Unregister(); AssExportFilterChain::Unregister(this);
} }

View file

@ -34,9 +34,6 @@
/// @ingroup export /// @ingroup export
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#include "ass_dialogue.h" #include "ass_dialogue.h"
@ -44,33 +41,12 @@
#include "ass_override.h" #include "ass_override.h"
#include "export_clean_info.h" #include "export_clean_info.h"
AssTransformCleanInfoFilter::AssTransformCleanInfoFilter()
/// @brief Constructor : AssExportFilter(_("Clean Script Info"), _("Removes all but the absolutely required fields from the Script Info section. You might want to run this on files that you plan to distribute in original form."))
/// {
AssTransformCleanInfoFilter::AssTransformCleanInfoFilter() {
initialized = false;
} }
void AssTransformCleanInfoFilter::ProcessSubs(AssFile *subs, wxWindow *) {
/// @brief Init
/// @return
///
void AssTransformCleanInfoFilter::Init() {
if (initialized) return;
initialized = true;
autoExporter = false;
Register(_("Clean Script Info"),0);
description = _("Removes all but the absolutely required fields from the Script Info section. You might want to run this on files that you plan to distribute in original form.");
}
/// @brief Process
/// @param subs
/// @param export_dialog
///
void AssTransformCleanInfoFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) {
using std::list; using std::list;
AssEntry *curEntry; AssEntry *curEntry;
entryIter cur, next = subs->Line.begin(); entryIter cur, next = subs->Line.begin();
@ -78,53 +54,28 @@ void AssTransformCleanInfoFilter::ProcessSubs(AssFile *subs, wxWindow *export_di
cur = next++; cur = next++;
curEntry = *cur; curEntry = *cur;
if (curEntry->group != _T("[Script Info]")) { if (curEntry->group != "[Script Info]") {
continue; continue;
} }
if (curEntry->GetEntryData().IsEmpty()) { if (curEntry->GetEntryData().empty()) {
continue; continue;
} }
if (curEntry->GetEntryData() == _T("[Script Info]")) { if (curEntry->GetEntryData() == "[Script Info]") {
continue; continue;
} }
if (curEntry->GetEntryData().Left(1) == _T(";")) { if (curEntry->GetEntryData().Left(1) == ";") {
continue; continue;
} }
wxString field = curEntry->GetEntryData().Left(curEntry->GetEntryData().Find(_T(':'))).Lower(); wxString field = curEntry->GetEntryData().Left(curEntry->GetEntryData().Find(_T(':'))).Lower();
if (field != _T("scripttype") && if (field != "scripttype" &&
field != _T("collisions") && field != "collisions" &&
field != _T("playresx") && field != "playresx" &&
field != _T("playresy") && field != "playresy" &&
field != _T("wrapstyle") && field != "wrapstyle" &&
field != _T("scaledborderandshadow")) { field != "scaledborderandshadow") {
delete curEntry; delete curEntry;
subs->Line.erase(cur); subs->Line.erase(cur);
} }
} }
} }
/// @brief Get dialog
/// @param parent
/// @return
///
wxWindow *AssTransformCleanInfoFilter::GetConfigDialogWindow(wxWindow *parent) {
return 0;
}
/// @brief Load settings
/// @param IsDefault
///
void AssTransformCleanInfoFilter::LoadSettings(bool IsDefault) {
}
/// DOCME
AssTransformCleanInfoFilter AssTransformCleanInfoFilter::instance;

View file

@ -34,32 +34,16 @@
/// @ingroup export /// @ingroup export
/// ///
///////////
// Headers
#include "ass_export_filter.h" #include "ass_export_filter.h"
/// DOCME /// DOCME
/// @class AssTransformCleanInfoFilter /// @class AssTransformCleanInfoFilter
/// @brief DOCME /// @brief Removes all but the absolutely required fields from the Script Info section
/// ///
/// DOCME /// DOCME
class AssTransformCleanInfoFilter : public AssExportFilter { class AssTransformCleanInfoFilter : public AssExportFilter {
private:
/// DOCME
static AssTransformCleanInfoFilter instance;
AssTransformCleanInfoFilter();
void Init();
public: public:
void ProcessSubs(AssFile *subs, wxWindow *export_dialog); void ProcessSubs(AssFile *subs, wxWindow *export_dialog);
wxWindow *GetConfigDialogWindow(wxWindow *parent); AssTransformCleanInfoFilter();
void LoadSettings(bool IsDefault);
}; };

View file

@ -46,37 +46,22 @@
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_style.h" #include "ass_style.h"
/// @brief Constructor AssFixStylesFilter::AssFixStylesFilter()
AssFixStylesFilter::AssFixStylesFilter() { : AssExportFilter(_("Fix Styles"), _("Fixes styles by replacing any style that isn't available on file with Default."), -5000)
initialized = false; {
}
/// @brief Init
void AssFixStylesFilter::Init() {
if (initialized) return;
initialized = true;
autoExporter = true; autoExporter = true;
Register(_("Fix Styles"),-5000);
description = _("Fixes styles by replacing any style that isn't available on file with Default.");
} }
/// @brief Process void AssFixStylesFilter::ProcessSubs(AssFile *subs, wxWindow *) {
/// @param subs
/// @param export_dialog
void AssFixStylesFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) {
wxArrayString styles = subs->GetStyles(); wxArrayString styles = subs->GetStyles();
std::for_each(styles.begin(), styles.end(), std::mem_fun_ref(&wxString::MakeLower)); for_each(styles.begin(), styles.end(), std::mem_fun_ref(&wxString::MakeLower));
styles.Sort(); styles.Sort();
for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) {
AssDialogue *diag = dynamic_cast<AssDialogue*>(*cur); if (AssDialogue *diag = dynamic_cast<AssDialogue*>(*cur)) {
if (diag) {
if (!std::binary_search(styles.begin(), styles.end(), diag->Style.Lower())) { if (!std::binary_search(styles.begin(), styles.end(), diag->Style.Lower())) {
diag->Style = L"Default"; diag->Style = "Default";
} }
} }
} }
} }
/// DOCME
AssFixStylesFilter AssFixStylesFilter::instance;

View file

@ -34,29 +34,18 @@
/// @ingroup export /// @ingroup export
/// ///
///////////
// Headers
#include "ass_export_filter.h" #include "ass_export_filter.h"
/// DOCME /// DOCME
/// @class AssFixStylesFilter /// @class AssFixStylesFilter
/// @brief DOCME /// @brief Fixes styles by replacing any style that isn't available on file with Default
/// ///
/// DOCME /// DOCME
class AssFixStylesFilter : public AssExportFilter { class AssFixStylesFilter : public AssExportFilter {
private:
/// DOCME
static AssFixStylesFilter instance;
AssFixStylesFilter();
void Init();
public: public:
void ProcessSubs(AssFile *subs, wxWindow *export_dialog); void ProcessSubs(AssFile *subs, wxWindow *export_dialog);
AssFixStylesFilter();
}; };

View file

@ -55,36 +55,16 @@
#include "utils.h" #include "utils.h"
#include "video_context.h" #include "video_context.h"
/// DOCME
/// @class LineData
/// @brief DOCME
///
/// DOCME
struct LineData {
AssDialogue *line;
int newStart;
int newEnd;
int newK;
int oldK;
};
/// IDs /// IDs
enum { enum {
Get_Input_From_Video = 2000 Get_Input_From_Video = 2000
}; };
AssTransformFramerateFilter::AssTransformFramerateFilter() { AssTransformFramerateFilter::AssTransformFramerateFilter()
initialized = false; : AssExportFilter(_("Transform Framerate"), _("Transform subtitle times, including those in override tags, from an input framerate to an output framerate.\n\nThis is useful for converting regular time subtitles to VFRaC time subtitles for hardsubbing.\nIt can also be used to convert subtitles to a different speed video, such as NTSC to PAL speedup."), 1000)
} , Input(0)
, Output(0)
void AssTransformFramerateFilter::Init() { {
if (initialized) return;
initialized = true;
autoExporter = true;
Register(_("Transform Framerate"),1000);
description = _("Transform subtitle times, including those in override tags, from an input framerate to an output framerate.\n\nThis is useful for converting regular time subtitles to VFRaC time subtitles for hardsubbing.\nIt can also be used to convert subtitles to a different speed video, such as NTSC to PAL speedup.");
Input = NULL;
Output = NULL;
} }
void AssTransformFramerateFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) { void AssTransformFramerateFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) {
@ -100,9 +80,10 @@ wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent) {
wxSizer *InputSizer = new wxBoxSizer(wxHORIZONTAL); wxSizer *InputSizer = new wxBoxSizer(wxHORIZONTAL);
wxString initialInput; wxString initialInput;
wxButton *FromVideo = new wxButton(base,Get_Input_From_Video,_("From Video")); wxButton *FromVideo = new wxButton(base,Get_Input_From_Video,_("From Video"));
if (Input->IsLoaded()) initialInput = wxString::Format(_T("%2.3f"),Input->FPS()); if (Input->IsLoaded())
initialInput = wxString::Format("%2.3f",Input->FPS());
else { else {
initialInput = _T("23.976"); initialInput = "23.976";
FromVideo->Enable(false); FromVideo->Enable(false);
} }
InputFramerate = new wxTextCtrl(base,-1,initialInput,wxDefaultPosition,wxSize(60,20)); InputFramerate = new wxTextCtrl(base,-1,initialInput,wxDefaultPosition,wxSize(60,20));
@ -179,18 +160,18 @@ int FORCEINLINE trunc_cs(int time) {
return (time / 10) * 10; return (time / 10) * 10;
} }
void AssTransformFramerateFilter::TransformTimeTags (wxString name,int n,AssOverrideParameter *curParam,void *curData) { void AssTransformFramerateFilter::TransformTimeTags(wxString name,int n,AssOverrideParameter *curParam,void *curData) {
VariableDataType type = curParam->GetType(); VariableDataType type = curParam->GetType();
if (type != VARDATA_INT && type != VARDATA_FLOAT) return; if (type != VARDATA_INT && type != VARDATA_FLOAT) return;
LineData *lineData = static_cast<LineData*>(curData); AssTransformFramerateFilter *instance = static_cast<AssTransformFramerateFilter*>(curData);
AssDialogue *curDiag = lineData->line; AssDialogue *curDiag = instance->line;
int parVal = curParam->Get<int>(); int parVal = curParam->Get<int>();
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; int value = instance->ConvertTime(trunc_cs(curDiag->Start.GetMS()) + parVal) - instance->newStart;
// An end time of 0 is actually the end time of the line, so ensure // An end time of 0 is actually the end time of the line, so ensure
// nonzero is never converted to 0 // nonzero is never converted to 0
@ -202,13 +183,13 @@ void AssTransformFramerateFilter::TransformTimeTags (wxString name,int n,AssOver
break; break;
} }
case PARCLASS_RELATIVE_TIME_END: case PARCLASS_RELATIVE_TIME_END:
curParam->Set(lineData->newEnd - instance.ConvertTime(trunc_cs(curDiag->End.GetMS()) - parVal)); curParam->Set(instance->newEnd - instance->ConvertTime(trunc_cs(curDiag->End.GetMS()) - parVal));
break; break;
case PARCLASS_KARAOKE: { case PARCLASS_KARAOKE: {
int start = curDiag->Start.GetMS() / 10 + lineData->oldK + parVal; int start = curDiag->Start.GetMS() / 10 + instance->oldK + parVal;
int value = (instance.ConvertTime(start * 10) - lineData->newStart) / 10 - lineData->newK; int value = (instance->ConvertTime(start * 10) - instance->newStart) / 10 - instance->newK;
lineData->oldK += parVal; instance->oldK += parVal;
lineData->newK += value; instance->newK += value;
curParam->Set(value); curParam->Set(value);
break; break;
} }
@ -223,18 +204,17 @@ void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
AssDialogue *curDialogue = dynamic_cast<AssDialogue*>(*cur); AssDialogue *curDialogue = dynamic_cast<AssDialogue*>(*cur);
if (curDialogue) { if (curDialogue) {
LineData data; line = curDialogue;
data.line = curDialogue; newK = 0;
data.newK = 0; oldK = 0;
data.oldK = 0; newStart = trunc_cs(ConvertTime(curDialogue->Start.GetMS()));
data.newStart = trunc_cs(ConvertTime(curDialogue->Start.GetMS())); newEnd = trunc_cs(ConvertTime(curDialogue->End.GetMS()) + 9);
data.newEnd = trunc_cs(ConvertTime(curDialogue->End.GetMS()) + 9);
// Process stuff // Process stuff
curDialogue->ParseASSTags(); curDialogue->ParseASSTags();
curDialogue->ProcessParameters(TransformTimeTags,&data); curDialogue->ProcessParameters(TransformTimeTags, this);
curDialogue->Start.SetMS(data.newStart); curDialogue->Start.SetMS(newStart);
curDialogue->End.SetMS(data.newEnd); curDialogue->End.SetMS(newEnd);
curDialogue->UpdateText(); curDialogue->UpdateText();
curDialogue->ClearBlocks(); curDialogue->ClearBlocks();
} }
@ -254,5 +234,3 @@ int AssTransformFramerateFilter::ConvertTime(int time) {
return newStart + newDur * dist; return newStart + newDur * dist;
} }
AssTransformFramerateFilter AssTransformFramerateFilter::instance;

View file

@ -45,27 +45,27 @@ class wxTextCtrl;
/// DOCME /// DOCME
/// @class AssTransformFramerateFilter /// @class AssTransformFramerateFilter
/// @brief DOCME /// @brief Transform subtitle times, including those in override tags, from an input framerate to an output framerate
class AssTransformFramerateFilter : public AssExportFilter { class AssTransformFramerateFilter : public AssExportFilter {
/// The singleton instance of this filter AssDialogue *line;
static AssTransformFramerateFilter instance; int newStart;
int newEnd;
int newK;
int oldK;
// Yes, these are backwards // Yes, these are backwards
const agi::vfr::Framerate *Input; /// Destination frame rate const agi::vfr::Framerate *Input; ///< Destination frame rate
const agi::vfr::Framerate *Output; /// Source frame rate const agi::vfr::Framerate *Output; ///< Source frame rate
agi::vfr::Framerate t1,t2; agi::vfr::Framerate t1,t2;
wxTextCtrl *InputFramerate; /// Input frame rate text box wxTextCtrl *InputFramerate; ///< Input frame rate text box
wxTextCtrl *OutputFramerate; /// Output frame rate text box wxTextCtrl *OutputFramerate; ///< Output frame rate text box
wxRadioButton *RadioOutputCFR; /// CFR radio control wxRadioButton *RadioOutputCFR; ///< CFR radio control
wxRadioButton *RadioOutputVFR; /// VFR radio control wxRadioButton *RadioOutputVFR; ///< VFR radio control
wxCheckBox *Reverse; /// Switch input and output wxCheckBox *Reverse; ///< Switch input and output
/// Constructor
AssTransformFramerateFilter();
/// @brief Apply the transformation to a file /// @brief Apply the transformation to a file
/// @param subs File to process /// @param subs File to process
@ -73,10 +73,8 @@ class AssTransformFramerateFilter : public AssExportFilter {
/// @brief Transform a single tag /// @brief Transform a single tag
/// @param name Name of the tag /// @param name Name of the tag
/// @param curParam Current parameter being processed /// @param curParam Current parameter being processed
/// @param userdata LineData passed /// @param userdata Filter instance
static void TransformTimeTags(wxString name,int,AssOverrideParameter *curParam,void *userdata); 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 /// @brief Convert a time from the input frame rate to the output frame rate
/// @param time Time in ms to convert /// @param time Time in ms to convert
@ -88,6 +86,8 @@ class AssTransformFramerateFilter : public AssExportFilter {
/// is in and the beginning of the next frame /// is in and the beginning of the next frame
int ConvertTime(int time); int ConvertTime(int time);
public: public:
/// Constructor
AssTransformFramerateFilter();
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);

View file

@ -67,6 +67,8 @@
#endif #endif
#include "charset_conv.h" #include "charset_conv.h"
#include "compat.h" #include "compat.h"
#include "export_clean_info.h"
#include "export_fixstyle.h"
#include "export_framerate.h" #include "export_framerate.h"
#include "frame_main.h" #include "frame_main.h"
#include "main.h" #include "main.h"
@ -285,8 +287,10 @@ bool AegisubApp::OnInit() {
#endif #endif
// Load export filters // Load export filters
StartupLog(_T("Prepare export filters")); StartupLog(L"Register export filters");
AssExportFilterChain::PrepareFilters(); AssExportFilterChain::Register(new AssFixStylesFilter);
AssExportFilterChain::Register(new AssTransformCleanInfoFilter);
AssExportFilterChain::Register(new AssTransformFramerateFilter);
// Get parameter subs // Get parameter subs
StartupLog(_T("Parse command line")); StartupLog(_T("Parse command line"));