Skip to main content

Media Events

To react to the player — a file loading, a seek completing, the title changing — override HandleMediaEvent on ModuleBase. The host decodes the underlying FFmpeg event stream into a curated, ABI-stable MediaEvent so plugins never touch FFmpeg or its types.

void HandleMediaEvent(const MediaEvent& e) override
{
if (e.type == MediaEventType::FileLoaded)
{
// tracks and metadata are now available
}
}

The relevant types live in <framelift/platform/IMediaPlayer.h>, included via the <framelift/platform.h> umbrella (and transitively by <framelift/core.h>).

Event types

MediaEvent::type is a MediaEventType:

TypeMeaning
StartFileA new file is starting to load.
FileLoadedThe file is loaded; tracks and metadata are ready.
PlaybackRestartPlayback resumed — fires after a seek completes.
SeekA seek was initiated.
EndFileThe current file ended. e.endReason is an EndFileReason (Eof / Error / Other).
VideoReconfigThe video resolution/format changed.
AudioReconfigThe audio output was reconfigured.
PropertyChangeAn observed player property changed (see below).
OtherAn event the host does not surface distinctly — safe to ignore.
NoneNo event pending — stop polling.

Property changes

When type == PropertyChange, the changed property is described by e.property. The active value is a tagged union: e.property.type says which member of e.property.value is live.

PropertyTypeRead from
Flage.property.value.flag (int used as bool)
Doublee.property.value.dbl
Int64e.property.value.i64
Stringe.property.value.str (NUL-terminated, copied, up to 256 bytes)

e.property.prop is a PlayerProperty identifying which property changed (e.g. Path, MediaTitle, HwDecCurrent, TimePos, Pause).

void HandleMediaEvent(const MediaEvent& e) override
{
if (e.type == MediaEventType::PropertyChange &&
e.property.prop == PlayerProperty::MediaTitle &&
e.property.type == PropertyType::String)
{
Log::Info("[MyPlugin] now playing: {}", e.property.value.str);
}
}
Lifetime

String payloads (and any const char* in an event) are valid only for the duration of the HandleMediaEvent call. If you need to keep the value, copy it into your own storage — do not stash the pointer. (The str union member is a fixed-size buffer copied into the event, so reading it during the call is always safe.)

Driving the player

HandleMediaEvent is for reacting. To command the player — load a file, pause, seek, switch tracks — discover the media interface family with ctx.GetService<T>():

  • IMediaPlaybackLoadFile, SetPause/TogglePause, Seek/SeekAbsolute, playback options.
  • IAudioControl — mute/volume, audio track selection, output devices.
  • ISubtitleControl — subtitle tracks, visibility, delay, styling.
  • IMediaProperties — async property queries (GetDoubleAsync, …).

See Services.

Media events vs app events

There are two distinct event channels, and they are easy to mix up:

  • HandleMediaEvent(const MediaEvent&) — the player's state (this page).
  • HandleKeyDownEvent(const AppEvent&)platform/window input: key presses, mouse, window exposure, file drops. See Keybinds and AppEvent.

For player actions (open a file, react to a file opening across plugins) you usually want the pub/sub events like FileOpenedEvent, which are higher-level than the raw media stream.