render method
Future<File>
render({
- required Widget composition,
- required Aspect aspect,
- required Duration duration,
- int fps = VideoDefaults.fps,
- int longEdge = VideoDefaults.longEdge,
- bool audio = true,
- bool warnOnDroppedAudio = true,
- String compositionKey = 'render',
- RenderProgressCallback? onProgress,
override
Renders composition for aspect over duration to an MP4 file in a
fresh sandbox directory, returning that file.
With audio left true, a Video's declared Audio tracks are staged
into the FFmpeg mix; pass false for a silent render (warned once
through the injected warning sink unless warnOnDroppedAudio is false).
Implementation
@override
Future<File> render({
required Widget composition,
required Aspect aspect,
required Duration duration,
int fps = VideoDefaults.fps,
int longEdge = VideoDefaults.longEdge,
bool audio = true,
bool warnOnDroppedAudio = true,
String compositionKey = 'render',
RenderProgressCallback? onProgress,
}) async {
final frameCount = frameCountFor(duration, fps);
final sandbox = await _sandboxFactory();
final scope = resolverScope(mediaResolver, networkAllowlist: networkAllowlist);
try {
if (!audio) _warnIfDroppingAudio(composition, warnOnDroppedAudio, fps, frameCount);
onProgress?.call(RenderProgress(RenderPhase.capturing, compositionKey: compositionKey));
final result = await runStage(
RenderPhase.capturing,
() => capture.render(
// The host mounts this with no app ancestors, so the tree needs an
// ambient Directionality for Text/RichText to lay out. Audio is
// collected from the raw Video by the capture entry itself, so the
// wrap is mount-only.
composition: Directionality(textDirection: TextDirection.ltr, child: composition),
aspect: aspect,
frameCount: frameCount,
outDir: sandbox,
service: _service,
pumpWidget: pumpWidget,
pumpFrame: pumpFrame,
longEdge: longEdge,
fps: fps,
compositionKey: compositionKey,
stageAudio: audio ? null : _silentAudio,
resolver: scope.resolver,
),
);
final manifest = result.manifest;
onProgress?.call(RenderProgress(RenderPhase.encoding, compositionKey: compositionKey));
await runStage(RenderPhase.encoding, () async {
await _runner.encode(args: manifest.ffmpegArgs, sandbox: sandbox);
final posterArgs = manifest.posterArgs;
if (posterArgs != null) {
await _runner.encode(args: posterArgs, sandbox: sandbox);
}
});
onProgress?.call(RenderProgress(RenderPhase.complete, compositionKey: compositionKey));
return File('${sandbox.path}/${manifest.outputFileName}');
} finally {
await runGuarded([
scope.dispose,
], (error, _) => _onWarning('Cleanup after render failed: $error'));
}
}