Skip to content

Commit cbe16fa

Browse files
committed
Document Storebaelt live playback reconnaissance
1 parent 4342434 commit cbe16fa

2 files changed

Lines changed: 194 additions & 4 deletions

File tree

docs/research/new-publisher-source-planning/Storebaelt_On_Demand_Live_Webcam_Enhancement_Plan_2026-06-03.md

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
**Date:** 2026-06-03
44
**Scope:** Demand-driven live/HLS enhancement for the Storebaelt webcam publisher and Explorer UI.
5-
**Related background:** `Storebaelt_Webcam_Poster_Integration_Status_and_UX_Options_2026-06-03.md`
5+
**Related background:**
6+
7+
- `Storebaelt_Webcam_Poster_Integration_Status_and_UX_Options_2026-06-03.md`
8+
- `Storebaelt_Phase_2A_Live_Playback_Reconnaissance_2026-06-03.md`
69

710
## Goal
811

@@ -33,6 +36,25 @@ Known source surfaces:
3336

3437
The HLS URLs should still be rediscovered/validated during implementation rather than hard-coded forever, because the provider can change player internals.
3538

39+
## Phase 2A Reconnaissance Outcome
40+
41+
Phase 2A browser/player reconnaissance found that the cheapest live path is viable enough to implement before building backend frame extraction.
42+
43+
Key findings:
44+
45+
- The Storebaelt player pages load in an iframe from the Explorer origin.
46+
- Browser JavaScript cannot `fetch()` the player pages because they do not send CORS headers, but iframe/open-tab usage does not require JS fetch.
47+
- HLS master playlists, variant playlists, `init.mp4`, and `.m4s` media segments are CORS-readable from `https://ogc-csapi-explorer.pages.dev`.
48+
- Chromium/Edge does not report native HLS support through `video.canPlayType(...)`.
49+
- Explorer does not currently include `hls.js`.
50+
51+
Recommendation from this reconnaissance:
52+
53+
1. Implement an Explorer live-video modal using `playerUrl` as an iframe source.
54+
2. Keep opening the provider player in a new tab as a fallback.
55+
3. Treat direct HLS playback with `hls.js` as the next browser-side option.
56+
4. Defer backend HLS frame extraction until the direct browser/player paths are proven insufficient.
57+
3658
## Design Principle
3759

3860
Use a **lease with TTL**.
@@ -145,7 +167,9 @@ Limitations:
145167
- May have iframe or cross-origin restrictions depending on player headers.
146168
- Provides less integrated telemetry than a live lease/status service.
147169

148-
Recommendation: use this as the immediate UX fallback and as a baseline comparison while building the lease-based live service.
170+
Recommendation: use this as the immediate Explorer implementation path and as a baseline comparison before building the lease-based live service.
171+
172+
Phase 2A testing indicates this should be feasible because the provider page loaded successfully in an iframe from the Explorer origin.
149173

150174
## Live Output Options
151175

@@ -266,7 +290,7 @@ Keep poster-source fields in the existing `storebaeltWebcamImage` output so long
266290
- Add fields such as `imageChanged`, `firstSeenTime`, `lastChangedTime`, `lastSeenTime`, `unchangedPollCount`, and `stalenessStatus`.
267291
- Update Explorer to separate `last checked` from `image changed`.
268292

269-
### Phase 2: Live source reconnaissance
293+
### Phase 2A: Live source reconnaissance and iframe player UX
270294

271295
- Inspect the Mediathand/Video.js player network behavior.
272296
- Confirm current HLS playlist paths:
@@ -278,6 +302,14 @@ Keep poster-source fields in the existing `storebaeltWebcamImage` output so long
278302
- Compare poster freshness against HLS segment freshness so the UI can avoid implying that a stale poster means stale live video.
279303
- Measure bandwidth, latency, cache behavior, and segment cadence.
280304
- Decide whether Phase 3 should expose only lease/live status first or also return a validated `hlsPlaylistUrl`.
305+
- Implement the first Explorer live UX as a provider-player iframe modal if embedding remains reliable.
306+
307+
### Phase 2B: Optional direct HLS browser prototype
308+
309+
- Add `hls.js` only if the iframe/player modal is not sufficient.
310+
- Play the CORS-readable HLS playlist in a controlled card/modal video element.
311+
- Keep the provider player URL as fallback.
312+
- Avoid server-side frame extraction during this phase.
281313

282314
### Phase 3: Live lease service prototype
283315

@@ -338,6 +370,8 @@ Keep poster-source fields in the existing `storebaeltWebcamImage` output so long
338370

339371
Phase 1 is now the correct baseline: it makes poster freshness observable and prevents users from mistaking publisher silence for source silence.
340372

341-
For Phase 2, prioritize direct validation of the HLS/player path before building frame extraction. The immediate user need is to reach the real live view when the poster is stale. Frame extraction should remain a later choice, used only if direct player/HLS handoff cannot provide an acceptable Explorer experience or if CSAPI-native live frame observations become a hard requirement.
373+
For Phase 2, prioritize the iframe provider-player modal. The immediate user need is to reach the real live view when the poster is stale, and Phase 2A found that the player page can load in an iframe. Direct HLS with `hls.js` is a plausible second browser-side option because the playlist and segments are CORS-readable, but it should not be the first implementation unless the iframe UX proves inadequate.
374+
375+
Frame extraction should remain a later choice, used only if direct player/HLS handoff cannot provide an acceptable Explorer experience or if CSAPI-native live frame observations become a hard requirement.
342376

343377
Then prototype the lease service with live status only before adding frame extraction. This keeps the design honest, observable, and reversible while preserving a path to a much better webcam experience.
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Storebaelt Phase 2A Live Playback Reconnaissance
2+
3+
**Date:** 2026-06-03
4+
**Scope:** Validate the cheapest live-video paths before building backend HLS lease/frame extraction services.
5+
6+
## Summary
7+
8+
The Storebaelt player and HLS source are usable enough that Explorer should try a direct live UX before any server-side frame extraction work.
9+
10+
Recommended next implementation path:
11+
12+
1. Add an Explorer `Open Live Video` modal/panel that embeds the Storebaelt player page in an iframe.
13+
2. Keep the current external `Open Live Video` link as fallback.
14+
3. Treat direct HLS playback with `hls.js` as the next option if we want a fully native in-card player.
15+
4. Defer backend HLS frame extraction until direct iframe/player and browser HLS options are proven insufficient.
16+
17+
## Tested Source Surfaces
18+
19+
| Camera | Player page | HLS playlist | Poster JPEG |
20+
| --- | --- | --- | --- |
21+
| Storebaelt Tower | `https://player.sob.m-dn.net/sb1-live.html` | `https://stream.sob.m-dn.net/live/sb1/index.m3u8` | `https://stream.sob.m-dn.net/res/sb1-live.jpg` |
22+
| Sprogo | `https://player.sob.m-dn.net/sb2-live.html` | `https://stream.sob.m-dn.net/live/sb2/index.m3u8` | `https://stream.sob.m-dn.net/res/sb2-live.jpg` |
23+
24+
Player page source confirms that the poster image and live stream are separate resources:
25+
26+
```html
27+
<video poster="//stream.sob.m-dn.net/res/sb1-live.jpg">
28+
<source src="//stream.sob.m-dn.net/live/sb1/index.m3u8" type="application/vnd.apple.mpegurl">
29+
</video>
30+
```
31+
32+
The same structure exists for `sb2`.
33+
34+
## Header and Browser Findings
35+
36+
### Player pages
37+
38+
Observed headers for `sb1-live.html` and `sb2-live.html`:
39+
40+
- `200 OK`
41+
- `Content-Type: text/html; charset=UTF-8`
42+
- `Server: Netlify`
43+
- No `X-Frame-Options` header observed.
44+
- No blocking `Content-Security-Policy` frame directive observed in the header probe.
45+
- JavaScript `fetch()` from `https://ogc-csapi-explorer.pages.dev` is blocked by CORS because the player page does not send `Access-Control-Allow-Origin`.
46+
- Embedding as an iframe from the Explorer origin loaded successfully in browser testing.
47+
48+
Interpretation: Explorer should not fetch or parse the player page from browser code, but it can likely embed or open it as a live-video surface.
49+
50+
### HLS playlists
51+
52+
Observed headers for `index.m3u8`:
53+
54+
- `200 OK`
55+
- `Content-Type: application/vnd.apple.mpegurl`
56+
- `Cache-Control: public, max-age=1`
57+
- `Server: MDN`
58+
59+
Browser-origin `fetch()` from `https://ogc-csapi-explorer.pages.dev` succeeded for:
60+
61+
- master playlist
62+
- variant playlist
63+
- `init.mp4`
64+
- `.m4s` media segments
65+
66+
Browser fetch result type was `cors`, which means the stream resources are readable by browser-side HLS code.
67+
68+
### Native browser playback
69+
70+
Chromium reported no native support for `application/vnd.apple.mpegurl` / HLS through `video.canPlayType(...)`.
71+
72+
Interpretation: a plain `<video src="...index.m3u8">` should not be relied on for desktop Chromium/Edge. Direct in-card HLS playback would require `hls.js` or equivalent Media Source Extensions support.
73+
74+
## Playlist Shape
75+
76+
The HLS master playlists advertise multiple variants, including:
77+
78+
- 288x162 low-bandwidth variants
79+
- 416x234
80+
- 640x360
81+
- 1024x576
82+
- 1280x720
83+
84+
The first variant playlist inspected contained:
85+
86+
- `#EXT-X-TARGETDURATION:6`
87+
- `#EXT-X-PROGRAM-DATE-TIME`, for example `2026-06-03T22:07:40.239Z`
88+
- `#EXT-X-MAP:URI="init.mp4"`
89+
- 6-second `.m4s` segments such as `33097.m4s`
90+
91+
Example segment headers:
92+
93+
- `200 OK`
94+
- `Content-Type: video/iso.segment`
95+
- `Cache-Control: public, max-age=120`
96+
97+
## Explorer Dependency Check
98+
99+
`demo/package.json` does not currently include `hls.js` or another HLS playback library.
100+
101+
That means:
102+
103+
- iframe/player modal is the lowest-risk, zero-dependency live UX;
104+
- direct HLS in a native card player requires adding a new dependency and player lifecycle code;
105+
- server-side extraction is not justified as the immediate next step.
106+
107+
## Recommended Implementation Decision
108+
109+
### First implementation: iframe/player modal
110+
111+
Add a webcam live-video modal in Explorer:
112+
113+
- Triggered by the existing `Open Live Video` action.
114+
- Uses `cameraPlayerUrl` as the iframe source.
115+
- Keeps `target="_blank"` fallback behavior available.
116+
- Leaves poster freshness visible behind or below the live player.
117+
- Labels the iframe/live view as provider live video, separate from CSAPI poster status.
118+
119+
Rationale:
120+
121+
- Uses the provider's intended player.
122+
- Avoids adding `hls.js` immediately.
123+
- Avoids backend compute and bandwidth.
124+
- Directly answers the user confusion: the live video can be opened without implying the poster is live.
125+
126+
### Second implementation option: direct HLS with `hls.js`
127+
128+
If iframe UX is not acceptable, add `hls.js` and play `hlsPlaylistUrl` directly in the card or modal.
129+
130+
This is technically plausible because playlists and segments are CORS-readable from Explorer's origin. It would require:
131+
132+
- adding `hls.js` to `demo/package.json`;
133+
- player lifecycle handling in Vue;
134+
- choosing quality/ABR defaults;
135+
- error handling and fallback to player page;
136+
- possibly adding `hlsPlaylistUrl` to the Storebaelt poster observation payload or deriving it client-side from known camera IDs.
137+
138+
### Defer: backend frame extraction
139+
140+
Server-side HLS frame extraction should remain deferred unless:
141+
142+
- iframe embedding fails operationally;
143+
- direct HLS playback with `hls.js` fails;
144+
- CSAPI-native live frame observations become an explicit requirement;
145+
- we need server-side snapshots for clients that cannot play video.
146+
147+
## Recommended Plan Update
148+
149+
Phase 2 should be split into:
150+
151+
- **Phase 2A:** Browser/player reconnaissance and Explorer iframe live modal.
152+
- **Phase 2B:** Optional direct HLS prototype with `hls.js`.
153+
- **Phase 3:** Lease/live status service, without frame extraction by default.
154+
- **Phase 4:** Backend frame extraction only if the direct live paths are insufficient.
155+
156+
This keeps the live path useful, understandable, and low-cost while preserving the lease architecture for later operational control.

0 commit comments

Comments
 (0)