{"id":16224155,"url":"https://github.com/vladmandic/stream-rtsp","last_synced_at":"2025-10-24T22:32:47.457Z","repository":{"id":37536346,"uuid":"357195281","full_name":"vladmandic/stream-rtsp","owner":"vladmandic","description":"Transcode \u0026 Play RTSP Video Streams in Browser","archived":true,"fork":false,"pushed_at":"2024-03-13T23:09:49.000Z","size":55,"stargazers_count":119,"open_issues_count":0,"forks_count":16,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-02-10T01:33:00.636Z","etag":null,"topics":["dash","hls","rtmp","rtsp","stream-server","webrtc"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/vladmandic.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}},"created_at":"2021-04-12T13:01:35.000Z","updated_at":"2025-01-07T14:37:44.000Z","dependencies_parsed_at":"2025-02-10T01:32:18.777Z","dependency_job_id":"8e14c5ea-02d8-40b2-b836-35464bc3a77b","html_url":"https://github.com/vladmandic/stream-rtsp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vladmandic/stream-rtsp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladmandic%2Fstream-rtsp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladmandic%2Fstream-rtsp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladmandic%2Fstream-rtsp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladmandic%2Fstream-rtsp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vladmandic","download_url":"https://codeload.github.com/vladmandic/stream-rtsp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vladmandic%2Fstream-rtsp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280878362,"owners_count":26406641,"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","status":"online","status_checked_at":"2025-10-24T02:00:06.418Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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","hls","rtmp","rtsp","stream-server","webrtc"],"created_at":"2024-10-10T12:22:50.303Z","updated_at":"2025-10-24T22:32:47.159Z","avatar_url":"https://github.com/vladmandic.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Transcode \u0026 Play RTSP Video Streams in Browser\n\nReal Time Streaming Protocol (RTSP) and Real Time Messaging Protocol (RTMP) are  \nfrequently used in security cameras and were originally supported in browsers  \nvia plugins such as *RealMedia* (for RTSP) or *Flash* (for RTMP)  \n\nHowever, such binary plugins are nowadays considered a security risk  \nand are disabled in all modern browsers  \n\n*So what are the options to view RTSP video stream in modern browsers?*  \n\n- First we need to encapsulate video stream from RTSP into  \n  a known streaming format on the server side  \n  (all solutions require a server component)  \n  And if camera already provides video stream in a well-known format such as H264,  \n  we only need to re-encapsulate it, we don't need to decode/encode it,  \n  so operation is lightweight  \n\n- Then we can access that new stream from the browser using standard `Video` element,  \neither natively or using a JavaScript library that provides  \nHTML5 Media Source Extensions to the Video element  \n\n## Options\n\nBest solution is to use latest web streaming standard **WebRTC** (*Web Real-Time Communication*)\n\nThis project also provides additional examples for:\n\n- Using `FFMpeg` to encapsulate **RTSP** into a **HLS** (*HTTP Live Streaming*)  \n  and using `hls.js` library to play stream in browser\n- Using `FFMpeg` to encapsulate **RTSP** into a **DASH** (*Dynamic Adaptive Streaming over HTTP*)  \n  and using `dash.js` library to play stream in browser\n- Using `FFMpeg` to encapsulate **RTSP** into a **FLV** (*Adobe Flash Video*)  \n  and using `flv.js` library to play stream in browser (TBD)\n\n\u003cbr\u003e\u003chr\u003e\n\n## Using RTSP to WebRTC  \n\nThis option is by far the fastest and uses least amount of resources as it does not require actual transcoding of the video stream and instead simply re-encapsulates available video stream found in `rtsp` into `webrtc` format  \n\nHowever, it requires that video stream presented by camera via `rtsp` is a supported codec:\n- video must be **H264**\n- audio stream can be **PCM_ALAW** or **OPUS**  \n\nIf video codec is not supported, then only option is to use actual transcoding - see options using `ffmpeg` instead.\n\n### 1. Build\n\nBuild stream server:\n\n\u003e npm run build\n\nWhich installs all required **GoLang** dependencies and creates a static executable `stream/stream`  \nBinaries are not prepackaged since:\n- They are platform specific (Linux, Windows, Mac, ARM, etc.),\n- Size - I don't want to post large binaries on GitHub (~13MB per platform)\n\n### 2. Configure\n\nCreate configuration `config.json`  \n\n```js\n{\n  \"server\": {\n    \"httpPort\": 8000, // port for local http server\n    \"httpsPort\": 8001, // port for local https server\n    \"encoderPort\": \":8002\", // http port for that will serve media stream\n    \"iceServers\": [], // not needed for local network access\n    \"webrtcMinPort\": 32768, // port range, no need to change\n    \"webrtcMaxPort\": 65535, // port range, no need to change\n    \"retryConnectSec\": 5, // if webcam is slow to respond you may need to increase value\n    \"startStreamServer\": true // automatically start rtsp to webrtc stream server, disable for hls or dash\n  },\n  \"streams\": { // define any number of streams, but has to be at least one\n    \"reowhite\": { // logical name of a stream\n      \"VOD\": false, // always false\n      \"disableAudio\": true, // you can stream audio as well although its not well supported\n      \"debug\": false, // enable protocol debugging\n      \"url\": \"rtsp://user:password@url:port/stream\" // actual uri of the stream you want to transcode\n    }\n  },\n  \"client\": {\n    \"debug\": true, // enable client side debug logs\n    \"defaultStream\": \"reowhite\" // must match a valid stream name configured above\n  }\n}\n```\n\n### 3. Start Server\n\n`npm start`\n\n\u003e stream-rtsp@0.0.1 start /home/vlado/dev/stream-rtsp  \n\u003e node server/serve\n\n```js\nINFO:  stream-rtsp version 0.0.1\nINFO:  User: vlado Platform: linux Arch: x64 Node: v19.1.0\nSTATE: http server listening: 8000\nSTATE: http2 server listening: 8001\nDATA:  stream: http server  :8002\nDATA:  stream: connect: reowhite\nDATA:  GET/2.0 full 200 text/html; charset=utf-8 885 /client/webrtc.html ::1\nDATA:  GET/2.0 full 200 text/javascript; charset=utf-8 3251 /client/webrtc.js ::1\nDATA:  GET/2.0 full 200 application/json; charset=utf-8 487 /config.json ::1\nDATA:  stream: video detected\nDATA:  stream: [GIN] 2022/11/24 - 09:41:45 | 200 |    41.581µs | ::1 | GET \"/stream/codec/reowhite\"\nDATA:  GET/2.0 full 200 image/x-icon 5063 /favicon.ico ::1\nDATA:  GET/2.0 full 200 application/octet-stream 305 /client/manifest.webmanifest ::1\nDATA:  stream: video detectedSet UDP ports to 32768 .. 65535\nDATA:  stream: [GIN] 2022/11/24 - 09:41:45 | 200 | 82.300765ms | ::1 | POST \"/stream/receiver/reowhite\"\n```\n\n### 4. Connect Client\n\nNavigate to: \u003chttps://localhost:8001/client/webrtc.html\u003e  \nIt should display the webrtc stream from camera  \n*Note: Lowest real-world video latency is below 1sec*\n\nFor details, check browser inspector console log:\n\n```js\nwebrtc client starting\nwebrtc server: http://localhost:8002 stream: reowhite\nwebrtc received streams: [{ \"Type\": \"video\" }]\nwebrtc negotiation start: RTCSessionDescription {\n  type: 'offer',\n  sdp: 'v=0\\r\\no=- 4399680908628474473 2 IN IP4 127.0.0.1\\r\\ns…:1\\r\\na=sctp-port:5000\\r\\na=max-message-size:262144\\r\\n'\n}\nwebrtc connection checking\nwebrtc received track: MediaStreamTrack {\n  kind: 'video', id: '8a13f611-eb50-4aa8-a8fd-3884139fe2cd', enabled: true, readyState: 'live',\n}\nwebrtc connection connected\nwebrtc channel open\nwebrtc resolution: 2560 1920\n```\n\n### 5. Troubleshoot\n\n#### Disconnect Loop\n\nif you see a loop of:\n```js\nDATA:  stream server: connect: reowhite\nDATA:  stream server: error: rtsp disconnected\n```\n\nit could be that:\n- camera is busy  \n  cameras have limited number of available connections and if youre using camera in some other software, it may not allow additional connections. even after you disconnect, it may take up to 30sec for camera to release connection handle and become available for new connections  \n- the url specified in `config.json` is not valid  \n- the video stream is corrupt or simply not recognized  \n\n#### Advanced Troubleshooting\n\nTo futher troubleshoot, enable debug in `config.json` streams configuration  \nThis is enables full protocol logging and results in binary output, so capture the log and look for following ascii snippets:\n\n```log\n[OPTIONS rtsp://reolink-white:554/h264Preview_01_main RTSP/1.0CSeq: 1User-Agent: Lavf58.76.100]\n\n[DESCRIBE rtsp://reolink-white:554/h264Preview_01_main RTSP/1.0CSeq: 3Authorization: Digest username=\"admin\", realm=\"LIVE555 Streaming Media\", nonce=\"6f861c23467c7282b1464f2f386f9c3c\", uri=\"rtsp://reolink-white:554/h264Preview_01_main\", response=\"a9f1d8debd46cc3b336d70492faccc3a\"Accept: application/sdpUs\ner-Agent: Lavf58.76A2]\n\n[RTSP/1.0 200 OKCSeq: 3Date: Thu, Nov 24 2022 15:10:19 GMTContent-Base: rtsp://192.168.0.203/h264Preview_01_main/Content-Type: application/sdpContent-Length: 718v=0o=- 1669289695611647 1 IN IP4 192.168.0.203s=Session streamed by \"preview\"i=h264Preview_01_maint=0 0a=tool:LIVE555 Streaming Media v2013.04.08a=type:broadcasta=control:*a=range:npt=0-a=x-qt-text-nam:Session streamed by \"preview\"a=x-qt-text-inf:h264Preview_01_mainm=video 0 RTP/AVP 96c=IN IP4 0.0.0.0b=AS:500a=rtpmap:96 H264/90000a=fmtp:96 packetization-mode=1;profile-level-id=640033;sprop-parameter-sets=Z2QAM6zoAoAPGQ==,aO48sA==a=control:trackID=1m=audio 0 RTP/AVP 97c=IN IP4 0.0.0.0b=AS:256a=rtpmap:97 MPEG4-GENERIC/16000a=fmtp:97 streamtype=5;profile-level-id=15;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1408; profile=1;a=control:trackID=2]\n\n[SETUP rtsp://192.168.0.203/h264Preview_01_main/trackID=1 RTSP/1.0CSeq: 4Authorization: Digest username=\"admin\", realm=\"LIVE555 Streaming Media\", nonce=\"6f861c23467c7282b1464f2f386f9c3c\", uri=\"rtsp://192.168.0.203/h264Preview_01_main/trackID=1\", response=\"17c7a56100c6680e6db34ef891bfc832\"Transport: RTP/AVP/TCP;unicast;interleaved=0-1User-Agent: Lavf58.76.100]\n\n[RTSP/1.0 200 OKCSeq: 4Date: Thu, Nov 24 2022 15:10:19 GMTTransport: RTP/AVP/TCP;unicast;destination=192.168.0.201;source=192.168.0.203;interleaved=0-1Session: D90CE24F]\n\n[PLAY rtsp://192.168.0.203/h264Preview_01_main/ RTSP/1.0CSeq: 5Authorization: Digest username=\"admin\", realm=\"LIVE555 Streaming Media\", nonce=\"6f861c23467c7282b1464f2f386f9c3c\", uri=\"rtsp://192.168.0.203/h264Preview_01_main/\", response=\"4d63a07805fa5089ee38935004fcdc8e\"User-Agent: Lavf58.76.100Session: D90CE24F]\n\n[RTSP/1.0 200 OKServer: Rtsp Server/2.0CSeq: 5Date: Thu, Nov 24 2022 15:10:19 GMTRange: npt=0.000-Session: D90CE24FRTP-Info: url=trackID=1;seq=23202;rtptime=3253684886;ssrc=204c95ce,url=trackID=2;seq=0;rtptime=0;ssrc=00000000]\n\n[GIN] 2022/11/24 - 10:29:04 | 200 |      38.338µs |             ::1 | GET      \"/stream/codec/reowhite\"\n\n[GIN] 2022/11/24 - 10:29:04 | 200 |  195.316064ms |             ::1 | POST     \"/stream/receiver/reowhite\"\n\n[OPTIONS rtsp://192.168.0.203/h264Preview_01_main/ RTSP/1.0CSeq: 6Authorization: Digest username=\"admin\", realm=\"LIVE555 Streaming Media\", nonce=\"82060d0e8391fdf8b0b34cf6ecd66ea7\", uri=\"rtsp://192.168.0.203/h264Preview_01_main/\", response=\"f01cd82bf3b52fc4090179eaa51d69dc\"Require: implicit-playUser-Agent: Lavf58.76.100Session: 4F156EE5]\n\n[OPTIONS rtsp://192.168.0.203/h264Preview_01_main/ RTSP/1.0CSeq: 7Authorization: Digest username=\"admin\", realm=\"LIVE555 Streaming Media\", nonce=\"82060d0e8391fdf8b0b34cf6ecd66ea7\", uri=\"rtsp://192.168.0.203/h264Preview_01_main/\", response=\"f01cd82bf3b52fc4090179eaa51d69dc\"Require: implicit-playUser-Agent: Lavf58.76.100Session: 4F156EE5]\n```\n\n\n\n*Note: Do not post full binary logs in a GitHub issue!*\n\n\u003cbr\u003e\u003chr\u003e\n\n## Using RTSP to HLS\n\n`hls.js`: \u003chttps://github.com/video-dev/hls.js/\u003e  \n`ffmpeg`: \u003chttps://ffmpeg.org/ffmpeg-formats.html#hls-2\u003e\n\n### Transcode to HLS\n\n- Read from RTSP source\n- Just copy video stream without re-encoding it\n- Set HLS low latency mode with total of 5 fragments each 1 sec and use MP4 encapsulation\n- Which means theoretical mininum latency will be 1sec\n\n```shell\nffmpeg -hide_banner -loglevel fatal \\\n  -rtsp_transport tcp -flags -global_header \\\n  -i \"rtsp://user:passowd@url:port/stream\" \\\n  -an -c:v copy -b:v 2048k \\\n  -f hls -lhls 1 -hls_time 1 -hls_wrap 5 -hls_segment_type fmp4 \\\n  \"tmp/stream.m3u8\"\n```\n\n### Test HLS Stream\n\n- Start stream transoding using `ffmpeg ...`\n- Start web server: `node server/serve.js`\n- Navigate to: `https://localhost:8001/client/hls.hmtl`\n\n*Note: Lowest real-world video latency is ~2.5sec*  \n*Targeting lower latency causes (recoverable) buffering issues*\n\n\u003cbr\u003e\u003chr\u003e\n\n## Using RTSP to Dash\n\n- `dash.js`: \u003chttps://github.com/Dash-Industry-Forum/dash.js/\u003e\n- `ffmpeg`: \u003chttps://ffmpeg.org/ffmpeg-formats.html\u003e\n\n### Transcode\n\n- Read from RTSP source\n- Just copy video stream without re-encoding it\n- Set DASH low latency mode with total of 3+1 fragments each 3 sec and use MP4 encapsulation\n- Which means theoretical mininum latency will be 3sec\n\n```shell\nffmpeg -hide_banner -loglevel fatal \\\n  -rtsp_transport tcp -flags -global_header \\\n  -i \"rtsp://user:passowd@url:port/stream\" \\\n  -an -c:v copy -b:v 2048k \\\n  -f dash -window_size 3 -extra_window_size 1 -ldash 1 -seg_duration 3 -frag_duration 1 -target_latency 5 -streaming 1 -remove_at_exit 1 \\\n  \"tmp/stream.mpd\"\n```\n\n### Test\n\n- Start stream transoding using `ffmpeg ...`\n- Start web server: `node server/serve.js`\n- Navigate to: `http://localhost:8001/client/dash.hmtl`\n\n*Note: Lowest real-world video latency is ~6.5sec*  \n*Targeting lower latency does not work with DASH and causes both runtime errors in the library as well as (recoverable) buffering issues*\n\n\u003cbr\u003e\u003chr\u003e\n\n## Future\n\n- Add embedded `ffmpeg` execution to `serve.js`\n- Investigate `ffmpeg` as `wasm`: \u003chttps://github.com/Kagami/ffmpeg.js\u003e\n- Investigate `rtmp` using `media-stream-library-js` or `video.js` or `hls.js`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvladmandic%2Fstream-rtsp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvladmandic%2Fstream-rtsp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvladmandic%2Fstream-rtsp/lists"}