📄 script.cpp
字号:
*eos = 0;
type = 's';
string = next_char+2;
next_char = eos+2;
} else {
throw FilterChainError(Sprintf("unexpected character \"%c\"", *next_char));
}
break;
}
while (isspace(*next_char))
++next_char;
}
class ScriptParser {
Tokenizer tokenizer;
VarTable var_table;
int line_no;
char line[2000];
PVideoFilter ParseStatement() {
// check for null statement
if (tokenizer.GetType() == 0)
return 0;
// return and end statements
if (tokenizer.GetType() == 'x') {
if (!lstrcmpi(tokenizer.GetAsIdentifier(), "end")) {
return var_table.GetValue("last");
} else if (!lstrcmpi(tokenizer.GetAsIdentifier(), "return")) {
tokenizer.NextToken();
return ParseExpressionAtEOL();
}
}
// assignment statement
PVideoFilter* result_dest = &var_table.Lookup("last")->val;
if (tokenizer.GetType() == 'x' && *tokenizer.NextCharPointer() == '=') {
result_dest = &var_table.Lookup(tokenizer.GetAsIdentifier())->val;
tokenizer.Reset(tokenizer.NextCharPointer()+1);
}
*result_dest = ParseExpressionAtEOL();
return 0;
}
PVideoFilter ParseExpressionAtEOL() {
PVideoFilter result = ParseExpression();
if (tokenizer.GetType() != 0) {
throw FilterChainError(Sprintf("mysterious gunk found around script line %d, position %d",
line_no, tokenizer.CurCharPointer() - line + 1));
}
return result;
}
PVideoFilter ParseExpression() {
PVideoFilter pvf = ParseOOP(0);
if (tokenizer.GetType() == '+' || tokenizer.GetType() == '++') {
bool aligned = (tokenizer.GetType() == '++');
tokenizer.NextToken();
return new_Splice(aligned, pvf, ParseExpression());
} else {
return pvf;
}
}
PVideoFilter ParseOOP(PVideoFilter object) {
PVideoFilter pvf;
if (!object && tokenizer.GetType() == '(') {
tokenizer.NextToken();
pvf = ParseExpression();
if (tokenizer.GetType() != ')') {
throw FilterChainError(Sprintf("expected a ) at script line %d, position %d",
line_no, tokenizer.CurCharPointer() - line + 1));
}
tokenizer.NextToken();
} else {
pvf = ParseFunction(object);
}
if (tokenizer.GetType() == '.') {
tokenizer.NextToken();
return ParseOOP(pvf);
} else {
return pvf;
}
}
PVideoFilter ParseFunction(PVideoFilter object) {
if (tokenizer.GetType() == 'x') {
const char* filter_name = SearchForFilterName(tokenizer.GetAsIdentifier());
if (filter_name) {
// filter
tokenizer.NextToken();
char arg_types[64];
Arg args[64];
int num_args = ParseArgumentList(args, arg_types, 60);
arg_types[num_args] = 0;
// add object as last arg
if (object) {
if (strchr(arg_types, 'c') || strchr(arg_types, '+') || strchr(arg_types, '*'))
throw FilterChainError("OOP notation can only be used with linear filters");
arg_types[num_args] = 'c';
args[num_args].clip = object;
arg_types[++num_args] = 0;
}
FilterInfo* fi = SearchForMatchingFilter(filter_name, arg_types);
if (!fi) {
// try adding implicit 'last' arg
if (!object) {
PVideoFilter& last = var_table.GetValue("last");
if (last) {
arg_types[num_args] = 'c';
args[num_args].clip = last;
arg_types[++num_args] = 0;
fi = SearchForMatchingFilter(filter_name, arg_types);
}
}
if (!fi)
throw FilterChainError(Sprintf("invalid arguments for filter %s", filter_name));
}
// promote int->float
for (int y = 0; fi->param_types[y]; ++y) {
if (fi->param_types[y] == 'f' && arg_types[y] == 'i') {
args[y].floating_pt = float(args[y].integer);
arg_types[y] = 'f';
}
}
// create the filter
return fi->pFilterFactoryFunction(fi, args, arg_types);
} else {
// variable
PVideoFilter result = var_table.GetValue(tokenizer.GetAsIdentifier());
if (object || result == 0) {
throw FilterChainError(Sprintf("I don't know what \"%s\" means on line %d",
tokenizer.GetAsIdentifier(), line_no));
}
tokenizer.NextToken();
return result;
}
} else {
throw FilterChainError(Sprintf("expected a %sfilter name at script line %d, position %d",
object ? "" : "variable or ", line_no, tokenizer.CurCharPointer() - line + 1));
}
}
int ParseArgumentList(Arg* args, char* arg_types, int max_args) {
bool parenthesized = false;
if (tokenizer.GetType() == '(') {
tokenizer.NextToken();
parenthesized = true;
} else if (tokenizer.GetType() == '.' || tokenizer.GetType() == ',' || tokenizer.GetType() == '+' || tokenizer.GetType() == '++' || tokenizer.GetType() == ')') {
return 0;
}
int num_args = 0;
while (1) {
if (parenthesized && tokenizer.GetType() == ')') {
tokenizer.NextToken();
return num_args;
}
if (!parenthesized && tokenizer.GetType() == 0) {
return num_args;
}
if (num_args) {
if (tokenizer.GetType() != ',') {
if (parenthesized) {
throw FilterChainError(Sprintf("expected a , or ) at script line %d, position %d",
line_no, tokenizer.CurCharPointer() - line + 1));
} else {
return num_args;
}
}
tokenizer.NextToken(); // skip ','
}
if (num_args == max_args) {
throw FilterChainError(Sprintf("argument list too long around script line %d, position %d",
line_no, tokenizer.CurCharPointer() - line + 1));
}
arg_types[num_args++] = ParseArgument(&args[num_args]);
}
}
char ParseArgument(Arg* arg) {
if (tokenizer.GetType() == 'i') {
// int
arg->integer = tokenizer.GetAsInt();
tokenizer.NextToken();
return 'i';
} else if (tokenizer.GetType() == 'f') {
// float
arg->floating_pt = tokenizer.GetAsFloat();
tokenizer.NextToken();
return 'f';
} else if (tokenizer.GetType() == 's') {
// string
arg->string = tokenizer.GetAsString();
tokenizer.NextToken();
return 's';
} else if (tokenizer.GetType() == 'x' || tokenizer.GetType() == '(') {
// expression
arg->clip = ParseExpression();
return 'c';
} else {
throw FilterChainError(Sprintf("expected a filter argument around script line %d, position %d",
line_no, tokenizer.CurCharPointer() - line + 1));
}
}
bool ParseDirective(const char* line) {
char filename[256];
if (sscanf(line, ".loadplugin \"%[^\"]\"", filename) == 1) {
LoadPlugin(filename);
return true;
}
return false;
}
public:
PVideoFilter ParseScript(const char filename[]) {
FILE* f = fopen(filename, "r");
try {
if (!f)
throw FilterChainError(Sprintf("Couldn't open input file %s", filename));
line_no = 0;
PVideoFilter result;
while (fgets(line, sizeof(line), f)) {
++line_no;
if (line[0] == '.') {
ParseDirective(line);
} else {
tokenizer.Reset(line);
result = ParseStatement();
if (result) break;
}
}
if (!result) result = var_table.GetValue("last");
if (!result)
throw FilterChainError("script has no return value!");
fclose(f);
return result;
}
catch (FilterChainError error) {
if (f) fclose(f);
VideoInfo viError;
memset(&viError, 0, sizeof(viError));
viError.width = (11*strlen(error.msg)) & -4;
viError.height = 32;
viError.fps_denominator = viError.fps_numerator = 1;
viError.num_frames = 10;
viError.pixel_type = VideoInfo::BGR24;
return new_Subtitle(error.msg, -1, 23, 0, 999999, "Arial", 24, 0xFF3333, 0, new_Blackness(&viError));
}
}
};
/********************************************************************
********************************************************************/
class CootieCatcher : public VideoFilterWithRefcount {
PVideoFilter child;
VideoInfo vi;
void MakeErrorStream(const char msg[]) {
child = new_Subtitle(msg, 0, 15, 0, 999999, "Arial", 16, 0xFF3333, 0, new_Blackness(&vi));
}
public:
CootieCatcher(PVideoFilter _child) : child(_child) { child->GetVideoInfo(&vi); }
void GetFrame(int n, unsigned char* buf) {
try {
child->GetFrame(n, buf);
}
catch (FilterChainError error) {
MakeErrorStream(error.msg);
child->GetFrame(n, buf);
}
}
void GetAudio(void* buf, int start, int count) {
try {
child->GetAudio(buf, start, count);
}
catch (FilterChainError error) {
MakeErrorStream(error.msg);
child->GetAudio(buf, start, count);
}
}
void GetVideoInfo(VideoInfo* pvi) { child->GetVideoInfo(pvi); }
bool GetParity(int n) { return child->GetParity(n); }
};
PVideoFilter CreateFilterChain(const char filename[]) {
ScriptParser parser;
return new CootieCatcher(parser.ParseScript(filename));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -