Skip to content

Filmstrip and Audio Samples

For building timelines that show video thumbnails and audio waveforms, the SDK can extract filmstrip frames and audio samples from each media entry in the Library.

Filmstrip (Video Thumbnails)

Enable filmstrip extraction from the Settings before adding media:

typescript
Engine.getInstance().getSettings().setClipVideoStoreFilmstrip(true);
Engine.getInstance().getSettings().setClipVideoFilmstripInterval(1.0); // one frame per second
Engine.getInstance().getSettings().setClipVideoFilmstripMaxWidth(160);
Engine.getInstance().getSettings().setClipVideoFilmstripMaxHeight(90);
Engine.getInstance().getSettings().setClipVideoFilmstripMaxFrames(120);
Engine.getInstance().getSettings().setClipVideoFilmstripMaxWorkers(2);
Engine.getInstance().getSettings().setClipVideoFilmstripKeyframesOnly(false);

Reading the Filmstrip

The filmstrip is attached to the MediaData. You can also access it directly on the clip:

typescript
import { MediaProcessStatusEnum } from "@rendley/sdk";

const state = videoClip.getFilmstripState();

if (state === MediaProcessStatusEnum.DONE) {
  const frames = videoClip.getFilmstripData();

  for (const frame of frames) {
    const blob = new Blob([frame.data], { type: "image/jpeg" });
    const url = URL.createObjectURL(blob);
    // Render `url` in your UI
  }
}

Each frame exposes its timestamp and a Uint8Array of image data.

Listening for Progress

typescript
Engine.getInstance().events.on(
  "library:media_filmstrip_updated",
  ({ mediaDataId, status }) => {
    if (status === "done") {
      refreshTimelineUi(mediaDataId);
    }
  },
);

Audio Samples (Waveforms)

To draw waveforms for audio or video clips, enable sample storage:

typescript
Engine.getInstance().getSettings().setClipAudioStoreSamples(true);
Engine.getInstance().getSettings().setClipAudioSampleRate(8000);
Engine.getInstance().getSettings().setClipAudioSampleForceMono(true);
Engine.getInstance().getSettings().setClipVideoStoreSamples(true); // for videos with audio

Samples are processed in a background thread and reported through the library:media_samples_updated event.

Reading Samples

getAudioSamples is synchronous. It returns an array of Float32Array, one per channel, or null if samples have not been extracted yet (make sure library:media:samples:updated fired with status: "done" first).

typescript
const samples = audioClip.getAudioSamples(0); // start at 0, full duration

if (samples) {
  for (const channel of samples) {
    // channel is a Float32Array of normalized samples in [-1, 1]
  }
}

// Read only a window (start=5s, length=10s):
const partial = audioClip.getAudioSamples(5, 10);

Video clips expose the same getAudioSamples method. If you want the samples without adding the media to the timeline, query them directly on the MediaData:

typescript
const mediaData = Engine.getInstance().getLibrary().getMediaById(mediaId);
const samples = mediaData?.getAudioSamples(0);

Listening for Progress

typescript
Engine.getInstance().events.on(
  "library:media_samples_updated",
  ({ mediaDataId, status }) => {
    if (status === "done") {
      refreshWaveform(mediaDataId);
    }
  },
);

Example: Waveform Animated by Audio

For a full example that turns audio samples into an animated visualizer, see the Custom Clip guide.