mirror of
https://github.com/eduard256/Strix
synced 2026-04-21 13:37:27 +00:00
Add ONVIF stream handler for tester
- Add testOnvif(): resolves all profiles via ONVIF client, tests each RTSP stream, returns two Results per profile (onvif + rtsp) with shared screenshot - Route onvif:// URLs in worker.go alongside homekit:// - Classify onvif:// streams as recommended in test.html - Harden create.html against undefined/null URL values
This commit is contained in:
parent
ce4b777e98
commit
0fb7356a5e
4 changed files with 118 additions and 8 deletions
104
pkg/tester/source_onvif.go
Normal file
104
pkg/tester/source_onvif.go
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
package tester
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/onvif"
|
||||
)
|
||||
|
||||
// testOnvif resolves all ONVIF profiles, tests each via RTSP,
|
||||
// and adds two Results per profile (onvif:// + rtsp://).
|
||||
// ex. "onvif://admin:pass@10.0.20.111" or "onvif://admin:pass@10.0.20.119:2020"
|
||||
func testOnvif(s *Session, rawURL string) {
|
||||
client, err := onvif.NewClient(rawURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tokens, err := client.GetProfilesTokens()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, token := range tokens {
|
||||
profileURL := rawURL + "?subtype=" + token
|
||||
|
||||
pc, err := onvif.NewClient(profileURL)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
rtspURI, err := pc.GetURI()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
testOnvifProfile(s, profileURL, rtspURI)
|
||||
}
|
||||
}
|
||||
|
||||
// testOnvifProfile tests a single RTSP stream and adds two Results (onvif + rtsp)
|
||||
func testOnvifProfile(s *Session, onvifURL, rtspURL string) {
|
||||
start := time.Now()
|
||||
|
||||
prod, err := rtspHandler(rtspURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() { _ = prod.Stop() }()
|
||||
|
||||
latency := time.Since(start).Milliseconds()
|
||||
|
||||
var codecs []string
|
||||
for _, media := range prod.GetMedias() {
|
||||
if media.Direction != core.DirectionRecvonly {
|
||||
continue
|
||||
}
|
||||
for _, codec := range media.Codecs {
|
||||
codecs = append(codecs, codec.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// capture screenshot
|
||||
var screenshotPath string
|
||||
var width, height int
|
||||
|
||||
if raw, codecName := getScreenshot(prod); raw != nil {
|
||||
var jpeg []byte
|
||||
|
||||
switch codecName {
|
||||
case core.CodecH264, core.CodecH265:
|
||||
jpeg = toJPEG(raw)
|
||||
default:
|
||||
jpeg = raw
|
||||
}
|
||||
|
||||
if jpeg != nil {
|
||||
idx := s.AddScreenshot(jpeg)
|
||||
screenshotPath = fmt.Sprintf("api/test/screenshot?id=%s&i=%d", s.ID, idx)
|
||||
width, height = jpegSize(jpeg)
|
||||
}
|
||||
}
|
||||
|
||||
// add onvif:// result
|
||||
s.AddResult(&Result{
|
||||
Source: onvifURL,
|
||||
Screenshot: screenshotPath,
|
||||
Codecs: codecs,
|
||||
Width: width,
|
||||
Height: height,
|
||||
LatencyMs: latency,
|
||||
})
|
||||
|
||||
// add rtsp:// result (same screenshot, same codecs)
|
||||
s.AddResult(&Result{
|
||||
Source: rtspURL,
|
||||
Screenshot: screenshotPath,
|
||||
Codecs: codecs,
|
||||
Width: width,
|
||||
Height: height,
|
||||
LatencyMs: latency,
|
||||
})
|
||||
}
|
||||
|
|
@ -56,6 +56,11 @@ func testURL(s *Session, rawURL string) {
|
|||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(rawURL, "onvif://") {
|
||||
testOnvif(s, rawURL)
|
||||
return
|
||||
}
|
||||
|
||||
handler := GetHandler(rawURL)
|
||||
if handler == nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -328,8 +328,9 @@
|
|||
|
||||
// Pre-populate custom streams from "url" query parameter (supports multiple)
|
||||
params.getAll('url').forEach(function(u) {
|
||||
if (!u || typeof u !== 'string') return;
|
||||
u = u.trim();
|
||||
if (u && u.indexOf('://') !== -1 && customStreams.indexOf(u) === -1) {
|
||||
if (u && u !== 'undefined' && u !== 'null' && u.indexOf('://') !== -1 && customStreams.indexOf(u) === -1) {
|
||||
customStreams.push(u);
|
||||
}
|
||||
});
|
||||
|
|
@ -395,7 +396,7 @@
|
|||
addInput.type = 'text';
|
||||
addInput.placeholder = 'rtsp://user:pass@host/path or bubble://...';
|
||||
addInput.spellcheck = false;
|
||||
addInput.value = pendingInput;
|
||||
addInput.value = pendingInput || '';
|
||||
|
||||
var addBtn = document.createElement('button');
|
||||
addBtn.className = 'btn-add';
|
||||
|
|
@ -404,7 +405,7 @@
|
|||
|
||||
function addCustom() {
|
||||
var v = addInput.value.trim();
|
||||
if (!v) return;
|
||||
if (!v || v === 'undefined' || v === 'null') return;
|
||||
if (v.indexOf('://') === -1) {
|
||||
showToast('URL must include protocol (rtsp://, http://, bubble://, ...)');
|
||||
return;
|
||||
|
|
@ -592,7 +593,7 @@
|
|||
addInput.type = 'text';
|
||||
addInput.placeholder = 'rtsp://user:pass@host/path or bubble://...';
|
||||
addInput.spellcheck = false;
|
||||
addInput.value = pendingInput;
|
||||
addInput.value = pendingInput || '';
|
||||
var addBtn = document.createElement('button');
|
||||
addBtn.className = 'btn-add';
|
||||
addBtn.type = 'button';
|
||||
|
|
@ -600,7 +601,7 @@
|
|||
|
||||
function addCustom() {
|
||||
var v = addInput.value.trim();
|
||||
if (!v) return;
|
||||
if (!v || v === 'undefined' || v === 'null') return;
|
||||
if (v.indexOf('://') === -1) { showToast('URL must include protocol (rtsp://, http://, bubble://, ...)'); return; }
|
||||
if (customStreams.indexOf(v) !== -1 || dbStreams.indexOf(v) !== -1) { showToast('This URL is already in the list'); return; }
|
||||
customStreams.push(v);
|
||||
|
|
|
|||
|
|
@ -423,11 +423,11 @@
|
|||
|
||||
function classifyResult(r) {
|
||||
var scheme = r.source.split('://')[0] || '';
|
||||
var isRtsp = scheme === 'rtsp' || scheme === 'rtsps';
|
||||
var isRecommended = scheme === 'rtsp' || scheme === 'rtsps' || scheme === 'onvif';
|
||||
var isHD = r.width >= 1280;
|
||||
|
||||
if (isRtsp && isHD) return 'rec-main';
|
||||
if (isRtsp) return 'rec-sub';
|
||||
if (isRecommended && isHD) return 'rec-main';
|
||||
if (isRecommended) return 'rec-sub';
|
||||
return 'alt';
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue