ChannelForge turns a library of video files into 24/7 linear streaming channels. You connect your own storage, organize videos into collections and programming blocks, generate a schedule, and stream it to YouTube or any RTMP destination. This guide explains every section of the app and what each setting does.
The shortest path to a live channel: Storage → import media → Quick Start.
Core concepts
| Term | Meaning |
|---|---|
| Asset | One video in your Media Library. ChannelForge references the file in your storage — it never copies your library. |
| Collection | A reusable group of assets: either a manual ordered list, or a dynamic saved filter (by tags, series, duration, …). |
| Programming block | A rule-based sequence built from one collection: ordering, target length, bumpers, interstitials, repeat-avoidance. Blocks are the units schedules are built from. |
| Schedule version | A generated timeline of events for a channel. Publishing creates an immutable live version; the channel plays it. |
| Destination | Where the stream goes: a YouTube live broadcast or a raw RTMP(S) URL + stream key. |
| Output profile | The encode format of the channel's stream (e.g. 1080p30). Media is normalized (transcoded) to match it. |
| Normalize | Transcode an asset so it can stream in the channel's output profile. |
| As-run log | The immutable record of what actually aired, versus what was scheduled. |
From upload to on-air — the walkthrough
The full journey, whichever way your media arrives. Steps 1–2 get videos into the library; after that every path is the same product.
Step 1 — get your videos in
Pick whichever matches where your videos live (Storage / Media Library pages):
| Your videos are… | Do this |
|---|---|
| On this computer | Media Library → Upload videos (or drag files anywhere onto the page) — up to 20 per batch. Large files upload in resumable chunks — a dropped connection picks up where it left off. For a whole library, connect its storage instead. |
| In an S3-compatible bucket (AWS, R2, B2, Wasabi, MinIO…) | Storage → Add a storage connection (pick your provider from the dropdown) → Import. Files are referenced in place, never copied. |
| In Google Drive | Storage → Connect Google Drive → authorize → paste the folder link → Import. |
| In Dropbox | Storage → Connect Dropbox → authorize → enter the folder path → Import. |
| On an SFTP server | Storage → Add SFTP server → host/user/password (or key) + path → Import. Re-run Import any time to pick up newly delivered files. |
Step 2 — let analysis and normalization run
Every imported asset is probed automatically. Assets whose format doesn't match your output profile need a one-time normalize (transcode). You can queue everything with Normalize pending on the Media Library — or skip this: Quick Start (below) queues exactly what its channel needs.
Step 3 — pick your path
Path A — "play my 10 videos in my order for X hours" (most creators start here):
- Collections → New collection (manual) → add your videos → drag them into the order you want them to air.
- Quick Start → pick that collection → Play order: Collection order → set Run length (hours) for a bounded run (leave empty to loop 24/7) → connect or pick a destination → Launch. Done — normalization, scheduling, publishing and (optionally) starting all happen automatically. A bounded run airs a slate when it ends; stop the channel when you're done.
Path B — the 24/7 shuffle loop:
Same as Path A but leave Play order on Shuffle and Run length empty. The channel programs itself a rolling week ahead, shuffled with a stable seed so regenerating doesn't reshuffle history.
Path C — a real programming grid (dayparts, series, bumpers):
- Make a collection per content group ("Morning flows", "Evening deep stretch").
- Make a programming block per daypart: ordering, a target duration (e.g. 3 h), intro/outro bumpers, interstitials, and a recurrence anchor (e.g. daily 06:00).
- Schedule → select the blocks → Generate for your horizon → adjust events by hand if needed → Validate → Publish.
- Channel page → attach destinations → Start.
Path D — hands-off auto-programming:
Use dynamic collections (saved filters by tag/series/duration) instead of manual ones in any path above. New uploads that match the filter flow into future schedules automatically; assets whose rights expire drop out on their own. Tag your library once and the channel programs itself.
Step 4 — go live and watch
- Destinations: Connect YouTube once per organization, then Provision destination on the channel (creates the broadcast + stream binding, enables stream health and viewer analytics) — or paste any RTMP(S) URL + stream key for Twitch, Kick, Facebook, or a custom ingest. Multiple destinations stream simultaneously.
- Start the channel; watch the live preview player, Now airing, and stream health on the channel page. The as-run log records what actually aired.
How it all fits together
The walkthrough above covers the steps; this is what happens underneath. The design in one line: encode each video once into a rigid uniform format, then run channels forever as cheap packet-copying.
Ingest. However a file arrives — direct upload (chunked, resumable, into platform-managed storage), S3, Google Drive, Dropbox, or SFTP — ChannelForge stores a reference (connection + object key + content fingerprint), never a copy. Each file becomes an asset; re-imports diff by fingerprint, so new files appear, changed files are re-analyzed, and deleted files are marked unavailable.
Analysis. Every new or changed asset is probed read-only: container, duration, video codec / resolution / frame rate / bit depth / HDR, audio codec / sample rate. The result is the compatibility verdict — stream as-is, rewrap the container, or transcode — with the exact mismatches saved as the asset's Problems list.
Normalization. Non-conformant files are transcoded once into a "mezzanine": MP4 (fast-start) · H.264 High 8-bit at the profile's exact resolution and constant frame rate, keyframe every 2 seconds · AAC stereo 48 kHz, loudness normalized to −16 LUFS · Rec.709 SDR (HDR tone-mapped, aspect preserved with letterboxing). Mezzanines live in platform rendition storage — your source bucket is never written to. This uniformity is the trick: because every file on a channel is byte-format-identical, playout can join them without decoding.
Organize & schedule. Collections group assets; blocks turn one collection into a rule-based sequence; Generate cycles blocks across the horizon into concrete events; Publish freezes an immutable schedule version. A background sweep keeps extending it while the channel runs.
Playout. A dedicated worker per channel takes an exclusive lease, downloads the upcoming mezzanines to a local cache (substituting via the fallback chain so there is never a hole), bakes the channel branding into each unique file once, writes a concat playlist, and runs a single FFmpeg in copy mode — repackaging existing packets at ~1–2% of a CPU core instead of encoding.
With one destination, the same packets are split two ways simultaneously:
concat playlist ──ffmpeg (copy)──┬─→ FLV over RTMP ──→ YouTube / your ingest
└─→ HLS segments ──→ the dashboard preview
RTMP is the primary output; the HLS preview is a side-tap of the identical frames. With multiple destinations it inverts: FFmpeg writes local HLS once and a lightweight relay per destination remuxes it to RTMP — five destinations still cost one pipeline. RTMP/FLV is just the container ingest servers speak; the H.264/AAC inside is passed through untouched.
Accountability. The worker heartbeats every 10 seconds (state, now/next, bitrate/fps); a control-plane sweep flags a silent worker as degraded and raises an alert. Every slot that airs — including fallback substitutions — is recorded in the immutable as-run log with planned vs actual times and an outcome.
Quick Start
A three-step wizard that spins up a 24/7 looping channel: pick a collection to loop, pick a destination, name the channel. ChannelForge generates a looping schedule, normalizes the media, publishes, and (optionally) starts streaming automatically.
- Output profile — the stream's resolution and frame rate. Everything in the collection is transcoded to match, which takes CPU time before the channel can go live.
- Start streaming automatically — the channel starts on its own once enough of the media is ready. You can close the tab; the launch continues in the background.
- Play order — Shuffle (varied, seeded loop) or Collection order (airs the collection exactly as you arranged it).
- Run length (hours) — empty loops 24/7; a number makes a bounded run (a marathon) that fills exactly that many hours and airs a slate when it ends.
Storage
Connect the storage where your videos live: S3-compatible buckets (AWS S3, R2, B2, Wasabi, MinIO, …), Google Drive, Dropbox, or an SFTP server. Connections only reference media — they never copy it. Files stay where they are; ChannelForge reads them when analyzing, normalizing, and streaming.
Adding a connection
| Field | What it does |
|---|---|
| Name | A label for you, e.g. "Production MinIO". |
| Bucket | The bucket name only — no s3://, no URL. |
| Access key ID / Secret access key | Credentials with read + list access (write access only needed for the Upload button). The secret is stored encrypted and never shown again. |
| Endpoint URL | Leave empty for AWS S3. For MinIO/Wasabi/other S3-compatibles, the server URL, e.g. https://minio.example.com. |
| Region | e.g. us-east-1. Leave empty unless your provider requires it. |
| Path prefix | A base folder inside the bucket. Every import and upload stays under this folder — the rest of the bucket is invisible to ChannelForge. |
| Addressing style | How the bucket appears in request URLs. path (https://endpoint/bucket/key) works for MinIO and most self-hosted storage; virtual (https://bucket.endpoint/key) is the AWS default. If Test fails with an odd DNS or 404 error, try the other style. |
The connection is tested before it is saved; a failing connection is never stored. The provider dropdown pre-fills the endpoint and addressing style for common services (Cloudflare R2, Backblaze B2, Wasabi, DigitalOcean Spaces, MinIO).
Google Drive, Dropbox, and SFTP
Besides S3, three read-only sources — all follow the same rule: files are referenced and downloaded when needed, never copied into a library:
- Google Drive — Connect → authorize with Google → paste a folder link. Import scans that folder.
- Dropbox — Connect → authorize → enter the folder path.
- SFTP — host, username, password or private key, and a remote path. Ideal as a watch-folder: a supplier drops files on the server and you re-run Import to pick up new deliveries.
Importing media
Import scans the bucket and registers every video file it finds as an asset
(supported: .mp4, .mov, .mkv, .m4v, .ts, .m3u8). Each new asset is automatically
queued for analysis. Imports are safe to re-run any time:
- new files → new assets,
- changed files (different content) → re-analyzed,
- files that disappeared from the bucket → marked unavailable (and become available again on a later import if the file returns).
Two optional inputs narrow a scan:
- Import prefix — only scan this folder, relative to the connection's path prefix.
Example: with path prefix
media/and import prefixshows/, onlymedia/shows/…is scanned. Leave empty to scan the whole connection. The disappeared-file check is also scoped to this folder, so importingshows/never marks files elsewhere unavailable. - Exclude path — skip everything under this folder during the import, e.g.
archive/.
Upload file is a convenience for testing: it puts the file under uploads/ in the
connection and imports just that file.
Media Library
Every imported asset, with its stream-readiness at a glance. New and changed assets are analyzed automatically (codecs, resolution, frame rate, HDR, duration), and — unless an owner turns off Prepare new media automatically under Organization → Media — any file that needs a transcode or rewrap is queued for normalization on its own. The manual Normalize buttons remain for retries and for orgs that prefer to pick.
Compatibility — can the file stream as-is in the channel's output profile?
| State | Meaning |
|---|---|
| Pending analysis | Not yet probed. |
| Compatible | Streams as-is, no work needed. |
| Repackage only | Right codecs, wrong container — a fast rewrap happens automatically. |
| Transcode required | Needs a full re-encode. Run Normalize (per asset, or "Normalize pending" for all). Transcodes are CPU-heavy. |
| Invalid | The file can't be used (e.g. no video stream). |
| Analysis failed | Probing errored — check the asset's Problems panel and re-run Analyze. |
| Missing | The source file is gone from storage. Re-import after restoring it. |
Availability — Unavailable means the source object vanished from its storage connection since the last import.
What analysis inspects
Analysis probes the file without modifying it and records: container and duration; video
codec/profile, resolution, pixel aspect ratio, frame rate (including whether it is
variable), bit depth, and HDR color metadata; audio codec, sample rate, and channels. It
also generates the poster thumbnail. The mismatches it finds are saved as the asset's
Problems list — e.g. frame rate 25.0 != 30 — so you can see exactly why a transcode
is needed. HDR, 10-bit, and variable-frame-rate sources always require a transcode: copied
as-is they would produce washed-out colors or drifting timestamps.
What normalization produces
Normalize transcodes the source into a fully conformant MP4 for the channel's output profile, so every file on a channel is format-identical:
- Video — H.264 8-bit at the profile's exact resolution and constant frame rate. Aspect ratio is always preserved: sources are scaled to fit and letterboxed/pillarboxed, never stretched. HDR sources are tone-mapped to standard SDR color.
- Audio — AAC stereo 48 kHz with EBU R128 loudness normalization (−16 LUFS), which is why volume stays consistent across programmes from different sources.
- Container — MP4 with fast-start metadata and a fixed 2-second keyframe cadence for clean streaming.
Transcodes are CPU-heavy (roughly real-time or slower per file); "Repackage only" files skip all of this and get a fast container rewrap automatically.
Uploading from this computer
Upload videos (or drag files anywhere onto the page) uploads up to 20 files per batch, sequentially and in resumable chunks — a dropped connection picks up where it left off. The cap is deliberate: a whole library belongs in a storage connection, where a single Import scans everything in one pass.
If an upload's content is identical to a video already in your library, its progress row shows possible duplicate of "…", naming the existing asset. It is a warning, never a block — the upload completes normally; keep both or delete the copy you don't want. It also saves a redundant transcode from running unnoticed.
Finding assets
Besides search and the state filters, the library filters by collection — showing exactly the assets that collection resolves to right now, dynamic filters included — and by imported date (on-or-after / on-or-before), handy for reviewing a fresh batch.
Asset detail page
- Metadata — edit the title (what viewers and the as-run log see — imported files start with their filename), description, content type, tags, series/season/episode, language, and the rights window. Tags and series are what dynamic collections filter on; the rights window excludes the asset from "rights-valid" collections outside its dates.
- Analyze — re-probe the file.
- Normalize / Cancel normalization — queue or cancel the transcode to the output profile.
- Enable / Disable — disabled assets are excluded from collections and never scheduled.
- Delete — permanently remove the video. Blocked while the video is scheduled to air on any channel's published schedule (the message names the channels); unschedule it or wait for the slot to pass. The as-run log keeps its title, so history stays intact.
- The versions table lists the original source file and any normalized rendition, with their states.
Editing or deleting many at once
Tick the checkboxes (the header checkbox selects the whole page) and a toolbar appears above the list:
- Bulk edit sets shared fields — content type, series, language, tags — on every selected asset. Only the fields you fill in are applied; blank fields leave each asset's existing values untouched. Per-asset fields like the title stay on the asset detail page, where bulk-setting them would corrupt rather than help.
- Delete removes the selected videos with per-item results: files and encodes are cleaned up, while the as-run log keeps their titles. Any video scheduled to air is skipped rather than deleted — the summary says how many were blocked.
Deletion only removes what ChannelForge produced (normalized outputs, thumbnails, platform uploads). Files in your own storage buckets are never deleted.
Collections
Reusable groups of assets — the input to programming blocks and Quick Start.
- Manual — a fixed, ordered list you pick by hand.
- Dynamic — a saved filter: tags (an asset matches if it has any of the listed tags), content type, series, language, min/max duration, enabled only (skip disabled assets), rights-valid only (skip assets whose rights window is not currently active — not yet started or already expired). Dynamic collections update themselves as your library changes.
Resolve previews exactly which assets a collection matches right now — useful to sanity-check a filter before building blocks on it.
Programming blocks
A block turns one collection into a playable sequence, using rules:
| Setting | What it does |
|---|---|
| Source collection | Where the programmes come from. |
| Ordering | manual = collection order · shuffle = random (seeded) · oldest_first / newest_first = by when assets were added. |
| Shuffle seed | Makes shuffle reproducible — same seed, same order every time. Change it for a different shuffle. |
| Target duration | Cycle the collection until the block reaches this length (e.g. 3600 s = a one-hour block). Empty = play each asset once. |
| Repeat-avoidance window | A count of programmes: while cycling to a target duration, the same asset won't appear again within the last N programmes. 0 disables. |
| Intro / Outro bumper | A short asset played once at the block's start / end. |
| Interstitial + every N | A short asset inserted after every N programmes (channel ident, ad slate, …). |
| Recurrence | Pin the block to a fixed local time — daily or on one weekday — during schedule generation. none lets it fill any slot. |
| Fallback collection | Used instead when the source collection resolves to nothing (all assets disabled, rights expired, …). |
Preview shows the exact plan a block would produce right now.
Schedule
Per-channel timeline building:
- Generate — pick blocks (they cycle in the order listed) and fill from Start for Horizon hours (168 = one week). No-repeat window (hours): an asset that already aired within the last N hours isn't scheduled again. Generating replaces the current draft.
- See the week — the draft opens as a calendar (one color per block, outlined slots are filler, hover for details); switch to the List view to edit.
- Edit — add single programmes (the minutes field pre-fills with the asset's duration; lower it to cut early), move events, snap an event to the previous event's end, or remove events.
- Validate — reports gaps, overlaps, and not-ready media before you go live.
- Publish — creates an immutable schedule version the channel plays. Re-publish any time; the channel picks up the new version at the next boundary.
Two things you don't have to do manually:
- A running channel never runs out of schedule. A background sweep automatically extends the published schedule by cycling the same blocks, so a 24/7 channel keeps going — you only regenerate when you want the programming to change. Aim for at least 72 hours of horizon; a validation warning reminds you below that.
- Recurring blocks handle DST. Daily/weekly anchors are pinned to the channel's local wall-clock time, so a 6 AM block stays at 6 AM across daylight-saving changes.
Channels
The channels list shows live state, what's airing now, uptime, alerts, and worker health.
Creating a channel needs a name, a timezone (IANA name like Asia/Kolkata — schedule
times are interpreted in it) and an output profile.
Channel states: idle (never started) · starting (worker preparing media) ·
running (on air) · degraded (on air but recovering from a problem — check Alerts) ·
stopping / stopped · failed (gave up; fix the cause and Start again).
How playout works (and why Start takes a moment)
When you press Start, a dedicated worker: downloads the schedule's media to its local cache, prepares each unique file once (branding is baked into the pixels), then streams the playlist to your destinations without re-encoding — this is what makes many channels per server affordable. Practical consequences:
- The first launch of a channel can take a few minutes before video appears (downloads + preparation); later restarts reuse the cache and are much faster.
- The live preview on the channel page is the same output the destinations receive, teed to HLS — expect ~5–10 seconds of latency, and give it ~30–60 s after Start.
- Because the logo is baked in at prepare time, branding changes take effect on the next restart, not mid-stream.
- When the worker reaches the end of its written playlist (typically after ~a day of continuous streaming), it recycles: it restarts with a freshly built playlist that picks up the extended schedule. The dashboard shows "Preparing playout" for the few seconds this takes and the stream resumes on its own — viewers see a brief stall, not an ended stream. No action is needed.
Channel detail page
- Start / Stop / Restart — operate the playout. Restart briefly drops the stream.
- Emergency slate — immediately switch output to a standby slate (for content emergencies). Resume programming rejoins the schedule at the next programme boundary.
- Destinations — attach YouTube or RTMP destinations (editable only while stopped). The first destination is the primary.
- YouTube — after connecting a YouTube account (OAuth), Provision destination
creates the live broadcast and stream binding on your YouTube channel automatically;
tokens refresh on their own. A destination shows
idleuntil the worker is actually pushing to it. - Output profile — changeable only while stopped; the panel shows how many assets would need re-normalizing before switching.
- Filler — when a scheduled asset can't play (missing, not normalized) or the schedule
has a gap, the channel never goes to dead air. It substitutes, in order: the block's
fallback collection → the channel's filler collection → the built-in emergency slate.
Every substitution is recorded in the As-run log (
replaced/filler/slate) and raises an alert. - Branding — an overlay logo: position (corner), opacity, and padding (inset from the corner, in pixels).
- Preflight — one-click go-live readiness check (destinations, schedule, media states).
As-run log
The immutable record of what actually aired: planned vs actual times and an outcome per event. Filter by channel, outcome, and date (the until date includes that whole day); export as CSV.
Outcomes: aired = played in full · partial = cut short · skipped = never started · replaced = other content was substituted · filler = the filler collection played · slate = the emergency slate was shown · failed = playback error.
Alerts
Operational incidents across all channels, deduplicated (the ×N badge is the occurrence count) and ranked by severity. Ack marks an alert as seen while the underlying issue persists; Resolve closes it.
Organization
- Members & roles —
owner(everything, incl. members, billing, audit) ·editor(manage content, channels, storage) ·operator(run channels: start/stop/slate) ·viewer(read-only). Invite by email with a role — when the platform's email relay is configured the invitee gets a link in their inbox; either way a token is shown as a shareable backup. - Notifications — alert emails per organization: new incidents (worker down, stream unhealthy, schedule running low) and their recoveries are emailed to the addresses you list, so nobody has to keep the dashboard open.
- Media — Prepare new media automatically (default on): imported files that need a transcode or rewrap are queued without anyone pressing Normalize.
- Destinations — org-wide RTMP(S) destinations (stream keys are write-only — stored encrypted, never shown again) and auto-created YouTube destinations. The Enabled/Disabled label is a toggle button.
- Plan — your limits: running channels, destinations per channel, upload quota, allowed output profiles. Limits apply at the next action — nothing running is interrupted.
Audit log
Owner-only, append-only record of every security-relevant change (who, when, from which
IP, with before/after values). Click a row to expand its detail. Action codes are
object.verb, e.g. channel.emergency_slate, membership.role_change.
Admin
Platform administrators only: every channel across all orgs with worker health, plus org plan management. Quarantine forces a channel off air and blocks starting it until re-enabled.
FAST channel supply
Beyond streaming to YouTube and RTMP, ChannelForge supplies broadcast-grade FAST channels to platforms and distributors — and it's operable from the dashboard. Any published channel can also be delivered as a monitored HLS origin with a public electronic programme guide. A normal single-destination channel is unchanged.
The workflow
- Publish a schedule for the channel (as usual).
- On the channel detail page, open the EPG & guide panel:
- New feed — name it, set a horizon (how many days ahead it must cover), and pick formats.
- Generate a version. You'll see whether it's valid and any issues (gaps, short horizon).
- Download the guide as XMLTV, JSON, or TV-Anytime, and copy the public feed URLs (the XMLTV guide and a now/next feed) to hand to a distributor. The guide regenerates automatically as the schedule rolls forward.
- The panel also shows what's airing now and next.
- In the Output endpoints panel, add a primary output (and a backup, if you run redundancy).
- Open the Distribution page (left nav):
- New agreement — the partner, territory, the channel, and any required output profile.
- Watch the certification checklist turn green (a channel is bound, a primary output exists, the EPG is valid), then move the agreement draft → … → live. Going live is blocked until the mandatory checks pass, and the origin only serves certified channels.
- Monitor on the NOC page — a live wallboard of every channel's state, worker heartbeat, EPG validity, output failover, and open incidents.
- Wire integrations on the Webhooks page — register an endpoint, choose events (schedule published, EPG generated/delivered, incident opened/resolved, …), and watch the signed delivery log (with retry + redeliver).
What each capability gives you
| Capability | What it gives you |
|---|---|
| HLS delivery origin | A monitored, standards HLS origin with a stable per-channel URL — the form FAST platforms and CDNs ingest. Atomic manifests, a live window, program-date-time, and immutable-segment caching for a CDN. |
| Public guide feeds | Per channel: a DTD-conformant XMLTV guide, a TV-Anytime rendering, and a now/next feed — public URLs you hand to a distributor. |
| EPG | Generated from your published schedule with rich metadata (descriptions, rating + system, series/episode, editorial flags), validated, versioned, auto-regenerated as the horizon rolls, and optionally pushed to an S3/SFTP/HTTP target. |
| Ad breaks (SCTE-35) | Scheduled ad avails signalled in the manifest as EXT-X-DATERANGE cues carrying SCTE-35, so a downstream SSAI/ad system inserts ads at the right moment. |
| Captions | WebVTT caption tracks declared and served in the HLS output, aligned to the video. |
| Agreements & certification | Distribution agreements move draft → … → live, gated on mandatory checks; an uncertified channel is not served. |
| Monitoring | Output probes watch manifest freshness, cue occurrence, captions, and primary/backup drift, raising deduplicated alerts; the NOC wallboard shows fleet health. |
| Webhooks | Signed, retrying event notifications (schedule/EPG/incident/…) with a delivery log and redeliver. |
Some advanced options are opt-in and enabled by us per account: primary/backup redundancy with automatic failover, broadcast loudness normalization on the live encode, multi-bitrate ABR, and server-side ad insertion (SSAI) decisioning via an external ad server — talk to us to enable them.
Ad decisioning and insertion are handled by an external SSAI ad server that ChannelForge integrates with — ChannelForge owns the avails, signalling, continuity, and reconciliation; the ad system owns which ad fills each break. An ad-system outage never stops your channel.