📄 dvdsubber-compile.cpp
字号:
time0 = fadein_time + base_field;
time1 = full_time + base_field;
time2 = fadeout_time + base_field;
time3 = off_time + base_field;
got_at = true;
}
void Subber::CmdAt(const int* times, const wchar_t*) {
At(times[0], times[0], times[1], times[1]);
}
void Subber::CmdFadeat(const int* times, const wchar_t*) {
At(times[0], times[1], times[2], times[3]);
}
bool Subber::Run() {
CloseBox();
// merge boxen into one big tree
int b;
for (b=0; b<30; ++b) {
if (boxen[b]) break;
}
Drawable* all_boxes = boxen[b];
boxen[b] = 0;
for (++b; b<30; ++b) {
if (boxen[b]) {
all_boxes = new_TextBoxen(all_boxes, boxen[b]);
boxen[b] = 0;
}
}
if (!all_boxes) {
throw "no text to render!";
}
boxen[0] = all_boxes;
// find all event times
int max_events = 4000;
unsigned* event_time;
unsigned* event_time_end;
for (;;) {
event_time = new unsigned[max_events];
event_time_end = all_boxes->GetEventTimes(event_time, event_time + max_events);
if (event_time_end < event_time + max_events) {
break;
} else {
delete[] event_time;
max_events *= 2;
continue;
}
}
sort(event_time, event_time_end);
// uniq in bits 2..31, taking min of bits 0..1
if (event_time_end > event_time) {
unsigned* dst = event_time + 1;
for (unsigned* src = event_time + 1; src < event_time_end; ++src)
if ((src[0] >> 2) != (src[-1] >> 2))
*dst++ = *src;
event_time_end = dst;
}
int num_events = event_time_end - event_time;
bool* event_blank = new bool[num_events];
int e;
int blanks = 0;
for (e=0; e<num_events; ++e) {
event_blank[e] = ((event_time[e] & 3) == 2) ? all_boxes->NothingToDraw(event_time[e] >> 2) : false;
blanks += event_blank[e];
}
g_compiler_callbacks->NotifySubpictureCount(num_events - blanks);
bool ntsc = g_compiler_callbacks->IsNTSC();
bool success = true;
for (e=0; e<num_events-1; ++e) {
if (event_blank[e]) {
continue;
}
error_time = event_time[e] >> 2;
static unsigned char static_buffer[720*576];
static DrawingBuf buf = { static_buffer, 720, 480, 1, 720 };
buf.left = buf.width; buf.right = 0;
buf.top = buf.height; buf.bottom = 0;
all_boxes->DrawSelf(event_time[e] >> 2, &buf, 0, 0);
if (buf.left >= buf.right || buf.top >= buf.bottom) {
continue;
}
SubpictureBuf subpicture_buf;
subpicture_buf.SubpictureOn(0, buf.ptr, buf.left, buf.right, buf.top, buf.bottom, ntsc);
if (event_blank[e+1]) {
subpicture_buf.SubpictureOff((event_time[e+1] >> 2) - (event_time[e] >> 2), ntsc);
}
const unsigned char* p = subpicture_buf.GetPtr();
g_compiler_callbacks->AddSubpicture(event_time[e] >> 2, p);
if (g_compiler_callbacks->UserAborted()) {
success = false;
break;
}
}
delete[] event_time;
delete[] event_blank;
return success;
}
struct Cmd {
const char* name;
const char* args;
void (Subber::*func) (const int* intargs, const wchar_t* stringarg);
};
Cmd cmds[] = {
{ "font ", "s", &Subber::CmdFont },
{ "size ", "u", &Subber::CmdSize },
{ "linespacing ", "i", &Subber::CmdLinespacing },
{ "color ", "xx", &Subber::CmdColor },
{ "textbox ", "iiiis", &Subber::CmdTextbox },
{ "fillbox ", "uuuux", &Subber::CmdFillbox },
{ "vts ", "u", &Subber::CmdVTS },
{ "angle ", "u", &Subber::CmdAngle },
{ "basefield ", "u", &Subber::CmdBasefield },
{ "at ", "uu", &Subber::CmdAt },
{ "fadeat ", "uuuu", &Subber::CmdFadeat },
{ "i", "", &Subber::CmdItalicOn },
{ "/i", "", &Subber::CmdItalicOff },
{ "b", "", &Subber::CmdBoldOn },
{ "/b", "", &Subber::CmdBoldOff },
{ "on", "", &Subber::CmdOn },
{ "off", "", &Subber::CmdOff },
};
// type: 0=eof, 1=text, 2=<>, 3=|
int Subber::GetSegment(FILE* f, char* buf, int buflen) {
int ch = getc(f);
if (ch == EOF) {
return 0;
} else if (ch == '|') {
return 3;
} else if (ch == '<') {
int bufpos = 0;
while ((ch = getc(f)) != '>') {
if (ch == EOF) {
throw "\"<\" without matching \">\" at end of file";
}
if (ch == '\n') {
throw "\"<\" without matching \">\"";
}
if (bufpos >= buflen-1) {
throw "Command too long";
}
buf[bufpos++] = (ch == '\\') ? getc(f) : ch;
}
buf[bufpos] = 0;
return 2;
} else {
int bufpos = 0;
for (;;) {
if (ch == '#') {
do {
ch = getc(f);
} while (ch != EOF && ch != '\n');
}
if (ch == '\n') {
++error_line_no;
} else if (ch == EOF || ch == '<' || ch == '|') {
break;
} else {
if (bufpos >= buflen-1) {
throw "Text too long";
}
buf[bufpos++] = (ch == '\\') ? getc(f) : ch;
}
ch = getc(f);
}
if (ch != EOF) {
ungetc(ch, f);
}
buf[bufpos] = 0;
return 1;
}
}
void Subber::ParseText(char* bytes) {
if (recording) {
Macro* m = new Macro;
m->type = 1;
m->data = strdup(bytes);
*recording = m;
recording = &m->next;
} else {
wchar_t unibuf[1024];
UTF8toUTF16(unibuf, bytes);
if (unibuf[0] == 0 || (unibuf[0] == 0xFEFF && unibuf[1] == 0)) {
return;
}
CmdText(unibuf);
}
}
void Subber::ParseCmd(char* bytes) {
if (bytes[0] == 0) return;
if (memcmp(bytes, "def ", 4) == 0) {
if (recording) {
throw "nested def";
} else {
Macros* m = new Macros;
m->next = macros;
macros = m;
m->name = strdup(bytes+4);
recording = &m->body;
}
} else if (memcmp(bytes, "enddef", 7) == 0) {
if (recording) {
*recording = 0;
recording = 0;
} else {
throw "enddef without def";
}
} else if (recording) {
Macro* m = new Macro;
m->type = 2;
m->data = strdup(bytes);
*recording = m;
recording = &m->next;
} else {
for (Macros* m = macros; m; m = m->next) {
if (strcmp(m->name, bytes) == 0) {
for (Macro* c = m->body; c; c = c->next) {
ParseSegment(c->type, c->data);
}
return;
}
}
for (int c = 0; c < sizeof(cmds)/sizeof(cmds[0]); ++c) {
if (memcmp(bytes, cmds[c].name, strlen(cmds[c].name)) == 0) {
int int_args[8];
wchar_t unibuf[1024];
unibuf[0] = 0;
const char* p = bytes + strlen(cmds[c].name);
char* q;
for (int a = 0; cmds[c].args[a]; ++a) {
if (a > 0) {
if (*p++ != ',') throw "expected comma";
}
switch (cmds[c].args[a]) {
case 'i':
int_args[a] = strtol(p, &q, 10);
break;
case 'u':
int_args[a] = strtoul(p, &q, 10);
break;
case 'x':
int_args[a] = strtoul(p, &q, 16);
break;
case 's':
UTF8toUTF16(unibuf, p);
q = strchr(p, 0);
break;
}
if (p == q) throw "invalid number";
p = q;
while (*p == ' ') ++p;
}
if (*p != 0)
throw "extra junk";
(this->*cmds[c].func)(int_args, unibuf);
return;
}
}
puts(bytes);
throw "Bad command";
}
}
void Subber::ParseLineBreak() {
if (recording) {
Macro* m = new Macro;
m->type = 3;
*recording = m;
recording = &m->next;
} else {
CmdLineBreak();
}
}
void Subber::ParseSegment(int type, char* bytebuf) {
switch (type) {
case 1:
ParseText(bytebuf);
break;
case 2:
ParseCmd(bytebuf);
break;
case 3:
ParseLineBreak();
break;
}
}
void Subber::ParseFile(FILE* f) {
char bytebuf[1024];
for (;;) {
int type = GetSegment(f, bytebuf, sizeof(bytebuf));
if (type == 0) break;
ParseSegment(type, bytebuf);
}
}
bool CompileSubtitles(FILE* subfile, ICompilerCallbacks* compiler_callbacks) {
g_compiler_callbacks = compiler_callbacks;
compiler_callbacks->Note("Reading the subtitle script...");
Subber subber;
try {
subber.ParseFile(subfile);
}
catch (const char* error) {
compiler_callbacks->ErrorAtLine(error, subber.error_line_no);
return false;
}
compiler_callbacks->NotifyDoneParsing();
compiler_callbacks->Note("Rendering the subtitles...");
try {
return subber.Run();
}
catch (const char* error) {
compiler_callbacks->ErrorAtTime(error, subber.error_time);
return false;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -