{"id":27910594,"url":"https://github.com/xaionaro-go/avd","last_synced_at":"2026-05-17T01:37:56.028Z","repository":{"id":291596471,"uuid":"977814946","full_name":"xaionaro-go/avd","owner":"xaionaro-go","description":"[WIP] (Lib)AV Daemon: a streaming server/router based on libav","archived":false,"fork":false,"pushed_at":"2025-05-05T14:52:44.000Z","size":5897,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-05T15:41:29.150Z","etag":null,"topics":["astiav","client","ffmpeg","go","golang","libav","rtmp","rtsp","server","srt"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xaionaro-go.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}},"created_at":"2025-05-05T02:22:30.000Z","updated_at":"2025-05-05T14:52:47.000Z","dependencies_parsed_at":"2025-05-05T15:53:34.238Z","dependency_job_id":null,"html_url":"https://github.com/xaionaro-go/avd","commit_stats":null,"previous_names":["xaionaro-go/avd"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xaionaro-go%2Favd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xaionaro-go%2Favd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xaionaro-go%2Favd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xaionaro-go%2Favd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xaionaro-go","download_url":"https://codeload.github.com/xaionaro-go/avd/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252658995,"owners_count":21784117,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["astiav","client","ffmpeg","go","golang","libav","rtmp","rtsp","server","srt"],"created_at":"2025-05-06T09:44:03.687Z","updated_at":"2026-05-17T01:37:56.016Z","avatar_url":"https://github.com/xaionaro-go.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `avd` -- (Lib)AV Daemon\n\n`avd` -- is a streaming server that uses [`libav`](https://github.com/FFmpeg/FFmpeg) under the hood (as an alternative to [`nginx-module-rtmp`](https://docs.nginx.com/nginx/admin-guide/dynamic-modules/rtmp/), [`mediamtx`](https://github.com/bluenviron/mediamtx), [`MonaServer`](https://github.com/MonaSolutions/MonaServer) or whatnot).\n\nOn one hand, `libav` is a legendary, powerful, fine-polished and fine-tuned video/audio processing library, that supports RTMP, RTSP, SRT and other protocols out of the box.\nOn the other hand, `libav` lacks capabilities to serve these protocols beyond just accepting a pre-defined stream or/and using the protocols as a client.\n\n`avd` fixes that problem, by wrapping around `libav` to manage multiple streams, that could be processed pretty similar to how you would do it with a normal streaming server.\n\n# Motivation\n\nThe best I found as a streaming server was [`mediamtx`](https://github.com/bluenviron/mediamtx), but unfortunately it handled pretty poorly all of my edge cases. While I need a tool I can trust: a tool that just works.\n\nInvestigating myself all the intricacies of H264, RTMP, RTSP, SRT, HEVC, AAC, etc, to find a way to workaround `mediamtx` was taking too much time. Moreover, `mediamtx` does not allow really integrating into other projects (because it keeps everything in `internal`) which is in a strong conflict with [one of my hobby project](https://github.com/xaionaro-go/streamctl/).\n\nSo I decided to just reuse all the fine-polishing of `libav` a make a server out of that. Gladfully, I've already previously made a library that makes that easy: [`avpipeline`](https://github.com/xaionaro-go/avpipeline).\n\n### The alternatives tried before starting this project\n\n* [`nginx-module-rtmp`](https://docs.nginx.com/nginx/admin-guide/dynamic-modules/rtmp/): very poor debugging, does not support the protocols I need; and not integratable into another Go project.\n* [`mediamtx`](https://github.com/bluenviron/mediamtx): does not work on my edge cases; and not integratable into another Go project.\n* [`livego`](https://github.com/gwuhaolin/livego): it was much worse than mediamtx for my use cases (do not remember the exact reasons); and not integratable into another Go project.\n* [`go2rtc`](https://github.com/AlexxIT/go2rtc): it appeared to be just a forwarding/routing server, rather than a normal server (e.g.: [ITS#1238](https://github.com/AlexxIT/go2rtc/issues/1238#issuecomment-2237036661)); not integratable into another Go project; and even those were not problems by now I'm convinced it would not have handled my edge cases better than mediamtx.\n* So on.\n\nI also tried to solve my problems with just small libraries/packages, e.g. [github.com/yutopp/go-rtmp](https://github.com/yutopp/go-rtmp) (see also [github.com/xaionaro-go/go-rtmp](https://github.com/xaionaro-go/go-rtmp)), but all of them were even further from supporting my edge cases. For example, IIRC, `go-rtmp` did not even support multihour streams (the timestamp field in RTMP was overflowing). \n\nThe general pattern is that a project:\n* Does not support protocols I need.\n* Works badly in edge cases.\n* Is too difficult to build for Android/iOS/Linux/whatever.\n* Is not integratable into an existing Go project.\n* Has major bugs/limitations even in normal cases.\n\nSo the hope is that if I'll just use `libav` I'll avoid these problems better than the other projects, but with focus on solving my personal edge cases.\n\n# Quick start (daemon)\n\n```sh\n$ avd --generate-config | tee ~/.avd.conf\n```\n```yaml\nports:\n- address: tcp:127.0.0.1:1936\n  mode: \"publishers\"\n  publish_mode: exclusive-takeover\n  protocol_handler:\n    rtmp: {}\n  default_route_path: \"\"\n  on_end: \"close_consumers\"\n- address: tcp:0.0.0.0:1935\n  mode: \"consumers\"\n  publish_mode: exclusive-takeover\n  protocol_handler:\n    rtmp: {}\n  default_route_path: \"\"\n  on_end: \"close_consumers\"\n- address: tcp:0.0.0.0:1937\n  mode: \"consumers\"\n  publish_mode: exclusive-takeover\n  protocol_handler:\n    rtmp: {}\n  default_route_path: \"\"\n  on_end: \"wait_for_new_publisher\"\n- address: tcp:127.0.0.1:8555\n  mode: \"publishers\"\n  publish_mode: exclusive-takeover\n  protocol_handler:\n    rtsp:\n      transport_protocol: \"\"\n  default_route_path: \"\"\n  on_end: \"close_consumers\"\n- address: udp:127.0.0.1:4445\n  mode: \"publishers\"\n  publish_mode: exclusive-takeover\n  protocol_handler:\n    mpegts: {}\n  default_route_path: mystream\n  on_end: \"close_consumers\"\nendpoints:\n  mystream:\n    forwardings:\n    - destination: {}\n      transcoding:\n        audio_track_configs:\n        - input_track_ids:\n          - 0\n          - 1\n          - 2\n          - 3\n          - 4\n          - 5\n          - 6\n          - 7\n          output_track_ids:\n          - 0\n          codec_name: copy\n          averaging_period: 0s\n          average_bit_rate: 0\n          custom_options: []\n          hardware_device_type: 0\n          hardware_device_name: \"\"\n        video_track_configs:\n        - input_track_ids:\n          - 0\n          - 1\n          - 2\n          - 3\n          - 4\n          - 5\n          - 6\n          - 7\n          output_track_ids:\n          - 1\n          codec_name: copy\n          averaging_period: 0s\n          average_bit_rate: 0\n          custom_options: []\n          hardware_device_type: 0\n          hardware_device_name: \"\"\n```\n\n```sh\n$ avd\n```\n\nIt should work. Now let's do something useful:\n\nModify the config to:\n```yaml\nports:\n- address: tcp:127.0.0.1:1936\n  rtmp:\n    mode: \"publishers\"\nendpoints:\n  mystream:\n    forwardings:\n    - destination:\n        url: \"rtmp://127.0.0.1:1399/test-stream\"\n```\n\nRun:\n```sh\n$ ffplay -f flv -listen 1 rtmp://127.0.0.1:1399/test-stream\n```\n\nRun the `avd` again:\n```sh\n$ avd\n```\n\nNow send some stream to `avd`, e.g.:\n```sh\n$ ffmpeg -re -i /tmp/1.flv -c copy -f flv rtmp://127.0.0.1:1936/mystream\n```\n\nIn result, you'll see that `ffplay` is playing your stream:\n```\nffmpeg -\u003e avd -\u003e ffplay\n```\n\n# Quick start (package)\n\nAn example of an RTMP server:\n```go\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/xaionaro-go/avd/pkg/avd\"\n)\n\nfunc serveRTMP(ctx context.Context) error {\n\tsrv := avd.NewServer()\n\n\t_, err = srv.Listen(ctx, \"tcp:127.0.0.1:1936\", avd.ProtocolRTMP, avd.RTMPModePublishers)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to listen %s with the RTMP-publishers handler: %w\", publishersListener.Addr(), err)\n\t}\n\n\t_, err = srv.Listen(ctx, \"tcp:0.0.0.0:1935\", avd.ProtocolRTMP, avd.RTMPModeConsumers)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to listen %s with the RTMP-consumers handler: %w\", consumersListener.Addr(), err)\n\t}\n\n\tsrv.Wait(ctx)\n\treturn nil\n}\n```\n\nUnfortunately we have to split publishers and consumers to two ports due to internal limitations of `libav`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxaionaro-go%2Favd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxaionaro-go%2Favd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxaionaro-go%2Favd/lists"}