compress method
Future<VideoCompressResult>
compress(
- String id,
- String path,
- VideoCompressConfig config,
- String? outputPath,
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? outputPath,
) async {
await _ensureLoaded();
_busy = true;
try {
final m = await _rawInfo(path);
final srcW = (m['width'] as num).toInt();
final srcH = (m['height'] as num).toInt();
final durationMs = (m['durationMs'] as num).toInt();
final srcKbps = (m['bitrateKbps'] as num).toInt();
final srcBytes = (m['sizeBytes'] as num).toInt();
final (tw, th) = _SizeMath.targetDimensions(srcW, srcH, config);
final videoBps =
_SizeMath.videoBitrateBps(config, durationMs, srcKbps, th);
final cfg = <String, Object?>{
'id': id,
'targetWidth': tw,
'targetHeight': th,
'videoBitrateBps': videoBps,
'frameRate': config.frameRate ?? 30,
// Requested codec; the JS engine encodes HEVC when the browser supports
// it, otherwise falls back to H.264 (and reports which was used).
'codec': config.codec.name,
// Hit the target closely when a size is requested; stay efficient (VBR)
// for quality/bitrate modes.
'bitrateMode': config.targetSizeMB != null ? 'constant' : 'variable',
'keepOriginalIfLarger': config.keepOriginalIfLarger,
'originalSizeBytes': srcBytes,
}.jsify()! as JSObject;
final onProgress = (double fraction, double outBytes) {
_progressCtrl.add(CompressionProgress(
id: id,
progress: fraction,
currentOutputBytes: outBytes > 0 ? outBytes.toInt() : null,
));
}.toJS;
final resJs = await _jsCompress(path, cfg, onProgress).toDart;
final r = (resJs.dartify() as Map).cast<dynamic, dynamic>();
return VideoCompressResult(
id: id,
outputPath: r['outputUrl'] as String,
originalSizeBytes: srcBytes,
compressedSizeBytes: (r['sizeBytes'] as num).toInt(),
width: (r['width'] as num).toInt(),
height: (r['height'] as num).toInt(),
durationMs: (r['durationMs'] as num).toInt(),
codec: r['codec'] as String,
skipped: r['skipped'] == true,
);
} catch (e) {
final msg = e.toString();
if (msg.contains('cancelled')) {
throw VideoCompressCancelledException();
}
throw VideoCompressException('compress_failed', msg);
} finally {
_busy = false;
}
}