@twick/ffmpeg 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VideoFrameExtractor = void 0;
4
+ const telemetry_1 = require("@twick/telemetry");
5
+ const ffmpeg = require("fluent-ffmpeg");
6
+ const fs = require("fs");
7
+ const os = require("os");
8
+ const path = require("path");
9
+ const uuid_1 = require("uuid");
10
+ const settings_1 = require("./settings");
11
+ const utils_1 = require("./utils");
12
+ /**
13
+ * Walks through a video file and extracts frames.
14
+ */
15
+ class VideoFrameExtractor {
16
+ constructor(filePath, startTime, fps, duration) {
17
+ this.ffmpegPath = settings_1.ffmpegSettings.getFfmpegPath();
18
+ this.buffer = Buffer.alloc(0);
19
+ this.bufferOffset = 0;
20
+ // Images are buffered in memory until they are requested.
21
+ this.imageBuffers = [];
22
+ this.lastImage = null;
23
+ this.framesProcessed = 0;
24
+ this.width = 0;
25
+ this.height = 0;
26
+ this.frameSize = 0;
27
+ this.codec = null;
28
+ this.process = null;
29
+ this.terminated = false;
30
+ this.state = 'processing';
31
+ this.filePath = filePath;
32
+ this.downloadedFilePath = VideoFrameExtractor.downloadedVideoMap.get(filePath)?.localPath;
33
+ this.startTimeOffset = VideoFrameExtractor.downloadedVideoMap.get(filePath)
34
+ ?.startTimeOffset;
35
+ this.startTime = startTime;
36
+ this.duration = duration;
37
+ this.toTime = this.getEndTime(this.startTime);
38
+ this.fps = fps;
39
+ (0, utils_1.getVideoMetadata)(this.downloadedFilePath).then(metadata => {
40
+ this.width = metadata.width;
41
+ this.height = metadata.height;
42
+ this.frameSize = this.width * this.height * 4;
43
+ this.buffer = Buffer.alloc(this.frameSize);
44
+ this.codec = metadata.codec;
45
+ if (this.startTime >= this.duration) {
46
+ this.process = this.createFfmpegProcessToExtractFirstFrame(this.downloadedFilePath, this.codec);
47
+ return;
48
+ }
49
+ this.process = this.createFfmpegProcess(this.startTime - this.startTimeOffset, this.toTime, this.downloadedFilePath, this.fps, this.codec);
50
+ });
51
+ }
52
+ static downloadVideoChunk(url, startTime, endTime) {
53
+ const outputDir = path.join(os.tmpdir(), `twick-decoder-chunks`);
54
+ if (!fs.existsSync(outputDir)) {
55
+ fs.mkdirSync(outputDir, { recursive: true });
56
+ }
57
+ return new Promise((resolve, reject) => {
58
+ ffmpeg.ffprobe(url, (err, metadata) => {
59
+ if (err) {
60
+ reject(err);
61
+ return;
62
+ }
63
+ const format = metadata.format.format_name?.split(',')[-1] || 'mp4';
64
+ const outputFileName = `chunk_${(0, uuid_1.v4)()}.${format}`;
65
+ const outputPath = path.join(outputDir, outputFileName);
66
+ const toleranceInSeconds = 0.5;
67
+ const adjustedStartTime = Math.max(startTime - toleranceInSeconds, 0);
68
+ ffmpeg(url)
69
+ .setFfmpegPath(settings_1.ffmpegSettings.getFfmpegPath())
70
+ .inputOptions([
71
+ `-ss ${adjustedStartTime}`,
72
+ `-to ${endTime + toleranceInSeconds}`,
73
+ ])
74
+ .outputOptions(['-c copy'])
75
+ .output(outputPath)
76
+ .on('end', () => {
77
+ this.downloadedVideoMap.set(url, {
78
+ localPath: outputPath,
79
+ startTimeOffset: adjustedStartTime,
80
+ });
81
+ resolve(outputPath);
82
+ })
83
+ .on('error', err => reject(err))
84
+ .run();
85
+ });
86
+ });
87
+ }
88
+ getTime() {
89
+ return this.startTime + this.framesProcessed / this.fps;
90
+ }
91
+ getLastTime() {
92
+ return this.startTime + (this.framesProcessed - 1) / this.fps;
93
+ }
94
+ getLastFrame() {
95
+ return this.lastImage;
96
+ }
97
+ getWidth() {
98
+ return this.width;
99
+ }
100
+ getHeight() {
101
+ return this.height;
102
+ }
103
+ getEndTime(startTime) {
104
+ return Math.min(startTime + VideoFrameExtractor.chunkLengthInSeconds, this.duration);
105
+ }
106
+ getArgs(codec, range, fps) {
107
+ const inputOptions = [];
108
+ const outputOptions = [];
109
+ inputOptions.push('-loglevel', settings_1.ffmpegSettings.getLogLevel());
110
+ if (range) {
111
+ inputOptions.push(...['-ss', range[0].toFixed(2), '-to', range[1].toFixed(2)]);
112
+ }
113
+ if (codec === 'vp9') {
114
+ inputOptions.push('-vcodec', 'libvpx-vp9');
115
+ }
116
+ if (fps) {
117
+ outputOptions.push('-vf', `fps=fps=${fps}`);
118
+ }
119
+ if (!range) {
120
+ outputOptions.push('-vframes', '1');
121
+ }
122
+ outputOptions.push('-f', 'rawvideo');
123
+ outputOptions.push('-pix_fmt', 'rgba');
124
+ return { inputOptions, outputOptions };
125
+ }
126
+ createFfmpegProcess(startTime, toTime, filePath, fps, codec) {
127
+ const { inputOptions, outputOptions } = this.getArgs(codec, [startTime, toTime], fps);
128
+ const process = ffmpeg(filePath)
129
+ .setFfmpegPath(this.ffmpegPath)
130
+ .inputOptions(inputOptions)
131
+ .outputOptions(outputOptions)
132
+ .on('end', () => {
133
+ this.handleClose(0);
134
+ })
135
+ .on('error', err => {
136
+ this.handleError(err);
137
+ })
138
+ .on('stderr', stderrLine => {
139
+ console.log(stderrLine);
140
+ })
141
+ .on('stdout', stderrLine => {
142
+ console.log(stderrLine);
143
+ });
144
+ const ffstream = process.pipe();
145
+ ffstream.on('data', (data) => {
146
+ this.processData(data);
147
+ });
148
+ return process;
149
+ }
150
+ /**
151
+ * We call this in the case that the time requested is greater than the
152
+ * duration of the video. In this case, we want to display the first frame
153
+ * of the video.
154
+ *
155
+ * Note: This does NOT match the behavior of the old implementation
156
+ * inside of 2d/src/lib/components/Video.ts. In the old implementation, the
157
+ * last frame is shown instead of the first frame.
158
+ */
159
+ createFfmpegProcessToExtractFirstFrame(filePath, codec) {
160
+ const { inputOptions, outputOptions } = this.getArgs(codec, undefined, undefined);
161
+ const process = ffmpeg(filePath)
162
+ .setFfmpegPath(this.ffmpegPath)
163
+ .inputOptions(inputOptions)
164
+ .outputOptions(outputOptions)
165
+ .on('end', () => {
166
+ this.handleClose(0);
167
+ })
168
+ .on('error', err => {
169
+ this.handleError(err);
170
+ })
171
+ .on('stderr', stderrLine => {
172
+ console.log(stderrLine);
173
+ })
174
+ .on('stdout', stderrLine => {
175
+ console.log(stderrLine);
176
+ });
177
+ const ffstream = process.pipe();
178
+ ffstream.on('data', (data) => {
179
+ this.processData(data);
180
+ });
181
+ return process;
182
+ }
183
+ processData(data) {
184
+ let dataOffset = 0;
185
+ while (dataOffset < data.length) {
186
+ const remainingSpace = this.frameSize - this.bufferOffset;
187
+ const chunkSize = Math.min(remainingSpace, data.length - dataOffset);
188
+ data.copy(this.buffer, this.bufferOffset, dataOffset, dataOffset + chunkSize);
189
+ this.bufferOffset += chunkSize;
190
+ dataOffset += chunkSize;
191
+ // We have a complete frame
192
+ if (this.bufferOffset === this.frameSize) {
193
+ this.imageBuffers.push(Buffer.from(this.buffer)); // Create a copy
194
+ this.bufferOffset = 0; // Reset buffer for next frame
195
+ }
196
+ }
197
+ }
198
+ async popImage() {
199
+ if (this.imageBuffers.length) {
200
+ const image = this.imageBuffers.shift();
201
+ this.framesProcessed++;
202
+ this.lastImage = image;
203
+ return image;
204
+ }
205
+ if (this.state === 'error') {
206
+ throw new Error('An error occurred while extracting the video frames.');
207
+ }
208
+ // If the video is done and there are no more frames to extract, return the last frame.
209
+ if (this.state === 'done' && this.toTime >= this.duration) {
210
+ return this.lastImage;
211
+ }
212
+ // If there are more frames to extract, request the next chunk.
213
+ if (this.state === 'done') {
214
+ this.startTime = this.toTime;
215
+ this.toTime = Math.min(this.startTime + VideoFrameExtractor.chunkLengthInSeconds, this.duration);
216
+ if (!this.codec) {
217
+ throw new Error("Can't extract frames without a codec. This error should never happen.");
218
+ }
219
+ this.process = this.createFfmpegProcess(this.startTime, this.toTime, this.downloadedFilePath, this.fps, this.codec);
220
+ this.state = 'processing';
221
+ }
222
+ while (this.imageBuffers.length < 1) {
223
+ await new Promise(resolve => setTimeout(resolve, 50));
224
+ }
225
+ const image = this.imageBuffers.shift();
226
+ this.framesProcessed++;
227
+ this.lastImage = image;
228
+ return image;
229
+ }
230
+ handleClose(code) {
231
+ this.state = code === 0 ? 'done' : 'error';
232
+ }
233
+ async handleError(err) {
234
+ const code = err.code;
235
+ if (this.terminated) {
236
+ return;
237
+ }
238
+ if (code === 'ENOENT') {
239
+ (0, telemetry_1.sendEvent)(telemetry_1.EventName.Error, { error: 'ffmpeg-not-found' });
240
+ throw new Error('Error: ffmpeg not found. Make sure ffmpeg is installed on your system.');
241
+ }
242
+ else if (err.message.includes('SIGSEGV')) {
243
+ (0, telemetry_1.sendEvent)(telemetry_1.EventName.Error, {
244
+ error: 'ffmpeg-sigsegv',
245
+ message: err.message,
246
+ });
247
+ throw new Error(`Error: Segmentation fault when running ffmpeg. This is a common issue on Linux, you might be able to fix it by installing nscd ('sudo apt-get install nscd'). For more information, see https://docs.re.video/common-issues/ffmpeg/`);
248
+ }
249
+ else {
250
+ await (0, telemetry_1.sendEvent)(telemetry_1.EventName.Error, {
251
+ error: 'ffmpeg-error',
252
+ message: err.message,
253
+ });
254
+ throw new Error(`An ffmpeg error occurred while fetching frames from source video ${this.filePath}: ${err}`);
255
+ }
256
+ }
257
+ destroy() {
258
+ this.terminated = true;
259
+ this.process?.kill('SIGTERM');
260
+ }
261
+ }
262
+ exports.VideoFrameExtractor = VideoFrameExtractor;
263
+ VideoFrameExtractor.chunkLengthInSeconds = 5;
264
+ VideoFrameExtractor.downloadedVideoMap = new Map();
265
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlkZW8tZnJhbWUtZXh0cmFjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3ZpZGVvLWZyYW1lLWV4dHJhY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxnREFBc0Q7QUFDdEQsd0NBQXdDO0FBQ3hDLHlCQUF5QjtBQUN6Qix5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLCtCQUFrQztBQUNsQyx5Q0FBMEM7QUFDMUMsbUNBQXlDO0FBSXpDOztHQUVHO0FBQ0gsTUFBYSxtQkFBbUI7SUFtQzlCLFlBQ0UsUUFBZ0IsRUFDaEIsU0FBaUIsRUFDakIsR0FBVyxFQUNYLFFBQWdCO1FBcENELGVBQVUsR0FBRyx5QkFBYyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBTXJELFdBQU0sR0FBVyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pDLGlCQUFZLEdBQVcsQ0FBQyxDQUFDO1FBRWpDLDBEQUEwRDtRQUNsRCxpQkFBWSxHQUFhLEVBQUUsQ0FBQztRQUM1QixjQUFTLEdBQWtCLElBQUksQ0FBQztRQU9oQyxvQkFBZSxHQUFXLENBQUMsQ0FBQztRQUU1QixVQUFLLEdBQVcsQ0FBQyxDQUFDO1FBQ2xCLFdBQU0sR0FBVyxDQUFDLENBQUM7UUFDbkIsY0FBUyxHQUFXLENBQUMsQ0FBQztRQUN0QixVQUFLLEdBQWtCLElBQUksQ0FBQztRQUM1QixZQUFPLEdBQWdDLElBQUksQ0FBQztRQUM1QyxlQUFVLEdBQVksS0FBSyxDQUFDO1FBYWxDLElBQUksQ0FBQyxLQUFLLEdBQUcsWUFBWSxDQUFDO1FBQzFCLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxtQkFBbUIsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQ2xFLFFBQVEsQ0FDVCxFQUFFLFNBQW1CLENBQUM7UUFDdkIsSUFBSSxDQUFDLGVBQWUsR0FBRyxtQkFBbUIsQ0FBQyxrQkFBa0IsQ0FB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
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@twick/ffmpeg",
3
+ "version": "0.11.0",
4
+ "description": "Ffmpeg utilities for twick",
5
+ "main": "dist/index.js",
6
+ "author": "twick",
7
+ "homepage": "https://re.video/",
8
+ "bugs": "https://github.com/ncounterspecialist/twick-base/issues",
9
+ "license": "MIT",
10
+ "scripts": {
11
+ "build": "tsc"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "types"
16
+ ],
17
+ "dependencies": {
18
+ "@ffmpeg-installer/ffmpeg": "^1.1.0",
19
+ "@ffprobe-installer/ffprobe": "^2.0.0",
20
+ "@twick/core": "^0.11.0",
21
+ "@twick/telemetry": "^0.11.0",
22
+ "fluent-ffmpeg": "^2.1.2",
23
+ "uuid": "^10.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/ffprobe-static": "^2.0.3",
27
+ "@types/fluent-ffmpeg": "^2.1.21",
28
+ "@types/uuid": "^10.0.0"
29
+ },
30
+ "gitHead": "59f38f4e7d3a9a30943bbad830dc0201eaa57ce7"
31
+ }