compress method
Future<VideoCompressResult>
compress(
- String id,
- String path,
- VideoCompressConfig config,
- String? outputDir,
- String? outputName,
override
Compress path using config. id identifies the job (for progress
correlation and cancellation). When outputPath is non-null the encoded
file is written there; otherwise it lands in the plugin cache.
Implementation
@override
Future<VideoCompressResult> compress(
String id,
String path,
VideoCompressConfig config,
String? outputDir,
String? outputName,
) async {
if (_preCancelledId == id) {
_preCancelledId = null;
throw VideoCompressCancelledException();
}
try {
await FfmpegBinaries.ensureAvailable();
final info = await FfmpegVideo.probe(path);
final originalSize = await File(path).length();
final durationMs = _clampDuration(info.durationMs, config);
final dims = SizeMath.targetDimensions(info.width, info.height, config);
final videoBps = SizeMath.videoBitrateBps(
config: config,
durationMs: durationMs,
sourceBitrateKbps: info.bitrateKbps,
targetHeight: dims.$2,
);
final outFile = PluginCache.resolveOutput(
outputDir: outputDir,
outputName: outputName,
sourcePath: path,
ext: 'mp4',
);
final result = await FfmpegVideo.compress(
id: id,
inputPath: path,
outputPath: outFile.path,
config: config,
info: info,
targetWidth: dims.$1,
targetHeight: dims.$2,
videoBitrateBps: videoBps,
durationMs: durationMs,
onProgress: (progress) {
if (!_progressController.isClosed) {
_progressController.add(
CompressionProgress(id: id, progress: progress),
);
}
},
onProcess: (proc) {
_activeProcess = proc;
_activeId = id;
},
isCancelled: () => _preCancelledId == id,
);
_activeProcess = null;
_activeId = null;
if (result.cancelled) {
throw VideoCompressCancelledException();
}
final usedCodec = result.usedCodec;
final compressedSize = await File(outFile.path).length();
final minSave = config.minSavingsPercent;
final savedPct = originalSize == 0
? 0.0
: (1 - compressedSize / originalSize) * 100;
final shouldSkip =
config.keepOriginalIfLarger &&
(compressedSize >= originalSize || savedPct < minSave);
if (shouldSkip) {
try {
await File(outFile.path).delete();
} catch (_) {}
return VideoCompressResult(
id: id,
outputPath: path,
originalSizeBytes: originalSize,
compressedSizeBytes: originalSize,
width: info.width,
height: info.height,
durationMs: info.durationMs,
codec: info.codec ?? usedCodec,
skipped: true,
frameRate: info.frameRate,
hasAudio: !config.removeAudio,
);
}
return VideoCompressResult(
id: id,
outputPath: outFile.path,
originalSizeBytes: originalSize,
compressedSizeBytes: compressedSize,
width: dims.$1,
height: dims.$2,
durationMs: durationMs,
codec: usedCodec,
skipped: false,
frameRate: config.frameRate ?? info.frameRate,
hasAudio: !config.removeAudio,
);
} on CompressException {
rethrow;
} catch (e) {
throw VideoCompressException(CompressErrorCode.compressFailed, '$e');
} finally {
_activeProcess = null;
if (_activeId == id) _activeId = null;
}
}