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,13 @@
1
+ import { CacheStrategy, CacheOptions } from './cacheStrategy';
2
+ import { StorageProvider } from '../storage/StorageProvider';
3
+ export declare class InternalCache extends CacheStrategy {
4
+ private cache;
5
+ private options;
6
+ private storage;
7
+ constructor(options: CacheOptions, storage: StorageProvider);
8
+ set(key: string, value: Buffer): Promise<void>;
9
+ get(key: string): Promise<Buffer | null>;
10
+ preload(key: string): Promise<void>;
11
+ clear(): Promise<void>;
12
+ private getNextChunkKey;
13
+ }
@@ -0,0 +1,6 @@
1
+ import { EventEmitter } from 'events';
2
+ import { QualityLevel } from './types';
3
+ export declare abstract class VideoEngine extends EventEmitter {
4
+ abstract processChunk(inputPath: string, outputPath: string, startTime: number, quality: QualityLevel): Promise<void>;
5
+ abstract getDuration(inputPath: string): Promise<number>;
6
+ }
@@ -0,0 +1,6 @@
1
+ export declare enum VideoEvent {
2
+ CHUNK_PROCESSED = "chunkProcessed",
3
+ QUALITY_PROCESSED = "qualityProcessed",
4
+ PROCESSING_COMPLETE = "processingComplete",
5
+ ERROR = "error"
6
+ }
@@ -0,0 +1,20 @@
1
+ export interface VideoConfig {
2
+ chunkSize: number;
3
+ cacheDir: string;
4
+ maxCacheSize: number;
5
+ defaultQualities: QualityLevel[];
6
+ }
7
+ export interface QualityLevel {
8
+ height: number;
9
+ bitrate: string;
10
+ }
11
+ export interface VideoChunk {
12
+ quality: number;
13
+ number: number;
14
+ path: string;
15
+ }
16
+ export interface VideoManifest {
17
+ videoId: string;
18
+ qualities: QualityLevel[];
19
+ chunks: VideoChunk[];
20
+ }
@@ -0,0 +1,6 @@
1
+ import { VideoEngine } from '../core/VideoEngine';
2
+ import { QualityLevel } from '../core/types';
3
+ export declare class FFmpegEngine extends VideoEngine {
4
+ processChunk(inputPath: string, outputPath: string, startTime: number, quality: QualityLevel): Promise<void>;
5
+ getDuration(inputPath: string): Promise<number>;
6
+ }
@@ -0,0 +1,10 @@
1
+ export * from './core/types';
2
+ export * from './core/events';
3
+ export * from './core/VideoEngine';
4
+ export * from './engines/FFmpegEngine';
5
+ export * from './storage/StorageProvider';
6
+ export * from './storage/FileSystemStorage';
7
+ export * from './cache/cacheStrategy';
8
+ export * from './cache/internalCache';
9
+ export * from './cache/ExternalCache';
10
+ export * from './processor';
@@ -0,0 +1,19 @@
1
+ import { VideoEngine } from './core/VideoEngine';
2
+ import { EventEmitter } from 'events';
3
+ import { StorageProvider } from './storage/StorageProvider';
4
+ import { VideoConfig, VideoManifest } from './core/types';
5
+ import { Readable } from 'stream';
6
+ export declare class VideoProcessor extends EventEmitter {
7
+ private engine;
8
+ private storage;
9
+ private streamManager;
10
+ private config;
11
+ constructor(engine: VideoEngine, storage: StorageProvider, config: VideoConfig);
12
+ processVideo(inputPath: string): Promise<VideoManifest>;
13
+ streamChunk(videoId: string, quality: number, chunkNumber: number, range?: {
14
+ start: number;
15
+ end: number;
16
+ }): Promise<Readable>;
17
+ private getChunkPath;
18
+ private generateVideoId;
19
+ }
@@ -0,0 +1,6 @@
1
+ import { StorageProvider } from './StorageProvider';
2
+ export declare class FileSystemStorage extends StorageProvider {
3
+ saveChunk(chunkPath: string, data: Buffer): Promise<void>;
4
+ getChunk(chunkPath: string): Promise<Buffer>;
5
+ deleteChunk(chunkPath: string): Promise<void>;
6
+ }
@@ -0,0 +1,5 @@
1
+ export declare abstract class StorageProvider {
2
+ abstract saveChunk(chunkPath: string, data: Buffer): Promise<void>;
3
+ abstract getChunk(chunkPath: string): Promise<Buffer>;
4
+ abstract deleteChunk(chunkPath: string): Promise<void>;
5
+ }
@@ -0,0 +1,10 @@
1
+ import { Readable } from 'stream';
2
+ import { StorageProvider } from '../storage/StorageProvider';
3
+ export declare class StreamManager {
4
+ private storage;
5
+ constructor(storage: StorageProvider);
6
+ createStream(chunkPath: string, range?: {
7
+ start: number;
8
+ end: number;
9
+ }): Promise<Readable>;
10
+ }
package/docs/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # Video Processing Framework Documentation
2
+
3
+ Comprehensive documentation for the mes-engine video processing framework.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Getting Started](#getting-started)
8
+ 2. [Core Concepts](#core-concepts)
9
+ 3. [Components](#components)
10
+ 4. [Advanced Usage](#advanced-usage)
11
+ 5. [API Reference](#api-reference)
12
+
13
+ ## Getting Started
14
+
15
+ ### Installation
16
+ ```bash
17
+ npm install mes-engine
18
+ ```
19
+
20
+ ### Engine Requirements
21
+
22
+ #### FFmpeg Engine
23
+ ```bash
24
+ npm install ffmpeg-static
25
+ ```
26
+
27
+ #### GStreamer Engine
28
+ Requires GStreamer to be installed on your system:
29
+ - Ubuntu/Debian: `apt-get install gstreamer1.0-tools`
30
+ - MacOS: `brew install gstreamer`
31
+ - Windows: Download from GStreamer website
32
+
33
+ ### Basic Configuration
34
+
35
+ ```typescript
36
+ import { VideoProcessor, FFmpegEngine, FileSystemStorage } from 'mes-engine';
37
+
38
+ const config = {
39
+ chunkSize: 10, // seconds
40
+ cacheDir: './cache',
41
+ maxCacheSize: 1000, // MB
42
+ defaultQualities: [
43
+ { height: 1080, bitrate: '4000k' },
44
+ { height: 720, bitrate: '2500k' },
45
+ { height: 480, bitrate: '1000k' }
46
+ ]
47
+ };
48
+
49
+ const processor = new VideoProcessor({
50
+ engine: new FFmpegEngine(),
51
+ storage: new FileSystemStorage(),
52
+ config
53
+ });
54
+ ```
55
+
56
+ ## Core Concepts
57
+
58
+ ### Video Processing Flow
59
+
60
+ 1. **Input**: Raw video file
61
+ 2. **Chunking**: Video split into segments
62
+ 3. **Transcoding**: Multiple quality versions
63
+ 4. **Storage**: Chunks saved to storage provider
64
+ 5. **Streaming**: Adaptive delivery
65
+
66
+ ### Events System
67
+
68
+ ```typescript
69
+ processor.on(VideoEvent.CHUNK_PROCESSED, (data) => {
70
+ console.log(`Chunk ${data.chunkNumber} processed at ${data.quality}p`);
71
+ });
72
+
73
+ processor.on(VideoEvent.PROCESSING_COMPLETE, (manifest) => {
74
+ console.log('Processing complete:', manifest);
75
+ });
76
+ ```
77
+
78
+ ## Components
79
+
80
+ ### Processing Engines
81
+
82
+ - **FFmpegEngine**: Standard video processing
83
+ - **GStreamerEngine**: High-performance alternative
84
+ - **Custom Engines**: Extend `VideoEngine` class
85
+
86
+ ```typescript
87
+ class CustomEngine extends VideoEngine {
88
+ async processChunk(
89
+ inputPath: string,
90
+ outputPath: string,
91
+ startTime: number,
92
+ quality: QualityLevel
93
+ ): Promise<void> {
94
+ // Implementation
95
+ }
96
+
97
+ async getDuration(inputPath: string): Promise<number> {
98
+ // Implementation
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### Storage Providers
104
+
105
+ - **FileSystemStorage**: Local file system storage
106
+ - **Custom Storage**: Implement `StorageProvider`
107
+
108
+ ```typescript
109
+ class CustomStorage extends StorageProvider {
110
+ async saveChunk(chunkPath: string, data: Buffer): Promise<void> {
111
+ // Implementation
112
+ }
113
+
114
+ async getChunk(chunkPath: string): Promise<Buffer> {
115
+ // Implementation
116
+ }
117
+
118
+ async deleteChunk(chunkPath: string): Promise<void> {
119
+ // Implementation
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### Caching Strategies
125
+
126
+ - **InternalCache**: Memory-based LRU cache
127
+ - **ExternalCache**: Remote cache service
128
+ - **Custom Cache**: Extend `CacheStrategy`
129
+
130
+ ## Advanced Usage
131
+
132
+ ### Custom Quality Levels
133
+
134
+ ```typescript
135
+ const customQualities = [
136
+ { height: 2160, bitrate: '8000k' }, // 4K
137
+ { height: 1440, bitrate: '6000k' }, // 2K
138
+ { height: 1080, bitrate: '4000k' }, // Full HD
139
+ ];
140
+
141
+ const manifest = await processor.processVideo('input.mp4', {
142
+ qualities: customQualities
143
+ });
144
+ ```
145
+
146
+ ### Bandwidth-Aware Streaming
147
+
148
+ ```typescript
149
+ import { BandwidthDetector } from 'mes-engine';
150
+
151
+ const detector = new BandwidthDetector();
152
+ detector.addSample(bytesTransferred, durationMs);
153
+ const estimatedBandwidth = detector.getEstimatedBandwidth();
154
+ ```
155
+
156
+ ## API Reference
157
+
158
+ See [API.md](./API.md) for detailed API documentation.
159
+
160
+ ## Testing
161
+
162
+ ```bash
163
+ npm run test # Run all tests
164
+ npm run test:watch # Watch mode
165
+ npm run test:coverage # Coverage report
166
+ ```
167
+
168
+ ## Contributing
169
+
170
+ See [CONTRIBUTING.md](../CONTRIBUTING.md) for contribution guidelines.
@@ -0,0 +1,58 @@
1
+ # Engines Support
2
+
3
+ ## FFmpegEngine
4
+ The `FFmpegEngine` uses `ffmpeg` for video processing. You will need to install an FFmpeg binary to use this engine.
5
+
6
+ ### Installation of FFmpeg
7
+ To use the `FFmpegEngine`, you must install FFmpeg or use `ffmpeg-static` to include the FFmpeg binary. You can install `ffmpeg-static` by running:
8
+
9
+ ```bash
10
+ npm install ffmpeg-static
11
+ ```
12
+
13
+ Alternatively, you can use any other FFmpeg binary that is compatible with your system.
14
+
15
+ ### Example Usage:
16
+
17
+ ```typescript
18
+ import { FFmpegEngine } from 'mes-engine';
19
+
20
+ // Create an FFmpeg engine instance
21
+ const engine = new FFmpegEngine();
22
+
23
+ // Use it to process video chunks
24
+ engine.processChunk('input.mp4', 'output.mp4', 0, { height: 720, bitrate: '2000k' })
25
+ .then(() => {
26
+ console.log('Chunk processed successfully');
27
+ })
28
+ .catch(error => {
29
+ console.error('Error processing chunk:', error);
30
+ });
31
+ ```
32
+
33
+ ## Custom Engines
34
+ You can implement your own video processing engine by extending the `VideoEngine` class. Here’s an example of how to create a custom engine:
35
+
36
+ ### Example Custom Engine:
37
+
38
+ ```typescript
39
+ import { VideoEngine } from 'mes-engine';
40
+
41
+ class CustomVideoEngine extends VideoEngine {
42
+ async processChunk(inputPath: string, outputPath: string, startTime: number, quality: any): Promise<void> {
43
+ // Implement custom video processing logic here
44
+ }
45
+
46
+ async getDuration(inputPath: string): Promise<number> {
47
+ // Implement custom duration calculation logic here
48
+ return 120; // Example
49
+ }
50
+ }
51
+ ```
52
+
53
+ For more details on implementing custom engines, see the [VideoEngine class](../src/core/VideoEngine.ts) in the codebase.
54
+
55
+ ## Other Supported Engines
56
+ You can extend this framework with any other video processing engine that implements the `VideoEngine` interface.
57
+
58
+ For more details, check the [source code](https://github.com/Bum-Ho12/mes-engine) and adapt it as needed for your requirements.
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "mes-engine",
3
+ "version": "0.0.1",
4
+ "description": "mes-engine is a video processing engine that handles video chunking, processing and other video high density and intensive processing and caching processes.",
5
+ "keywords": [
6
+ "mes",
7
+ "mes-engine",
8
+ "video",
9
+ "processing",
10
+ "video-framework",
11
+ "framework"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+"
16
+ },
17
+ "license": "MIT",
18
+ "author": "Bumho Nisubire",
19
+ "main": "dist/index.js",
20
+ "scripts": {
21
+ "test": "mocha -r ts-node/register 'tests/**/*.test.ts' --timeout 10000",
22
+ "build": "rollup -c rollup.config.js"
23
+ },
24
+ "dependencies": {
25
+ "@types/node-fetch": "^2.6.12",
26
+ "mes-engine": "file:",
27
+ "node-fetch": "^3.3.2",
28
+ "tslib": "^2.8.1"
29
+ },
30
+ "devDependencies": {
31
+ "@rollup/plugin-commonjs": "^28.0.2",
32
+ "@rollup/plugin-node-resolve": "^16.0.0",
33
+ "@rollup/plugin-typescript": "^12.1.2",
34
+ "@types/chai": "^4.3.11",
35
+ "@types/jest": "^29.5.14",
36
+ "@types/mocha": "^10.0.6",
37
+ "@types/node": "^22.10.5",
38
+ "chai": "^4.3.10",
39
+ "jest": "^29.7.0",
40
+ "mocha": "^10.8.2",
41
+ "rollup": "^4.30.1",
42
+ "rollup-plugin-peer-deps-external": "^2.2.4",
43
+ "ts-jest": "^29.2.5",
44
+ "ts-mocha": "^10.0.0",
45
+ "ts-node": "^10.9.2",
46
+ "typescript": "^5.3.3"
47
+ }
48
+ }
@@ -0,0 +1,24 @@
1
+ import typescript from '@rollup/plugin-typescript';
2
+ import { nodeResolve } from '@rollup/plugin-node-resolve';
3
+ import commonjs from '@rollup/plugin-commonjs';
4
+ import peerDepsExternal from 'rollup-plugin-peer-deps-external';
5
+
6
+ export default {
7
+ input: 'src/index.ts', // Entry point
8
+ output: [
9
+ {
10
+ file: 'dist/index.js', // Output file
11
+ format: 'es', // ES module format
12
+ sourcemap: true, // Enable source maps
13
+ },
14
+ ],
15
+ plugins: [
16
+ peerDepsExternal(), // Externalize peer dependencies
17
+ nodeResolve(), // Resolve dependencies from node_modules
18
+ commonjs(), // Convert CommonJS to ES6
19
+ typescript({ tsconfig: './tsconfig.json' }), // TypeScript plugin
20
+ ],
21
+ external: [
22
+ 'node-fetch', // Prevent bundling node-fetch
23
+ ],
24
+ };
@@ -0,0 +1,30 @@
1
+
2
+ // bandwidth.ts
3
+ class BandwidthDetector {
4
+ private samples: Array<[number, number]> = [];
5
+ private readonly windowSize = 10000; // 10 seconds in ms
6
+
7
+ addSample(bytesTransferred: number, durationMs: number): void {
8
+ const bandwidth = (bytesTransferred * 8) / (durationMs * 1000); // Mbps
9
+ const timestamp = Date.now();
10
+ this.samples.push([timestamp, bandwidth]);
11
+ this._cleanOldSamples();
12
+ }
13
+
14
+ getEstimatedBandwidth(): number {
15
+ if (this.samples.length === 0) return Infinity;
16
+ const bandwidths = this.samples.map(([, b]) => b);
17
+ return this._median(bandwidths);
18
+ }
19
+
20
+ private _cleanOldSamples(): void {
21
+ const cutoff = Date.now() - this.windowSize;
22
+ this.samples = this.samples.filter(([t]) => t > cutoff);
23
+ }
24
+
25
+ private _median(values: number[]): number {
26
+ const sorted = [...values].sort((a, b) => a - b);
27
+ const mid = Math.floor(sorted.length / 2);
28
+ return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
29
+ }
30
+ }
@@ -0,0 +1,49 @@
1
+
2
+ // cache/ExternalCache.ts
3
+ import fetch from 'node-fetch';
4
+ import { CacheStrategy, CacheOptions } from './cacheStrategy';
5
+
6
+ export class ExternalCache extends CacheStrategy {
7
+ private baseUrl: string;
8
+ private options: CacheOptions;
9
+
10
+ constructor(options: CacheOptions) {
11
+ super();
12
+ this.options = options;
13
+ this.baseUrl = options.externalCacheUrl!;
14
+ }
15
+
16
+ async set(key: string, value: Buffer): Promise<void> {
17
+ await fetch(`${this.baseUrl}/cache/${key}`, {
18
+ method: 'POST',
19
+ body: value,
20
+ headers: {
21
+ 'Content-Type': 'application/octet-stream',
22
+ 'TTL': this.options.ttl.toString()
23
+ }
24
+ });
25
+ }
26
+
27
+ async get(key: string): Promise<Buffer | null> {
28
+ const response = await fetch(`${this.baseUrl}/cache/${key}`);
29
+ return response.ok ? Buffer.from(await response.arrayBuffer()) : null;
30
+ }
31
+
32
+ async preload(key: string): Promise<void> {
33
+ if (this.options.preloadNextChunk) {
34
+ const nextChunkKey = this.getNextChunkKey(key);
35
+ await fetch(`${this.baseUrl}/preload/${nextChunkKey}`);
36
+ }
37
+ }
38
+
39
+ async clear(): Promise<void> {
40
+ await fetch(`${this.baseUrl}/cache`, { method: 'DELETE' });
41
+ }
42
+
43
+ private getNextChunkKey(currentKey: string): string {
44
+ const parts = currentKey.split('_');
45
+ const currentChunk = parseInt(parts[parts.length - 1]);
46
+ parts[parts.length - 1] = (currentChunk + 1).toString();
47
+ return parts.join('_');
48
+ }
49
+ }
@@ -0,0 +1,35 @@
1
+
2
+ // cache/LRU.ts
3
+ export class LRU<T> {
4
+ private maxSize: number;
5
+ private cache: Map<string, T>;
6
+
7
+ constructor(maxSize: number) {
8
+ this.maxSize = maxSize;
9
+ this.cache = new Map();
10
+ }
11
+
12
+ set(key: string, value: T): void {
13
+ if (this.cache.has(key)) {
14
+ this.cache.delete(key);
15
+ } else if (this.cache.size >= this.maxSize) {
16
+ const oldestKey = this.cache.keys().next().value;
17
+ if (oldestKey !== undefined) {
18
+ this.cache.delete(oldestKey);
19
+ }
20
+ }
21
+ this.cache.set(key, value);
22
+ }
23
+
24
+ get(key: string): T | undefined {
25
+ if (!this.cache.has(key)) return undefined;
26
+ const value = this.cache.get(key)!;
27
+ this.cache.delete(key);
28
+ this.cache.set(key, value);
29
+ return value;
30
+ }
31
+
32
+ clear(): void {
33
+ this.cache.clear();
34
+ }
35
+ }
@@ -0,0 +1,15 @@
1
+
2
+ // cache/CacheStrategy.ts
3
+ export interface CacheOptions {
4
+ maxSize: number;
5
+ ttl: number;
6
+ preloadNextChunk: boolean;
7
+ externalCacheUrl?: string;
8
+ }
9
+
10
+ export abstract class CacheStrategy {
11
+ abstract set(key: string, value: Buffer): Promise<void>;
12
+ abstract get(key: string): Promise<Buffer | null>;
13
+ abstract preload(key: string): Promise<void>;
14
+ abstract clear(): Promise<void>;
15
+ }
@@ -0,0 +1,60 @@
1
+
2
+ // cache/internalCache.ts
3
+ import { LRU } from './LRU';
4
+ import { CacheStrategy, CacheOptions } from './cacheStrategy';
5
+ import { StorageProvider } from '../storage/StorageProvider';
6
+
7
+ export class InternalCache extends CacheStrategy {
8
+ private cache: LRU<Buffer>;
9
+ private options: CacheOptions;
10
+ private storage: StorageProvider;
11
+
12
+ constructor(options: CacheOptions, storage: StorageProvider) {
13
+ super();
14
+ this.options = options;
15
+ this.cache = new LRU(options.maxSize);
16
+ this.storage = storage;
17
+ }
18
+
19
+ async set(key: string, value: Buffer): Promise<void> {
20
+ this.cache.set(key, value);
21
+ }
22
+
23
+ async get(key: string): Promise<Buffer | null> {
24
+ const cached = this.cache.get(key);
25
+ if (cached) return cached;
26
+
27
+ try {
28
+ const data = await this.storage.getChunk(key);
29
+ await this.set(key, data);
30
+ return data;
31
+ } catch {
32
+ return null;
33
+ }
34
+ }
35
+
36
+ async preload(key: string): Promise<void> {
37
+ if (this.options.preloadNextChunk) {
38
+ const nextChunkKey = this.getNextChunkKey(key);
39
+ if (!this.cache.get(nextChunkKey)) {
40
+ try {
41
+ const data = await this.storage.getChunk(nextChunkKey);
42
+ await this.set(nextChunkKey, data);
43
+ } catch {
44
+ // Ignore preload failures
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ async clear(): Promise<void> {
51
+ this.cache.clear();
52
+ }
53
+
54
+ private getNextChunkKey(currentKey: string): string {
55
+ const parts = currentKey.split('_');
56
+ const currentChunk = parseInt(parts[parts.length - 1]);
57
+ parts[parts.length - 1] = (currentChunk + 1).toString();
58
+ return parts.join('_');
59
+ }
60
+ }
@@ -0,0 +1,16 @@
1
+
2
+ // core/VideoEngine.ts
3
+ import { EventEmitter } from 'events';
4
+ import { VideoConfig, QualityLevel, VideoManifest } from './types';
5
+ import { VideoEvent } from './events';
6
+
7
+ export abstract class VideoEngine extends EventEmitter {
8
+ abstract processChunk(
9
+ inputPath: string,
10
+ outputPath: string,
11
+ startTime: number,
12
+ quality: QualityLevel
13
+ ): Promise<void>;
14
+
15
+ abstract getDuration(inputPath: string): Promise<number>;
16
+ }
@@ -0,0 +1,7 @@
1
+
2
+ export enum VideoEvent {
3
+ CHUNK_PROCESSED = 'chunkProcessed',
4
+ QUALITY_PROCESSED = 'qualityProcessed',
5
+ PROCESSING_COMPLETE = 'processingComplete',
6
+ ERROR = 'error'
7
+ }
@@ -0,0 +1,26 @@
1
+
2
+ // core/types.ts
3
+
4
+ export interface VideoConfig {
5
+ chunkSize: number;
6
+ cacheDir: string;
7
+ maxCacheSize: number;
8
+ defaultQualities: QualityLevel[];
9
+ }
10
+
11
+ export interface QualityLevel {
12
+ height: number;
13
+ bitrate: string;
14
+ }
15
+
16
+ export interface VideoChunk {
17
+ quality: number;
18
+ number: number;
19
+ path: string;
20
+ }
21
+
22
+ export interface VideoManifest {
23
+ videoId: string;
24
+ qualities: QualityLevel[];
25
+ chunks: VideoChunk[];
26
+ }