capacitor-native-video-compressor 1.1.1 → 1.1.3

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":"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","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { toBlobURL } from '@ffmpeg/util';\nimport {\n ALL_FORMATS,\n BlobSource,\n BufferTarget,\n Conversion,\n ConversionCanceledError,\n Input,\n Mp4OutputFormat,\n Output,\n Quality,\n canEncodeVideo,\n} from 'mediabunny';\n\nimport type {\n NativeVideoCompressorPlugin,\n CompressOptions,\n CompressResult,\n CancelOptions,\n CancelResult,\n} from './definitions';\nimport { CANCELLED } from './definitions';\n\ntype VideoQuality = NonNullable<CompressOptions['quality']>;\n\n/**\n * Rejection shape for a cancelled compress. `code` matches what `call.reject`\n * puts on the error object on iOS/Android, so one `error.code === 'CANCELLED'`\n * check works on every platform — and on both web engines below.\n */\nclass CancelledError extends Error {\n code = CANCELLED;\n constructor() {\n super('Đã hủy nén');\n this.name = 'CancelledError';\n }\n}\n\n/**\n * WebCodecs target per quality tier: cap height + a bitrate ceiling. The\n * quantizer (constant 26, CRF-like) drives quality where the encoder honours\n * it; H.264 on most browsers is bitrate-driven, so `bitrate` is the real knob.\n * fps is capped to 30 at call time (never upsampled). Audio is left to\n * mediabunny, which re-encodes to AAC for the MP4 container.\n */\nconst WEBCODECS_LADDER: Record<VideoQuality, { height: number; bitrate: number }> = {\n VERY_HIGH: { height: 1080, bitrate: 4000000 },\n HIGH: { height: 720, bitrate: 2000000 },\n MEDIUM: { height: 540, bitrate: 1200000 },\n LOW: { height: 480, bitrate: 1000000 },\n '360P': { height: 360, bitrate: 700000 },\n VERY_LOW: { height: 240, bitrate: 350000 },\n};\n\nconst WEBCODECS_QUANTIZER = 26;\nconst FPS_CAP = 30;\n\nconst CORE_BASE_URL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n\n/**\n * Cancelling means terminating the worker, which drops the loaded core with\n * it — so without this the next compress re-downloads ~30 MB of wasm and\n * \"cancel\" quietly costs more than it saves. Module scope, not instance: the\n * bytes are identical for every instance and every job. Only the ffmpeg\n * fallback ever pays this download; the WebCodecs primary path needs no core.\n */\nlet corePromise: Promise<{ coreURL: string; wasmURL: string }> | null = null;\n\nconst loadCoreURLs = () => {\n if (!corePromise) {\n corePromise = Promise.all([\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.js`, 'text/javascript'),\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.wasm`, 'application/wasm'),\n ])\n .then(([coreURL, wasmURL]) => ({ coreURL, wasmURL }))\n .catch((e) => {\n // Don't cache a failure — a flaky network shouldn't make every later\n // compress in this session fail too.\n corePromise = null;\n throw e;\n });\n }\n return corePromise;\n};\n\nexport class NativeVideoCompressorWeb extends WebPlugin implements NativeVideoCompressorPlugin {\n private ffmpeg: FFmpeg | null = null;\n private isLoaded = false;\n /** The mediabunny conversion running now, so `cancel()` can abort it. */\n private activeConversion: Conversion | null = null;\n /** The job `compressVideo` is running right now, for `cancel({ jobId })`. */\n private currentJobId: string | null = null;\n private cancelRequested = false;\n\n async initialize(): Promise<{ success: boolean; message?: string }> {\n // WebCodecs (the primary path) needs no core download, so there is nothing\n // to warm. Eagerly loading the ffmpeg core here would pull ~30 MB for a\n // path most compresses never take. The fallback lazy-loads its core on\n // first use. Kept as a resolving no-op so callers that await it still pass.\n return { success: true, message: 'ready' };\n }\n\n async compressVideo(options: CompressOptions): Promise<CompressResult> {\n this.currentJobId = options.jobId ?? 'default';\n this.cancelRequested = false;\n\n // Checked at every stage boundary, not just around the encode: cancelling\n // an engine only reaches work already handed to it, so a cancel during the\n // source fetch or before init has nothing to interrupt and would otherwise\n // let the compress carry on as if nothing had happened.\n const throwIfCancelled = () => {\n if (this.cancelRequested) throw new CancelledError();\n };\n\n try {\n throwIfCancelled();\n\n const blob = await this.fetchSourceBlob(options.sourcePath);\n throwIfCancelled();\n\n const quality: VideoQuality = options.quality ?? 'MEDIUM';\n\n if (await this.canUseWebCodecs(quality)) {\n try {\n const result = await this.compressWithWebCodecs(blob, quality, throwIfCancelled);\n if (result) return result;\n // null → conversion invalid / tracks discarded → fall back to ffmpeg.\n } catch (e: any) {\n if (e?.code === CANCELLED) throw e; // user cancel: never fall back\n console.warn('[compress] WebCodecs failed, falling back to ffmpeg:', e);\n throwIfCancelled();\n }\n }\n\n return await this.compressWithFfmpeg(blob, quality, throwIfCancelled);\n } catch (error: any) {\n if (error?.code === CANCELLED) {\n console.log('[compress] cancelled');\n } else {\n console.error('[compress] failed:', error);\n }\n throw error;\n } finally {\n this.currentJobId = null;\n this.cancelRequested = false;\n this.activeConversion = null;\n }\n }\n\n /**\n * Kill whichever engine is mid-compress. Only one is ever active at a time,\n * so acting on both is safe.\n *\n * WebCodecs: `conversion.cancel()` makes the in-flight `execute()` reject\n * with `ConversionCanceledError`, surfaced as a `CancelledError` below.\n * ffmpeg: `exec()` runs synchronously inside the worker and never reaches a\n * message poll while encoding, so `worker.terminate()` is the only way to\n * stop it — its cost is the loaded core, which is why the core URLs are\n * cached above.\n */\n async cancel(options?: CancelOptions): Promise<CancelResult> {\n if (!this.currentJobId) return { cancelled: false };\n if (options?.jobId && options.jobId !== this.currentJobId) return { cancelled: false };\n\n // Set even when neither engine exists yet: the job may still be fetching\n // the source or inside loadFFmpeg, which read this flag at their boundaries.\n this.cancelRequested = true;\n\n const conversion = this.activeConversion;\n this.activeConversion = null;\n // Fire-and-forget: the CancelledError surfaces from the execute() rejection,\n // not from here; awaiting would only make cancel() slower.\n conversion?.cancel().catch(() => undefined);\n\n this.ffmpeg?.terminate();\n this.ffmpeg = null;\n this.isLoaded = false;\n\n return { cancelled: true };\n }\n\n private async fetchSourceBlob(sourcePath: string): Promise<Blob> {\n try {\n const response = await fetch(sourcePath);\n return await response.blob();\n } catch (err) {\n console.error('[compress] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n }\n\n private async canUseWebCodecs(quality: VideoQuality): Promise<boolean> {\n try {\n const { bitrate } = WEBCODECS_LADDER[quality];\n return await canEncodeVideo('avc', {\n quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }),\n });\n } catch {\n return false;\n }\n }\n\n private async compressWithWebCodecs(\n blob: Blob,\n quality: VideoQuality,\n throwIfCancelled: () => void,\n ): Promise<CompressResult | null> {\n const { height, bitrate } = WEBCODECS_LADDER[quality];\n\n const input = new Input({ formats: ALL_FORMATS, source: new BlobSource(blob) });\n const output = new Output({ format: new Mp4OutputFormat(), target: new BufferTarget() });\n\n // Cap fps at 30, but never upsample: probe the source and take the min.\n // A failed probe just omits frameRate, leaving the source rate untouched.\n let frameRate: number | undefined;\n try {\n const track = await input.getPrimaryVideoTrack();\n if (track) {\n const stats = await track.computePacketStats(100);\n if (stats.averagePacketRate > 0) {\n frameRate = Math.min(FPS_CAP, Math.round(stats.averagePacketRate));\n }\n }\n } catch {\n frameRate = undefined;\n }\n\n throwIfCancelled();\n\n const conversion = await Conversion.init({\n input,\n output,\n video: {\n height,\n quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }),\n hardwareAcceleration: 'prefer-hardware',\n ...(frameRate ? { frameRate } : {}),\n },\n });\n\n if (!conversion.isValid) {\n console.warn(\n '[compress] WebCodecs conversion invalid:',\n conversion.discardedTracks.map((t) => t.reason),\n );\n return null;\n }\n\n this.activeConversion = conversion;\n\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n conversion.onProgress = (progress) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n };\n\n throwIfCancelled();\n try {\n await conversion.execute();\n } catch (e: any) {\n if (this.cancelRequested || e instanceof ConversionCanceledError) throw new CancelledError();\n throw e;\n }\n\n const buffer = output.target.buffer;\n if (!buffer) throw new Error('WebCodecs produced no output');\n\n const outBlob = new Blob([buffer], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n\n private async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg) return;\n\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n\n // Built on a local, published to the field only once it is ready and still\n // wanted. Assigning `this.ffmpeg` up front and setting `isLoaded` after the\n // await left a window where a cancel could null the instance and the load,\n // finishing a moment later, would set `isLoaded = true` on nothing at all —\n // after which every compressVideo threw 'FFmpeg failed to load' for the\n // rest of the page's life.\n const instance = new FFmpeg();\n\n instance.on('progress', ({ progress }) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n\n instance.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n\n try {\n await instance.load(await loadCoreURLs());\n } catch (e: any) {\n instance.terminate();\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n\n // Cancelled while this was loading. Terminate what we just built rather\n // than publish it — the caller asked for none of it.\n if (this.cancelRequested) {\n instance.terminate();\n throw new CancelledError();\n }\n\n this.ffmpeg = instance;\n this.isLoaded = true;\n }\n\n private async compressWithFfmpeg(\n blob: Blob,\n quality: VideoQuality,\n throwIfCancelled: () => void,\n ): Promise<CompressResult> {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n throwIfCancelled();\n\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n // Bound once. `this.ffmpeg` is nulled by cancel(), so reading it after any\n // of the awaits below can hand back null on a reference the compiler\n // narrowed here — surfacing a cancel as a TypeError, not a CancelledError.\n const ffmpeg = this.ffmpeg;\n\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n\n let crf = '28';\n let scale = '';\n let audioBitrate = '128k';\n\n switch (quality) {\n case 'VERY_HIGH':\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH':\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM':\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW':\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P':\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW':\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n\n const inputData = new Uint8Array(await blob.arrayBuffer());\n\n try {\n await ffmpeg.writeFile(inputFileName, inputData);\n } catch (err) {\n if (this.cancelRequested) throw new CancelledError();\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n throwIfCancelled();\n\n const args: string[] = ['-i', inputFileName];\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n if (scale) {\n args.push(...scale.split(' '));\n }\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n args.push(outputFileName);\n\n try {\n await ffmpeg.exec(args);\n } catch (err) {\n // terminate() rejects every in-flight call, so a cancel arrives here\n // looking like a generic failure unless we name it.\n if (this.cancelRequested) throw new CancelledError();\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n throwIfCancelled();\n\n let data: any;\n try {\n data = await ffmpeg.readFile(outputFileName);\n } catch (err) {\n if (this.cancelRequested) throw new CancelledError();\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n\n await ffmpeg.deleteFile(inputFileName);\n await ffmpeg.deleteFile(outputFileName);\n\n const outBlob = new Blob([data as any], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { toBlobURL } from '@ffmpeg/util';\nimport {\n ALL_FORMATS,\n BlobSource,\n BufferTarget,\n Conversion,\n ConversionCanceledError,\n Input,\n Mp4OutputFormat,\n Output,\n Quality,\n canEncodeVideo,\n} from 'mediabunny';\n\nimport type {\n NativeVideoCompressorPlugin,\n CompressOptions,\n CompressResult,\n CancelOptions,\n CancelResult,\n} from './definitions';\nimport { CANCELLED } from './definitions';\n\ntype VideoQuality = NonNullable<CompressOptions['quality']>;\n\n/**\n * Rejection shape for a cancelled compress. `code` matches what `call.reject`\n * puts on the error object on iOS/Android, so one `error.code === 'CANCELLED'`\n * check works on every platform — and on both web engines below.\n */\nclass CancelledError extends Error {\n code = CANCELLED;\n constructor() {\n super('Đã hủy nén');\n this.name = 'CancelledError';\n }\n}\n\n/**\n * WebCodecs target per quality tier: cap height + a bitrate ceiling. The\n * quantizer (constant 26, CRF-like) drives quality where the encoder honours\n * it; H.264 on most browsers is bitrate-driven, so `bitrate` is the real knob.\n * fps is capped to 30 at call time (never upsampled). Audio is left to\n * mediabunny, which re-encodes to AAC for the MP4 container.\n */\nconst WEBCODECS_LADDER: Record<VideoQuality, { height: number; bitrate: number }> = {\n VERY_HIGH: { height: 1080, bitrate: 4000000 },\n HIGH: { height: 720, bitrate: 2000000 },\n MEDIUM: { height: 540, bitrate: 1200000 },\n LOW: { height: 480, bitrate: 1000000 },\n '360P': { height: 360, bitrate: 700000 },\n VERY_LOW: { height: 240, bitrate: 350000 },\n};\n\nconst WEBCODECS_QUANTIZER = 26;\nconst FPS_CAP = 30;\n\nconst CORE_BASE_URL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n\n/**\n * Cancelling means terminating the worker, which drops the loaded core with\n * it — so without this the next compress re-downloads ~30 MB of wasm and\n * \"cancel\" quietly costs more than it saves. Module scope, not instance: the\n * bytes are identical for every instance and every job. Only the ffmpeg\n * fallback ever pays this download; the WebCodecs primary path needs no core.\n */\nlet corePromise: Promise<{ coreURL: string; wasmURL: string }> | null = null;\n\nconst loadCoreURLs = () => {\n if (!corePromise) {\n corePromise = Promise.all([\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.js`, 'text/javascript'),\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.wasm`, 'application/wasm'),\n ])\n .then(([coreURL, wasmURL]) => ({ coreURL, wasmURL }))\n .catch((e) => {\n // Don't cache a failure — a flaky network shouldn't make every later\n // compress in this session fail too.\n corePromise = null;\n throw e;\n });\n }\n return corePromise;\n};\n\nexport class NativeVideoCompressorWeb extends WebPlugin implements NativeVideoCompressorPlugin {\n private ffmpeg: FFmpeg | null = null;\n private isLoaded = false;\n /** The mediabunny conversion running now, so `cancel()` can abort it. */\n private activeConversion: Conversion | null = null;\n /** The job `compressVideo` is running right now, for `cancel({ jobId })`. */\n private currentJobId: string | null = null;\n private cancelRequested = false;\n\n async initialize(): Promise<{ success: boolean; message?: string }> {\n // WebCodecs (the primary path) needs no core download, so there is nothing\n // to warm. Eagerly loading the ffmpeg core here would pull ~30 MB for a\n // path most compresses never take. The fallback lazy-loads its core on\n // first use. Kept as a resolving no-op so callers that await it still pass.\n return { success: true, message: 'ready' };\n }\n\n async compressVideo(options: CompressOptions): Promise<CompressResult> {\n this.currentJobId = options.jobId ?? 'default';\n this.cancelRequested = false;\n\n // Checked at every stage boundary, not just around the encode: cancelling\n // an engine only reaches work already handed to it, so a cancel during the\n // source fetch or before init has nothing to interrupt and would otherwise\n // let the compress carry on as if nothing had happened.\n const throwIfCancelled = () => {\n if (this.cancelRequested) throw new CancelledError();\n };\n\n try {\n throwIfCancelled();\n\n const blob = await this.fetchSourceBlob(options.sourcePath);\n throwIfCancelled();\n\n const quality: VideoQuality = options.quality ?? 'MEDIUM';\n\n if (await this.canUseWebCodecs(quality)) {\n try {\n const result = await this.compressWithWebCodecs(blob, quality, throwIfCancelled);\n if (result) return result;\n // null → conversion invalid / tracks discarded → fall back to ffmpeg.\n } catch (e: any) {\n if (e?.code === CANCELLED) throw e; // user cancel: never fall back\n console.warn('[compress] WebCodecs failed, falling back to ffmpeg:', e);\n throwIfCancelled();\n }\n }\n\n return await this.compressWithFfmpeg(blob, quality, throwIfCancelled);\n } catch (error: any) {\n if (error?.code === CANCELLED) {\n console.log('[compress] cancelled');\n } else {\n console.error('[compress] failed:', error);\n }\n throw error;\n } finally {\n this.currentJobId = null;\n this.cancelRequested = false;\n this.activeConversion = null;\n }\n }\n\n /**\n * Kill whichever engine is mid-compress. Only one is ever active at a time,\n * so acting on both is safe.\n *\n * WebCodecs: `conversion.cancel()` makes the in-flight `execute()` reject\n * with `ConversionCanceledError`, surfaced as a `CancelledError` below.\n * ffmpeg: `exec()` runs synchronously inside the worker and never reaches a\n * message poll while encoding, so `worker.terminate()` is the only way to\n * stop it — its cost is the loaded core, which is why the core URLs are\n * cached above.\n */\n /**\n * Chỉ Android mới có foreground service để mà hạ xuống. Hiện diện ở đây để\n * caller gọi thẳng, không phải rẽ nhánh theo platform ở mọi call site.\n */\n async finishUpload(): Promise<void> {\n return;\n }\n\n async cancel(options?: CancelOptions): Promise<CancelResult> {\n if (!this.currentJobId) return { cancelled: false };\n if (options?.jobId && options.jobId !== this.currentJobId) return { cancelled: false };\n\n // Set even when neither engine exists yet: the job may still be fetching\n // the source or inside loadFFmpeg, which read this flag at their boundaries.\n this.cancelRequested = true;\n\n const conversion = this.activeConversion;\n this.activeConversion = null;\n // Fire-and-forget: the CancelledError surfaces from the execute() rejection,\n // not from here; awaiting would only make cancel() slower.\n conversion?.cancel().catch(() => undefined);\n\n this.ffmpeg?.terminate();\n this.ffmpeg = null;\n this.isLoaded = false;\n\n return { cancelled: true };\n }\n\n private async fetchSourceBlob(sourcePath: string): Promise<Blob> {\n try {\n const response = await fetch(sourcePath);\n return await response.blob();\n } catch (err) {\n console.error('[compress] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n }\n\n private async canUseWebCodecs(quality: VideoQuality): Promise<boolean> {\n try {\n const { bitrate } = WEBCODECS_LADDER[quality];\n return await canEncodeVideo('avc', {\n quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }),\n });\n } catch {\n return false;\n }\n }\n\n private async compressWithWebCodecs(\n blob: Blob,\n quality: VideoQuality,\n throwIfCancelled: () => void,\n ): Promise<CompressResult | null> {\n const { height, bitrate } = WEBCODECS_LADDER[quality];\n\n const input = new Input({ formats: ALL_FORMATS, source: new BlobSource(blob) });\n const output = new Output({ format: new Mp4OutputFormat(), target: new BufferTarget() });\n\n // Cap fps at 30, but never upsample: probe the source and take the min.\n // A failed probe just omits frameRate, leaving the source rate untouched.\n let frameRate: number | undefined;\n try {\n const track = await input.getPrimaryVideoTrack();\n if (track) {\n const stats = await track.computePacketStats(100);\n if (stats.averagePacketRate > 0) {\n frameRate = Math.min(FPS_CAP, Math.round(stats.averagePacketRate));\n }\n }\n } catch {\n frameRate = undefined;\n }\n\n throwIfCancelled();\n\n const conversion = await Conversion.init({\n input,\n output,\n video: {\n height,\n quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }),\n hardwareAcceleration: 'prefer-hardware',\n ...(frameRate ? { frameRate } : {}),\n },\n });\n\n if (!conversion.isValid) {\n console.warn(\n '[compress] WebCodecs conversion invalid:',\n conversion.discardedTracks.map((t) => t.reason),\n );\n return null;\n }\n\n this.activeConversion = conversion;\n\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n conversion.onProgress = (progress) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n };\n\n throwIfCancelled();\n try {\n await conversion.execute();\n } catch (e: any) {\n if (this.cancelRequested || e instanceof ConversionCanceledError) throw new CancelledError();\n throw e;\n }\n\n const buffer = output.target.buffer;\n if (!buffer) throw new Error('WebCodecs produced no output');\n\n const outBlob = new Blob([buffer], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n\n private async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg) return;\n\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n\n // Built on a local, published to the field only once it is ready and still\n // wanted. Assigning `this.ffmpeg` up front and setting `isLoaded` after the\n // await left a window where a cancel could null the instance and the load,\n // finishing a moment later, would set `isLoaded = true` on nothing at all —\n // after which every compressVideo threw 'FFmpeg failed to load' for the\n // rest of the page's life.\n const instance = new FFmpeg();\n\n instance.on('progress', ({ progress }) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n\n instance.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n\n try {\n await instance.load(await loadCoreURLs());\n } catch (e: any) {\n instance.terminate();\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n\n // Cancelled while this was loading. Terminate what we just built rather\n // than publish it — the caller asked for none of it.\n if (this.cancelRequested) {\n instance.terminate();\n throw new CancelledError();\n }\n\n this.ffmpeg = instance;\n this.isLoaded = true;\n }\n\n private async compressWithFfmpeg(\n blob: Blob,\n quality: VideoQuality,\n throwIfCancelled: () => void,\n ): Promise<CompressResult> {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n throwIfCancelled();\n\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n // Bound once. `this.ffmpeg` is nulled by cancel(), so reading it after any\n // of the awaits below can hand back null on a reference the compiler\n // narrowed here — surfacing a cancel as a TypeError, not a CancelledError.\n const ffmpeg = this.ffmpeg;\n\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n\n let crf = '28';\n let scale = '';\n let audioBitrate = '128k';\n\n switch (quality) {\n case 'VERY_HIGH':\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH':\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM':\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW':\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P':\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW':\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n\n const inputData = new Uint8Array(await blob.arrayBuffer());\n\n try {\n await ffmpeg.writeFile(inputFileName, inputData);\n } catch (err) {\n if (this.cancelRequested) throw new CancelledError();\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n throwIfCancelled();\n\n const args: string[] = ['-i', inputFileName];\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n if (scale) {\n args.push(...scale.split(' '));\n }\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n args.push(outputFileName);\n\n try {\n await ffmpeg.exec(args);\n } catch (err) {\n // terminate() rejects every in-flight call, so a cancel arrives here\n // looking like a generic failure unless we name it.\n if (this.cancelRequested) throw new CancelledError();\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n throwIfCancelled();\n\n let data: any;\n try {\n data = await ffmpeg.readFile(outputFileName);\n } catch (err) {\n if (this.cancelRequested) throw new CancelledError();\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n\n await ffmpeg.deleteFile(inputFileName);\n await ffmpeg.deleteFile(outputFileName);\n\n const outBlob = new Blob([data as any], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n}\n"]}
@@ -147,6 +147,13 @@ class NativeVideoCompressorWeb extends core.WebPlugin {
147
147
  * stop it — its cost is the loaded core, which is why the core URLs are
148
148
  * cached above.
149
149
  */
150
+ /**
151
+ * Chỉ Android mới có foreground service để mà hạ xuống. Hiện diện ở đây để
152
+ * caller gọi thẳng, không phải rẽ nhánh theo platform ở mọi call site.
153
+ */
154
+ async finishUpload() {
155
+ return;
156
+ }
150
157
  async cancel(options) {
151
158
  var _a;
152
159
  if (!this.currentJobId)
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["/**\n * `code` on the error `compressVideo` rejects with when `cancel()` stopped it.\n * Callers should treat it as \"the user asked for this\" — no error toast, no\n * retry prompt — and tell it apart from a genuine compression failure.\n */\nexport const CANCELLED = 'CANCELLED';\n//# sourceMappingURL=definitions.js.map","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 { toBlobURL } from '@ffmpeg/util';\nimport { ALL_FORMATS, BlobSource, BufferTarget, Conversion, ConversionCanceledError, Input, Mp4OutputFormat, Output, Quality, canEncodeVideo, } from 'mediabunny';\nimport { CANCELLED } from './definitions';\n/**\n * Rejection shape for a cancelled compress. `code` matches what `call.reject`\n * puts on the error object on iOS/Android, so one `error.code === 'CANCELLED'`\n * check works on every platform — and on both web engines below.\n */\nclass CancelledError extends Error {\n constructor() {\n super('Đã hủy nén');\n this.code = CANCELLED;\n this.name = 'CancelledError';\n }\n}\n/**\n * WebCodecs target per quality tier: cap height + a bitrate ceiling. The\n * quantizer (constant 26, CRF-like) drives quality where the encoder honours\n * it; H.264 on most browsers is bitrate-driven, so `bitrate` is the real knob.\n * fps is capped to 30 at call time (never upsampled). Audio is left to\n * mediabunny, which re-encodes to AAC for the MP4 container.\n */\nconst WEBCODECS_LADDER = {\n VERY_HIGH: { height: 1080, bitrate: 4000000 },\n HIGH: { height: 720, bitrate: 2000000 },\n MEDIUM: { height: 540, bitrate: 1200000 },\n LOW: { height: 480, bitrate: 1000000 },\n '360P': { height: 360, bitrate: 700000 },\n VERY_LOW: { height: 240, bitrate: 350000 },\n};\nconst WEBCODECS_QUANTIZER = 26;\nconst FPS_CAP = 30;\nconst CORE_BASE_URL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n/**\n * Cancelling means terminating the worker, which drops the loaded core with\n * it — so without this the next compress re-downloads ~30 MB of wasm and\n * \"cancel\" quietly costs more than it saves. Module scope, not instance: the\n * bytes are identical for every instance and every job. Only the ffmpeg\n * fallback ever pays this download; the WebCodecs primary path needs no core.\n */\nlet corePromise = null;\nconst loadCoreURLs = () => {\n if (!corePromise) {\n corePromise = Promise.all([\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.js`, 'text/javascript'),\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.wasm`, 'application/wasm'),\n ])\n .then(([coreURL, wasmURL]) => ({ coreURL, wasmURL }))\n .catch((e) => {\n // Don't cache a failure — a flaky network shouldn't make every later\n // compress in this session fail too.\n corePromise = null;\n throw e;\n });\n }\n return corePromise;\n};\nexport class NativeVideoCompressorWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.ffmpeg = null;\n this.isLoaded = false;\n /** The mediabunny conversion running now, so `cancel()` can abort it. */\n this.activeConversion = null;\n /** The job `compressVideo` is running right now, for `cancel({ jobId })`. */\n this.currentJobId = null;\n this.cancelRequested = false;\n }\n async initialize() {\n // WebCodecs (the primary path) needs no core download, so there is nothing\n // to warm. Eagerly loading the ffmpeg core here would pull ~30 MB for a\n // path most compresses never take. The fallback lazy-loads its core on\n // first use. Kept as a resolving no-op so callers that await it still pass.\n return { success: true, message: 'ready' };\n }\n async compressVideo(options) {\n var _a, _b;\n this.currentJobId = (_a = options.jobId) !== null && _a !== void 0 ? _a : 'default';\n this.cancelRequested = false;\n // Checked at every stage boundary, not just around the encode: cancelling\n // an engine only reaches work already handed to it, so a cancel during the\n // source fetch or before init has nothing to interrupt and would otherwise\n // let the compress carry on as if nothing had happened.\n const throwIfCancelled = () => {\n if (this.cancelRequested)\n throw new CancelledError();\n };\n try {\n throwIfCancelled();\n const blob = await this.fetchSourceBlob(options.sourcePath);\n throwIfCancelled();\n const quality = (_b = options.quality) !== null && _b !== void 0 ? _b : 'MEDIUM';\n if (await this.canUseWebCodecs(quality)) {\n try {\n const result = await this.compressWithWebCodecs(blob, quality, throwIfCancelled);\n if (result)\n return result;\n // null → conversion invalid / tracks discarded → fall back to ffmpeg.\n }\n catch (e) {\n if ((e === null || e === void 0 ? void 0 : e.code) === CANCELLED)\n throw e; // user cancel: never fall back\n console.warn('[compress] WebCodecs failed, falling back to ffmpeg:', e);\n throwIfCancelled();\n }\n }\n return await this.compressWithFfmpeg(blob, quality, throwIfCancelled);\n }\n catch (error) {\n if ((error === null || error === void 0 ? void 0 : error.code) === CANCELLED) {\n console.log('[compress] cancelled');\n }\n else {\n console.error('[compress] failed:', error);\n }\n throw error;\n }\n finally {\n this.currentJobId = null;\n this.cancelRequested = false;\n this.activeConversion = null;\n }\n }\n /**\n * Kill whichever engine is mid-compress. Only one is ever active at a time,\n * so acting on both is safe.\n *\n * WebCodecs: `conversion.cancel()` makes the in-flight `execute()` reject\n * with `ConversionCanceledError`, surfaced as a `CancelledError` below.\n * ffmpeg: `exec()` runs synchronously inside the worker and never reaches a\n * message poll while encoding, so `worker.terminate()` is the only way to\n * stop it — its cost is the loaded core, which is why the core URLs are\n * cached above.\n */\n async cancel(options) {\n var _a;\n if (!this.currentJobId)\n return { cancelled: false };\n if ((options === null || options === void 0 ? void 0 : options.jobId) && options.jobId !== this.currentJobId)\n return { cancelled: false };\n // Set even when neither engine exists yet: the job may still be fetching\n // the source or inside loadFFmpeg, which read this flag at their boundaries.\n this.cancelRequested = true;\n const conversion = this.activeConversion;\n this.activeConversion = null;\n // Fire-and-forget: the CancelledError surfaces from the execute() rejection,\n // not from here; awaiting would only make cancel() slower.\n conversion === null || conversion === void 0 ? void 0 : conversion.cancel().catch(() => undefined);\n (_a = this.ffmpeg) === null || _a === void 0 ? void 0 : _a.terminate();\n this.ffmpeg = null;\n this.isLoaded = false;\n return { cancelled: true };\n }\n async fetchSourceBlob(sourcePath) {\n try {\n const response = await fetch(sourcePath);\n return await response.blob();\n }\n catch (err) {\n console.error('[compress] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n }\n async canUseWebCodecs(quality) {\n try {\n const { bitrate } = WEBCODECS_LADDER[quality];\n return await canEncodeVideo('avc', {\n quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }),\n });\n }\n catch (_a) {\n return false;\n }\n }\n async compressWithWebCodecs(blob, quality, throwIfCancelled) {\n const { height, bitrate } = WEBCODECS_LADDER[quality];\n const input = new Input({ formats: ALL_FORMATS, source: new BlobSource(blob) });\n const output = new Output({ format: new Mp4OutputFormat(), target: new BufferTarget() });\n // Cap fps at 30, but never upsample: probe the source and take the min.\n // A failed probe just omits frameRate, leaving the source rate untouched.\n let frameRate;\n try {\n const track = await input.getPrimaryVideoTrack();\n if (track) {\n const stats = await track.computePacketStats(100);\n if (stats.averagePacketRate > 0) {\n frameRate = Math.min(FPS_CAP, Math.round(stats.averagePacketRate));\n }\n }\n }\n catch (_a) {\n frameRate = undefined;\n }\n throwIfCancelled();\n const conversion = await Conversion.init({\n input,\n output,\n video: Object.assign({ height, quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }), hardwareAcceleration: 'prefer-hardware' }, (frameRate ? { frameRate } : {})),\n });\n if (!conversion.isValid) {\n console.warn('[compress] WebCodecs conversion invalid:', conversion.discardedTracks.map((t) => t.reason));\n return null;\n }\n this.activeConversion = conversion;\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n conversion.onProgress = (progress) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n };\n throwIfCancelled();\n try {\n await conversion.execute();\n }\n catch (e) {\n if (this.cancelRequested || e instanceof ConversionCanceledError)\n throw new CancelledError();\n throw e;\n }\n const buffer = output.target.buffer;\n if (!buffer)\n throw new Error('WebCodecs produced no output');\n const outBlob = new Blob([buffer], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg)\n return;\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n // Built on a local, published to the field only once it is ready and still\n // wanted. Assigning `this.ffmpeg` up front and setting `isLoaded` after the\n // await left a window where a cancel could null the instance and the load,\n // finishing a moment later, would set `isLoaded = true` on nothing at all —\n // after which every compressVideo threw 'FFmpeg failed to load' for the\n // rest of the page's life.\n const instance = new FFmpeg();\n instance.on('progress', ({ progress }) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n instance.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n try {\n await instance.load(await loadCoreURLs());\n }\n catch (e) {\n instance.terminate();\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n // Cancelled while this was loading. Terminate what we just built rather\n // than publish it — the caller asked for none of it.\n if (this.cancelRequested) {\n instance.terminate();\n throw new CancelledError();\n }\n this.ffmpeg = instance;\n this.isLoaded = true;\n }\n async compressWithFfmpeg(blob, quality, throwIfCancelled) {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n throwIfCancelled();\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n // Bound once. `this.ffmpeg` is nulled by cancel(), so reading it after any\n // of the awaits below can hand back null on a reference the compiler\n // narrowed here — surfacing a cancel as a TypeError, not a CancelledError.\n const ffmpeg = this.ffmpeg;\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n let crf = '28';\n let scale = '';\n let audioBitrate = '128k';\n switch (quality) {\n case 'VERY_HIGH':\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH':\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM':\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW':\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P':\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW':\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n const inputData = new Uint8Array(await blob.arrayBuffer());\n try {\n await ffmpeg.writeFile(inputFileName, inputData);\n }\n catch (err) {\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n throwIfCancelled();\n const args = ['-i', inputFileName];\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n if (scale) {\n args.push(...scale.split(' '));\n }\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n args.push(outputFileName);\n try {\n await ffmpeg.exec(args);\n }\n catch (err) {\n // terminate() rejects every in-flight call, so a cancel arrives here\n // looking like a generic failure unless we name it.\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n throwIfCancelled();\n let data;\n try {\n data = await ffmpeg.readFile(outputFileName);\n }\n catch (err) {\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n await ffmpeg.deleteFile(inputFileName);\n await ffmpeg.deleteFile(outputFileName);\n const outBlob = new Blob([data], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","toBlobURL","WebPlugin","canEncodeVideo","Quality","Input","ALL_FORMATS","BlobSource","Output","Mp4OutputFormat","BufferTarget","Conversion","ConversionCanceledError","FFmpeg"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["/**\n * `code` on the error `compressVideo` rejects with when `cancel()` stopped it.\n * Callers should treat it as \"the user asked for this\" — no error toast, no\n * retry prompt — and tell it apart from a genuine compression failure.\n */\nexport const CANCELLED = 'CANCELLED';\n//# sourceMappingURL=definitions.js.map","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 { toBlobURL } from '@ffmpeg/util';\nimport { ALL_FORMATS, BlobSource, BufferTarget, Conversion, ConversionCanceledError, Input, Mp4OutputFormat, Output, Quality, canEncodeVideo, } from 'mediabunny';\nimport { CANCELLED } from './definitions';\n/**\n * Rejection shape for a cancelled compress. `code` matches what `call.reject`\n * puts on the error object on iOS/Android, so one `error.code === 'CANCELLED'`\n * check works on every platform — and on both web engines below.\n */\nclass CancelledError extends Error {\n constructor() {\n super('Đã hủy nén');\n this.code = CANCELLED;\n this.name = 'CancelledError';\n }\n}\n/**\n * WebCodecs target per quality tier: cap height + a bitrate ceiling. The\n * quantizer (constant 26, CRF-like) drives quality where the encoder honours\n * it; H.264 on most browsers is bitrate-driven, so `bitrate` is the real knob.\n * fps is capped to 30 at call time (never upsampled). Audio is left to\n * mediabunny, which re-encodes to AAC for the MP4 container.\n */\nconst WEBCODECS_LADDER = {\n VERY_HIGH: { height: 1080, bitrate: 4000000 },\n HIGH: { height: 720, bitrate: 2000000 },\n MEDIUM: { height: 540, bitrate: 1200000 },\n LOW: { height: 480, bitrate: 1000000 },\n '360P': { height: 360, bitrate: 700000 },\n VERY_LOW: { height: 240, bitrate: 350000 },\n};\nconst WEBCODECS_QUANTIZER = 26;\nconst FPS_CAP = 30;\nconst CORE_BASE_URL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n/**\n * Cancelling means terminating the worker, which drops the loaded core with\n * it — so without this the next compress re-downloads ~30 MB of wasm and\n * \"cancel\" quietly costs more than it saves. Module scope, not instance: the\n * bytes are identical for every instance and every job. Only the ffmpeg\n * fallback ever pays this download; the WebCodecs primary path needs no core.\n */\nlet corePromise = null;\nconst loadCoreURLs = () => {\n if (!corePromise) {\n corePromise = Promise.all([\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.js`, 'text/javascript'),\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.wasm`, 'application/wasm'),\n ])\n .then(([coreURL, wasmURL]) => ({ coreURL, wasmURL }))\n .catch((e) => {\n // Don't cache a failure — a flaky network shouldn't make every later\n // compress in this session fail too.\n corePromise = null;\n throw e;\n });\n }\n return corePromise;\n};\nexport class NativeVideoCompressorWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.ffmpeg = null;\n this.isLoaded = false;\n /** The mediabunny conversion running now, so `cancel()` can abort it. */\n this.activeConversion = null;\n /** The job `compressVideo` is running right now, for `cancel({ jobId })`. */\n this.currentJobId = null;\n this.cancelRequested = false;\n }\n async initialize() {\n // WebCodecs (the primary path) needs no core download, so there is nothing\n // to warm. Eagerly loading the ffmpeg core here would pull ~30 MB for a\n // path most compresses never take. The fallback lazy-loads its core on\n // first use. Kept as a resolving no-op so callers that await it still pass.\n return { success: true, message: 'ready' };\n }\n async compressVideo(options) {\n var _a, _b;\n this.currentJobId = (_a = options.jobId) !== null && _a !== void 0 ? _a : 'default';\n this.cancelRequested = false;\n // Checked at every stage boundary, not just around the encode: cancelling\n // an engine only reaches work already handed to it, so a cancel during the\n // source fetch or before init has nothing to interrupt and would otherwise\n // let the compress carry on as if nothing had happened.\n const throwIfCancelled = () => {\n if (this.cancelRequested)\n throw new CancelledError();\n };\n try {\n throwIfCancelled();\n const blob = await this.fetchSourceBlob(options.sourcePath);\n throwIfCancelled();\n const quality = (_b = options.quality) !== null && _b !== void 0 ? _b : 'MEDIUM';\n if (await this.canUseWebCodecs(quality)) {\n try {\n const result = await this.compressWithWebCodecs(blob, quality, throwIfCancelled);\n if (result)\n return result;\n // null → conversion invalid / tracks discarded → fall back to ffmpeg.\n }\n catch (e) {\n if ((e === null || e === void 0 ? void 0 : e.code) === CANCELLED)\n throw e; // user cancel: never fall back\n console.warn('[compress] WebCodecs failed, falling back to ffmpeg:', e);\n throwIfCancelled();\n }\n }\n return await this.compressWithFfmpeg(blob, quality, throwIfCancelled);\n }\n catch (error) {\n if ((error === null || error === void 0 ? void 0 : error.code) === CANCELLED) {\n console.log('[compress] cancelled');\n }\n else {\n console.error('[compress] failed:', error);\n }\n throw error;\n }\n finally {\n this.currentJobId = null;\n this.cancelRequested = false;\n this.activeConversion = null;\n }\n }\n /**\n * Kill whichever engine is mid-compress. Only one is ever active at a time,\n * so acting on both is safe.\n *\n * WebCodecs: `conversion.cancel()` makes the in-flight `execute()` reject\n * with `ConversionCanceledError`, surfaced as a `CancelledError` below.\n * ffmpeg: `exec()` runs synchronously inside the worker and never reaches a\n * message poll while encoding, so `worker.terminate()` is the only way to\n * stop it — its cost is the loaded core, which is why the core URLs are\n * cached above.\n */\n /**\n * Chỉ Android mới có foreground service để mà hạ xuống. Hiện diện ở đây để\n * caller gọi thẳng, không phải rẽ nhánh theo platform ở mọi call site.\n */\n async finishUpload() {\n return;\n }\n async cancel(options) {\n var _a;\n if (!this.currentJobId)\n return { cancelled: false };\n if ((options === null || options === void 0 ? void 0 : options.jobId) && options.jobId !== this.currentJobId)\n return { cancelled: false };\n // Set even when neither engine exists yet: the job may still be fetching\n // the source or inside loadFFmpeg, which read this flag at their boundaries.\n this.cancelRequested = true;\n const conversion = this.activeConversion;\n this.activeConversion = null;\n // Fire-and-forget: the CancelledError surfaces from the execute() rejection,\n // not from here; awaiting would only make cancel() slower.\n conversion === null || conversion === void 0 ? void 0 : conversion.cancel().catch(() => undefined);\n (_a = this.ffmpeg) === null || _a === void 0 ? void 0 : _a.terminate();\n this.ffmpeg = null;\n this.isLoaded = false;\n return { cancelled: true };\n }\n async fetchSourceBlob(sourcePath) {\n try {\n const response = await fetch(sourcePath);\n return await response.blob();\n }\n catch (err) {\n console.error('[compress] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n }\n async canUseWebCodecs(quality) {\n try {\n const { bitrate } = WEBCODECS_LADDER[quality];\n return await canEncodeVideo('avc', {\n quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }),\n });\n }\n catch (_a) {\n return false;\n }\n }\n async compressWithWebCodecs(blob, quality, throwIfCancelled) {\n const { height, bitrate } = WEBCODECS_LADDER[quality];\n const input = new Input({ formats: ALL_FORMATS, source: new BlobSource(blob) });\n const output = new Output({ format: new Mp4OutputFormat(), target: new BufferTarget() });\n // Cap fps at 30, but never upsample: probe the source and take the min.\n // A failed probe just omits frameRate, leaving the source rate untouched.\n let frameRate;\n try {\n const track = await input.getPrimaryVideoTrack();\n if (track) {\n const stats = await track.computePacketStats(100);\n if (stats.averagePacketRate > 0) {\n frameRate = Math.min(FPS_CAP, Math.round(stats.averagePacketRate));\n }\n }\n }\n catch (_a) {\n frameRate = undefined;\n }\n throwIfCancelled();\n const conversion = await Conversion.init({\n input,\n output,\n video: Object.assign({ height, quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }), hardwareAcceleration: 'prefer-hardware' }, (frameRate ? { frameRate } : {})),\n });\n if (!conversion.isValid) {\n console.warn('[compress] WebCodecs conversion invalid:', conversion.discardedTracks.map((t) => t.reason));\n return null;\n }\n this.activeConversion = conversion;\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n conversion.onProgress = (progress) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n };\n throwIfCancelled();\n try {\n await conversion.execute();\n }\n catch (e) {\n if (this.cancelRequested || e instanceof ConversionCanceledError)\n throw new CancelledError();\n throw e;\n }\n const buffer = output.target.buffer;\n if (!buffer)\n throw new Error('WebCodecs produced no output');\n const outBlob = new Blob([buffer], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg)\n return;\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n // Built on a local, published to the field only once it is ready and still\n // wanted. Assigning `this.ffmpeg` up front and setting `isLoaded` after the\n // await left a window where a cancel could null the instance and the load,\n // finishing a moment later, would set `isLoaded = true` on nothing at all —\n // after which every compressVideo threw 'FFmpeg failed to load' for the\n // rest of the page's life.\n const instance = new FFmpeg();\n instance.on('progress', ({ progress }) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n instance.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n try {\n await instance.load(await loadCoreURLs());\n }\n catch (e) {\n instance.terminate();\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n // Cancelled while this was loading. Terminate what we just built rather\n // than publish it — the caller asked for none of it.\n if (this.cancelRequested) {\n instance.terminate();\n throw new CancelledError();\n }\n this.ffmpeg = instance;\n this.isLoaded = true;\n }\n async compressWithFfmpeg(blob, quality, throwIfCancelled) {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n throwIfCancelled();\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n // Bound once. `this.ffmpeg` is nulled by cancel(), so reading it after any\n // of the awaits below can hand back null on a reference the compiler\n // narrowed here — surfacing a cancel as a TypeError, not a CancelledError.\n const ffmpeg = this.ffmpeg;\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n let crf = '28';\n let scale = '';\n let audioBitrate = '128k';\n switch (quality) {\n case 'VERY_HIGH':\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH':\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM':\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW':\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P':\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW':\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n const inputData = new Uint8Array(await blob.arrayBuffer());\n try {\n await ffmpeg.writeFile(inputFileName, inputData);\n }\n catch (err) {\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n throwIfCancelled();\n const args = ['-i', inputFileName];\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n if (scale) {\n args.push(...scale.split(' '));\n }\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n args.push(outputFileName);\n try {\n await ffmpeg.exec(args);\n }\n catch (err) {\n // terminate() rejects every in-flight call, so a cancel arrives here\n // looking like a generic failure unless we name it.\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n throwIfCancelled();\n let data;\n try {\n data = await ffmpeg.readFile(outputFileName);\n }\n catch (err) {\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n await ffmpeg.deleteFile(inputFileName);\n await ffmpeg.deleteFile(outputFileName);\n const outBlob = new Blob([data], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","toBlobURL","WebPlugin","canEncodeVideo","Quality","Input","ALL_FORMATS","BlobSource","Output","Mp4OutputFormat","BufferTarget","Conversion","ConversionCanceledError","FFmpeg"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACY,MAAC,SAAS,GAAG;;ACJpB,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;;ACED;AACA;AACA;AACA;AACA;AACA,MAAM,cAAc,SAAS,KAAK,CAAC;AACnC,IAAI,WAAW,GAAG;AAClB,QAAQ,KAAK,CAAC,YAAY,CAAC;AAC3B,QAAQ,IAAI,CAAC,IAAI,GAAG,SAAS;AAC7B,QAAQ,IAAI,CAAC,IAAI,GAAG,gBAAgB;AACpC,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,gBAAgB,GAAG;AACzB,IAAI,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE;AACjD,IAAI,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;AAC3C,IAAI,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;AAC7C,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE;AAC1C,IAAI,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE;AAC5C,IAAI,QAAQ,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE;AAC9C,CAAC;AACD,MAAM,mBAAmB,GAAG,EAAE;AAC9B,MAAM,OAAO,GAAG,EAAE;AAClB,MAAM,aAAa,GAAG,gDAAgD;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,GAAG,IAAI;AACtB,MAAM,YAAY,GAAG,MAAM;AAC3B,IAAI,IAAI,CAAC,WAAW,EAAE;AACtB,QAAQ,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;AAClC,YAAYC,cAAS,CAAC,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,EAAE,iBAAiB,CAAC;AAC3E,YAAYA,cAAS,CAAC,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;AAC9E,SAAS;AACT,aAAa,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAChE,aAAa,KAAK,CAAC,CAAC,CAAC,KAAK;AAC1B;AACA;AACA,YAAY,WAAW,GAAG,IAAI;AAC9B,YAAY,MAAM,CAAC;AACnB,QAAQ,CAAC,CAAC;AACV,IAAI;AACJ,IAAI,OAAO,WAAW;AACtB,CAAC;AACM,MAAM,wBAAwB,SAASC,cAAS,CAAC;AACxD,IAAI,WAAW,GAAG;AAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;AAC3B,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI;AAC1B,QAAQ,IAAI,CAAC,QAAQ,GAAG,KAAK;AAC7B;AACA,QAAQ,IAAI,CAAC,gBAAgB,GAAG,IAAI;AACpC;AACA,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI;AAChC,QAAQ,IAAI,CAAC,eAAe,GAAG,KAAK;AACpC,IAAI;AACJ,IAAI,MAAM,UAAU,GAAG;AACvB;AACA;AACA;AACA;AACA,QAAQ,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE;AAClD,IAAI;AACJ,IAAI,MAAM,aAAa,CAAC,OAAO,EAAE;AACjC,QAAQ,IAAI,EAAE,EAAE,EAAE;AAClB,QAAQ,IAAI,CAAC,YAAY,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,SAAS;AAC3F,QAAQ,IAAI,CAAC,eAAe,GAAG,KAAK;AACpC;AACA;AACA;AACA;AACA,QAAQ,MAAM,gBAAgB,GAAG,MAAM;AACvC,YAAY,IAAI,IAAI,CAAC,eAAe;AACpC,gBAAgB,MAAM,IAAI,cAAc,EAAE;AAC1C,QAAQ,CAAC;AACT,QAAQ,IAAI;AACZ,YAAY,gBAAgB,EAAE;AAC9B,YAAY,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,UAAU,CAAC;AACvE,YAAY,gBAAgB,EAAE;AAC9B,YAAY,MAAM,OAAO,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG,QAAQ;AAC5F,YAAY,IAAI,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE;AACrD,gBAAgB,IAAI;AACpB,oBAAoB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,gBAAgB,CAAC;AACpG,oBAAoB,IAAI,MAAM;AAC9B,wBAAwB,OAAO,MAAM;AACrC;AACA,gBAAgB;AAChB,gBAAgB,OAAO,CAAC,EAAE;AAC1B,oBAAoB,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,SAAS;AACpF,wBAAwB,MAAM,CAAC,CAAC;AAChC,oBAAoB,OAAO,CAAC,IAAI,CAAC,sDAAsD,EAAE,CAAC,CAAC;AAC3F,oBAAoB,gBAAgB,EAAE;AACtC,gBAAgB;AAChB,YAAY;AACZ,YAAY,OAAO,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,gBAAgB,CAAC;AACjF,QAAQ;AACR,QAAQ,OAAO,KAAK,EAAE;AACtB,YAAY,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,IAAI,MAAM,SAAS,EAAE;AAC1F,gBAAgB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;AACnD,YAAY;AACZ,iBAAiB;AACjB,gBAAgB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC;AAC1D,YAAY;AACZ,YAAY,MAAM,KAAK;AACvB,QAAQ;AACR,gBAAgB;AAChB,YAAY,IAAI,CAAC,YAAY,GAAG,IAAI;AACpC,YAAY,IAAI,CAAC,eAAe,GAAG,KAAK;AACxC,YAAY,IAAI,CAAC,gBAAgB,GAAG,IAAI;AACxC,QAAQ;AACR,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ;AACR,IAAI;AACJ,IAAI,MAAM,MAAM,CAAC,OAAO,EAAE;AAC1B,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY;AAC9B,YAAY,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE;AACvC,QAAQ,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,YAAY;AACpH,YAAY,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE;AACvC;AACA;AACA,QAAQ,IAAI,CAAC,eAAe,GAAG,IAAI;AACnC,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB;AAChD,QAAQ,IAAI,CAAC,gBAAgB,GAAG,IAAI;AACpC;AACA;AACA,QAAQ,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AAC1G,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,SAAS,EAAE;AAC9E,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI;AAC1B,QAAQ,IAAI,CAAC,QAAQ,GAAG,KAAK;AAC7B,QAAQ,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE;AAClC,IAAI;AACJ,IAAI,MAAM,eAAe,CAAC,UAAU,EAAE;AACtC,QAAQ,IAAI;AACZ,YAAY,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC;AACpD,YAAY,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE;AACxC,QAAQ;AACR,QAAQ,OAAO,GAAG,EAAE;AACpB,YAAY,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,CAAC;AACxE,YAAY,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC;AAChE,QAAQ;AACR,IAAI;AACJ,IAAI,MAAM,eAAe,CAAC,OAAO,EAAE;AACnC,QAAQ,IAAI;AACZ,YAAY,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC;AACzD,YAAY,OAAO,MAAMC,yBAAc,CAAC,KAAK,EAAE;AAC/C,gBAAgB,OAAO,EAAE,IAAIC,kBAAO,CAAC,EAAE,SAAS,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAC;AACjF,aAAa,CAAC;AACd,QAAQ;AACR,QAAQ,OAAO,EAAE,EAAE;AACnB,YAAY,OAAO,KAAK;AACxB,QAAQ;AACR,IAAI;AACJ,IAAI,MAAM,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,gBAAgB,EAAE;AACjE,QAAQ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC;AAC7D,QAAQ,MAAM,KAAK,GAAG,IAAIC,gBAAK,CAAC,EAAE,OAAO,EAAEC,sBAAW,EAAE,MAAM,EAAE,IAAIC,qBAAU,CAAC,IAAI,CAAC,EAAE,CAAC;AACvF,QAAQ,MAAM,MAAM,GAAG,IAAIC,iBAAM,CAAC,EAAE,MAAM,EAAE,IAAIC,0BAAe,EAAE,EAAE,MAAM,EAAE,IAAIC,uBAAY,EAAE,EAAE,CAAC;AAChG;AACA;AACA,QAAQ,IAAI,SAAS;AACrB,QAAQ,IAAI;AACZ,YAAY,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,oBAAoB,EAAE;AAC5D,YAAY,IAAI,KAAK,EAAE;AACvB,gBAAgB,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC;AACjE,gBAAgB,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC,EAAE;AACjD,oBAAoB,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;AACtF,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,EAAE,EAAE;AACnB,YAAY,SAAS,GAAG,SAAS;AACjC,QAAQ;AACR,QAAQ,gBAAgB,EAAE;AAC1B,QAAQ,MAAM,UAAU,GAAG,MAAMC,qBAAU,CAAC,IAAI,CAAC;AACjD,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAIP,kBAAO,CAAC,EAAE,SAAS,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAC,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,GAAG,SAAS,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE;AAC1L,SAAS,CAAC;AACV,QAAQ,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE;AACjC,YAAY,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC;AACrH,YAAY,OAAO,IAAI;AACvB,QAAQ;AACR,QAAQ,IAAI,CAAC,gBAAgB,GAAG,UAAU;AAC1C,QAAQ,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAC7E,QAAQ,UAAU,CAAC,UAAU,GAAG,CAAC,QAAQ,KAAK;AAC9C,YAAY,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC;AAC3G,QAAQ,CAAC;AACT,QAAQ,gBAAgB,EAAE;AAC1B,QAAQ,IAAI;AACZ,YAAY,MAAM,UAAU,CAAC,OAAO,EAAE;AACtC,QAAQ;AACR,QAAQ,OAAO,CAAC,EAAE;AAClB,YAAY,IAAI,IAAI,CAAC,eAAe,IAAI,CAAC,YAAYQ,kCAAuB;AAC5E,gBAAgB,MAAM,IAAI,cAAc,EAAE;AAC1C,YAAY,MAAM,CAAC;AACnB,QAAQ;AACR,QAAQ,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM;AAC3C,QAAQ,IAAI,CAAC,MAAM;AACnB,YAAY,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;AAC3D,QAAQ,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AACjE,QAAQ,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE;AACxE,IAAI;AACJ,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM;AACxC,YAAY;AACZ,QAAQ,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAClF;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,MAAM,QAAQ,GAAG,IAAIC,aAAM,EAAE;AACrC,QAAQ,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK;AAClD,YAAY,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC;AAC3G,QAAQ,CAAC,CAAC;AACV,QAAQ,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK;AAC5C,YAAY,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC;AAChD,QAAQ,CAAC,CAAC;AACV,QAAQ,IAAI;AACZ,YAAY,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,YAAY,EAAE,CAAC;AACrD,QAAQ;AACR,QAAQ,OAAO,CAAC,EAAE;AAClB,YAAY,QAAQ,CAAC,SAAS,EAAE;AAChC,YAAY,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC,CAAC;AACtD,YAAY,MAAM,CAAC;AACnB,QAAQ;AACR;AACA;AACA,QAAQ,IAAI,IAAI,CAAC,eAAe,EAAE;AAClC,YAAY,QAAQ,CAAC,SAAS,EAAE;AAChC,YAAY,MAAM,IAAI,cAAc,EAAE;AACtC,QAAQ;AACR,QAAQ,IAAI,CAAC,MAAM,GAAG,QAAQ;AAC9B,QAAQ,IAAI,CAAC,QAAQ,GAAG,IAAI;AAC5B,IAAI;AACJ,IAAI,MAAM,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,gBAAgB,EAAE;AAC9D,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAC5B,YAAY,MAAM,IAAI,CAAC,UAAU,EAAE;AACnC,QAAQ;AACR,QAAQ,gBAAgB,EAAE;AAC1B,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;AAC1B,YAAY,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC;AACpD,QAAQ;AACR;AACA;AACA;AACA,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM;AAClC,QAAQ,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAC7E,QAAQ,MAAM,aAAa,GAAG,WAAW;AACzC,QAAQ,MAAM,cAAc,GAAG,YAAY;AAC3C,QAAQ,IAAI,GAAG,GAAG,IAAI;AACtB,QAAQ,IAAI,KAAK,GAAG,EAAE;AACtB,QAAQ,IAAI,YAAY,GAAG,MAAM;AACjC,QAAQ,QAAQ,OAAO;AACvB,YAAY,KAAK,WAAW;AAC5B,gBAAgB,GAAG,GAAG,IAAI;AAC1B,gBAAgB,KAAK,GAAG,mBAAmB;AAC3C,gBAAgB,YAAY,GAAG,MAAM;AACrC,gBAAgB;AAChB,YAAY,KAAK,MAAM;AACvB,gBAAgB,GAAG,GAAG,IAAI;AAC1B,gBAAgB,KAAK,GAAG,kBAAkB;AAC1C,gBAAgB,YAAY,GAAG,MAAM;AACrC,gBAAgB;AAChB,YAAY,KAAK,QAAQ;AACzB,gBAAgB,GAAG,GAAG,IAAI;AAC1B,gBAAgB,KAAK,GAAG,kBAAkB;AAC1C,gBAAgB,YAAY,GAAG,KAAK;AACpC,gBAAgB;AAChB,YAAY,KAAK,KAAK;AACtB,gBAAgB,GAAG,GAAG,IAAI;AAC1B,gBAAgB,KAAK,GAAG,kBAAkB;AAC1C,gBAAgB,YAAY,GAAG,KAAK;AACpC,gBAAgB;AAChB,YAAY,KAAK,MAAM;AACvB,gBAAgB,GAAG,GAAG,IAAI;AAC1B,gBAAgB,KAAK,GAAG,kBAAkB;AAC1C,gBAAgB,YAAY,GAAG,KAAK;AACpC,gBAAgB;AAChB,YAAY,KAAK,UAAU;AAC3B,gBAAgB,GAAG,GAAG,IAAI;AAC1B,gBAAgB,KAAK,GAAG,kBAAkB;AAC1C,gBAAgB,YAAY,GAAG,KAAK;AACpC,gBAAgB;AAChB;AACA,QAAQ,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;AAClE,QAAQ,IAAI;AACZ,YAAY,MAAM,MAAM,CAAC,SAAS,CAAC,aAAa,EAAE,SAAS,CAAC;AAC5D,QAAQ;AACR,QAAQ,OAAO,GAAG,EAAE;AACpB,YAAY,IAAI,IAAI,CAAC,eAAe;AACpC,gBAAgB,MAAM,IAAI,cAAc,EAAE;AAC1C,YAAY,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC;AAC/D,YAAY,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;AAC3D,QAAQ;AACR,QAAQ,gBAAgB,EAAE;AAC1B,QAAQ,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC;AAC1C,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC;AACzE,QAAQ,IAAI,KAAK,EAAE;AACnB,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC1C,QAAQ;AACR,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC;AACtD,QAAQ,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;AACjC,QAAQ,IAAI;AACZ,YAAY,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AACnC,QAAQ;AACR,QAAQ,OAAO,GAAG,EAAE;AACpB;AACA;AACA,YAAY,IAAI,IAAI,CAAC,eAAe;AACpC,gBAAgB,MAAM,IAAI,cAAc,EAAE;AAC1C,YAAY,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC;AACnE,YAAY,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AACtD,QAAQ;AACR,QAAQ,gBAAgB,EAAE;AAC1B,QAAQ,IAAI,IAAI;AAChB,QAAQ,IAAI;AACZ,YAAY,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC;AACxD,QAAQ;AACR,QAAQ,OAAO,GAAG,EAAE;AACpB,YAAY,IAAI,IAAI,CAAC,eAAe;AACpC,gBAAgB,MAAM,IAAI,cAAc,EAAE;AAC1C,YAAY,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,GAAG,CAAC;AACrE,YAAY,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;AAC3D,QAAQ;AACR,QAAQ,MAAM,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC;AAC9C,QAAQ,MAAM,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC;AAC/C,QAAQ,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC/D,QAAQ,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE;AACxE,IAAI;AACJ;;;;;;;;;;"}
package/dist/plugin.js CHANGED
@@ -143,6 +143,13 @@ var capacitorNativeVideoCompressor = (function (exports, core, ffmpeg, util, med
143
143
  * stop it — its cost is the loaded core, which is why the core URLs are
144
144
  * cached above.
145
145
  */
146
+ /**
147
+ * Chỉ Android mới có foreground service để mà hạ xuống. Hiện diện ở đây để
148
+ * caller gọi thẳng, không phải rẽ nhánh theo platform ở mọi call site.
149
+ */
150
+ async finishUpload() {
151
+ return;
152
+ }
146
153
  async cancel(options) {
147
154
  var _a;
148
155
  if (!this.currentJobId)
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["/**\n * `code` on the error `compressVideo` rejects with when `cancel()` stopped it.\n * Callers should treat it as \"the user asked for this\" — no error toast, no\n * retry prompt — and tell it apart from a genuine compression failure.\n */\nexport const CANCELLED = 'CANCELLED';\n//# sourceMappingURL=definitions.js.map","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 { toBlobURL } from '@ffmpeg/util';\nimport { ALL_FORMATS, BlobSource, BufferTarget, Conversion, ConversionCanceledError, Input, Mp4OutputFormat, Output, Quality, canEncodeVideo, } from 'mediabunny';\nimport { CANCELLED } from './definitions';\n/**\n * Rejection shape for a cancelled compress. `code` matches what `call.reject`\n * puts on the error object on iOS/Android, so one `error.code === 'CANCELLED'`\n * check works on every platform — and on both web engines below.\n */\nclass CancelledError extends Error {\n constructor() {\n super('Đã hủy nén');\n this.code = CANCELLED;\n this.name = 'CancelledError';\n }\n}\n/**\n * WebCodecs target per quality tier: cap height + a bitrate ceiling. The\n * quantizer (constant 26, CRF-like) drives quality where the encoder honours\n * it; H.264 on most browsers is bitrate-driven, so `bitrate` is the real knob.\n * fps is capped to 30 at call time (never upsampled). Audio is left to\n * mediabunny, which re-encodes to AAC for the MP4 container.\n */\nconst WEBCODECS_LADDER = {\n VERY_HIGH: { height: 1080, bitrate: 4000000 },\n HIGH: { height: 720, bitrate: 2000000 },\n MEDIUM: { height: 540, bitrate: 1200000 },\n LOW: { height: 480, bitrate: 1000000 },\n '360P': { height: 360, bitrate: 700000 },\n VERY_LOW: { height: 240, bitrate: 350000 },\n};\nconst WEBCODECS_QUANTIZER = 26;\nconst FPS_CAP = 30;\nconst CORE_BASE_URL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n/**\n * Cancelling means terminating the worker, which drops the loaded core with\n * it — so without this the next compress re-downloads ~30 MB of wasm and\n * \"cancel\" quietly costs more than it saves. Module scope, not instance: the\n * bytes are identical for every instance and every job. Only the ffmpeg\n * fallback ever pays this download; the WebCodecs primary path needs no core.\n */\nlet corePromise = null;\nconst loadCoreURLs = () => {\n if (!corePromise) {\n corePromise = Promise.all([\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.js`, 'text/javascript'),\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.wasm`, 'application/wasm'),\n ])\n .then(([coreURL, wasmURL]) => ({ coreURL, wasmURL }))\n .catch((e) => {\n // Don't cache a failure — a flaky network shouldn't make every later\n // compress in this session fail too.\n corePromise = null;\n throw e;\n });\n }\n return corePromise;\n};\nexport class NativeVideoCompressorWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.ffmpeg = null;\n this.isLoaded = false;\n /** The mediabunny conversion running now, so `cancel()` can abort it. */\n this.activeConversion = null;\n /** The job `compressVideo` is running right now, for `cancel({ jobId })`. */\n this.currentJobId = null;\n this.cancelRequested = false;\n }\n async initialize() {\n // WebCodecs (the primary path) needs no core download, so there is nothing\n // to warm. Eagerly loading the ffmpeg core here would pull ~30 MB for a\n // path most compresses never take. The fallback lazy-loads its core on\n // first use. Kept as a resolving no-op so callers that await it still pass.\n return { success: true, message: 'ready' };\n }\n async compressVideo(options) {\n var _a, _b;\n this.currentJobId = (_a = options.jobId) !== null && _a !== void 0 ? _a : 'default';\n this.cancelRequested = false;\n // Checked at every stage boundary, not just around the encode: cancelling\n // an engine only reaches work already handed to it, so a cancel during the\n // source fetch or before init has nothing to interrupt and would otherwise\n // let the compress carry on as if nothing had happened.\n const throwIfCancelled = () => {\n if (this.cancelRequested)\n throw new CancelledError();\n };\n try {\n throwIfCancelled();\n const blob = await this.fetchSourceBlob(options.sourcePath);\n throwIfCancelled();\n const quality = (_b = options.quality) !== null && _b !== void 0 ? _b : 'MEDIUM';\n if (await this.canUseWebCodecs(quality)) {\n try {\n const result = await this.compressWithWebCodecs(blob, quality, throwIfCancelled);\n if (result)\n return result;\n // null → conversion invalid / tracks discarded → fall back to ffmpeg.\n }\n catch (e) {\n if ((e === null || e === void 0 ? void 0 : e.code) === CANCELLED)\n throw e; // user cancel: never fall back\n console.warn('[compress] WebCodecs failed, falling back to ffmpeg:', e);\n throwIfCancelled();\n }\n }\n return await this.compressWithFfmpeg(blob, quality, throwIfCancelled);\n }\n catch (error) {\n if ((error === null || error === void 0 ? void 0 : error.code) === CANCELLED) {\n console.log('[compress] cancelled');\n }\n else {\n console.error('[compress] failed:', error);\n }\n throw error;\n }\n finally {\n this.currentJobId = null;\n this.cancelRequested = false;\n this.activeConversion = null;\n }\n }\n /**\n * Kill whichever engine is mid-compress. Only one is ever active at a time,\n * so acting on both is safe.\n *\n * WebCodecs: `conversion.cancel()` makes the in-flight `execute()` reject\n * with `ConversionCanceledError`, surfaced as a `CancelledError` below.\n * ffmpeg: `exec()` runs synchronously inside the worker and never reaches a\n * message poll while encoding, so `worker.terminate()` is the only way to\n * stop it — its cost is the loaded core, which is why the core URLs are\n * cached above.\n */\n async cancel(options) {\n var _a;\n if (!this.currentJobId)\n return { cancelled: false };\n if ((options === null || options === void 0 ? void 0 : options.jobId) && options.jobId !== this.currentJobId)\n return { cancelled: false };\n // Set even when neither engine exists yet: the job may still be fetching\n // the source or inside loadFFmpeg, which read this flag at their boundaries.\n this.cancelRequested = true;\n const conversion = this.activeConversion;\n this.activeConversion = null;\n // Fire-and-forget: the CancelledError surfaces from the execute() rejection,\n // not from here; awaiting would only make cancel() slower.\n conversion === null || conversion === void 0 ? void 0 : conversion.cancel().catch(() => undefined);\n (_a = this.ffmpeg) === null || _a === void 0 ? void 0 : _a.terminate();\n this.ffmpeg = null;\n this.isLoaded = false;\n return { cancelled: true };\n }\n async fetchSourceBlob(sourcePath) {\n try {\n const response = await fetch(sourcePath);\n return await response.blob();\n }\n catch (err) {\n console.error('[compress] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n }\n async canUseWebCodecs(quality) {\n try {\n const { bitrate } = WEBCODECS_LADDER[quality];\n return await canEncodeVideo('avc', {\n quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }),\n });\n }\n catch (_a) {\n return false;\n }\n }\n async compressWithWebCodecs(blob, quality, throwIfCancelled) {\n const { height, bitrate } = WEBCODECS_LADDER[quality];\n const input = new Input({ formats: ALL_FORMATS, source: new BlobSource(blob) });\n const output = new Output({ format: new Mp4OutputFormat(), target: new BufferTarget() });\n // Cap fps at 30, but never upsample: probe the source and take the min.\n // A failed probe just omits frameRate, leaving the source rate untouched.\n let frameRate;\n try {\n const track = await input.getPrimaryVideoTrack();\n if (track) {\n const stats = await track.computePacketStats(100);\n if (stats.averagePacketRate > 0) {\n frameRate = Math.min(FPS_CAP, Math.round(stats.averagePacketRate));\n }\n }\n }\n catch (_a) {\n frameRate = undefined;\n }\n throwIfCancelled();\n const conversion = await Conversion.init({\n input,\n output,\n video: Object.assign({ height, quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }), hardwareAcceleration: 'prefer-hardware' }, (frameRate ? { frameRate } : {})),\n });\n if (!conversion.isValid) {\n console.warn('[compress] WebCodecs conversion invalid:', conversion.discardedTracks.map((t) => t.reason));\n return null;\n }\n this.activeConversion = conversion;\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n conversion.onProgress = (progress) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n };\n throwIfCancelled();\n try {\n await conversion.execute();\n }\n catch (e) {\n if (this.cancelRequested || e instanceof ConversionCanceledError)\n throw new CancelledError();\n throw e;\n }\n const buffer = output.target.buffer;\n if (!buffer)\n throw new Error('WebCodecs produced no output');\n const outBlob = new Blob([buffer], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg)\n return;\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n // Built on a local, published to the field only once it is ready and still\n // wanted. Assigning `this.ffmpeg` up front and setting `isLoaded` after the\n // await left a window where a cancel could null the instance and the load,\n // finishing a moment later, would set `isLoaded = true` on nothing at all —\n // after which every compressVideo threw 'FFmpeg failed to load' for the\n // rest of the page's life.\n const instance = new FFmpeg();\n instance.on('progress', ({ progress }) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n instance.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n try {\n await instance.load(await loadCoreURLs());\n }\n catch (e) {\n instance.terminate();\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n // Cancelled while this was loading. Terminate what we just built rather\n // than publish it — the caller asked for none of it.\n if (this.cancelRequested) {\n instance.terminate();\n throw new CancelledError();\n }\n this.ffmpeg = instance;\n this.isLoaded = true;\n }\n async compressWithFfmpeg(blob, quality, throwIfCancelled) {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n throwIfCancelled();\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n // Bound once. `this.ffmpeg` is nulled by cancel(), so reading it after any\n // of the awaits below can hand back null on a reference the compiler\n // narrowed here — surfacing a cancel as a TypeError, not a CancelledError.\n const ffmpeg = this.ffmpeg;\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n let crf = '28';\n let scale = '';\n let audioBitrate = '128k';\n switch (quality) {\n case 'VERY_HIGH':\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH':\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM':\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW':\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P':\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW':\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n const inputData = new Uint8Array(await blob.arrayBuffer());\n try {\n await ffmpeg.writeFile(inputFileName, inputData);\n }\n catch (err) {\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n throwIfCancelled();\n const args = ['-i', inputFileName];\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n if (scale) {\n args.push(...scale.split(' '));\n }\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n args.push(outputFileName);\n try {\n await ffmpeg.exec(args);\n }\n catch (err) {\n // terminate() rejects every in-flight call, so a cancel arrives here\n // looking like a generic failure unless we name it.\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n throwIfCancelled();\n let data;\n try {\n data = await ffmpeg.readFile(outputFileName);\n }\n catch (err) {\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n await ffmpeg.deleteFile(inputFileName);\n await ffmpeg.deleteFile(outputFileName);\n const outBlob = new Blob([data], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","toBlobURL","WebPlugin","canEncodeVideo","Quality","Input","ALL_FORMATS","BlobSource","Output","Mp4OutputFormat","BufferTarget","Conversion","ConversionCanceledError","FFmpeg"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["/**\n * `code` on the error `compressVideo` rejects with when `cancel()` stopped it.\n * Callers should treat it as \"the user asked for this\" — no error toast, no\n * retry prompt — and tell it apart from a genuine compression failure.\n */\nexport const CANCELLED = 'CANCELLED';\n//# sourceMappingURL=definitions.js.map","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 { toBlobURL } from '@ffmpeg/util';\nimport { ALL_FORMATS, BlobSource, BufferTarget, Conversion, ConversionCanceledError, Input, Mp4OutputFormat, Output, Quality, canEncodeVideo, } from 'mediabunny';\nimport { CANCELLED } from './definitions';\n/**\n * Rejection shape for a cancelled compress. `code` matches what `call.reject`\n * puts on the error object on iOS/Android, so one `error.code === 'CANCELLED'`\n * check works on every platform — and on both web engines below.\n */\nclass CancelledError extends Error {\n constructor() {\n super('Đã hủy nén');\n this.code = CANCELLED;\n this.name = 'CancelledError';\n }\n}\n/**\n * WebCodecs target per quality tier: cap height + a bitrate ceiling. The\n * quantizer (constant 26, CRF-like) drives quality where the encoder honours\n * it; H.264 on most browsers is bitrate-driven, so `bitrate` is the real knob.\n * fps is capped to 30 at call time (never upsampled). Audio is left to\n * mediabunny, which re-encodes to AAC for the MP4 container.\n */\nconst WEBCODECS_LADDER = {\n VERY_HIGH: { height: 1080, bitrate: 4000000 },\n HIGH: { height: 720, bitrate: 2000000 },\n MEDIUM: { height: 540, bitrate: 1200000 },\n LOW: { height: 480, bitrate: 1000000 },\n '360P': { height: 360, bitrate: 700000 },\n VERY_LOW: { height: 240, bitrate: 350000 },\n};\nconst WEBCODECS_QUANTIZER = 26;\nconst FPS_CAP = 30;\nconst CORE_BASE_URL = 'https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm';\n/**\n * Cancelling means terminating the worker, which drops the loaded core with\n * it — so without this the next compress re-downloads ~30 MB of wasm and\n * \"cancel\" quietly costs more than it saves. Module scope, not instance: the\n * bytes are identical for every instance and every job. Only the ffmpeg\n * fallback ever pays this download; the WebCodecs primary path needs no core.\n */\nlet corePromise = null;\nconst loadCoreURLs = () => {\n if (!corePromise) {\n corePromise = Promise.all([\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.js`, 'text/javascript'),\n toBlobURL(`${CORE_BASE_URL}/ffmpeg-core.wasm`, 'application/wasm'),\n ])\n .then(([coreURL, wasmURL]) => ({ coreURL, wasmURL }))\n .catch((e) => {\n // Don't cache a failure — a flaky network shouldn't make every later\n // compress in this session fail too.\n corePromise = null;\n throw e;\n });\n }\n return corePromise;\n};\nexport class NativeVideoCompressorWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.ffmpeg = null;\n this.isLoaded = false;\n /** The mediabunny conversion running now, so `cancel()` can abort it. */\n this.activeConversion = null;\n /** The job `compressVideo` is running right now, for `cancel({ jobId })`. */\n this.currentJobId = null;\n this.cancelRequested = false;\n }\n async initialize() {\n // WebCodecs (the primary path) needs no core download, so there is nothing\n // to warm. Eagerly loading the ffmpeg core here would pull ~30 MB for a\n // path most compresses never take. The fallback lazy-loads its core on\n // first use. Kept as a resolving no-op so callers that await it still pass.\n return { success: true, message: 'ready' };\n }\n async compressVideo(options) {\n var _a, _b;\n this.currentJobId = (_a = options.jobId) !== null && _a !== void 0 ? _a : 'default';\n this.cancelRequested = false;\n // Checked at every stage boundary, not just around the encode: cancelling\n // an engine only reaches work already handed to it, so a cancel during the\n // source fetch or before init has nothing to interrupt and would otherwise\n // let the compress carry on as if nothing had happened.\n const throwIfCancelled = () => {\n if (this.cancelRequested)\n throw new CancelledError();\n };\n try {\n throwIfCancelled();\n const blob = await this.fetchSourceBlob(options.sourcePath);\n throwIfCancelled();\n const quality = (_b = options.quality) !== null && _b !== void 0 ? _b : 'MEDIUM';\n if (await this.canUseWebCodecs(quality)) {\n try {\n const result = await this.compressWithWebCodecs(blob, quality, throwIfCancelled);\n if (result)\n return result;\n // null → conversion invalid / tracks discarded → fall back to ffmpeg.\n }\n catch (e) {\n if ((e === null || e === void 0 ? void 0 : e.code) === CANCELLED)\n throw e; // user cancel: never fall back\n console.warn('[compress] WebCodecs failed, falling back to ffmpeg:', e);\n throwIfCancelled();\n }\n }\n return await this.compressWithFfmpeg(blob, quality, throwIfCancelled);\n }\n catch (error) {\n if ((error === null || error === void 0 ? void 0 : error.code) === CANCELLED) {\n console.log('[compress] cancelled');\n }\n else {\n console.error('[compress] failed:', error);\n }\n throw error;\n }\n finally {\n this.currentJobId = null;\n this.cancelRequested = false;\n this.activeConversion = null;\n }\n }\n /**\n * Kill whichever engine is mid-compress. Only one is ever active at a time,\n * so acting on both is safe.\n *\n * WebCodecs: `conversion.cancel()` makes the in-flight `execute()` reject\n * with `ConversionCanceledError`, surfaced as a `CancelledError` below.\n * ffmpeg: `exec()` runs synchronously inside the worker and never reaches a\n * message poll while encoding, so `worker.terminate()` is the only way to\n * stop it — its cost is the loaded core, which is why the core URLs are\n * cached above.\n */\n /**\n * Chỉ Android mới có foreground service để mà hạ xuống. Hiện diện ở đây để\n * caller gọi thẳng, không phải rẽ nhánh theo platform ở mọi call site.\n */\n async finishUpload() {\n return;\n }\n async cancel(options) {\n var _a;\n if (!this.currentJobId)\n return { cancelled: false };\n if ((options === null || options === void 0 ? void 0 : options.jobId) && options.jobId !== this.currentJobId)\n return { cancelled: false };\n // Set even when neither engine exists yet: the job may still be fetching\n // the source or inside loadFFmpeg, which read this flag at their boundaries.\n this.cancelRequested = true;\n const conversion = this.activeConversion;\n this.activeConversion = null;\n // Fire-and-forget: the CancelledError surfaces from the execute() rejection,\n // not from here; awaiting would only make cancel() slower.\n conversion === null || conversion === void 0 ? void 0 : conversion.cancel().catch(() => undefined);\n (_a = this.ffmpeg) === null || _a === void 0 ? void 0 : _a.terminate();\n this.ffmpeg = null;\n this.isLoaded = false;\n return { cancelled: true };\n }\n async fetchSourceBlob(sourcePath) {\n try {\n const response = await fetch(sourcePath);\n return await response.blob();\n }\n catch (err) {\n console.error('[compress] Error fetching source file:', err);\n throw new Error('Could not fetch source video file');\n }\n }\n async canUseWebCodecs(quality) {\n try {\n const { bitrate } = WEBCODECS_LADDER[quality];\n return await canEncodeVideo('avc', {\n quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }),\n });\n }\n catch (_a) {\n return false;\n }\n }\n async compressWithWebCodecs(blob, quality, throwIfCancelled) {\n const { height, bitrate } = WEBCODECS_LADDER[quality];\n const input = new Input({ formats: ALL_FORMATS, source: new BlobSource(blob) });\n const output = new Output({ format: new Mp4OutputFormat(), target: new BufferTarget() });\n // Cap fps at 30, but never upsample: probe the source and take the min.\n // A failed probe just omits frameRate, leaving the source rate untouched.\n let frameRate;\n try {\n const track = await input.getPrimaryVideoTrack();\n if (track) {\n const stats = await track.computePacketStats(100);\n if (stats.averagePacketRate > 0) {\n frameRate = Math.min(FPS_CAP, Math.round(stats.averagePacketRate));\n }\n }\n }\n catch (_a) {\n frameRate = undefined;\n }\n throwIfCancelled();\n const conversion = await Conversion.init({\n input,\n output,\n video: Object.assign({ height, quality: new Quality({ quantizer: WEBCODECS_QUANTIZER, bitrate }), hardwareAcceleration: 'prefer-hardware' }, (frameRate ? { frameRate } : {})),\n });\n if (!conversion.isValid) {\n console.warn('[compress] WebCodecs conversion invalid:', conversion.discardedTracks.map((t) => t.reason));\n return null;\n }\n this.activeConversion = conversion;\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n conversion.onProgress = (progress) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n };\n throwIfCancelled();\n try {\n await conversion.execute();\n }\n catch (e) {\n if (this.cancelRequested || e instanceof ConversionCanceledError)\n throw new CancelledError();\n throw e;\n }\n const buffer = output.target.buffer;\n if (!buffer)\n throw new Error('WebCodecs produced no output');\n const outBlob = new Blob([buffer], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n async loadFFmpeg() {\n if (this.isLoaded && this.ffmpeg)\n return;\n this.notifyListeners('onProgress', { status: 'loading_core', percent: 0 });\n // Built on a local, published to the field only once it is ready and still\n // wanted. Assigning `this.ffmpeg` up front and setting `isLoaded` after the\n // await left a window where a cancel could null the instance and the load,\n // finishing a moment later, would set `isLoaded = true` on nothing at all —\n // after which every compressVideo threw 'FFmpeg failed to load' for the\n // rest of the page's life.\n const instance = new FFmpeg();\n instance.on('progress', ({ progress }) => {\n this.notifyListeners('onProgress', { status: 'progress', percent: Math.round(progress * 100) });\n });\n instance.on('log', ({ message }) => {\n console.log('[FFmpeg Log]', message);\n });\n try {\n await instance.load(await loadCoreURLs());\n }\n catch (e) {\n instance.terminate();\n console.error('Failed to load FFmpeg:', e);\n throw e;\n }\n // Cancelled while this was loading. Terminate what we just built rather\n // than publish it — the caller asked for none of it.\n if (this.cancelRequested) {\n instance.terminate();\n throw new CancelledError();\n }\n this.ffmpeg = instance;\n this.isLoaded = true;\n }\n async compressWithFfmpeg(blob, quality, throwIfCancelled) {\n if (!this.isLoaded) {\n await this.loadFFmpeg();\n }\n throwIfCancelled();\n if (!this.ffmpeg) {\n throw new Error('FFmpeg failed to load');\n }\n // Bound once. `this.ffmpeg` is nulled by cancel(), so reading it after any\n // of the awaits below can hand back null on a reference the compiler\n // narrowed here — surfacing a cancel as a TypeError, not a CancelledError.\n const ffmpeg = this.ffmpeg;\n this.notifyListeners('onProgress', { status: 'started', percent: 0 });\n const inputFileName = 'input.mp4';\n const outputFileName = 'output.mp4';\n let crf = '28';\n let scale = '';\n let audioBitrate = '128k';\n switch (quality) {\n case 'VERY_HIGH':\n crf = '23';\n scale = '-vf scale=-2:1080';\n audioBitrate = '128k';\n break;\n case 'HIGH':\n crf = '28';\n scale = '-vf scale=-2:720';\n audioBitrate = '128k';\n break;\n case 'MEDIUM':\n crf = '30';\n scale = '-vf scale=-2:540';\n audioBitrate = '96k';\n break;\n case 'LOW':\n crf = '32';\n scale = '-vf scale=-2:480';\n audioBitrate = '96k';\n break;\n case '360P':\n crf = '28';\n scale = '-vf scale=-2:360';\n audioBitrate = '64k';\n break;\n case 'VERY_LOW':\n crf = '35';\n scale = '-vf scale=-2:240';\n audioBitrate = '48k';\n break;\n }\n const inputData = new Uint8Array(await blob.arrayBuffer());\n try {\n await ffmpeg.writeFile(inputFileName, inputData);\n }\n catch (err) {\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error writing to FS:', err);\n throw new Error('Could not write to FFmpeg FS');\n }\n throwIfCancelled();\n const args = ['-i', inputFileName];\n args.push('-c:v', 'libx264', '-preset', 'superfast', '-crf', crf);\n if (scale) {\n args.push(...scale.split(' '));\n }\n args.push('-c:a', 'aac', '-b:a', audioBitrate);\n args.push(outputFileName);\n try {\n await ffmpeg.exec(args);\n }\n catch (err) {\n // terminate() rejects every in-flight call, so a cancel arrives here\n // looking like a generic failure unless we name it.\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error executing command:', err);\n throw new Error('FFmpeg execution failed');\n }\n throwIfCancelled();\n let data;\n try {\n data = await ffmpeg.readFile(outputFileName);\n }\n catch (err) {\n if (this.cancelRequested)\n throw new CancelledError();\n console.error('[FFmpeg] Error reading output file:', err);\n throw new Error('Could not read FFmpeg output');\n }\n await ffmpeg.deleteFile(inputFileName);\n await ffmpeg.deleteFile(outputFileName);\n const outBlob = new Blob([data], { type: 'video/mp4' });\n return { success: true, destPath: URL.createObjectURL(outBlob) };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","toBlobURL","WebPlugin","canEncodeVideo","Quality","Input","ALL_FORMATS","BlobSource","Output","Mp4OutputFormat","BufferTarget","Conversion","ConversionCanceledError","FFmpeg"],"mappings":"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"}
@@ -15,7 +15,8 @@ public class NativeVideoCompressorPlugin: CAPPlugin, CAPBridgedPlugin {
15
15
  public let pluginMethods:[CAPPluginMethod] = [
16
16
  CAPPluginMethod(name: "compressVideo", returnType: CAPPluginReturnPromise),
17
17
  CAPPluginMethod(name: "cancel", returnType: CAPPluginReturnPromise),
18
- CAPPluginMethod(name: "initialize", returnType: CAPPluginReturnPromise)
18
+ CAPPluginMethod(name: "initialize", returnType: CAPPluginReturnPromise),
19
+ CAPPluginMethod(name: "finishUpload", returnType: CAPPluginReturnPromise)
19
20
  ]
20
21
 
21
22
  /// The job `compressVideo` is running right now, for `cancel(jobId:)`.
@@ -41,6 +42,13 @@ public class NativeVideoCompressorPlugin: CAPPlugin, CAPBridgedPlugin {
41
42
  * down the `else` branch — `markAsFinished()`, `group.leave()` — and the
42
43
  * existing completion handler runs. No new exit path, no polling.
43
44
  */
45
+ /// Chỉ Android mới có foreground service để hạ xuống. Khai ở đây để caller
46
+ /// gọi thẳng mà không phải rẽ nhánh theo platform ở mọi call site - thiếu
47
+ /// nó thì mỗi lần gọi trên iOS là một promise bị reject "not implemented".
48
+ @objc func finishUpload(_ call: CAPPluginCall) {
49
+ call.resolve()
50
+ }
51
+
44
52
  @objc func cancel(_ call: CAPPluginCall) {
45
53
  stateLock.lock()
46
54
  let running = currentJobId
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-native-video-compressor",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Native video compressor using LightCompressor and AVFoundation",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",