-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathReplaceFramesSimple.cpp
152 lines (134 loc) · 4.88 KB
/
ReplaceFramesSimple.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "Common.h"
struct ReplaceData {
VSNodeRef *node1;
VSNodeRef *node2;
VSVideoInfo vi;
std::vector<unsigned int> frameMap;
};
static void VS_CC replaceInit(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi) {
ReplaceData *d{ static_cast<ReplaceData*>(*instanceData) };
vsapi->setVideoInfo(&d->vi, 1, node);
}
static const VSFrameRef *VS_CC replaceGetFrame(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) {
ReplaceData *d{ static_cast<ReplaceData*>(*instanceData) };
if (activationReason == arInitial) {
//Check whether frameMap returns 0 or 1 for the current frame and return the corresponding clip.
vsapi->requestFrameFilter(n, (d->frameMap[n] ? d->node2 : d->node1), frameCtx);
}
else if (activationReason == arAllFramesReady) {
return vsapi->getFrameFilter(n, (d->frameMap[n] ? d->node2 : d->node1), frameCtx);
}
return nullptr;
}
static void VS_CC replaceFree(void *instanceData, VSCore *core, const VSAPI *vsapi) {
ReplaceData *d{ static_cast<ReplaceData*>(instanceData) };
vsapi->freeNode(d->node1);
vsapi->freeNode(d->node2);
delete d;
}
//Loops through the string/file checking for ranges or integers and sets frameMap values accordingly.
static void parse(std::string name, std::vector<unsigned int> &frameMap, void *stream, bool file, int maxFrames) {
int line{ 0 };
int col{ 0 };
if (!file) {
skipWhitespace(name, col);
if (col == name.size())
return;
}
std::string temp;
while (file ? std::getline(*static_cast<std::ifstream*>(stream), temp) : std::getline(*static_cast<std::stringstream*>(stream), temp)) {
col = 0;
while (col < temp.size()) {
skipWhitespace(temp, col);
char ch{ getChar(temp, col) };
if (ch != 0) {
if (ch == '#')
continue;
else if (std::isdigit(ch) || ch == '-')
frameMap[getInt(temp, col, line, file, maxFrames, Filter::REPLACE_FRAMES_SIMPLE)] = 1;
else if (ch == '[') {
++col;
Range range;
fillRange(temp, col, range, line, file, maxFrames, Filter::REPLACE_FRAMES_SIMPLE);
for (int i = range.start; i <= range.end; i++) {
frameMap[i] = 1;
}
}
else {
std::string location{ file ? " text file " : " mappings " };
std::string error{ "ReplaceFramesSimple: Parse Error in" + location + "at line " + std::to_string(line + 1) + ", column " + std::to_string(col + 1) };
throw std::runtime_error(error);
}
}
}
line++;
}
}
void VS_CC replaceCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) {
ReplaceData d;
d.node1 = vsapi->propGetNode(in, "baseclip", 0, 0);
d.node2 = vsapi->propGetNode(in, "sourceclip", 0, 0);
d.vi = *vsapi->getVideoInfo(d.node1);
int err;
std::string filename;
const char* fn{ vsapi->propGetData(in, "filename", 0, &err) };
if (err)
filename = "";
else
filename = fn;
std::string mappings;
const char* mp{ vsapi->propGetData(in, "mappings", 0, &err) };
if (err)
mappings = "";
else
mappings = mp;
bool mismatch{ !!vsapi->propGetInt(in, "mismatch", 0, &err) };
if (err)
mismatch = false;
MismatchCauses mismatchCause = findCommonVi(&d.vi, d.node2, vsapi);
if (mismatchCause == MismatchCauses::DIFFERENT_LENGTHS) {
vsapi->setError(out, "ReplaceFramesSimple: Clip lengths don't match");
vsapi->freeNode(d.node1);
vsapi->freeNode(d.node2);
return;
}
if (static_cast<bool>(mismatchCause) && (!mismatch)) {
if (mismatchCause == MismatchCauses::DIFFERENT_DIMENSIONS)
vsapi->setError(out, "ReplaceFramesSimple: Clip dimensions don't match");
else if (mismatchCause == MismatchCauses::DIFFERENT_FORMATS)
vsapi->setError(out, "ReplaceFramesSimple: Clip formats don't match");
else if (mismatchCause == MismatchCauses::DIFFERENT_FRAMERATES)
vsapi->setError(out, "ReplaceFramesSimple: Clip frame rates don't match");
vsapi->freeNode(d.node1);
vsapi->freeNode(d.node2);
return;
}
//All frames map to baseclip by default
//0 = baseclip
//1 = sourceclip
d.frameMap.assign(d.vi.numFrames, 0);
try {
if (!filename.empty()) {
std::ifstream file(filename);
if (!file) {
vsapi->setError(out, "ReplaceFramesSimple: Failed to open the timecodes file.");
vsapi->freeNode(d.node1);
vsapi->freeNode(d.node2);
return;
}
parse(filename, d.frameMap, &file, true, d.vi.numFrames);
}
if (!mappings.empty()) {
std::stringstream stream(mappings);
parse(mappings, d.frameMap, &stream, false, d.vi.numFrames);
}
}
catch (const std::exception &ex) {
vsapi->setError(out, ex.what());
vsapi->freeNode(d.node1);
vsapi->freeNode(d.node2);
return;
}
ReplaceData *data = new ReplaceData{ d };
vsapi->createFilter(in, out, "Replace", replaceInit, replaceGetFrame, replaceFree, fmParallel, 0, data, core);
}