{"id":50212067,"url":"https://github.com/datvietvac-techhub/open-streamer","last_synced_at":"2026-05-26T06:04:51.463Z","repository":{"id":348244524,"uuid":"1196945939","full_name":"datvietvac-techhub/open-streamer","owner":"datvietvac-techhub","description":"A high-availability live media server in Go.","archived":false,"fork":false,"pushed_at":"2026-05-22T10:33:57.000Z","size":2266,"stargazers_count":45,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T15:41:22.276Z","etag":null,"topics":["dash","failover","fallback-mechanism","golang","hls","hot-reload","livestream","low-latency","media-server","mpegts","multimedia","playback","prometheus-metrics","rtmp","rtsp","srt","streaming","transcoding-server","video"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/datvietvac-techhub.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-31T07:27:43.000Z","updated_at":"2026-05-22T14:07:11.000Z","dependencies_parsed_at":"2026-05-04T06:04:36.773Z","dependency_job_id":null,"html_url":"https://github.com/datvietvac-techhub/open-streamer","commit_stats":null,"previous_names":["ntthuan060102github/open-streamer","ntt0601zcoder/open-streamer","datvietvac-techhub/open-streamer"],"tags_count":107,"template":false,"template_full_name":null,"purl":"pkg:github/datvietvac-techhub/open-streamer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datvietvac-techhub%2Fopen-streamer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datvietvac-techhub%2Fopen-streamer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datvietvac-techhub%2Fopen-streamer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datvietvac-techhub%2Fopen-streamer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datvietvac-techhub","download_url":"https://codeload.github.com/datvietvac-techhub/open-streamer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datvietvac-techhub%2Fopen-streamer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33506512,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dash","failover","fallback-mechanism","golang","hls","hot-reload","livestream","low-latency","media-server","mpegts","multimedia","playback","prometheus-metrics","rtmp","rtsp","srt","streaming","transcoding-server","video"],"created_at":"2026-05-26T06:04:40.578Z","updated_at":"2026-05-26T06:04:51.457Z","avatar_url":"https://github.com/datvietvac-techhub.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Open Streamer\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/ntt0601zcoder/open-streamer.svg)](https://pkg.go.dev/github.com/ntt0601zcoder/open-streamer)\n[![CI](https://github.com/datvietvac-techhub/open-streamer/actions/workflows/ci.yml/badge.svg)](https://github.com/datvietvac-techhub/open-streamer/actions/workflows/ci.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/ntt0601zcoder/open-streamer)](https://goreportcard.com/report/github.com/ntt0601zcoder/open-streamer)\n[![Coverage](https://codecov.io/gh/ntt0601zcoder/open-streamer/branch/main/graph/badge.svg)](https://codecov.io/gh/ntt0601zcoder/open-streamer)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nA high-availability live media server in Go. Ingests from any\ncommon protocol, normalises through an internal MPEG-TS pipeline,\noptionally transcodes in-process via libavcodec, and publishes over HLS, DASH, RTMP,\nRTSP, and SRT — all from one binary, one process per host.\n\n```mermaid\nflowchart LR\n    subgraph Ingest\n        S1[\"RTMP / RTSP / SRT\"]\n        S2[\"HLS / HTTP / UDP\"]\n        S3[\"File / S3\"]\n        S4[\"copy:// / mixer://\"]\n    end\n\n    subgraph Pipeline\n        Hub((\"Buffer Hub\")):::data\n        Tx[\"Transcoder\u003cbr/\u003elibavcodec subprocess\"]\n        DVR[\"DVR + events\"]\n        Hub --\u003e Tx\n        Tx --\u003e Hub\n        Hub --\u003e DVR\n    end\n\n    subgraph Deliver\n        D1[\"HLS / DASH\"]\n        D2[\"RTMP / RTSP / SRT\"]\n        D3[\"Push out — RTMP / RTMPS\"]\n        D4[\"Webhooks (HMAC)\u003cbr/\u003eor file sink\"]\n    end\n\n    S1 --\u003e Hub\n    S2 --\u003e Hub\n    S3 --\u003e Hub\n    S4 --\u003e Hub\n\n    Hub --\u003e D1\n    Hub --\u003e D2\n    Hub --\u003e D3\n    DVR -.-\u003e|\"events\"| D4\n\n    Mgr[\"Stream Manager\u003cbr/\u003efailover — no transcoder restart\"]\n    Mgr -.-\u003e|\"health\"| Ingest\n\n    classDef data fill:#5a3a1f,stroke:#e0a060,color:#fff\n```\n\n---\n\n## Why Open Streamer\n\n- **No process-per-stream.** One Go process handles N streams across N\n  goroutines. Transcoding runs in-process (libavcodec) in a per-stream\n  subprocess; ingest is pure Go.\n- **Failover at the Go level.** When an input degrades, the Stream\n  Manager swaps to the next-priority source in ~150ms without\n  restarting the transcoder. Buffer continuity → players see one\n  `#EXT-X-DISCONTINUITY` and resume.\n- **Hot-reload by diff.** `PUT /streams/{code}` restarts only what\n  changed — adding a push destination doesn't disturb HLS viewers,\n  toggling DASH doesn't drop RTMP push sessions.\n- **Write never blocks.** The Buffer Hub fan-out is non-blocking —\n  slow consumers drop packets, the writer is shielded. One stuck DVR\n  cannot freeze every viewer.\n- **Self-healing.** Transcoder-subprocess crashes restart with exponential\n  backoff forever; the pipeline never tears down. Health detection flips\n  status to `degraded` after sustained failure so ops sees it.\n\n---\n\n## Quick start\n\n```bash\n# 1. Install via the systemd installer (Linux)\nsudo bash \u003c(curl -sL https://raw.githubusercontent.com/ntt0601zcoder/open-streamer/main/build/reinstall.sh) v1.0.0\n\n# 2. Or build from source\ngit clone https://github.com/ntt0601zcoder/open-streamer.git\ncd open-streamer\nmake build \u0026\u0026 ./bin/open-streamer\n\n# 3. Or Docker\nmake compose-up\n```\n\nThen create a stream:\n\n```bash\ncurl -XPOST http://localhost:8080/api/v1/streams/news -d '{\n  \"inputs\":   [{ \"url\": \"https://upstream/playlist.m3u8\", \"priority\": 0 }],\n  \"protocols\": { \"hls\": true }\n}'\n```\n\nStream is live at `http://localhost:8080/news/index.m3u8`. Full setup\nwalkthrough in [USER_GUIDE.md](./docs/USER_GUIDE.md).\n\n---\n\n## Documentation\n\n| Doc | Audience | What's in it |\n|---|---|---|\n| [USER_GUIDE.md](./docs/USER_GUIDE.md) | Operator | Install, create streams, hot-reload, hooks, troubleshooting |\n| [CONFIG.md](./docs/CONFIG.md) | Operator | Every config field with examples + defaults reference |\n| [ARCHITECTURE.md](./docs/ARCHITECTURE.md) | Contributor | Subsystem design, invariants, data flow |\n| [APP_FLOW.md](./docs/APP_FLOW.md) | Contributor / Ops | Step-by-step traces (boot, failover, transcoder crash, hot-reload) + full events reference |\n| [EVENTS.md](./docs/EVENTS.md) | Operator / Integrator | Catalogue of every domain event, payload shape, hook recipes |\n| [METRICS.md](./docs/METRICS.md) | Operator / SRE | Prometheus metrics reference + dashboard / alert PromQL examples |\n| [FEATURES_CHECKLIST.md](./docs/FEATURES_CHECKLIST.md) | Everyone | What's implemented today, what's planned, what's locked-out |\n\nAPI spec auto-generated at `/swagger/` (run `make swagger` to\nregenerate from annotations).\n\n---\n\n## Highlights\n\n- **URL-driven ingest** — protocol + push/pull mode detected from\n  scheme/host. Supports RTMP, RTSP, SRT, UDP/multicast, HLS, raw\n  HTTP-TS, file (with loop), S3, plus `copy://` (in-process re-stream)\n  and `mixer://` (combine video + audio from two streams).\n- **Multi-input failover** — N inputs per stream, prioritised. Manager\n  monitors health, switches transparently. Last 20 switches recorded\n  with reason (`error` / `timeout` / `manual` / `failback` / `recovery`\n  / `input_added` / `input_removed`).\n- **ABR transcoding** — in-process libavcodec with NVENC / VAAPI / QSV /\n  VideoToolbox. Per-rung profiles (resolution, bitrate, codec, preset,\n  GOP, B-frames, refs, SAR, resize mode). Full-GPU pipeline\n  (NVDEC → scale_cuda → NVENC, no hwdownload round-trip) on NVENC hosts.\n- **Single decode, N renditions** — one `open-streamer-transcoder`\n  subprocess per stream decodes once and fans out to every rung, so an\n  N-rung ladder costs 1×decode + N×encode.\n- **Seamless input switch** — on failover the subprocess swaps only its\n  decoder; the encoders stay alive, so players don't re-initialise.\n- **HLS + DASH ABR** — master playlist + per-track variants;\n  `#EXT-X-DISCONTINUITY` per failover.\n- **RTSP / RTMP / SRT play** — shared listeners (one port per\n  protocol). Single-segment codes use the `live/` prefix:\n  `rtmp://host/live/news`. Multi-segment codes are addressed at their\n  raw path: `rtmp://host/region/north/news`. The server strips a\n  leading `live/` when present, so either form reaches multi-segment\n  streams.\n- **Templates** — reusable bundle of stream config (transcoder,\n  protocols, push, DVR, watermark, thumbnail, inputs, tags,\n  stream-key). Reference one from a stream via the `template` field\n  and the stream inherits every config-like field it leaves at the\n  zero value. Updating the template hot-reloads every running stream\n  that inherits from it.\n- **Auto-publish** — a template can declare URL-path prefixes. When\n  an encoder pushes to a path matching one of the prefixes and the\n  template carries a `publish://` input, the server materialises a\n  **runtime stream** on the fly. Runtime streams are RAM-only, appear\n  in `GET /streams` with `source: \"runtime\"`, and disappear 30 s\n  after the last packet.\n- **Push out** — RTMP/RTMPS to platforms (popular live platforms,\n  CDN). Per-destination state visible at\n  `runtime.publisher.pushes[]`.\n- **DVR + Timeshift** — persistent recording per stream; resume across\n  restarts; absolute / relative timeshift VOD endpoints; size + time\n  retention.\n- **Watermarks** — text (drawtext + strftime) or image (overlay) per\n  stream. Position presets + raw libavfilter expressions for full\n  flexibility (animated, time-aware). Image asset library with REST\n  upload (`POST /watermarks`). Pure-GPU pipeline auto-bridges via\n  hwdownload/hwupload_cuda for portability.\n- **Play sessions** — track every viewer across HLS / DASH / RTMP /\n  SRT / RTSP. Fingerprint dedup for pull protocols, UUID for\n  connection-bound. Idle reaper, kick API, hot-reload config,\n  `session.opened`/`closed` events on the bus.\n- **Webhooks + file sink** — domain events delivered via HTTP (HMAC\n  signed) or appended as JSON-lines to a local log file (drop-in for\n  Filebeat / Vector / Promtail). Per-hook retries, event/stream filters,\n  metadata injection.\n- **Transcoder capability probe** — boot + on-demand check for\n  required/optional encoders; UI sees a checklist before saving.\n- **Pluggable storage** — JSON flat-file (default) or YAML single-document.\n- **Prometheus metrics** + structured slog logging.\n\nFull feature matrix in [FEATURES_CHECKLIST.md](./docs/FEATURES_CHECKLIST.md).\n\n---\n\n## Development\n\n```bash\nmake build          # → bin/open-streamer\nmake run            # run without persisting binary\nmake test           # go test -race -shuffle=on -count=1 -timeout=5m ./...\nmake lint           # golangci-lint run ./...\nmake check          # tidy + vet + lint + test (full local CI)\nmake swagger        # regenerate api/docs from swag annotations\nmake hooks-install  # install pre-commit hook (auto-regen swagger)\n```\n\nSingle test: `go test -run TestName ./internal/\u003cpkg\u003e/...`\n\nRequires Go 1.25.x+. Transcoding links libavcodec (FFmpeg's libraries) into\nthe `open-streamer-transcoder` binary — the builder image and release\nbundles provide them; the boot probe catches missing required encoders.\n\nRepository layout:\n\n```\ncmd/server/           # main entrypoint\ninternal/\n  api/                # chi router + handlers\n  api/handler/        # HTTP handlers (incl. /templates CRUD)\n  autopublish/        # template-prefix matcher + runtime stream registry + idle reaper\n  buffer/             # ring buffer + fan-out\n  coordinator/        # pipeline lifecycle + diff engine\n  ingestor/           # pull workers (RTMP/RTSP/SRT/HLS/...) + push servers\n  manager/            # input failover state machine\n  transcoder/         # libavcodec subprocess supervisor + native pipeline + watermarks\n  publisher/          # HLS/DASH segmenters + serve listeners + push out\n  dvr/                # recording + retention + timeshift\n  events/             # in-process event bus\n  hooks/              # webhook (HTTP) + file sink delivery\n  sessions/           # play-session tracker (HLS/DASH/RTMP/SRT/RTSP viewers)\n  watermarks/         # asset library backing /watermarks REST API\n  domain/             # types + defaults + resolvers (incl. Template / ResolveStream)\n  store/              # repository pattern (json / yaml backends; Stream + Template repos)\n  runtime/            # service lifecycle wrapper\nconfig/               # bootstrap config (storage backend selection)\nbuild/                # systemd unit + installer\nbench/                # capacity sweep tooling (sample.sh / run-all.sh / aggregate.sh)\ndocs/                 # → see Documentation table above\n```\n\n---\n\n## Contributing\n\nPRs welcome. Before submitting:\n\n1. `make hooks-install` — installs the pre-commit hook that\n   auto-regenerates swagger when Go files change\n2. `make check` — runs full local CI (tidy + vet + lint + tests)\n3. Match the project's design invariants documented in\n   [ARCHITECTURE.md § Design mindset](./docs/ARCHITECTURE.md#1-design-mindset)\n\nTests are required for new features. The native transcoder's libavcodec\nstages (decoder / encoder / scaler / pipeline) have table tests that link\nagainst libav — exercised in the builder image (`Dockerfile.builder`).\n\n---\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatvietvac-techhub%2Fopen-streamer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatvietvac-techhub%2Fopen-streamer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatvietvac-techhub%2Fopen-streamer/lists"}