Skip to content

Filters

Filters are looks that stay out of the filmstrip bundle. They live in filmstrip-effects-filters, so an app that doesn’t use one doesn’t carry one. See Installation for the artifact.

Call filters() on the builder. A filter with no renderer registered is refused by name at plan time.

val filmstrip =
Filmstrip {
allBackends()
filters()
}

vhs makes a frame look like it was played back from a tape. It softens luma, smears chroma along each line, wobbles the lines, bends the bottom of the frame like a head switch, and adds streaky noise, dropouts and the odd tracking band. Every backend draws the same tape, and the pattern follows the frame’s composition time, so a seek or a smaller preview shows the same picture.

val composition =
compositionOf {
clip(MediaSource.of("/path/to/home-movie.mp4"))
effects {
vhs(intensity = 0.6f, tape = TapeSpeed.LP)
}
}
Argument What it does
intensity How strong the look is. 0f leaves the frame alone and is listed as an inert notice
tape TapeSpeed.SP, LP or EP, from sharpest to softest. Defaults to EP
seed Picks the pattern of noise and events. Equal seeds draw the same tape

A vhs on the composition covers the whole frame, bars included. One on a clip or a track doesn’t grade the bars, and picture it moves into a bar lands over the fill. It runs under any overlay at its own scope, so a caption next to it stays clean. A clip overlay under a composition vhs is part of the clip’s frame by then, and is burned in with it.

An HDR source tone maps to SDR first. HdrMode.Auto reports that as an HdrToneMapped adjustment naming the effect, and HdrMode.KeepHdr is refused. See HDR.

crt makes a frame look like it is showing on a curved tube. The picture bows out with black past its edge, scanlines and a phosphor mask run over it, and the corners fall off. The scanlines and the mask are the average over each pixel, so a smaller preview draws the larger frame’s picture at its own size. Nothing reads the clock, so a seek changes nothing.

val composition =
compositionOf {
clip(MediaSource.of("/path/to/arcade.mp4"))
effects {
crt(intensity = 0.75f)
}
}
Argument What it does
intensity How strong the look is. 0f leaves the frame alone and is listed as an inert notice

A crt on the composition covers the whole frame, bars included. One on a clip or a track doesn’t grade the bars, and the picture’s curve ends in black while a clear bar stays clear. It runs under any overlay at its own scope, so a caption next to it stays clean. A clip overlay under a composition crt is part of the clip’s frame by then, and is burned in with it.

An HDR source tone maps to SDR first. HdrMode.Auto reports that as an HdrToneMapped adjustment naming the effect, and HdrMode.KeepHdr is refused. See HDR.

lut maps a frame’s colours through a colour table from a .cube file. Every backend reads the table trilinearly, and intensity mixes the table with one that changes nothing. A table is a function of each pixel’s colour alone, so a seek or a smaller preview draws the same colours.

val table = CubeLut.parse(cubeFileText)
val composition =
compositionOf {
clip(MediaSource.of("/path/to/holiday.mp4"))
effects {
lut(table, intensity = 0.75f)
}
}
Argument What it does
table A CubeLut from CubeLut.parse, which takes the text of the file. Reading the file is yours
intensity How strong the table is. 0f leaves the frame alone, and so does an identity table. Both are inert notices

CubeLut.parse holds a grid of 2 to 129 points, applies DOMAIN_MIN and DOMAIN_MAX, and holds an entry past 0 or 1 at the end it passed, since an SDR code stops there. It throws an IllegalArgumentException naming the line for a 1D table, a size outside that range, a line it can’t read, the wrong number of rows, or a file over 137 million characters.

A lut on the composition covers the whole frame, bars included. One on a clip or a track doesn’t grade the bars, and a clear bar stays clear. Colour effects at the same scope run before it, and filters at the same scope run in the order you added them. It runs under any overlay at its own scope, so a caption next to it stays clean.

The table maps SDR codes, so an HDR source tone maps to SDR first. HdrMode.Auto reports that as an HdrToneMapped adjustment naming the effect, and HdrMode.KeepHdr is refused. See HDR. A table authored for HDR isn’t supported.