HDR
ExportSpec.hdr says what to do with a high dynamic range source. Probing tells you if a source is HDR at all, through
hdrTransfer on its video track.
val keepIfPossible = ExportSpec()val mustKeep = ExportSpec(hdr = HdrMode.KeepHdr)val sdr = ExportSpec(hdr = HdrMode.ToneMapToSdr)| Mode | What happens |
|---|---|
Auto |
Keeps HDR when it can, otherwise tone maps and says so |
KeepHdr |
Keeps HDR, and refuses the export if the device can’t |
ToneMapToSdr |
Always tone maps down to SDR |
Auto keeps a grade when the sources share one transfer, no effect in the edit needs SDR frames, and either the device can
encode HDR or a stream copy keeps it without an encoder. Anything else tone maps, and the HdrToneMapped adjustment says
which of those it was.
An SDR source resolves to keep whatever you asked for, since there’s no grade to map. The Upload and Share
presets tone map, and Archive keeps.
Keeping a grade
Section titled “Keeping a grade”A kept grade needs a 10-bit profile, so a re-encode is pinned to one whatever codec the spec asks for. Android, Apple and
ffmpeg write HEVC, and the browser writes VP9 Profile 2. Asking for another codec as well reports a CodecFallback.
A stream copy keeps its grade without an encoder, so an untouched clip keeps HDR even on a device that can’t encode it.
Sources that don’t share one transfer, an HDR clip beside an SDR one included, have no single grade to keep. Auto tone
maps them together, and KeepHdr refuses.
Tone mapping
Section titled “Tone mapping”Tone mapping is available on every backend. When Auto tone maps, the plan comes back Degraded, carrying an adjustment
of kind HdrToneMapped that you can show before the user commits.
val toneMapped = when (val verdict = filmstrip.plan(composition, ExportSpec())) { is Verdict.Degraded -> verdict.adjustments.any { it.kind == AdjustmentKind.HdrToneMapped } is Verdict.Capable, is Verdict.Incapable -> false }The browser, ffmpeg and Apple run one shared tone curve. Android runs media3’s curve, which the shared one is copied from.
Previewing a grade
Section titled “Previewing a grade”A preview shows the grade its export will write. Pass the export’s spec as PlayerConfig.exportSpec, the whole spec, since
Auto depends on the rest of it. A spec that names a bitrate can turn a stream copy into a transcode, and on a device with
no HDR encoder that tone maps.
val spec = ExportSpec(hdr = HdrMode.ToneMapToSdr)val player = filmstrip.preview(composition, PlayerConfig(exportSpec = spec))
// Later, on the same player.player.setExportSpec(ExportSpec(hdr = HdrMode.KeepHdr))- Only the grade is mirrored. Height, frame rate, codec and bitrate don’t reach the preview’s frame.
- A spec that moves the grade rebuilds the pipeline and keeps the transport and the playhead. One that leaves it alone
rebuilds nothing.
rememberFilmstripPlayercalls the setters for you when its config changes. - A refused export is a refused preview.
KeepHdrwith no way to keep, an effect that needs SDR underKeepHdr, or a setting the export refuses, like a height of zero or a bitrate named beside a quality, reaches your listeners asPlaybackError.UnsupportedFormatin the planner’s words, and the frame on screen stays. strictisn’t mirrored. A strict spec previews theAutograde, andplanis what reports the refusal.- Frames and thumbnails take the same
exportSpec, onFrameRenderer.frame,FrameRenderer.frames,ThumbnailRequest,rememberFilmstripFrame,rememberFilmstripFrames,FilmstripImageandFilmstripTimeline. A new spec fetches the strip again.