mes-engine 0.0.1

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.
Files changed (40) hide show
  1. package/CONTRIBUTING.md +199 -0
  2. package/README.md +86 -0
  3. package/dist/index.js +301 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/types/bandwidth.d.ts +8 -0
  6. package/dist/types/cache/ExternalCache.d.ts +11 -0
  7. package/dist/types/cache/LRU.d.ts +8 -0
  8. package/dist/types/cache/cacheStrategy.d.ts +12 -0
  9. package/dist/types/cache/internalCache.d.ts +13 -0
  10. package/dist/types/core/VideoEngine.d.ts +6 -0
  11. package/dist/types/core/events.d.ts +6 -0
  12. package/dist/types/core/types.d.ts +20 -0
  13. package/dist/types/engines/FFmpegEngine.d.ts +6 -0
  14. package/dist/types/index.d.ts +10 -0
  15. package/dist/types/processor.d.ts +19 -0
  16. package/dist/types/storage/FileSystemStorage.d.ts +6 -0
  17. package/dist/types/storage/StorageProvider.d.ts +5 -0
  18. package/dist/types/streaming/StreamManager.d.ts +10 -0
  19. package/docs/README.md +170 -0
  20. package/docs/engines.md +58 -0
  21. package/package.json +48 -0
  22. package/rollup.config.js +24 -0
  23. package/src/bandwidth.ts +30 -0
  24. package/src/cache/ExternalCache.ts +49 -0
  25. package/src/cache/LRU.ts +35 -0
  26. package/src/cache/cacheStrategy.ts +15 -0
  27. package/src/cache/internalCache.ts +60 -0
  28. package/src/core/VideoEngine.ts +16 -0
  29. package/src/core/events.ts +7 -0
  30. package/src/core/types.ts +26 -0
  31. package/src/engines/FFmpegEngine.ts +51 -0
  32. package/src/engines/GStreamerEngine.ts +45 -0
  33. package/src/index.ts +13 -0
  34. package/src/processor.ts +90 -0
  35. package/src/storage/FileSystemStorage.ts +19 -0
  36. package/src/storage/StorageProvider.ts +7 -0
  37. package/src/streaming/StreamManager.ts +26 -0
  38. package/tests/video-processor.test.ts +247 -0
  39. package/tsconfig.json +16 -0
  40. package/tsconfig.test.json +16 -0
@@ -0,0 +1,199 @@
1
+ # Contributing to mes-engine
2
+
3
+ Thank you for your interest in contributing to mes-engine! This document provides guidelines and instructions for contributing to the project.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Code of Conduct](#code-of-conduct)
8
+ - [Getting Started](#getting-started)
9
+ - [Development Process](#development-process)
10
+ - [Pull Request Process](#pull-request-process)
11
+ - [Coding Standards](#coding-standards)
12
+ - [Testing Guidelines](#testing-guidelines)
13
+ - [Documentation](#documentation)
14
+ - [Release Process](#release-process)
15
+
16
+ ## Code of Conduct
17
+
18
+ By participating in this project, you are expected to uphold our Code of Conduct:
19
+
20
+ - Use welcoming and inclusive language
21
+ - Be respectful of differing viewpoints and experiences
22
+ - Accept constructive criticism gracefully
23
+ - Focus on what is best for the community
24
+ - Show empathy towards other community members
25
+
26
+ ## Getting Started
27
+
28
+ 1. Fork the repository
29
+ 2. Clone your fork:
30
+ ```bash
31
+ git clone https://github.com/your-username/mes-engine.git
32
+ ```
33
+ 3. Add the upstream remote:
34
+ ```bash
35
+ git remote add upstream https://github.com/original-owner/mes-engine.git
36
+ ```
37
+ 4. Install dependencies:
38
+ ```bash
39
+ npm install
40
+ ```
41
+
42
+ ## Development Process
43
+
44
+ 1. Create a new branch for your feature/fix:
45
+ ```bash
46
+ git checkout -b feature/your-feature-name
47
+ # or
48
+ git checkout -b fix/your-fix-name
49
+ ```
50
+
51
+ 2. Make your changes, following our [coding standards](#coding-standards)
52
+
53
+ 3. Run tests and ensure they pass:
54
+ ```bash
55
+ npm test
56
+ ```
57
+
58
+ 4. Update documentation as needed
59
+
60
+ 5. Commit your changes using conventional commits:
61
+ ```bash
62
+ git commit -m "feat: add new video processing engine"
63
+ git commit -m "fix: resolve memory leak in cache system"
64
+ ```
65
+
66
+ ## Pull Request Process
67
+
68
+ 1. Update the README.md with details of changes if applicable
69
+ 2. Update the docs/ with any necessary documentation
70
+ 3. Add or update tests as needed
71
+ 4. Ensure all tests pass and code coverage meets requirements
72
+ 5. Submit a pull request to the `main` branch
73
+ 6. Address any review comments
74
+
75
+ ### PR Title Format
76
+ - feat: Add new feature
77
+ - fix: Fix an issue
78
+ - docs: Documentation changes
79
+ - style: Code style changes
80
+ - refactor: Code refactoring
81
+ - test: Add or update tests
82
+ - chore: Maintenance tasks
83
+
84
+ ## Coding Standards
85
+
86
+ ### TypeScript Guidelines
87
+
88
+ - Use TypeScript strict mode
89
+ - Prefer interfaces over types when possible
90
+ - Use explicit typing instead of inferring when the type isn't obvious
91
+ - Use meaningful variable and function names
92
+
93
+ ```typescript
94
+ // Good
95
+ interface VideoConfig {
96
+ quality: number;
97
+ format: string;
98
+ }
99
+
100
+ // Avoid
101
+ type Config = {
102
+ q: number;
103
+ f: string;
104
+ }
105
+ ```
106
+
107
+ ### Code Style
108
+
109
+ - Use 2 spaces for indentation
110
+ - Use semicolons
111
+ - Use single quotes for strings
112
+ - Add trailing commas in objects and arrays
113
+ - Keep lines under 100 characters
114
+
115
+ ### Best Practices
116
+
117
+ - Write pure functions when possible
118
+ - Use early returns to avoid deep nesting
119
+ - Handle errors appropriately
120
+ - Document complex algorithms
121
+ - Write self-documenting code
122
+
123
+ ## Testing Guidelines
124
+
125
+ ### Test Structure
126
+
127
+ ```typescript
128
+ describe('Component', () => {
129
+ describe('method()', () => {
130
+ it('should handle normal case', () => {
131
+ // Test
132
+ });
133
+
134
+ it('should handle error case', () => {
135
+ // Test
136
+ });
137
+ });
138
+ });
139
+ ```
140
+
141
+ ### Coverage Requirements
142
+
143
+ - Statements: 85%
144
+ - Branches: 80%
145
+ - Functions: 90%
146
+ - Lines: 85%
147
+
148
+ ### Running Tests
149
+
150
+ ```bash
151
+ npm test # Run all tests
152
+ npm run test:watch # Run tests in watch mode
153
+ npm run test:coverage # Generate coverage report
154
+ ```
155
+
156
+ ## Documentation
157
+
158
+ - Update API documentation for any new or modified functionality
159
+ - Include JSDoc comments for public APIs
160
+ - Add examples for new features
161
+ - Update README.md if adding new features
162
+ - Keep docs/ up to date with changes
163
+
164
+ ### Documentation Style
165
+
166
+ ```typescript
167
+ /**
168
+ * Processes a video chunk with specified quality settings
169
+ * @param inputPath - Path to the input video file
170
+ * @param quality - Quality settings for processing
171
+ * @returns Promise resolving to processed chunk data
172
+ * @throws {ProcessingError} When processing fails
173
+ */
174
+ ```
175
+
176
+ ## Release Process
177
+
178
+ 1. Update version number in package.json
179
+ 2. Update CHANGELOG.md
180
+ 3. Create release notes
181
+ 4. Create a tagged release
182
+ 5. Publish to npm
183
+
184
+ ### Version Numbers
185
+
186
+ Follow semantic versioning (MAJOR.MINOR.PATCH):
187
+ - MAJOR: Breaking changes
188
+ - MINOR: New features, no breaking changes
189
+ - PATCH: Bug fixes, no breaking changes
190
+
191
+ ## Questions or Problems?
192
+
193
+ - File an issue in the GitHub issue tracker
194
+ - Tag issues appropriately (bug, enhancement, question, etc.)
195
+ - Provide as much relevant information as possible
196
+
197
+ ## License
198
+
199
+ By contributing, you agree that your contributions will be licensed under the same MIT License that covers the project.
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # mes-engine
2
+
3
+ A powerful and flexible video processing framework for Node.js with support for multiple processing engines, adaptive streaming, and intelligent caching.
4
+
5
+ [![npm version](https://badge.fury.io/js/mes-engine.svg)](https://badge.fury.io/js/mes-engine)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - 🎥 Multiple video processing engines (FFmpeg, GStreamer)
11
+ - 🔄 Adaptive streaming with quality switching
12
+ - 📦 Chunk-based processing for efficient streaming
13
+ - 💾 Flexible storage providers
14
+ - 🚀 Built-in caching strategies (internal/external)
15
+ - 📡 Event-driven architecture
16
+ - 🔌 Extensible plugin system
17
+
18
+ ## Quick Start
19
+
20
+ ### Installation
21
+
22
+ ```bash
23
+ npm install mes-engine
24
+
25
+ # Install required engine
26
+ npm install ffmpeg-static # For FFmpeg engine
27
+ # or
28
+ npm install gstreamer # For GStreamer engine
29
+ ```
30
+
31
+ ### Basic Usage
32
+
33
+ ```typescript
34
+ import {
35
+ VideoProcessor,
36
+ FFmpegEngine,
37
+ FileSystemStorage,
38
+ InternalCache
39
+ } from 'mes-engine';
40
+
41
+ // Initialize processor
42
+ const processor = new VideoProcessor({
43
+ engine: new FFmpegEngine(),
44
+ storage: new FileSystemStorage(),
45
+ cache: new InternalCache({
46
+ maxSize: 1024 * 1024 * 100, // 100MB
47
+ ttl: 3600,
48
+ preloadNextChunk: true
49
+ })
50
+ });
51
+
52
+ // Process video
53
+ const manifest = await processor.processVideo('input.mp4');
54
+
55
+ // Stream video chunk
56
+ const stream = await processor.streamChunk(
57
+ manifest.videoId,
58
+ 720, // quality
59
+ 0 // chunk number
60
+ );
61
+ ```
62
+
63
+ ## Documentation
64
+
65
+ Full documentation is available in the [docs directory](./docs).
66
+
67
+ ### Key Topics:
68
+ - [Getting Started](./docs/getting-started.md)
69
+ - [Video Engines](./docs/engines.md)
70
+ - [Storage Providers](./docs/storage.md)
71
+ - [Caching Strategies](./docs/caching.md)
72
+ - [API Reference](./docs/api.md)
73
+
74
+ ## Supported Engines
75
+
76
+ - **FFmpegEngine**: Full-featured video processing using FFmpeg
77
+ - **GStreamerEngine**: High-performance processing using GStreamer
78
+ - **Custom Engines**: Create your own by extending `VideoEngine`
79
+
80
+ ## Contributing
81
+
82
+ Contributions are welcome! Please see our [Contributing Guide](./CONTRIBUTING.md) for details.
83
+
84
+ ## License
85
+
86
+ MIT © [Bumho Nisubire]
package/dist/index.js ADDED
@@ -0,0 +1,301 @@
1
+ import { EventEmitter } from 'events';
2
+ import { spawn } from 'child_process';
3
+ import { Readable } from 'stream';
4
+ import { promises } from 'fs';
5
+ import fetch from 'node-fetch';
6
+ import { join } from 'path';
7
+
8
+ var VideoEvent;
9
+ (function (VideoEvent) {
10
+ VideoEvent["CHUNK_PROCESSED"] = "chunkProcessed";
11
+ VideoEvent["QUALITY_PROCESSED"] = "qualityProcessed";
12
+ VideoEvent["PROCESSING_COMPLETE"] = "processingComplete";
13
+ VideoEvent["ERROR"] = "error";
14
+ })(VideoEvent || (VideoEvent = {}));
15
+
16
+ // core/VideoEngine.ts
17
+ class VideoEngine extends EventEmitter {
18
+ }
19
+
20
+ // engines/FFmpegEngine.ts
21
+ class FFmpegEngine extends VideoEngine {
22
+ async processChunk(inputPath, outputPath, startTime, quality) {
23
+ return new Promise((resolve, reject) => {
24
+ const ffmpeg = spawn('ffmpeg', [
25
+ '-i', inputPath,
26
+ '-ss', startTime.toString(),
27
+ '-t', '10',
28
+ '-vf', `scale=-1:${quality.height}`,
29
+ '-c:v', 'libx264',
30
+ '-b:v', quality.bitrate,
31
+ '-c:a', 'aac',
32
+ '-b:a', '128k',
33
+ '-preset', 'fast',
34
+ '-y',
35
+ outputPath
36
+ ]);
37
+ ffmpeg.on('close', code => {
38
+ code === 0 ? resolve() : reject(new Error(`FFmpeg error: ${code}`));
39
+ });
40
+ });
41
+ }
42
+ async getDuration(inputPath) {
43
+ return new Promise((resolve, reject) => {
44
+ const ffprobe = spawn('ffprobe', [
45
+ '-v', 'error',
46
+ '-show_entries', 'format=duration',
47
+ '-of', 'default=noprint_wrappers=1:nokey=1',
48
+ inputPath
49
+ ]);
50
+ let output = '';
51
+ ffprobe.stdout.on('data', data => output += data);
52
+ ffprobe.on('close', code => {
53
+ code === 0 ? resolve(parseFloat(output)) : reject(new Error(`FFprobe error: ${code}`));
54
+ });
55
+ });
56
+ }
57
+ }
58
+
59
+ // streaming/StreamManager.ts
60
+ class StreamManager {
61
+ constructor(storage) {
62
+ this.storage = storage;
63
+ }
64
+ async createStream(chunkPath, range) {
65
+ const data = await this.storage.getChunk(chunkPath);
66
+ const stream = new Readable();
67
+ if (range) {
68
+ stream.push(data.slice(range.start, range.end + 1));
69
+ }
70
+ else {
71
+ stream.push(data);
72
+ }
73
+ stream.push(null);
74
+ return stream;
75
+ }
76
+ }
77
+
78
+ class GStreamerEngine extends VideoEngine {
79
+ async processChunk(inputPath, outputPath, startTime, quality) {
80
+ return new Promise((resolve, reject) => {
81
+ const gst = spawn('gst-launch-1.0', [
82
+ 'filesrc', `location=${inputPath}`,
83
+ '!', 'decodebin',
84
+ '!', 'videoconvert',
85
+ '!', 'videoscale',
86
+ '!', `video/x-raw,width=-1,height=${quality.height}`,
87
+ '!', 'x264enc', `bitrate=${quality.bitrate}`,
88
+ '!', 'mp4mux', '!', 'filesink', `location=${outputPath}`
89
+ ]);
90
+ gst.on('close', code => {
91
+ code === 0 ? resolve() : reject(new Error(`GStreamer error: ${code}`));
92
+ });
93
+ });
94
+ }
95
+ async getDuration(inputPath) {
96
+ return new Promise((resolve, reject) => {
97
+ const gst = spawn('gst-launch-1.0', [
98
+ 'filesrc', `location=${inputPath}`,
99
+ '!', 'decodebin',
100
+ '!', 'identity', '-debug', 'duration'
101
+ ]);
102
+ let output = '';
103
+ gst.stdout.on('data', data => output += data);
104
+ gst.on('close', code => {
105
+ code === 0 ? resolve(parseFloat(output)) : reject(new Error(`GStreamer error: ${code}`));
106
+ });
107
+ });
108
+ }
109
+ }
110
+
111
+ // storage/StorageProvider.ts
112
+ class StorageProvider {
113
+ }
114
+
115
+ // storage/FileSystemStorage.ts
116
+ class FileSystemStorage extends StorageProvider {
117
+ async saveChunk(chunkPath, data) {
118
+ await promises.writeFile(chunkPath, data);
119
+ }
120
+ async getChunk(chunkPath) {
121
+ return promises.readFile(chunkPath);
122
+ }
123
+ async deleteChunk(chunkPath) {
124
+ await promises.unlink(chunkPath);
125
+ }
126
+ }
127
+
128
+ class CacheStrategy {
129
+ }
130
+
131
+ // cache/LRU.ts
132
+ class LRU {
133
+ constructor(maxSize) {
134
+ this.maxSize = maxSize;
135
+ this.cache = new Map();
136
+ }
137
+ set(key, value) {
138
+ if (this.cache.has(key)) {
139
+ this.cache.delete(key);
140
+ }
141
+ else if (this.cache.size >= this.maxSize) {
142
+ const oldestKey = this.cache.keys().next().value;
143
+ if (oldestKey !== undefined) {
144
+ this.cache.delete(oldestKey);
145
+ }
146
+ }
147
+ this.cache.set(key, value);
148
+ }
149
+ get(key) {
150
+ if (!this.cache.has(key))
151
+ return undefined;
152
+ const value = this.cache.get(key);
153
+ this.cache.delete(key);
154
+ this.cache.set(key, value);
155
+ return value;
156
+ }
157
+ clear() {
158
+ this.cache.clear();
159
+ }
160
+ }
161
+
162
+ // cache/internalCache.ts
163
+ class InternalCache extends CacheStrategy {
164
+ constructor(options, storage) {
165
+ super();
166
+ this.options = options;
167
+ this.cache = new LRU(options.maxSize);
168
+ this.storage = storage;
169
+ }
170
+ async set(key, value) {
171
+ this.cache.set(key, value);
172
+ }
173
+ async get(key) {
174
+ const cached = this.cache.get(key);
175
+ if (cached)
176
+ return cached;
177
+ try {
178
+ const data = await this.storage.getChunk(key);
179
+ await this.set(key, data);
180
+ return data;
181
+ }
182
+ catch {
183
+ return null;
184
+ }
185
+ }
186
+ async preload(key) {
187
+ if (this.options.preloadNextChunk) {
188
+ const nextChunkKey = this.getNextChunkKey(key);
189
+ if (!this.cache.get(nextChunkKey)) {
190
+ try {
191
+ const data = await this.storage.getChunk(nextChunkKey);
192
+ await this.set(nextChunkKey, data);
193
+ }
194
+ catch {
195
+ // Ignore preload failures
196
+ }
197
+ }
198
+ }
199
+ }
200
+ async clear() {
201
+ this.cache.clear();
202
+ }
203
+ getNextChunkKey(currentKey) {
204
+ const parts = currentKey.split('_');
205
+ const currentChunk = parseInt(parts[parts.length - 1]);
206
+ parts[parts.length - 1] = (currentChunk + 1).toString();
207
+ return parts.join('_');
208
+ }
209
+ }
210
+
211
+ // cache/ExternalCache.ts
212
+ class ExternalCache extends CacheStrategy {
213
+ constructor(options) {
214
+ super();
215
+ this.options = options;
216
+ this.baseUrl = options.externalCacheUrl;
217
+ }
218
+ async set(key, value) {
219
+ await fetch(`${this.baseUrl}/cache/${key}`, {
220
+ method: 'POST',
221
+ body: value,
222
+ headers: {
223
+ 'Content-Type': 'application/octet-stream',
224
+ 'TTL': this.options.ttl.toString()
225
+ }
226
+ });
227
+ }
228
+ async get(key) {
229
+ const response = await fetch(`${this.baseUrl}/cache/${key}`);
230
+ return response.ok ? Buffer.from(await response.arrayBuffer()) : null;
231
+ }
232
+ async preload(key) {
233
+ if (this.options.preloadNextChunk) {
234
+ const nextChunkKey = this.getNextChunkKey(key);
235
+ await fetch(`${this.baseUrl}/preload/${nextChunkKey}`);
236
+ }
237
+ }
238
+ async clear() {
239
+ await fetch(`${this.baseUrl}/cache`, { method: 'DELETE' });
240
+ }
241
+ getNextChunkKey(currentKey) {
242
+ const parts = currentKey.split('_');
243
+ const currentChunk = parseInt(parts[parts.length - 1]);
244
+ parts[parts.length - 1] = (currentChunk + 1).toString();
245
+ return parts.join('_');
246
+ }
247
+ }
248
+
249
+ class VideoProcessor extends EventEmitter {
250
+ constructor(engine, storage, config) {
251
+ super();
252
+ this.engine = engine;
253
+ this.streamManager = new StreamManager(storage);
254
+ this.config = config;
255
+ }
256
+ async processVideo(inputPath) {
257
+ const videoId = await this.generateVideoId(inputPath);
258
+ const manifest = {
259
+ videoId,
260
+ qualities: this.config.defaultQualities,
261
+ chunks: []
262
+ };
263
+ const duration = await this.engine.getDuration(inputPath);
264
+ const chunks = Math.ceil(duration / this.config.chunkSize);
265
+ for (const quality of this.config.defaultQualities) {
266
+ for (let i = 0; i < chunks; i++) {
267
+ const chunkPath = this.getChunkPath(videoId, quality.height, i);
268
+ try {
269
+ await this.engine.processChunk(inputPath, chunkPath, i * this.config.chunkSize, quality);
270
+ manifest.chunks.push({
271
+ quality: quality.height,
272
+ number: i,
273
+ path: chunkPath
274
+ });
275
+ this.emit(VideoEvent.CHUNK_PROCESSED, { quality, chunkNumber: i });
276
+ }
277
+ catch (error) {
278
+ this.emit(VideoEvent.ERROR, error);
279
+ throw error;
280
+ }
281
+ }
282
+ this.emit(VideoEvent.QUALITY_PROCESSED, quality);
283
+ }
284
+ this.emit(VideoEvent.PROCESSING_COMPLETE, manifest);
285
+ return manifest;
286
+ }
287
+ async streamChunk(videoId, quality, chunkNumber, range) {
288
+ const chunkPath = this.getChunkPath(videoId, quality, chunkNumber);
289
+ return this.streamManager.createStream(chunkPath, range);
290
+ }
291
+ getChunkPath(videoId, quality, chunkNumber) {
292
+ return join(this.config.cacheDir, videoId, `${quality}p`, `chunk_${chunkNumber}.mp4`);
293
+ }
294
+ async generateVideoId(inputPath) {
295
+ const stats = await promises.stat(inputPath);
296
+ return `${inputPath.split('/').pop()?.split('.')[0]}_${stats.mtimeMs}`;
297
+ }
298
+ }
299
+
300
+ export { CacheStrategy, ExternalCache, FFmpegEngine, FileSystemStorage, GStreamerEngine, InternalCache, StorageProvider, StreamManager, VideoEngine, VideoEvent, VideoProcessor };
301
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/core/events.ts","../../src/core/VideoEngine.ts","../../src/engines/FFmpegEngine.ts","../../src/streaming/StreamManager.ts","../../src/engines/GStreamerEngine.ts","../../src/storage/StorageProvider.ts","../../src/storage/FileSystemStorage.ts","../../src/cache/cacheStrategy.ts","../../src/cache/LRU.ts","../../src/cache/internalCache.ts","../../src/cache/ExternalCache.ts","../../src/processor.ts"],"sourcesContent":["\r\nexport enum VideoEvent {\r\n CHUNK_PROCESSED = 'chunkProcessed',\r\n QUALITY_PROCESSED = 'qualityProcessed',\r\n PROCESSING_COMPLETE = 'processingComplete',\r\n ERROR = 'error'\r\n}\r\n","\r\n// core/VideoEngine.ts\r\nimport { EventEmitter } from 'events';\r\nimport { VideoConfig, QualityLevel, VideoManifest } from './types';\r\nimport { VideoEvent } from './events';\r\n\r\nexport abstract class VideoEngine extends EventEmitter {\r\n abstract processChunk(\r\n inputPath: string,\r\n outputPath: string,\r\n startTime: number,\r\n quality: QualityLevel\r\n ): Promise<void>;\r\n\r\n abstract getDuration(inputPath: string): Promise<number>;\r\n}","\r\n// engines/FFmpegEngine.ts\r\nimport { spawn } from 'child_process';\r\nimport { VideoEngine } from '../core/VideoEngine';\r\nimport { QualityLevel } from '../core/types';\r\n\r\nexport class FFmpegEngine extends VideoEngine {\r\n async processChunk(\r\n inputPath: string,\r\n outputPath: string,\r\n startTime: number,\r\n quality: QualityLevel\r\n ): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const ffmpeg = spawn('ffmpeg', [\r\n '-i', inputPath,\r\n '-ss', startTime.toString(),\r\n '-t', '10',\r\n '-vf', `scale=-1:${quality.height}`,\r\n '-c:v', 'libx264',\r\n '-b:v', quality.bitrate,\r\n '-c:a', 'aac',\r\n '-b:a', '128k',\r\n '-preset', 'fast',\r\n '-y',\r\n outputPath\r\n ]);\r\n\r\n ffmpeg.on('close', code => {\r\n code === 0 ? resolve() : reject(new Error(`FFmpeg error: ${code}`));\r\n });\r\n });\r\n }\r\n\r\n async getDuration(inputPath: string): Promise<number> {\r\n return new Promise((resolve, reject) => {\r\n const ffprobe = spawn('ffprobe', [\r\n '-v', 'error',\r\n '-show_entries', 'format=duration',\r\n '-of', 'default=noprint_wrappers=1:nokey=1',\r\n inputPath\r\n ]);\r\n\r\n let output = '';\r\n ffprobe.stdout.on('data', data => output += data);\r\n ffprobe.on('close', code => {\r\n code === 0 ? resolve(parseFloat(output)) : reject(new Error(`FFprobe error: ${code}`));\r\n });\r\n });\r\n }\r\n}","\r\n// streaming/StreamManager.ts\r\nimport { Readable } from 'stream';\r\nimport { StorageProvider } from '../storage/StorageProvider';\r\n\r\nexport class StreamManager {\r\n private storage: StorageProvider;\r\n\r\n constructor(storage: StorageProvider) {\r\n this.storage = storage;\r\n }\r\n\r\n async createStream(chunkPath: string, range?: { start: number; end: number }): Promise<Readable> {\r\n const data = await this.storage.getChunk(chunkPath);\r\n const stream = new Readable();\r\n\r\n if (range) {\r\n stream.push(data.slice(range.start, range.end + 1));\r\n } else {\r\n stream.push(data);\r\n }\r\n\r\n stream.push(null);\r\n return stream;\r\n }\r\n}","import { spawn } from 'child_process';\r\nimport { VideoEngine } from '../core/VideoEngine';\r\nimport { QualityLevel } from '../core/types';\r\n\r\nexport class GStreamerEngine extends VideoEngine {\r\n async processChunk(\r\n inputPath: string,\r\n outputPath: string,\r\n startTime: number,\r\n quality: QualityLevel\r\n ): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const gst = spawn('gst-launch-1.0', [\r\n 'filesrc', `location=${inputPath}`,\r\n '!', 'decodebin',\r\n '!', 'videoconvert',\r\n '!', 'videoscale',\r\n '!', `video/x-raw,width=-1,height=${quality.height}`,\r\n '!', 'x264enc', `bitrate=${quality.bitrate}`,\r\n '!', 'mp4mux', '!', 'filesink', `location=${outputPath}`\r\n ]);\r\n\r\n gst.on('close', code => {\r\n code === 0 ? resolve() : reject(new Error(`GStreamer error: ${code}`));\r\n });\r\n });\r\n }\r\n\r\n async getDuration(inputPath: string): Promise<number> {\r\n return new Promise((resolve, reject) => {\r\n const gst = spawn('gst-launch-1.0', [\r\n 'filesrc', `location=${inputPath}`,\r\n '!', 'decodebin',\r\n '!', 'identity', '-debug', 'duration'\r\n ]);\r\n\r\n let output = '';\r\n gst.stdout.on('data', data => output += data);\r\n gst.on('close', code => {\r\n code === 0 ? resolve(parseFloat(output)) : reject(new Error(`GStreamer error: ${code}`));\r\n });\r\n });\r\n }\r\n}\r\n","\r\n// storage/StorageProvider.ts\r\nexport abstract class StorageProvider {\r\n abstract saveChunk(chunkPath: string, data: Buffer): Promise<void>;\r\n abstract getChunk(chunkPath: string): Promise<Buffer>;\r\n abstract deleteChunk(chunkPath: string): Promise<void>;\r\n}","\r\n\r\n// storage/FileSystemStorage.ts\r\nimport { promises as fs } from 'fs';\r\nimport { StorageProvider } from './StorageProvider';\r\n\r\nexport class FileSystemStorage extends StorageProvider {\r\n async saveChunk(chunkPath: string, data: Buffer): Promise<void> {\r\n await fs.writeFile(chunkPath, data);\r\n }\r\n\r\n async getChunk(chunkPath: string): Promise<Buffer> {\r\n return fs.readFile(chunkPath);\r\n }\r\n\r\n async deleteChunk(chunkPath: string): Promise<void> {\r\n await fs.unlink(chunkPath);\r\n }\r\n}","\r\n// cache/CacheStrategy.ts\r\nexport interface CacheOptions {\r\n maxSize: number;\r\n ttl: number;\r\n preloadNextChunk: boolean;\r\n externalCacheUrl?: string;\r\n}\r\n\r\nexport abstract class CacheStrategy {\r\n abstract set(key: string, value: Buffer): Promise<void>;\r\n abstract get(key: string): Promise<Buffer | null>;\r\n abstract preload(key: string): Promise<void>;\r\n abstract clear(): Promise<void>;\r\n}","\r\n// cache/LRU.ts\r\nexport class LRU<T> {\r\n private maxSize: number;\r\n private cache: Map<string, T>;\r\n\r\n constructor(maxSize: number) {\r\n this.maxSize = maxSize;\r\n this.cache = new Map();\r\n }\r\n\r\n set(key: string, value: T): void {\r\n if (this.cache.has(key)) {\r\n this.cache.delete(key);\r\n } else if (this.cache.size >= this.maxSize) {\r\n const oldestKey = this.cache.keys().next().value;\r\n if (oldestKey !== undefined) {\r\n this.cache.delete(oldestKey);\r\n }\r\n }\r\n this.cache.set(key, value);\r\n }\r\n\r\n get(key: string): T | undefined {\r\n if (!this.cache.has(key)) return undefined;\r\n const value = this.cache.get(key)!;\r\n this.cache.delete(key);\r\n this.cache.set(key, value);\r\n return value;\r\n }\r\n\r\n clear(): void {\r\n this.cache.clear();\r\n }\r\n}","\r\n// cache/internalCache.ts\r\nimport { LRU } from './LRU';\r\nimport { CacheStrategy, CacheOptions } from './cacheStrategy';\r\nimport { StorageProvider } from '../storage/StorageProvider';\r\n\r\nexport class InternalCache extends CacheStrategy {\r\n private cache: LRU<Buffer>;\r\n private options: CacheOptions;\r\n private storage: StorageProvider;\r\n\r\n constructor(options: CacheOptions, storage: StorageProvider) {\r\n super();\r\n this.options = options;\r\n this.cache = new LRU(options.maxSize);\r\n this.storage = storage;\r\n }\r\n\r\n async set(key: string, value: Buffer): Promise<void> {\r\n this.cache.set(key, value);\r\n }\r\n\r\n async get(key: string): Promise<Buffer | null> {\r\n const cached = this.cache.get(key);\r\n if (cached) return cached;\r\n\r\n try {\r\n const data = await this.storage.getChunk(key);\r\n await this.set(key, data);\r\n return data;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n async preload(key: string): Promise<void> {\r\n if (this.options.preloadNextChunk) {\r\n const nextChunkKey = this.getNextChunkKey(key);\r\n if (!this.cache.get(nextChunkKey)) {\r\n try {\r\n const data = await this.storage.getChunk(nextChunkKey);\r\n await this.set(nextChunkKey, data);\r\n } catch {\r\n // Ignore preload failures\r\n }\r\n }\r\n }\r\n }\r\n\r\n async clear(): Promise<void> {\r\n this.cache.clear();\r\n }\r\n\r\n private getNextChunkKey(currentKey: string): string {\r\n const parts = currentKey.split('_');\r\n const currentChunk = parseInt(parts[parts.length - 1]);\r\n parts[parts.length - 1] = (currentChunk + 1).toString();\r\n return parts.join('_');\r\n }\r\n}","\r\n// cache/ExternalCache.ts\r\nimport fetch from 'node-fetch';\r\nimport { CacheStrategy, CacheOptions } from './cacheStrategy';\r\n\r\nexport class ExternalCache extends CacheStrategy {\r\n private baseUrl: string;\r\n private options: CacheOptions;\r\n\r\n constructor(options: CacheOptions) {\r\n super();\r\n this.options = options;\r\n this.baseUrl = options.externalCacheUrl!;\r\n }\r\n\r\n async set(key: string, value: Buffer): Promise<void> {\r\n await fetch(`${this.baseUrl}/cache/${key}`, {\r\n method: 'POST',\r\n body: value,\r\n headers: {\r\n 'Content-Type': 'application/octet-stream',\r\n 'TTL': this.options.ttl.toString()\r\n }\r\n });\r\n }\r\n\r\n async get(key: string): Promise<Buffer | null> {\r\n const response = await fetch(`${this.baseUrl}/cache/${key}`);\r\n return response.ok ? Buffer.from(await response.arrayBuffer()) : null;\r\n }\r\n\r\n async preload(key: string): Promise<void> {\r\n if (this.options.preloadNextChunk) {\r\n const nextChunkKey = this.getNextChunkKey(key);\r\n await fetch(`${this.baseUrl}/preload/${nextChunkKey}`);\r\n }\r\n }\r\n\r\n async clear(): Promise<void> {\r\n await fetch(`${this.baseUrl}/cache`, { method: 'DELETE' });\r\n }\r\n\r\n private getNextChunkKey(currentKey: string): string {\r\n const parts = currentKey.split('_');\r\n const currentChunk = parseInt(parts[parts.length - 1]);\r\n parts[parts.length - 1] = (currentChunk + 1).toString();\r\n return parts.join('_');\r\n }\r\n}","\r\n// processor.ts\r\nimport { VideoEngine } from './core/VideoEngine';\r\nimport { EventEmitter } from 'events';\r\nimport { StorageProvider } from './storage/StorageProvider';\r\nimport { StreamManager } from './streaming/StreamManager';\r\nimport { VideoConfig, VideoManifest } from './core/types';\r\nimport { join } from 'path';\r\nimport { promises as fs } from 'fs';\r\nimport { Readable } from 'stream';\r\nimport { VideoEvent } from './core/events';\r\n\r\nexport class VideoProcessor extends EventEmitter {\r\n private engine: VideoEngine;\r\n private streamManager: StreamManager;\r\n private config: VideoConfig;\r\n\r\n constructor(\r\n engine: VideoEngine,\r\n storage: StorageProvider,\r\n config: VideoConfig\r\n ) {\r\n super();\r\n this.engine = engine;\r\n this.streamManager = new StreamManager(storage);\r\n this.config = config;\r\n }\r\n\r\n async processVideo(inputPath: string): Promise<VideoManifest> {\r\n const videoId = await this.generateVideoId(inputPath);\r\n const manifest: VideoManifest = {\r\n videoId,\r\n qualities: this.config.defaultQualities,\r\n chunks: []\r\n };\r\n\r\n const duration = await this.engine.getDuration(inputPath);\r\n const chunks = Math.ceil(duration / this.config.chunkSize);\r\n\r\n for (const quality of this.config.defaultQualities) {\r\n for (let i = 0; i < chunks; i++) {\r\n const chunkPath = this.getChunkPath(videoId, quality.height, i);\r\n\r\n try {\r\n await this.engine.processChunk(\r\n inputPath,\r\n chunkPath,\r\n i * this.config.chunkSize,\r\n quality\r\n );\r\n\r\n manifest.chunks.push({\r\n quality: quality.height,\r\n number: i,\r\n path: chunkPath\r\n });\r\n\r\n this.emit(VideoEvent.CHUNK_PROCESSED, { quality, chunkNumber: i });\r\n } catch (error) {\r\n this.emit(VideoEvent.ERROR, error);\r\n throw error;\r\n }\r\n }\r\n\r\n this.emit(VideoEvent.QUALITY_PROCESSED, quality);\r\n }\r\n\r\n this.emit(VideoEvent.PROCESSING_COMPLETE, manifest);\r\n return manifest;\r\n }\r\n\r\n async streamChunk(\r\n videoId: string,\r\n quality: number,\r\n chunkNumber: number,\r\n range?: { start: number; end: number }\r\n ): Promise<Readable> {\r\n const chunkPath = this.getChunkPath(videoId, quality, chunkNumber);\r\n return this.streamManager.createStream(chunkPath, range);\r\n }\r\n\r\n private getChunkPath(videoId: string, quality: number, chunkNumber: number): string {\r\n return join(this.config.cacheDir, videoId, `${quality}p`, `chunk_${chunkNumber}.mp4`);\r\n }\r\n\r\n private async generateVideoId(inputPath: string): Promise<string> {\r\n const stats = await fs.stat(inputPath);\r\n return `${inputPath.split('/').pop()?.split('.')[0]}_${stats.mtimeMs}`;\r\n }\r\n}"],"names":["fs"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ declare class BandwidthDetector {
2
+ private samples;
3
+ private readonly windowSize;
4
+ addSample(bytesTransferred: number, durationMs: number): void;
5
+ getEstimatedBandwidth(): number;
6
+ private _cleanOldSamples;
7
+ private _median;
8
+ }
@@ -0,0 +1,11 @@
1
+ import { CacheStrategy, CacheOptions } from './cacheStrategy';
2
+ export declare class ExternalCache extends CacheStrategy {
3
+ private baseUrl;
4
+ private options;
5
+ constructor(options: CacheOptions);
6
+ set(key: string, value: Buffer): Promise<void>;
7
+ get(key: string): Promise<Buffer | null>;
8
+ preload(key: string): Promise<void>;
9
+ clear(): Promise<void>;
10
+ private getNextChunkKey;
11
+ }
@@ -0,0 +1,8 @@
1
+ export declare class LRU<T> {
2
+ private cache;
3
+ private maxSize;
4
+ constructor(maxSize: number);
5
+ get(key: string): T | undefined;
6
+ set(key: string, value: T): void;
7
+ clear(): void;
8
+ }
@@ -0,0 +1,12 @@
1
+ export interface CacheOptions {
2
+ maxSize: number;
3
+ ttl: number;
4
+ preloadNextChunk: boolean;
5
+ externalCacheUrl?: string;
6
+ }
7
+ export declare abstract class CacheStrategy {
8
+ abstract set(key: string, value: Buffer): Promise<void>;
9
+ abstract get(key: string): Promise<Buffer | null>;
10
+ abstract preload(key: string): Promise<void>;
11
+ abstract clear(): Promise<void>;
12
+ }