-
Notifications
You must be signed in to change notification settings - Fork 0
/
script.js
137 lines (124 loc) · 4.21 KB
/
script.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
const inputElement = document.getElementById("file_input");
const asciiContainer = document.getElementById("ascii_container");
const loading = document.getElementById("loading");
const replayButton = document.getElementById("replay");
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const playingVideo = [];
const { createWorker } = FFmpeg;
const worker = createWorker({});
const width = 128;
const height = 128;
const toggleLoading = state => {
if (state) {
loading.classList.remove("hide");
inputElement.classList.add("hide");
return;
}
loading.classList.add("hide");
inputElement.classList.remove("hide")
}
const toggleReplayButton = state => {
state ? replayButton.classList.remove("hide") : replayButton.classList.add("hide");
}
const convertFrameToAscii = (arr, height, width) => {
return new Promise((resolve, reject) => {
try {
let frameData = "";
for (let i = 0; i < height; i++) {
for (let j = 0; j < (width * 4); j += 4) {
if (arr[j + 3] === 0) { frameData += "░"; continue; };
const total = arr[j] + arr[j + 1] + arr[j + 2];
const greyscale = parseInt(total / 3);
arr[j] = greyscale;
arr[j + 1] = greyscale;
arr[j + 2] = greyscale;
frameData += greyscale > 100 ? "▒" : greyscale > 75 ? "▓" : "█";
}
frameData += "\n";
arr = arr.slice((width * 4));
}
resolve(frameData);
} catch (error) {
reject(error);
}
})
}
const handleFrame = async frame => {
canvas.width = width;
canvas.height = height;
asciiContainer.innerText = "";
ctx.drawImage(frame, 0, 0, width, height);
const imgData = ctx.getImageData(0, 0, width, height);
let arr = imgData.data;
canvas.style.border = "1px solid black";
const asciiFrame = await convertFrameToAscii(arr, height, width);
return asciiFrame;
}
const loadVideo = videoUrl => new Promise((resolve, reject) => {
try {
const video = document.createElement("video");
video.preload = "metadata";
video.onloadedmetadata = () => {
resolve(video);
}
video.onerror = () => {
reject("Invalid video. Please select a video file.")
}
video.src = videoUrl;
} catch (error) {
reject(error);
}
})
const playVideo = (duration, asciiFrames, frames) => {
if (playingVideo.length) {
clearInterval(playingVideo[0]);
playingVideo.pop();
}
let frameCount = 0;
const fps = frames.length / duration;
const playVideo = setInterval(() => {
asciiContainer.innerText = asciiFrames[frameCount];
frameCount++;
if (frameCount === frames.length) {
clearInterval(playVideo);
}
}, 1000 / fps);
playingVideo.push(playVideo);
}
const getVideoDetails = async e => {
toggleLoading(true);
toggleReplayButton(false);
clearInterval(playingVideo[0]);
playingVideo.pop();
const frames = [];
const name = e.target.files[0].name.replace(/ /g, "")
await worker.load();
await worker.write(name, e.target.files[0]);
await worker.run(`-i ${name} -vf scale=${width}:${height} ${name}%d.jpg`);
let i = 1;
while(true){
try {
const { data } = await worker.read(`${name}${i}.jpg`);
const image = URL.createObjectURL(new Blob([data], { type: 'image/jpg' }));
const imageElement = document.createElement("img");
imageElement.src = image;
frames.push(imageElement);
i++;
} catch(e) {
break;
}
}
const videoUrl = URL.createObjectURL(e.target.files[0]);
const { duration } = await loadVideo(videoUrl);
//const frames = await getFrames(videoUrl);
let asciiFrames = [];
frames.forEach(async (frame, i) => {
asciiFrames[i] = await handleFrame(frame);
})
toggleLoading(false);
toggleReplayButton(true);
playVideo(duration, asciiFrames, frames);
replayButton.addEventListener("click", () => playVideo(duration, asciiFrames, frames));
}
inputElement.addEventListener("input", getVideoDetails);