📄 dvdsubber-compile.cpp
字号:
/***********************************************************************
Copyright 2002 Ben Rudiak-Gould.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
or visit <http://www.gnu.org/copyleft/gpl.html>.
***********************************************************************/
#include <string.h>
#include "DVDSubber-compile.h"
#include "DVDSubber-format.h"
#include "DVDSubber-render.h"
#include "DVDSubber-encode.h"
#include <algorithm>
using namespace std;
template<class T> static inline T Min(T a, T b) { return a<b?a:b; }
template<class T> static inline T Max(T a, T b) { return a<b?b:a; }
ICompilerCallbacks* g_compiler_callbacks;
/********************************************************************
********************************************************************/
class DataVectorBase {
protected:
unsigned char* data;
unsigned len;
public:
DataVectorBase() { data = 0; len = 0; }
~DataVectorBase() { delete[] data; }
void grow();
};
void DataVectorBase::grow() {
unsigned new_len = len ? len*2 : 4096;
unsigned char* new_data = new unsigned char[new_len];
memcpy(new_data, data, len);
delete[] data;
data = new_data;
len = new_len;
}
template<class T>
class DataVector : public DataVectorBase {
unsigned n;
public:
DataVector() { n = 0; }
unsigned size() const { return n; }
T* begin() { return (T*)data; }
T* end() { return (T*)data + n; }
void push_back(const T& datum) {
if ((n+1)*sizeof(T) > len)
grow();
((T*)data)[n++] = datum;
}
};
/********************************************************************
********************************************************************/
const wchar_t UNICODE_REPLACEMENT = 0xFFFD;
int UTF8toUTF16(wchar_t* dst, const char* _src) {
const unsigned char* src = (const unsigned char*)_src;
int dst_pos = 0;
for (;;) {
unsigned char ch = *src++;
if (ch < 0x80) {
dst[dst_pos] = ch;
if (ch == 0) {
break;
}
++dst_pos;
} else if (ch < 0xC0) {
dst[dst_pos++] = UNICODE_REPLACEMENT;
} else {
unsigned uch = ch;
int additional = 0;
while (*src >= 0x80 && *src < 0xC0) {
uch = (uch << 6) + (*src & 63);
++src;
++additional;
}
unsigned mask_bits = 32 - 6 - additional*5;
uch &= 0xFFFFFFFFU >> mask_bits;
unsigned minimum_for_this_encoding = (0x8000000 >> mask_bits);
static const unsigned char first_byte_range[] = { 0xC0, 0xE0, 0xF0, 0xF8 };
if (additional < 1 || additional > 3
|| ch < first_byte_range[additional-1]
|| ch >= first_byte_range[additional]
|| uch < 0x80 || uch < minimum_for_this_encoding
|| (uch >= 0xD800 && uch < 0xE000)
|| uch > 0x10FFFF)
{
uch = UNICODE_REPLACEMENT;
}
if (uch < 0x10000) {
dst[dst_pos] = (wchar_t)uch;
} else {
uch -= 0x10000;
dst[dst_pos++] = 0xD800 + (uch >> 10);
dst[dst_pos] = 0xDC00 + (uch & 1023);
}
++dst_pos;
}
}
return dst_pos;
}
/********************************************************************
********************************************************************/
class Subber {
struct Macro {
Macro* next;
int type;
char* data;
};
struct Macros {
Macros* next;
char* name;
Macro* body;
};
Macros* macros;
Macro** recording;
wchar_t fontname[32];
int size;
bool bold, italic;
unsigned char textcolor, halocolor;
int linespacing;
int base_field;
int time0, time1, time2, time3;
int linealign, boxalign;
int boxleft, boxright, boxtop, boxbottom;
bool vertical;
bool on;
bool got_vts, got_font, got_size, got_color, got_textbox, got_at;
Drawable* boxen[30];
Drawable* lines;
Drawable* line;
int ColorLookup(unsigned c) {
unsigned alpha = c >> 24;
if (alpha == 0) return 0;
unsigned rgb = c & 0xFFFFFF;
int index = g_compiler_callbacks->ColorLookup(rgb);
if (index >= 0)
return index + alpha*16;
else
throw "too many colors";
}
void CloseBox() {
if (line) {
lines = lines ? new_TextLines(lines, line, linealign) : line;
line = 0;
}
if (lines) {
Drawable* box = new_TextBox(lines, boxleft, boxtop, boxright, boxbottom, linealign, boxalign, vertical);
for (int n=0; ; ++n) {
if (boxen[n]) {
box = new_TextBoxen(box, boxen[n]);
boxen[n] = 0;
} else {
boxen[n] = box;
break;
}
}
lines = 0;
}
}
public:
int error_line_no;
unsigned error_time;
Subber() {
error_line_no = 1;
error_time = 0;
macros = 0;
recording = 0;
base_field = 0;
bold = false;
italic = false;
linespacing = 0;
on = true;
got_at = got_textbox = got_color = got_size = got_font = false;
memset(boxen, 0, sizeof(boxen));
lines = 0;
line = 0;
}
~Subber() {
for (int i=0; i<30; ++i) {
delete boxen[i];
}
delete lines;
delete line;
}
int GetSegment(FILE* f, char* buf, int buflen);
void ParseText(char* bytes);
void ParseCmd(char* bytes);
void ParseLineBreak();
void ParseSegment(int type, char* bytebuf);
void ParseFile(FILE* f);
void CmdText(const wchar_t* text) {
if (!(got_vts & got_font & got_size & got_color & got_textbox & got_at))
throw "Must have <vts>, <font>, <size>, <color>, <box>, and <at> before the first text";
if (!on) return;
FontInfo* font = LoadFont(fontname, size, bold, italic);
// cast away const to fix broken gcc wcsdup prototype
Drawable* phrase = new_Text(wcsdup((wchar_t*)text), font, textcolor, halocolor, linespacing, time0, time1, time2, time3);
line = line ? new_TextLine(line, phrase) : phrase;
}
void CmdLineBreak() {
if (!on) return;
if (!line) {
CmdText(L"");
}
lines = lines ? new_TextLines(lines, line, linealign) : line;
line = 0;
}
void CmdVTS(const int* pvtsn, const wchar_t*) {
g_compiler_callbacks->SetVTSNumber(*pvtsn);
got_vts = true;
}
void CmdAngle(const int* pangle, const wchar_t*) {
g_compiler_callbacks->SetAngle(*pangle);
}
void CmdFont(const int*, const wchar_t* fontname) {
// check length!
if (wcslen(fontname) >= 32) {
throw "font name too long!";
} else {
wcscpy(this->fontname, fontname);
got_font = true;
}
}
void CmdSize(const int* psize, const wchar_t*) {
size = *psize;
got_size = true;
}
void CmdLinespacing(const int* pspacing, const wchar_t*) {
linespacing = *pspacing;
}
void CmdColor(const int* colors, const wchar_t*) {
textcolor = ColorLookup(colors[0]);
halocolor = ColorLookup(colors[1]);
got_color = true;
}
void CmdItalicOn(const int*, const wchar_t*) {
italic = true;
}
void CmdItalicOff(const int*, const wchar_t*) {
italic = false;
}
void CmdBoldOn(const int*, const wchar_t*) {
bold = true;
}
void CmdBoldOff(const int*, const wchar_t*) {
bold = false;
}
void CmdTextbox(const int* dims, const wchar_t* alignment);
void CmdFillbox(const int* args, const wchar_t*) {
}
void CmdBasefield(const int* pbase, const wchar_t*) {
base_field = *pbase;
}
void At(unsigned fadein_time, unsigned full_time, unsigned fadeout_time, unsigned off_time);
void CmdAt(const int* times, const wchar_t*);
void CmdFadeat(const int* times, const wchar_t*);
void CmdOn(const int*, const wchar_t*) {
on = true;
}
void CmdOff(const int*, const wchar_t*) {
on = false;
}
bool Run();
};
void Subber::CmdTextbox(const int* dims, const wchar_t* alignment) {
CloseBox();
boxleft = dims[0];
boxright = dims[1];
boxtop = dims[2];
boxbottom = dims[3];
vertical = false;
if (*alignment == L'-') {
vertical = true;
++alignment;
}
if (alignment[0] >= L'1' && alignment[0] <= L'9') {
boxalign = alignment[0] - '1';
} else {
throw "Bad alignment value";
}
switch (alignment[1]) {
case 'L': case 'T': linealign = -1; break;
case 'C': case 'M': linealign = 0; break;
case 'R': case 'B': linealign = +1; break;
default: throw "Bad alignment value";
}
if (vertical) {
int t = boxleft; boxleft = boxtop; boxtop = 720-boxright; boxright = boxbottom; boxbottom = 720-t;
static unsigned char rotate[9] = { 2, 5, 8, 1, 4, 7, 0, 3, 6 };
boxalign = rotate[boxalign];
}
got_textbox = true;
}
void Subber::At(unsigned fadein_time, unsigned full_time, unsigned fadeout_time, unsigned off_time) {
if (fadein_time > full_time || full_time > fadeout_time || fadeout_time > off_time) {
throw "subtitle display times are backwards";
} else if (fadein_time >= off_time) {
throw "subtitle on and off times are the same";
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -