Move the SMPTE timecode stuff out of the AssTime class and put it in a class of its own, FractionalTime. The AssTime to SMPTE part is tested and verified to work (in fact it looks like I unintentionally fixed an overlap bug in the TranStation export filter), while the SMPTE to AssTime part is completely untested (but it's currently not used anywhere so it's not like it matters).

Originally committed to SVN as r2909.
This commit is contained in:
Karl Blomster 2009-05-10 03:50:58 +00:00
parent 61a3c5657a
commit ebcdf0ce46
4 changed files with 97 additions and 15 deletions

View file

@ -38,6 +38,7 @@
// Includes // Includes
#include "config.h" #include "config.h"
#include <wx/regex.h>
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#include "ass_time.h" #include "ass_time.h"
@ -244,15 +245,6 @@ wxString AssTime::GetSRTFormated () {
} }
///////////////////
// SMPTE formatted
wxString AssTime::GetSMPTE(double fps)
{
int f = int(GetTimeMiliseconds() * fps / 1000.0);
return wxString::Format(_T("%02i:%02i:%02i:%02i"),GetTimeHours(),GetTimeMinutes(),GetTimeSeconds(),f);
}
////////////////////// //////////////////////
// AssTime comparison // AssTime comparison
bool operator < (AssTime &t1, AssTime &t2) { bool operator < (AssTime &t1, AssTime &t2) {
@ -292,3 +284,69 @@ int AssTime::GetTimeMinutes() { return (time % 3600000)/60000; }
int AssTime::GetTimeSeconds() { return (time % 60000)/1000; } int AssTime::GetTimeSeconds() { return (time % 60000)/1000; }
int AssTime::GetTimeMiliseconds() { return (time % 1000); } int AssTime::GetTimeMiliseconds() { return (time % 1000); }
int AssTime::GetTimeCentiseconds() { return (time % 1000)/10; } int AssTime::GetTimeCentiseconds() { return (time % 1000)/10; }
FractionalTime::FractionalTime (wxString separator, double numerator, double denominator) {
num = numerator;
den = denominator;
sep = separator;
// fractions < 1 are not welcome here
if ((num <= 0 || den <= 0) || (num < den))
throw _T("FractionalTime: nonsensical enumerator or denominator");
if (sep.IsEmpty())
throw _T("FractionalTime: no separator specified");
}
FractionalTime::~FractionalTime () {
sep.Clear();
}
int64_t FractionalTime::ToMillisecs (wxString _text) {
wxString text = _text;
wxString re_str = _T("");
wxString sep_e = _T("\\") + sep; // escape this just in case it may be a reserved regex character
text.Trim(false);
text.Trim(true);
long h=0,m=0,s=0,ms=0,f=0;
// hour minute second fraction
re_str << _T("(\\d+)") << sep_e << _T("(\\d+)") << sep_e << _T("(\\d+)") << sep_e << _T("(\\d+)");
wxRegEx re(re_str, wxRE_ADVANCED);
if (!re.IsValid())
throw _T("FractionalTime: regex failure");
if (!re.Matches(text))
return 0; // FIXME: throw here too?
re.GetMatch(text, 1).ToLong(&h);
re.GetMatch(text, 2).ToLong(&m);
re.GetMatch(text, 3).ToLong(&s);
re.GetMatch(text, 4).ToLong(&f);
// FIXME: find out how to do this in a sane way
//if ((double)f >= ((double)num/(double)den) // overflow?
// f = (num/den - 1);
ms = long((1000.0 / (num/den)) * (double)f);
return (int64_t)((h * 3600000) + (m * 60000) + (s * 1000) + ms);
}
AssTime FractionalTime::ToAssTime (wxString _text) {
AssTime time;
time.SetMS((int)ToMillisecs(_text));
return time;
}
wxString FractionalTime::FromAssTime(AssTime time) {
return FromMillisecs((int64_t)time.GetMS());
}
wxString FractionalTime::FromMillisecs(int64_t msec) {
int h = msec / 3600000;
int m = (msec % 3600000)/60000;
int s = (msec % 60000)/1000;
int f = int((msec % 1000) * ((num/den) / 1000.0));
return wxString::Format(_T("%02i") + sep + _T("%02i") + sep + _T("%02i") + sep + _T("%02i"),h,m,s,f);
}

View file

@ -41,6 +41,7 @@
// Headers // Headers
#include <wx/wxprec.h> #include <wx/wxprec.h>
#include <wx/string.h> #include <wx/string.h>
#include <stdint.h>
///////////////////////////// /////////////////////////////
@ -66,7 +67,6 @@ public:
void ParseSRT(const wxString text); // Sets value to text-form time, in SRT format void ParseSRT(const wxString text); // Sets value to text-form time, in SRT format
wxString GetASSFormated(bool ms=false); // Returns the ASS representation of time wxString GetASSFormated(bool ms=false); // Returns the ASS representation of time
wxString GetSRTFormated(); // Returns the SRT representation of time wxString GetSRTFormated(); // Returns the SRT representation of time
wxString GetSMPTE(double fps); // Returns the SMPTE timecodes for the given frame rate
}; };
// Comparison operators // Comparison operators
@ -76,3 +76,24 @@ bool operator < (AssTime &t1, AssTime &t2);
bool operator > (AssTime &t1, AssTime &t2); bool operator > (AssTime &t1, AssTime &t2);
bool operator <= (AssTime &t1, AssTime &t2); bool operator <= (AssTime &t1, AssTime &t2);
bool operator >= (AssTime &t1, AssTime &t2); bool operator >= (AssTime &t1, AssTime &t2);
/////////////////////////////
// Class for that annoying SMPTE format timecodes stuff
class FractionalTime {
private:
int64_t time; // milliseconds, like in AssTime
double num, den; // numerator/denominator
wxString sep; // separator; someone might have separators of more than one character :V
public:
// dumb assumption? I give no fuck
FractionalTime(wxString separator, double numerator=30.0, double denominator=1.0);
~FractionalTime();
AssTime ToAssTime(wxString fractime);
int64_t ToMillisecs(wxString fractime);
wxString FromAssTime(AssTime time);
wxString FromMillisecs(int64_t msec);
};

View file

@ -87,14 +87,15 @@ void EncoreSubtitleFormat::WriteFile(wxString _filename,wxString encoding) {
// Write lines // Write lines
using std::list; using std::list;
int i = 0; int i = 0;
// Encore wants ; instead of : if we're dealing with NTSC
FractionalTime fp(fps > 26.0 ? _T(";") : _T(":"), fps);
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) { for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
AssDialogue *current = AssEntry::GetAsDialogue(*cur); AssDialogue *current = AssEntry::GetAsDialogue(*cur);
if (current && !current->Comment) { if (current && !current->Comment) {
// Time stamps // Time stamps
wxString timeStamps = wxString::Format(_T("%i "),++i) + current->Start.GetSMPTE(fps) + _T(" ") + current->End.GetSMPTE(fps); wxString timeStamps = wxString::Format(_T("%i "),++i) + fp.FromAssTime(current->Start) + _T(" ") + fp.FromAssTime(current->End);
// Convert : to ; if it's NTSC
if (fps > 26.0) timeStamps.Replace(_T(":"),_T(";"));
// Write // Write
file.WriteLineToFile(timeStamps + current->Text); file.WriteLineToFile(timeStamps + current->Text);

View file

@ -41,6 +41,7 @@
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "ass_style.h" #include "ass_style.h"
#include "ass_time.h"
#include "subtitle_format_transtation.h" #include "subtitle_format_transtation.h"
#include "text_file_writer.h" #include "text_file_writer.h"
#include <stdio.h> #include <stdio.h>
@ -115,7 +116,8 @@ void TranStationSubtitleFormat::WriteFile(wxString _filename,wxString encoding)
// and we otherwise run the risk of having two lines overlap in a // and we otherwise run the risk of having two lines overlap in a
// frame, when they should run right into each other. // frame, when they should run right into each other.
end.SetMS(end.GetMS() - (int)(500.0/fps)); end.SetMS(end.GetMS() - (int)(500.0/fps));
wxString header = wxString::Format(_T("SUB[%i%s%s "),valign,halign,type) + start.GetSMPTE(fps) + _T(">") + end.GetSMPTE(fps) + _T("]"); FractionalTime ft(_T(":"),fps);
wxString header = wxString::Format(_T("SUB[%i%s%s "),valign,halign,type) + ft.FromAssTime(start) + _T(">") + ft.FromAssTime(end) + _T("]");
file.WriteLineToFile(header); file.WriteLineToFile(header);
// Process text // Process text