amigazen AWeb 3 AmigaPython ToolKit unsui FastForward Engi Zen
FastForward

Welcome to the future
FastForward
What it is, how it is built, and what formats it supports

FastForward documentation
Overview  |  User’s Guide  |  Developer’s Guide  |  Plugin Developer’s Guide

GitHub
https://github.com/amigazen/FastForward


The Amiga personal computer is the greatest multimedia computer ever made and as such deserves a full-fledged pluggable multimedia framework at the operating system level — shared infrastructure for playback, editing, streaming, and format handling that any application can build on.

Apple had QuickTime, BeOS its Media Kit, even Windows had DirectShow.

Now it's time for Amiga to catch up with FastForward

FastForward from amigazen project expands upon the foundations provided by realtime.library and datatypes.library to provide a native, performance optimised multimedia subsystem — a LoadSeg-pluggable pipeline from byte stream to pixels and samples, with QuickTime/MP4-style multimedia container parsing and a BeOS-style filter graph for editors, sequencers and transcoders.

FastForward comprises:

fastforward.library — the shared engine: plugin registry, pipeline and filter graph, movie and graph APIs, sniffing, buffer pools, clocks, events, probe, stats, metadata and thumbnail support
Play — Universal media player tool (Source/play/)
Examine — Shell command media inspector; reports containers, streams, and which plugins would bind to the file being examined
player.gadget and playback.gadget — BOOPSI gadget classes for embedding a media player and its playback controls in Intuition applications
Built-in plugins

mem.source — in-memory byte streams
callback.sink — delivers frames to application callbacks
FastForward plugins

Sourcesfile.source for local files, http-live.source for HTTP-LS streams, rtsp.source for RTSP streams

Demuxerspcm.demux, mov.demux, avi.demux, cdxl.demux, au.demux, fpadpcm.demux, rm.demux, mpegaudio.demux, mpeg.demux, ts.demux, ogg.demux, flac.demux, mkv.demux

Codecspcm.codec, ima4.codec, fpadpcm.codec, msadpcm.codec, dviadpcm.codec, mace.codec, mpegaudio.codec, mpegvideo.codec, vorbis.codec, cvid.codec, svq1.codec, msvc.codec, rpza.codec, smc.codec, qtrle.codec, cdxl.codec, ra144.codec, ra288.codec, a52.codec, aac.codec

Filtersvolume.filter, fade.filter

Sinksaudio.sink, ahi.sink, video.sink, ham.sink, null.sink

amigazen project

A web, suddenly

Forty years meditation

Minds awaken, free

amigazen project is using modern software development tools and methods to update and rerelease classic Amiga open source software. Projects include a new AWeb, a new Amiga Python 2, and the ToolKit project — a universal SDK for Amiga development. All amigazen project releases are guaranteed to build against the ToolKit standard so that anyone can download and begin contributing straightaway without having to tailor the toolchain for their own setup.

FastForward is an original work of the amigazen project, released under the BSD 2-Clause License.

The amigazen project philosophy is based on openness:

Open to anyone and everyone — Open source and free for all — Open your mind and create!

PRs for all projects are gratefully received at GitHub. While the focus now is on classic 68k software, it is intended that all amigazen project releases can be ported to other Amiga-like systems including AROS and MorphOS where feasible.

About FastForward

fastforward.library is a standalone multimedia engine for classic Amiga. It performs format sniffing, container demuxing, codec decode, and device output through a linear or arbitrary filter graph. It does not replace datatypes.library for still images — PNG, ILBM, JPEG, and GIF stay on datatypes. FastForward owns timed media, and in fact implements the backend needed for the movie.datatype rootclass.

dos.library, utility.library, and realtime.library (for Conductor-backed clocks) open on-demand inside the engine. Codec backends are plugin-owned — the core library opens none of them at init time. Plugins can be self-contained or defer to optional Exec shared libraries opened lazily through FFHost.

Inspirations

FastForward stands on decades of Amiga and cross-platform multimedia work. The design deliberately combines ideas that already proved themselves elsewhere, expressed in Amiga-native primitives:

Inspiration What we took from it
BeOS Media Kit (1998) Node-per-thread topology, BBuffer flowing between nodes on kernel ports, a master time source anchoring the graph. FastForward maps this onto Exec Tasks, Message/PutMsg/ReplyMsg, and realtime.library Conductors — the architecture BeOS got right, on primitives Amiga has had since 1985.
MacOS QuickTime The Movie / Track model for player apps: one high-level FFMovie handle, per-track mute/volume/sink control, and metadata introspection without exposing the underlying graph.
AmigaOS realtime.library Conductor + Player as the master clock for sequencers and NLE timelines; per-element Players slaved to one graph Conductor for sample-accurate multi-track sync.

Two metaphors read the architecture out loud. Orchestral language fits the timing layer (Conductor, Player, tempo, ticks). Tape-deck language fits the application boundary (Play, Pause, Stop, scrub, and FastForward).

Contact

• At GitHub https://github.com/amigazen/FastForward/
• On the web at http://www.amigazen.com/fastforward/ (Amiga browser compatible)
• Or email fastforward@amigazen.com
Acknowledgements

Amiga is a trademark of Amiga Inc.


Architecture

Overview

FastForward is a pluggable, pipelined Amiga-native multimedia engine for AmigaOS 3 (68k). Applications such as Play link against fastforward.library and never load codec engines directly. Demuxers, codecs, filters, sources, and sinks are LoadSeg plugin modules whose directory is resolved at init time (see the User’s Guide).


Tiers

Tier Component Role
1 fastforward.library Registry, linear pipeline, sniffing, buffer pool, host services
2 LoadSeg plugin Source, demux, codec, filter, sink entry points
3 Exec libraries Optional heavy backends (e.g. mpega.library) opened via host fh_OpenLibrary
4 Devices ahi.device, future CGX/P96 video


Pipeline (MVP)

Linear chain built by BuildFFPipelineFromFile():

file source → PCM demux → PCM codec → AHI sink

Data flows as FFBuffer records. Ring buffers default to 64 KiB per edge (FF_DEFAULT_RING). Fast RAM is used for engine/plugin instance state and streaming buffers; chip RAM is reserved for AHI sample buffers in ahi.sink.


Plugin ABI

Headers: Source/include/libraries/ffplugin.h (plugins) and Source/include/libraries/fastforward.h (applications).

Each plugin binary begins with FFPluginHead (ph_Security = 0x70FF4E75, ph_ID = 'FFPI'). One or more FFPlugin structures follow. The loader (Source/library/ff_loader.c) scans LoadSeg segments and registers plugins by kind and identifier.

Per-instance state lives in FFInstance + plugin-private data allocated through FFHost::fh_Alloc. Plugins must not keep mutable static globals.


Host services

FFHost provides allocation, logging, and optional OpenLibrary/CloseLibrary. All plugins receive the same vtable at Open().


Built-in plugins

For development, FFRegisterBuiltinPlugins() registers symbols linked into fastforward.library. Production installs use external plugin files only.



Supported formats and plugins

FastForward discovers and loads plugins from LIBS:FastForward/Plugins/ (or the assign / ENV paths described in the User’s Guide). Each plugin registers an identifier and kind; the engine scores candidates during sniff and probe to build a pipeline for the media at hand.

Plugin kinds

Sources (FFK_SOURCE) — byte streams from files, memory, HTTP-LS, or RTSP
Demuxers (FFK_DEMUX) — container parsers that split streams
Codecs (FFK_CODEC) — audio and video decoders (and future encoders)
Filters (FFK_FILTER) — in-graph transforms such as gain and fade
Sinks (FFK_SINK) — AHI audio, Intuition video, callbacks, or null output
Muxers (FFK_MUX) — transcode and export (planned)

3. Implemented (MVP)

These four plugins plus the callback sink (built into the engine) form the current vertical slice: WAV / AIFF / 8SVX / 16SV → AHI.

Plugin Kind Source Notes
file.source FFK_SOURCE FastForward Source/plugins/file_source.c BPTR / path byte reader; all file-based chains start here
(built-in) mem.source FFK_SOURCE Source/plugins/mem_source.c Memory buffer reader for previews and embedded media
pcm.demux FFK_DEMUX same + sniff logic in Source/library/ff_sniff.c WAV, AIFF, 8SVX, 16SV IFF containers
pcm.codec FFK_CODEC same Pass-through PCM (identity codec); format negotiation
ahi.sink FFK_SINK same AHI output via ahi.device; chip RAM sample buffers
(built-in) callback.sink FFK_SINK Source/library/ff_callback_sink.c Delivers frames to app FFCallbacks; not a LoadSeg file



18. Implemented plugins (status)

These plugins live in Source/plugins/ and build via its smakefile. The list grows as plugins land in tree.

Plugin Kind Status Capabilities
file.source FFK_SOURCE done Local file byte reader
pcm.demux FFK_DEMUX done IFF / WAV / AU container detection
pcm.codec FFK_CODEC done Endian-swap + bit-depth pass-through
ahi.sink FFK_SINK done AHI double-buffered playback
au.demux FFK_DEMUX done Sun / NeXT .au (S8 / S16BE)
null.sink FFK_SINK done Bit-bucket sink for benchmarking
volume.filter FFK_FILTER done PCM gain (S8 / S16 / U8)
mpegaudio.demux FFK_DEMUX done MP1 / MP2 / MP3 elementary stream framing, ID3v2 skip
mpeg.demux FFK_DEMUX done MPEG-1 / MPEG-2 Program Stream (audio + video PES split)
mpega.codec FFK_CODEC planned MPEG audio Layers I–III decode
helixmp3.codec FFK_CODEC planned MP3 Layer III decode (68k-optimised path)
mpeg2.codec FFK_CODEC planned MPEG-1 / MPEG-2 video decode


Two metaphors that read the architecture out loud

FastForward leans on two metaphors that are already baked into the primitives we use, and they map cleanly onto two different reader populations.

Orchestral — for the timing layer

realtime.library itself is named for an orchestra, and our timing code follows suit. Authors of CAMD / OctaMED / Bars&Pipes plugins already think in these terms.

Orchestra realtime.library FastForward
Conductor struct Conductor FFClock.fc_Conductor (the master timing source)
Player on the podium struct Player, CreatePlayerA FFClock.fc_Player plus per-element FFElement.fe_Player (each producer has its own Player slaved to the graph's Conductor)
Tempo marking on the score PLAYER_Tempo FFClock.fc_Tempo (BPM × 1000)
Beat / tick subdivision PLAYER_Ticks FFClock.fc_TickRate
External sync source (a click track, SMPTE feed, MIDI clock) PLAYER_ExtSync, ExternalSync() FFCT_ExternalSync + FFCT_PlayerHandle; see API.md §19
The score itself (no equivalent) FFGraph — the rehearsed plan
One performer (no equivalent) FFElement — one player of one part
Their instrument's range (no equivalent) FFPad.fp_Caps, fp_Audio, fp_Video

We deliberately do not rename FFGraph / FFElement / FFPad to orchestral terms. The framework is multi-medium — a video frame is not really a "phrase" — and Player / Conductor are already realtime.library types we would shadow. The metaphor names why we do what we do, not what we call our types.

Tape-deck — for the transport layer

The library is named after the FastForward button. The application- facing transport is, by design, exactly the buttons on a real tape deck. Docs/API.md §3 walks through these in code, but the mental model is:

Tape deck button FastForward call
Play PlayFFMovie()
Pause PauseFFMovie()
Stop StopFFMovie()
Cue / scrub SeekFFMovie(time, flags)
Rewind to head RewindFFMovie() (macro: Stop + Seek 0)
Eject the tape EjectFFMovie() (alias of CloseFFMovie())
Resume from pause ResumeFFMovie() (alias of PlayFFMovie())
Fast-forward 2x FastForwardFFMovie() (sets FFMT_PlayRate = 2.0)
Reverse 1x ReverseFFMovie() (sets FFMT_PlayRate = -1.0)
Variable scan ScanFFMovie(rate) (signed Q16.16 — FF_RATE_FF_4X etc.)
Loop / autoreverse FFMT_LoopMode = FFLM_LOOP / FFLM_PINGPONG / FFLM_REGION

These are deliberately macros, not new LVOs. They compose existing LVOs (PlayFFMovie, SeekFFMovie, SetFFMovieAttrsA) so the ABI surface stays small, and any plugin that honours FFMT_PlayRate participates automatically. Plugins that only support 1× playback silently stay at 1× and the engine posts FFEV_QOS so the UI can grey out the affordances that are not supported by the current codec.

The two metaphors complement each other: orchestral language is right at the timing boundary where FastForward already speaks realtime.library; tape-deck language is right at the application boundary where humans drive the deck. Inside the library we use neither — FFGraph, FFElement, FFPad, FFBuffer are technical names for technical concepts.

Scheduling decisions. Amiga unified memory means the framework can pass references everywhere except the final sink hand-off. The memory class hint (FFBM_FAST / FFBM_CHIP / FFBM_LOCAL / FFBM_ANY) on each FFBuffer keeps the decoder/filter chain in Fast RAM where the 68k is fastest, and only the AHI sink's DMA buffer lives in Chip RAM where Paula can read it without the CPU. Video sinks follow the same rule: chunky-to-planar conversion happens once into a Chip-RAM bitmap that the blitter and copper then consume directly.

Run modes. Every FFElement defaults to FFER_INLINE, so single-thread linear graphs (the MVP audio path) keep their existing behaviour with zero overhead. Heavy elements opt into their own Task by passing FFE_RunMode = FFER_TASK; sources and sinks that need dos.library calls use FFER_PROCESS (a CreateNewProc so Lock, Read, OpenDevice all work). Mixed graphs are normal: Play stays single-thread for cheap WAV decode; an NLE timeline runs each track as its own Task; a music sequencer attaches every producer to the master Conductor so audio, MIDI and video track heads stay sample-accurate.

Topology granularity on classic 68k. Exec context switching is cheap by 2026 standards — sub-millisecond on a stock 68030 — but it is not free, and a graph that puts every filter on its own Task spends measurable cycles on Signal / PutMsg / WaitPort per buffer. The recommended pattern on classic hardware is coarse- grained: keep FFER_INLINE as the aggressive default so a single caller-task slice runs Pull → Decode → Filter sequentially, and cross to FFER_TASK / FFER_PROCESS only at boundaries where you genuinely want the asynchronicity — disk I/O, the AHI / video sink, a CPU-heavy codec that wants its own pacing. Long pipelines of fine-grained nodes are an RTG / 68060+ luxury; on a stock 68030 they trade frame-rate for thread-count and lose. The graph builder honours whatever the application requests; it does not silently fold elements together.

Why not real process isolation. AmigaOS 3 has no MMU separation between Tasks; a buggy codec can scribble on the engine no matter how many message ports we put between them. Pretending otherwise would just slow us down. Defensive parsing (counted FFString / FFData everywhere a media file's bytes cross into the engine) is the realistic safety net. WarpOS PPC plugins do get effective crash isolation as a side effect of the PPC kernel boundary — see TODO.md.

See the plugin lists at the top of this page for the full set of registered identifiers. The Developer’s Guide documents the Movie API, Graph API, and BOOPSI gadgets. The Plugin Developer’s Guide covers LoadSeg plugin authoring.


See the User’s Guide for installation and Play. See the Developer’s Guide for the full API reference.  |  Back to top