-
Notifications
You must be signed in to change notification settings - Fork 13
/
app.js
158 lines (139 loc) · 8.41 KB
/
app.js
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
153
154
155
156
157
158
const argv = require('minimist')(process.argv.slice(2)),
fs = require('fs-extra'),
path = require('path'),
Q = require('q'),
printf = require('printf'),
uuidv1 = require('uuid/v1');
const cutils = require('./lib/console-utils'),
utils = require('./lib/utils');
var showBanner = function() {
console.log(' # # # ##### ###### #### ##### # # ');
console.log(' # # # # # # # # # # # # ');
console.log(' # # # # # ##### # # # ## ');
console.log(' # # # # # # # # ##### ## ');
console.log(' # # # # # # # # # # # ');
console.log(' ## # ##### ###### #### ####### # # ');
console.log(' ');
};
var getRequiredArgument = function(argName) {
if(argv[argName]) {
return argv[argName];
} else {
console.log(printf('Error: missing argument "%s"', argName));
process.exit(-1);
}
};
var initConfig = function() {
var deferred = Q.defer();
var configPath = argv.c ? argv.c : './config/default.json';
utils.performStep(printf('Reading config file in "%s"', configPath), fs.readJson, [configPath]).then(function(config) {
// attach argument values into config
config.input = getRequiredArgument('i');
config.output = argv.o ? argv.o : null;
if(!config.output) {
const FILE_EXTENSION = path.extname(config.input);
config.output = printf('%s_new%s', path.basename(config.input, FILE_EXTENSION), FILE_EXTENSION);
}
deferred.resolve(config);
}, cutils.showError);
return deferred.promise;
};
var start = function(config) {
// ensure workspace directory is a completly new directory
const WORK_DIRECTORY = path.join(config.workDirectory, uuidv1()),
EXTRACTED_FRAMES_DIRECTORY = path.join(WORK_DIRECTORY, 'extracted'),
UPSCALED_FRAMES_DIRECTORY = path.join(WORK_DIRECTORY, 'upscaled'),
FRAME_FILE_PATTERN = 'frame%d.png';
var startTime = Date.now();
var metadata, originalFrameSize, upscaledFrameSize;
utils.performStep('Retrieving video metadata', function() {
return utils.getVideoMetadata(config.input);
}).then(function(data) {
metadata = data;
return utils.performStep(printf('Creating new workspace directory: %s', WORK_DIRECTORY), fs.emptyDir, [WORK_DIRECTORY]);
}).then(function() {
return utils.performStep(printf('Creating directory under workspace to store extracted frames: %s', EXTRACTED_FRAMES_DIRECTORY), fs.emptyDir, [EXTRACTED_FRAMES_DIRECTORY]);
}).then(function() {
return utils.performStep(printf('Creating directory under workspace to store upscaled frames: %s', UPSCALED_FRAMES_DIRECTORY), fs.emptyDir, [UPSCALED_FRAMES_DIRECTORY]);
}).then(function() {
return utils.performStep('Extracting frames from source video', function() {
var d = Q.defer();
var startTime = Date.now();
utils.extractPNGFromSourceVideo(config.ffmpeg, config.input, EXTRACTED_FRAMES_DIRECTORY, FRAME_FILE_PATTERN).then(function() {
// show statistics
utils.getDirectorySize(EXTRACTED_FRAMES_DIRECTORY).then(function(dirInfo) {
originalFrameSize = dirInfo.totalSize / (1024 * 1024 * 1024);
cutils.stepComment(printf('Extracted %i frames from "%s" (Size: %0.2f GB, Time: %0.2f hours, approx. %0.0f minutes)', dirInfo.files.length, config.input, originalFrameSize, utils.timeDiffHrs(startTime), utils.timeDiffMins(startTime)));
d.resolve(dirInfo.files);
}, d.reject);
}, d.reject);
return d.promise;
});
}).then(function(extractedFrames) {
var oldResolution = printf('%ix%i', metadata.stream.width, metadata.stream.height);
var newResolution = printf('%ix%i', config.width, config.height);
return utils.performStep(printf('Upscaling the extracted frames from %s to %s', oldResolution, newResolution), function() {
var d = Q.defer();
utils.performStep('Splitting up the frames into smaller groups, each to be processed by its own waifu2x thread', function() {
var startTime = Date.now();
var waifu2xThreads = [], currFrameIndex = 0, totalFrames = extractedFrames.length;
for(var i = 0; i < config.waifu2x.threads.length; i++) {
var currThread = config.waifu2x.threads[i];
var threadNum = i + 1;
var totalFramesHandled = Math.floor(totalFrames * currThread.weight);
if(i < config.waifu2x.threads.length - 1) {
cutils.stepComment(printf('[Thread%i] %i (%.1f%) frames - %s mode', threadNum, totalFramesHandled, currThread.weight * 100, currThread.type));
} else {
totalFramesHandled = totalFrames - currFrameIndex;
cutils.stepComment(printf('[Thread%i] %i (%.1f%) frames - %s mode', threadNum, totalFramesHandled, (totalFramesHandled / totalFrames) * 100, currThread.type));
}
var currThreadWorkspace = path.join(EXTRACTED_FRAMES_DIRECTORY, 'thread' + threadNum);
fs.emptyDirSync(currThreadWorkspace);
for(var k = 0; k < totalFramesHandled; k++) {
var frameIndex = currFrameIndex + k;
fs.moveSync(path.join(EXTRACTED_FRAMES_DIRECTORY, extractedFrames[frameIndex]), path.join(currThreadWorkspace, extractedFrames[frameIndex]));
}
currFrameIndex += totalFramesHandled;
var newWaifu2xThread = utils.spawnWaifu2x(threadNum, config.waifu2x.directory, config.waifu2x[currThread.preset].concat(config.waifu2x.COMMON_PRESET), config.width, config.height, currThreadWorkspace, UPSCALED_FRAMES_DIRECTORY, config.waifu2x.model);
newWaifu2xThread.done(function(threadId) {
cutils.stepComment(printf('[Thread%i] Completed in %0.2f hours (approx. %0.0f minutes)', threadId, utils.timeDiffHrs(startTime), utils.timeDiffMins(startTime)));
});
waifu2xThreads.push(newWaifu2xThread);
}
// just add a line break to make it easier to see
cutils.stepComment('');
return Q.allSettled(waifu2xThreads);
}).then(function() {
// show statistics
utils.getDirectorySize(UPSCALED_FRAMES_DIRECTORY).then(function(dirInfo) {
upscaledFrameSize = dirInfo.totalSize / (1024 * 1024 * 1024);
cutils.stepComment(printf('All waifu2x threads successfully finished. Upscaled %i frames (Size: %0.2f GB, %0.2fx the original size)', dirInfo.files.length, upscaledFrameSize, upscaledFrameSize / originalFrameSize));
d.resolve();
}), d.reject;
});
return d.promise;
});
}).then(function() {
return utils.performStep('Converting upscaled frames to new video', function() {
var d = Q.defer();
var startTime = Date.now();
utils.combinePNGToNewVideo(metadata, config.ffmpeg, config.input, path.join(UPSCALED_FRAMES_DIRECTORY, FRAME_FILE_PATTERN), config.output).then(function() {
var originalVideoSize = (fs.statSync(config.input).size) / (1024 * 1024 * 1024);
var newVideoSize = (fs.statSync(config.output).size) / (1024 * 1024 * 1024);
cutils.stepComment(printf('New video created "%s" (Size: %0.2f GB, %0.2fx the original size, Time: %0.2f hours, approx. %0.0f minutes)', config.output, newVideoSize, newVideoSize / originalVideoSize, utils.timeDiffHrs(startTime), utils.timeDiffMins(startTime)));
d.resolve();
}, d.reject);
return d.promise;
});
}).then(function() {
return utils.performStep(printf('Cleaning up workspace directory: %s', WORK_DIRECTORY), fs.remove, [WORK_DIRECTORY]);
}).then(function() {
cutils.stepComment(printf('Video2x successfully finished all tasks in %0.2f hours', utils.timeDiffHrs(startTime)));
process.exit(0);
}).catch(cutils.showError);
};
// start
showBanner();
initConfig().done(function(config) {
start(config);
});