capacitor-native-video-compressor 1.0.2 → 1.0.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,OAAO,wBAAyB,SAAQ,SAAS;IACrD,KAAK,CAAC,aAAa,CAAC,OAAwB;QAC1C,OAAO,CAAC,IAAI,CAAC,iEAAiE,EAAE,OAAO,CAAC,CAAC;QAEzF,sEAAsE;QACtE,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;QAEpD,oFAAoF;QACpF,WAAW;QACX,oBAAoB;QACpB,iCAAiC;QACjC,KAAK;IACP,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport type { NativeVideoCompressorPlugin, CompressOptions, CompressResult } from './definitions';\n\nexport class NativeVideoCompressorWeb extends WebPlugin implements NativeVideoCompressorPlugin {\n async compressVideo(options: CompressOptions): Promise<CompressResult> {\n console.warn('Tính năng nén video bằng GPU không hỗ trợ trên trình duyệt Web.', options);\n\n // Báo lỗi cho chuẩn Capacitor báo rằng nền tảng này không được hỗ trợ\n throw this.unimplemented('Not implemented on web.');\n\n // (Hoặc nếu bạn không muốn văng lỗi trên web, bạn có thể trả về luôn đường dẫn gốc)\n // return {\n // success: false,\n // destPath: options.sourcePath\n // };\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIpD,MAAM,OAAO,wBAAyB,SAAQ,SAAS;IAAvD;;QACU,WAAM,GAAkB,IAAI,CAAC;QAC7B,aAAQ,GAAG,KAAK,CAAC;IA+K3B,CAAC;IA7KS,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzC,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAE3E,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YAE3B,kEAAkE;YAClE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;gBAC1C,yCAAyC;gBACzC,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC;YAClG,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;gBACpC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;YACvC,CAAC,CAAC,CAAC;YAEH,8EAA8E;YAC9E,oEAAoE;YACpE,MAAM,OAAO,GAAG,gDAAgD,CAAC;YAEjE,OAAO,CAAC,GAAG,CAAC,oCAAoC,EAAE,OAAO,CAAC,CAAC;YAC3D,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBACrB,OAAO,EAAE,MAAM,SAAS,CAAC,GAAG,OAAO,iBAAiB,EAAE,iBAAiB,CAAC;gBACxE,OAAO,EAAE,MAAM,SAAS,CAAC,GAAG,OAAO,mBAAmB,EAAE,kBAAkB,CAAC;aAC5E,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;YAC3D,CAAC;YACD,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YACxB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC;QACjE,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,uBAAuB,EAAE,CAAC;QAC3E,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB;QAC1C,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACnB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1B,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAC3C,CAAC;YAED,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YAEtE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC;YACnD,MAAM,aAAa,GAAG,WAAW,CAAC;YAClC,MAAM,cAAc,GAAG,YAAY,CAAC;YAEpC,+CAA+C;YAC/C,IAAI,GAAG,GAAG,IAAI,CAAC;YACf,IAAI,KAAK,GAAG,EAAE,CAAC,CAAC,0BAA0B;YAC1C,IAAI,YAAY,GAAG,MAAM,CAAC;YAE1B,QAAQ,OAAO,EAAE,CAAC;gBAChB,KAAK,WAAW,EAAE,QAAQ;oBACxB,GAAG,GAAG,IAAI,CAAC;oBACX,KAAK,GAAG,mBAAmB,CAAC;oBAC5B,YAAY,GAAG,MAAM,CAAC;oBACtB,MAAM;gBACR,KAAK,MAAM,EAAE,OAAO;oBAClB,GAAG,GAAG,IAAI,CAAC;oBACX,KAAK,GAAG,kBAAkB,CAAC;oBAC3B,YAAY,GAAG,MAAM,CAAC;oBACtB,MAAM;gBACR,KAAK,QAAQ,EAAE,OAAO;oBACpB,GAAG,GAAG,IAAI,CAAC;oBACX,KAAK,GAAG,kBAAkB,CAAC;oBAC3B,YAAY,GAAG,KAAK,CAAC;oBACrB,MAAM;gBACR,KAAK,KAAK,EAAE,OAAO;oBACjB,GAAG,GAAG,IAAI,CAAC;oBACX,KAAK,GAAG,kBAAkB,CAAC;oBAC3B,YAAY,GAAG,KAAK,CAAC;oBACrB,MAAM;gBACR,KAAK,MAAM,EAAE,OAAO;oBAClB,GAAG,GAAG,IAAI,CAAC;oBACX,KAAK,GAAG,kBAAkB,CAAC;oBAC3B,YAAY,GAAG,KAAK,CAAC;oBACrB,MAAM;gBACR,KAAK,UAAU,EAAE,OAAO;oBACtB,GAAG,GAAG,IAAI,CAAC;oBACX,KAAK,GAAG,kBAAkB,CAAC;oBAC3B,YAAY,GAAG,KAAK,CAAC;oBACrB,MAAM;YACV,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,kCAAkC,EAAE,UAAU,CAAC,CAAC;YAC5D,IAAI,SAAqB,CAAC;YAC1B,IAAI,CAAC;gBACH,SAAS,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;YAC1C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;gBAC3D,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC7E,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;YACxD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;gBACpD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAClD,CAAC;YAED,iCAAiC;YACjC,MAAM,IAAI,GAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;YAE7C,8FAA8F;YAC9F,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;YAElE,oCAAoC;YACpC,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YACjC,CAAC;YAED,kCAAkC;YAClC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;YAE/C,SAAS;YACT,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAE1B,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3D,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC7C,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,OAAO,CAAC,CAAC;YACvD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;gBACxD,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC7C,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;YAC/C,IAAI,IAAS,CAAC;YACd,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YACpD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,GAAG,CAAC,CAAC;gBAC1D,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAClD,CAAC;YAED,cAAc;YACd,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAC5C,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAE7C,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACnF,2CAA2C;YAC3C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,IAAW,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;YAC5D,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAE3C,OAAO,CAAC,GAAG,CAAC,gDAAgD,EAAE,QAAQ,CAAC,CAAC;YACxE,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,QAAQ;aACnB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;YAC7D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { fetchFile, toBlobURL } from '@ffmpeg/util';\n\nimport type { NativeVideoCompressorPlugin, CompressOptions, CompressResult } from './definitions';\n\nexport class NativeVideoCompressorWeb extends WebPlugin implements NativeVideoCompressorPlugin {\n private ffmpeg: FFmpeg | null = null;\n private isLoaded = false;\n\n private async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg) return;\n\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n\n try {\n this.ffmpeg = new FFmpeg();\n\n // Listen to FFmpeg progress and map it to capacitor plugin events\n this.ffmpeg.on('progress', ({ progress }) => {\n // progress is a fraction between 0 and 1\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n\n this.ffmpeg.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n\n // Use standard single-threaded version for best compatibility across browsers\n // without requiring complex SharedArrayBuffer headers configuration\n const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n\n console.log('Starting to load FFmpeg core from:', baseURL);\n await this.ffmpeg.load({\n coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n });\n\n this.isLoaded = true;\n console.log('FFmpeg core loaded successfully');\n } catch (e: any) {\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n }\n\n async initialize(): Promise<{ success: boolean; message?: string }> {\n try {\n if (this.isLoaded) {\n return { success: true, message: 'Already initialized' };\n }\n await this.loadFFmpeg();\n return { success: true, message: 'Initialization successful' };\n } catch (e: any) {\n return { success: false, message: e.message || 'Initialization failed' };\n }\n }\n\n async compressVideo(options: CompressOptions): Promise<CompressResult> {\n try {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n\n const { sourcePath, quality = 'MEDIUM' } = options;\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n\n // Map quality to CRF, Scale, and Audio Bitrate\n let crf = '28';\n let scale = ''; // default keep resolution\n let audioBitrate = '128k';\n\n switch (quality) {\n case 'VERY_HIGH': // 1080p\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH': // 720p\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM': // 540p\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW': // 480p\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P': // 360p\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW': // 240p\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n\n console.log('[FFmpeg] Fetching source file...', sourcePath);\n let inputData: Uint8Array;\n try {\n inputData = await fetchFile(sourcePath);\n } catch (err) {\n console.error('[FFmpeg] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n\n console.log('[FFmpeg] Writing file to FS...', inputData.byteLength, 'bytes');\n try {\n await this.ffmpeg.writeFile(inputFileName, inputData);\n } catch (err) {\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n\n // Construct FFmpeg command array\n const args: string[] = ['-i', inputFileName];\n\n // Video codec and compression parameters (superfast provides much better size than ultrafast)\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n\n // Resize if needed (split by space)\n if (scale) {\n args.push(...scale.split(' '));\n }\n\n // Audio re-encoding to save space\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n\n // Output\n args.push(outputFileName);\n\n console.log('[FFmpeg] Executing command:', args.join(' '));\n try {\n const retCode = await this.ffmpeg.exec(args);\n console.log('[FFmpeg] Exec returned code:', retCode);\n } catch (err) {\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n\n console.log('[FFmpeg] Reading output file...');\n let data: any;\n try {\n data = await this.ffmpeg.readFile(outputFileName);\n } catch (err) {\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n\n // Free memory\n await this.ffmpeg.deleteFile(inputFileName);\n await this.ffmpeg.deleteFile(outputFileName);\n\n console.log('[FFmpeg] Creating Blob URL from output...', data.byteLength, 'bytes');\n // Create a blob URL for the resulting file\n const blob = new Blob([data as any], { type: 'video/mp4' });\n const destPath = URL.createObjectURL(blob);\n\n console.log('[FFmpeg] Compression complete, returning path:', destPath);\n return {\n success: true,\n destPath: destPath,\n };\n } catch (error: any) {\n console.error('[FFmpeg] Compression process failed:', error);\n throw error;\n }\n }\n}\n"]}
@@ -1,21 +1,173 @@
1
1
  'use strict';
2
2
 
3
3
  var core = require('@capacitor/core');
4
+ var ffmpeg = require('@ffmpeg/ffmpeg');
5
+ var util = require('@ffmpeg/util');
4
6
 
5
7
  const NativeVideoCompressor = core.registerPlugin('NativeVideoCompressor', {
6
8
  web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.NativeVideoCompressorWeb()),
7
9
  });
8
10
 
9
11
  class NativeVideoCompressorWeb extends core.WebPlugin {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.ffmpeg = null;
15
+ this.isLoaded = false;
16
+ }
17
+ async loadFFmpeg() {
18
+ if (this.isLoaded && this.ffmpeg)
19
+ return;
20
+ this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });
21
+ try {
22
+ this.ffmpeg = new ffmpeg.FFmpeg();
23
+ // Listen to FFmpeg progress and map it to capacitor plugin events
24
+ this.ffmpeg.on('progress', ({ progress }) => {
25
+ // progress is a fraction between 0 and 1
26
+ this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });
27
+ });
28
+ this.ffmpeg.on('log', ({ message }) => {
29
+ console.log('[FFmpeg Log]', message);
30
+ });
31
+ // Use standard single-threaded version for best compatibility across browsers
32
+ // without requiring complex SharedArrayBuffer headers configuration
33
+ const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';
34
+ console.log('Starting to load FFmpeg core from:', baseURL);
35
+ await this.ffmpeg.load({
36
+ coreURL: await util.toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
37
+ wasmURL: await util.toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
38
+ });
39
+ this.isLoaded = true;
40
+ console.log('FFmpeg core loaded successfully');
41
+ }
42
+ catch (e) {
43
+ console.error('Failed to load FFmpeg:', e);
44
+ throw e;
45
+ }
46
+ }
47
+ async initialize() {
48
+ try {
49
+ if (this.isLoaded) {
50
+ return { success: true, message: 'Already initialized' };
51
+ }
52
+ await this.loadFFmpeg();
53
+ return { success: true, message: 'Initialization successful' };
54
+ }
55
+ catch (e) {
56
+ return { success: false, message: e.message || 'Initialization failed' };
57
+ }
58
+ }
10
59
  async compressVideo(options) {
11
- console.warn('Tính năng nén video bằng GPU không hỗ trợ trên trình duyệt Web.', options);
12
- // Báo lỗi cho chuẩn Capacitor báo rằng nền tảng này không được hỗ trợ
13
- throw this.unimplemented('Not implemented on web.');
14
- // (Hoặc nếu bạn không muốn văng lỗi trên web, bạn có thể trả về luôn đường dẫn gốc)
15
- // return {
16
- // success: false,
17
- // destPath: options.sourcePath
18
- // };
60
+ try {
61
+ if (!this.isLoaded) {
62
+ await this.loadFFmpeg();
63
+ }
64
+ if (!this.ffmpeg) {
65
+ throw new Error('FFmpeg failed to load');
66
+ }
67
+ this.notifyListeners('onProgress', { status: 'started', percent: 0 });
68
+ const { sourcePath, quality = 'MEDIUM' } = options;
69
+ const inputFileName = 'input.mp4';
70
+ const outputFileName = 'output.mp4';
71
+ // Map quality to CRF, Scale, and Audio Bitrate
72
+ let crf = '28';
73
+ let scale = ''; // default keep resolution
74
+ let audioBitrate = '128k';
75
+ switch (quality) {
76
+ case 'VERY_HIGH': // 1080p
77
+ crf = '23';
78
+ scale = '-vf scale=-2:1080';
79
+ audioBitrate = '128k';
80
+ break;
81
+ case 'HIGH': // 720p
82
+ crf = '28';
83
+ scale = '-vf scale=-2:720';
84
+ audioBitrate = '128k';
85
+ break;
86
+ case 'MEDIUM': // 540p
87
+ crf = '30';
88
+ scale = '-vf scale=-2:540';
89
+ audioBitrate = '96k';
90
+ break;
91
+ case 'LOW': // 480p
92
+ crf = '32';
93
+ scale = '-vf scale=-2:480';
94
+ audioBitrate = '96k';
95
+ break;
96
+ case '360P': // 360p
97
+ crf = '28';
98
+ scale = '-vf scale=-2:360';
99
+ audioBitrate = '64k';
100
+ break;
101
+ case 'VERY_LOW': // 240p
102
+ crf = '35';
103
+ scale = '-vf scale=-2:240';
104
+ audioBitrate = '48k';
105
+ break;
106
+ }
107
+ console.log('[FFmpeg] Fetching source file...', sourcePath);
108
+ let inputData;
109
+ try {
110
+ inputData = await util.fetchFile(sourcePath);
111
+ }
112
+ catch (err) {
113
+ console.error('[FFmpeg] Error fetching source file:', err);
114
+ throw new Error('Could not fetch source video file');
115
+ }
116
+ console.log('[FFmpeg] Writing file to FS...', inputData.byteLength, 'bytes');
117
+ try {
118
+ await this.ffmpeg.writeFile(inputFileName, inputData);
119
+ }
120
+ catch (err) {
121
+ console.error('[FFmpeg] Error writing to FS:', err);
122
+ throw new Error('Could not write to FFmpeg FS');
123
+ }
124
+ // Construct FFmpeg command array
125
+ const args = ['-i', inputFileName];
126
+ // Video codec and compression parameters (superfast provides much better size than ultrafast)
127
+ args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);
128
+ // Resize if needed (split by space)
129
+ if (scale) {
130
+ args.push(...scale.split(' '));
131
+ }
132
+ // Audio re-encoding to save space
133
+ args.push('-c:a', 'aac', '-b:a', audioBitrate);
134
+ // Output
135
+ args.push(outputFileName);
136
+ console.log('[FFmpeg] Executing command:', args.join(' '));
137
+ try {
138
+ const retCode = await this.ffmpeg.exec(args);
139
+ console.log('[FFmpeg] Exec returned code:', retCode);
140
+ }
141
+ catch (err) {
142
+ console.error('[FFmpeg] Error executing command:', err);
143
+ throw new Error('FFmpeg execution failed');
144
+ }
145
+ console.log('[FFmpeg] Reading output file...');
146
+ let data;
147
+ try {
148
+ data = await this.ffmpeg.readFile(outputFileName);
149
+ }
150
+ catch (err) {
151
+ console.error('[FFmpeg] Error reading output file:', err);
152
+ throw new Error('Could not read FFmpeg output');
153
+ }
154
+ // Free memory
155
+ await this.ffmpeg.deleteFile(inputFileName);
156
+ await this.ffmpeg.deleteFile(outputFileName);
157
+ console.log('[FFmpeg] Creating Blob URL from output...', data.byteLength, 'bytes');
158
+ // Create a blob URL for the resulting file
159
+ const blob = new Blob([data], { type: 'video/mp4' });
160
+ const destPath = URL.createObjectURL(blob);
161
+ console.log('[FFmpeg] Compression complete, returning path:', destPath);
162
+ return {
163
+ success: true,
164
+ destPath: destPath,
165
+ };
166
+ }
167
+ catch (error) {
168
+ console.error('[FFmpeg] Compression process failed:', error);
169
+ throw error;
170
+ }
19
171
  }
20
172
  }
21
173
 
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst NativeVideoCompressor = registerPlugin('NativeVideoCompressor', {\n web: () => import('./web').then((m) => new m.NativeVideoCompressorWeb()),\n});\nexport * from './definitions';\nexport { NativeVideoCompressor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class NativeVideoCompressorWeb extends WebPlugin {\n async compressVideo(options) {\n console.warn('Tính năng nén video bằng GPU không hỗ trợ trên trình duyệt Web.', options);\n // Báo lỗi cho chuẩn Capacitor báo rằng nền tảng này không được hỗ trợ\n throw this.unimplemented('Not implemented on web.');\n // (Hoặc nếu bạn không muốn văng lỗi trên web, bạn có thể trả về luôn đường dẫn gốc)\n // return {\n // success: false,\n // destPath: options.sourcePath\n // };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,qBAAqB,GAAGA,mBAAc,CAAC,uBAAuB,EAAE;AACtE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,wBAAwB,EAAE,CAAC;AAC5E,CAAC;;ACFM,MAAM,wBAAwB,SAASC,cAAS,CAAC;AACxD,IAAI,MAAM,aAAa,CAAC,OAAO,EAAE;AACjC,QAAQ,OAAO,CAAC,IAAI,CAAC,iEAAiE,EAAE,OAAO,CAAC;AAChG;AACA,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;AAC3D;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst NativeVideoCompressor = registerPlugin('NativeVideoCompressor', {\n web: () => import('./web').then((m) => new m.NativeVideoCompressorWeb()),\n});\nexport * from './definitions';\nexport { NativeVideoCompressor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nimport { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { fetchFile, toBlobURL } from '@ffmpeg/util';\nexport class NativeVideoCompressorWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.ffmpeg = null;\n this.isLoaded = false;\n }\n async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg)\n return;\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n try {\n this.ffmpeg = new FFmpeg();\n // Listen to FFmpeg progress and map it to capacitor plugin events\n this.ffmpeg.on('progress', ({ progress }) => {\n // progress is a fraction between 0 and 1\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n this.ffmpeg.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n // Use standard single-threaded version for best compatibility across browsers\n // without requiring complex SharedArrayBuffer headers configuration\n const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n console.log('Starting to load FFmpeg core from:', baseURL);\n await this.ffmpeg.load({\n coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n });\n this.isLoaded = true;\n console.log('FFmpeg core loaded successfully');\n }\n catch (e) {\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n }\n async initialize() {\n try {\n if (this.isLoaded) {\n return { success: true, message: 'Already initialized' };\n }\n await this.loadFFmpeg();\n return { success: true, message: 'Initialization successful' };\n }\n catch (e) {\n return { success: false, message: e.message || 'Initialization failed' };\n }\n }\n async compressVideo(options) {\n try {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n const { sourcePath, quality = 'MEDIUM' } = options;\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n // Map quality to CRF, Scale, and Audio Bitrate\n let crf = '28';\n let scale = ''; // default keep resolution\n let audioBitrate = '128k';\n switch (quality) {\n case 'VERY_HIGH': // 1080p\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH': // 720p\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM': // 540p\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW': // 480p\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P': // 360p\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW': // 240p\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n console.log('[FFmpeg] Fetching source file...', sourcePath);\n let inputData;\n try {\n inputData = await fetchFile(sourcePath);\n }\n catch (err) {\n console.error('[FFmpeg] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n console.log('[FFmpeg] Writing file to FS...', inputData.byteLength, 'bytes');\n try {\n await this.ffmpeg.writeFile(inputFileName, inputData);\n }\n catch (err) {\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n // Construct FFmpeg command array\n const args = ['-i', inputFileName];\n // Video codec and compression parameters (superfast provides much better size than ultrafast)\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n // Resize if needed (split by space)\n if (scale) {\n args.push(...scale.split(' '));\n }\n // Audio re-encoding to save space\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n // Output\n args.push(outputFileName);\n console.log('[FFmpeg] Executing command:', args.join(' '));\n try {\n const retCode = await this.ffmpeg.exec(args);\n console.log('[FFmpeg] Exec returned code:', retCode);\n }\n catch (err) {\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n console.log('[FFmpeg] Reading output file...');\n let data;\n try {\n data = await this.ffmpeg.readFile(outputFileName);\n }\n catch (err) {\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n // Free memory\n await this.ffmpeg.deleteFile(inputFileName);\n await this.ffmpeg.deleteFile(outputFileName);\n console.log('[FFmpeg] Creating Blob URL from output...', data.byteLength, 'bytes');\n // Create a blob URL for the resulting file\n const blob = new Blob([data], { type: 'video/mp4' });\n const destPath = URL.createObjectURL(blob);\n console.log('[FFmpeg] Compression complete, returning path:', destPath);\n return {\n success: true,\n destPath: destPath,\n };\n }\n catch (error) {\n console.error('[FFmpeg] Compression process failed:', error);\n throw error;\n }\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin","FFmpeg","toBlobURL","fetchFile"],"mappings":"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"}
package/dist/plugin.js CHANGED
@@ -1,4 +1,4 @@
1
- var capacitorNativeVideoCompressor = (function (exports, core) {
1
+ var capacitorNativeVideoCompressor = (function (exports, core, ffmpeg, util) {
2
2
  'use strict';
3
3
 
4
4
  const NativeVideoCompressor = core.registerPlugin('NativeVideoCompressor', {
@@ -6,15 +6,165 @@ var capacitorNativeVideoCompressor = (function (exports, core) {
6
6
  });
7
7
 
8
8
  class NativeVideoCompressorWeb extends core.WebPlugin {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.ffmpeg = null;
12
+ this.isLoaded = false;
13
+ }
14
+ async loadFFmpeg() {
15
+ if (this.isLoaded && this.ffmpeg)
16
+ return;
17
+ this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });
18
+ try {
19
+ this.ffmpeg = new ffmpeg.FFmpeg();
20
+ // Listen to FFmpeg progress and map it to capacitor plugin events
21
+ this.ffmpeg.on('progress', ({ progress }) => {
22
+ // progress is a fraction between 0 and 1
23
+ this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });
24
+ });
25
+ this.ffmpeg.on('log', ({ message }) => {
26
+ console.log('[FFmpeg Log]', message);
27
+ });
28
+ // Use standard single-threaded version for best compatibility across browsers
29
+ // without requiring complex SharedArrayBuffer headers configuration
30
+ const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';
31
+ console.log('Starting to load FFmpeg core from:', baseURL);
32
+ await this.ffmpeg.load({
33
+ coreURL: await util.toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
34
+ wasmURL: await util.toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
35
+ });
36
+ this.isLoaded = true;
37
+ console.log('FFmpeg core loaded successfully');
38
+ }
39
+ catch (e) {
40
+ console.error('Failed to load FFmpeg:', e);
41
+ throw e;
42
+ }
43
+ }
44
+ async initialize() {
45
+ try {
46
+ if (this.isLoaded) {
47
+ return { success: true, message: 'Already initialized' };
48
+ }
49
+ await this.loadFFmpeg();
50
+ return { success: true, message: 'Initialization successful' };
51
+ }
52
+ catch (e) {
53
+ return { success: false, message: e.message || 'Initialization failed' };
54
+ }
55
+ }
9
56
  async compressVideo(options) {
10
- console.warn('Tính năng nén video bằng GPU không hỗ trợ trên trình duyệt Web.', options);
11
- // Báo lỗi cho chuẩn Capacitor báo rằng nền tảng này không được hỗ trợ
12
- throw this.unimplemented('Not implemented on web.');
13
- // (Hoặc nếu bạn không muốn văng lỗi trên web, bạn có thể trả về luôn đường dẫn gốc)
14
- // return {
15
- // success: false,
16
- // destPath: options.sourcePath
17
- // };
57
+ try {
58
+ if (!this.isLoaded) {
59
+ await this.loadFFmpeg();
60
+ }
61
+ if (!this.ffmpeg) {
62
+ throw new Error('FFmpeg failed to load');
63
+ }
64
+ this.notifyListeners('onProgress', { status: 'started', percent: 0 });
65
+ const { sourcePath, quality = 'MEDIUM' } = options;
66
+ const inputFileName = 'input.mp4';
67
+ const outputFileName = 'output.mp4';
68
+ // Map quality to CRF, Scale, and Audio Bitrate
69
+ let crf = '28';
70
+ let scale = ''; // default keep resolution
71
+ let audioBitrate = '128k';
72
+ switch (quality) {
73
+ case 'VERY_HIGH': // 1080p
74
+ crf = '23';
75
+ scale = '-vf scale=-2:1080';
76
+ audioBitrate = '128k';
77
+ break;
78
+ case 'HIGH': // 720p
79
+ crf = '28';
80
+ scale = '-vf scale=-2:720';
81
+ audioBitrate = '128k';
82
+ break;
83
+ case 'MEDIUM': // 540p
84
+ crf = '30';
85
+ scale = '-vf scale=-2:540';
86
+ audioBitrate = '96k';
87
+ break;
88
+ case 'LOW': // 480p
89
+ crf = '32';
90
+ scale = '-vf scale=-2:480';
91
+ audioBitrate = '96k';
92
+ break;
93
+ case '360P': // 360p
94
+ crf = '28';
95
+ scale = '-vf scale=-2:360';
96
+ audioBitrate = '64k';
97
+ break;
98
+ case 'VERY_LOW': // 240p
99
+ crf = '35';
100
+ scale = '-vf scale=-2:240';
101
+ audioBitrate = '48k';
102
+ break;
103
+ }
104
+ console.log('[FFmpeg] Fetching source file...', sourcePath);
105
+ let inputData;
106
+ try {
107
+ inputData = await util.fetchFile(sourcePath);
108
+ }
109
+ catch (err) {
110
+ console.error('[FFmpeg] Error fetching source file:', err);
111
+ throw new Error('Could not fetch source video file');
112
+ }
113
+ console.log('[FFmpeg] Writing file to FS...', inputData.byteLength, 'bytes');
114
+ try {
115
+ await this.ffmpeg.writeFile(inputFileName, inputData);
116
+ }
117
+ catch (err) {
118
+ console.error('[FFmpeg] Error writing to FS:', err);
119
+ throw new Error('Could not write to FFmpeg FS');
120
+ }
121
+ // Construct FFmpeg command array
122
+ const args = ['-i', inputFileName];
123
+ // Video codec and compression parameters (superfast provides much better size than ultrafast)
124
+ args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);
125
+ // Resize if needed (split by space)
126
+ if (scale) {
127
+ args.push(...scale.split(' '));
128
+ }
129
+ // Audio re-encoding to save space
130
+ args.push('-c:a', 'aac', '-b:a', audioBitrate);
131
+ // Output
132
+ args.push(outputFileName);
133
+ console.log('[FFmpeg] Executing command:', args.join(' '));
134
+ try {
135
+ const retCode = await this.ffmpeg.exec(args);
136
+ console.log('[FFmpeg] Exec returned code:', retCode);
137
+ }
138
+ catch (err) {
139
+ console.error('[FFmpeg] Error executing command:', err);
140
+ throw new Error('FFmpeg execution failed');
141
+ }
142
+ console.log('[FFmpeg] Reading output file...');
143
+ let data;
144
+ try {
145
+ data = await this.ffmpeg.readFile(outputFileName);
146
+ }
147
+ catch (err) {
148
+ console.error('[FFmpeg] Error reading output file:', err);
149
+ throw new Error('Could not read FFmpeg output');
150
+ }
151
+ // Free memory
152
+ await this.ffmpeg.deleteFile(inputFileName);
153
+ await this.ffmpeg.deleteFile(outputFileName);
154
+ console.log('[FFmpeg] Creating Blob URL from output...', data.byteLength, 'bytes');
155
+ // Create a blob URL for the resulting file
156
+ const blob = new Blob([data], { type: 'video/mp4' });
157
+ const destPath = URL.createObjectURL(blob);
158
+ console.log('[FFmpeg] Compression complete, returning path:', destPath);
159
+ return {
160
+ success: true,
161
+ destPath: destPath,
162
+ };
163
+ }
164
+ catch (error) {
165
+ console.error('[FFmpeg] Compression process failed:', error);
166
+ throw error;
167
+ }
18
168
  }
19
169
  }
20
170
 
@@ -27,5 +177,5 @@ var capacitorNativeVideoCompressor = (function (exports, core) {
27
177
 
28
178
  return exports;
29
179
 
30
- })({}, capacitorExports);
180
+ })({}, capacitorExports, ffmpeg, util);
31
181
  //# sourceMappingURL=plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst NativeVideoCompressor = registerPlugin('NativeVideoCompressor', {\n web: () => import('./web').then((m) => new m.NativeVideoCompressorWeb()),\n});\nexport * from './definitions';\nexport { NativeVideoCompressor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class NativeVideoCompressorWeb extends WebPlugin {\n async compressVideo(options) {\n console.warn('Tính năng nén video bằng GPU không hỗ trợ trên trình duyệt Web.', options);\n // Báo lỗi cho chuẩn Capacitor báo rằng nền tảng này không được hỗ trợ\n throw this.unimplemented('Not implemented on web.');\n // (Hoặc nếu bạn không muốn văng lỗi trên web, bạn có thể trả về luôn đường dẫn gốc)\n // return {\n // success: false,\n // destPath: options.sourcePath\n // };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,qBAAqB,GAAGA,mBAAc,CAAC,uBAAuB,EAAE;IACtE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,wBAAwB,EAAE,CAAC;IAC5E,CAAC;;ICFM,MAAM,wBAAwB,SAASC,cAAS,CAAC;IACxD,IAAI,MAAM,aAAa,CAAC,OAAO,EAAE;IACjC,QAAQ,OAAO,CAAC,IAAI,CAAC,iEAAiE,EAAE,OAAO,CAAC;IAChG;IACA,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D;IACA;IACA;IACA;IACA;IACA,IAAI;IACJ;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst NativeVideoCompressor = registerPlugin('NativeVideoCompressor', {\n web: () => import('./web').then((m) => new m.NativeVideoCompressorWeb()),\n});\nexport * from './definitions';\nexport { NativeVideoCompressor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nimport { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { fetchFile, toBlobURL } from '@ffmpeg/util';\nexport class NativeVideoCompressorWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.ffmpeg = null;\n this.isLoaded = false;\n }\n async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg)\n return;\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n try {\n this.ffmpeg = new FFmpeg();\n // Listen to FFmpeg progress and map it to capacitor plugin events\n this.ffmpeg.on('progress', ({ progress }) => {\n // progress is a fraction between 0 and 1\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n this.ffmpeg.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n // Use standard single-threaded version for best compatibility across browsers\n // without requiring complex SharedArrayBuffer headers configuration\n const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n console.log('Starting to load FFmpeg core from:', baseURL);\n await this.ffmpeg.load({\n coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n });\n this.isLoaded = true;\n console.log('FFmpeg core loaded successfully');\n }\n catch (e) {\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n }\n async initialize() {\n try {\n if (this.isLoaded) {\n return { success: true, message: 'Already initialized' };\n }\n await this.loadFFmpeg();\n return { success: true, message: 'Initialization successful' };\n }\n catch (e) {\n return { success: false, message: e.message || 'Initialization failed' };\n }\n }\n async compressVideo(options) {\n try {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n const { sourcePath, quality = 'MEDIUM' } = options;\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n // Map quality to CRF, Scale, and Audio Bitrate\n let crf = '28';\n let scale = ''; // default keep resolution\n let audioBitrate = '128k';\n switch (quality) {\n case 'VERY_HIGH': // 1080p\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH': // 720p\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM': // 540p\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW': // 480p\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P': // 360p\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW': // 240p\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n console.log('[FFmpeg] Fetching source file...', sourcePath);\n let inputData;\n try {\n inputData = await fetchFile(sourcePath);\n }\n catch (err) {\n console.error('[FFmpeg] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n console.log('[FFmpeg] Writing file to FS...', inputData.byteLength, 'bytes');\n try {\n await this.ffmpeg.writeFile(inputFileName, inputData);\n }\n catch (err) {\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n // Construct FFmpeg command array\n const args = ['-i', inputFileName];\n // Video codec and compression parameters (superfast provides much better size than ultrafast)\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n // Resize if needed (split by space)\n if (scale) {\n args.push(...scale.split(' '));\n }\n // Audio re-encoding to save space\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n // Output\n args.push(outputFileName);\n console.log('[FFmpeg] Executing command:', args.join(' '));\n try {\n const retCode = await this.ffmpeg.exec(args);\n console.log('[FFmpeg] Exec returned code:', retCode);\n }\n catch (err) {\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n console.log('[FFmpeg] Reading output file...');\n let data;\n try {\n data = await this.ffmpeg.readFile(outputFileName);\n }\n catch (err) {\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n // Free memory\n await this.ffmpeg.deleteFile(inputFileName);\n await this.ffmpeg.deleteFile(outputFileName);\n console.log('[FFmpeg] Creating Blob URL from output...', data.byteLength, 'bytes');\n // Create a blob URL for the resulting file\n const blob = new Blob([data], { type: 'video/mp4' });\n const destPath = URL.createObjectURL(blob);\n console.log('[FFmpeg] Compression complete, returning path:', destPath);\n return {\n success: true,\n destPath: destPath,\n };\n }\n catch (error) {\n console.error('[FFmpeg] Compression process failed:', error);\n throw error;\n }\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin","FFmpeg","toBlobURL","fetchFile"],"mappings":"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"}