mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-11-20 09:56:07 -05:00
store full rtsp urls
My dad's "GW-GW4089IP" cameras use separate ports for the main and sub streams: rtsp://192.168.1.110:5050/H264?channel=0&subtype=0&unicast=true&proto=Onvif rtsp://192.168.1.110:5049/H264?channel=0&subtype=1&unicast=true&proto=Onvif Previously I could get one of the streams to work by including :5050 or :5049 in the host field of the camera. But not both. Now make the camera's host field reflect the ONVIF port (which is also non-standard on these cameras, :85). It's not directly used yet but probably will be sooner or later. Make each stream know its full URL.
This commit is contained in:
62
db/db.rs
62
db/db.rs
@@ -348,7 +348,7 @@ pub struct Camera {
|
||||
pub uuid: Uuid,
|
||||
pub short_name: String,
|
||||
pub description: String,
|
||||
pub host: String,
|
||||
pub onvif_host: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub streams: [Option<i32>; 2],
|
||||
@@ -402,7 +402,7 @@ pub struct Stream {
|
||||
pub camera_id: i32,
|
||||
pub sample_file_dir_id: Option<i32>,
|
||||
pub type_: StreamType,
|
||||
pub rtsp_path: String,
|
||||
pub rtsp_url: String,
|
||||
pub retain_bytes: i64,
|
||||
pub flush_if_sec: i64,
|
||||
|
||||
@@ -465,7 +465,7 @@ pub struct LiveSegment {
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct StreamChange {
|
||||
pub sample_file_dir_id: Option<i32>,
|
||||
pub rtsp_path: String,
|
||||
pub rtsp_url: String,
|
||||
pub record: bool,
|
||||
pub flush_if_sec: i64,
|
||||
}
|
||||
@@ -475,7 +475,7 @@ pub struct StreamChange {
|
||||
pub struct CameraChange {
|
||||
pub short_name: String,
|
||||
pub description: String,
|
||||
pub host: String,
|
||||
pub onvif_host: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
|
||||
@@ -678,7 +678,7 @@ impl StreamStateChanger {
|
||||
d, sc.sample_file_dir_id, sid);
|
||||
}
|
||||
}
|
||||
if !have_data && sc.rtsp_path.is_empty() && sc.sample_file_dir_id.is_none() &&
|
||||
if !have_data && sc.rtsp_url.is_empty() && sc.sample_file_dir_id.is_none() &&
|
||||
!sc.record {
|
||||
// Delete stream.
|
||||
let mut stmt = tx.prepare_cached(r#"
|
||||
@@ -692,7 +692,7 @@ impl StreamStateChanger {
|
||||
// Update stream.
|
||||
let mut stmt = tx.prepare_cached(r#"
|
||||
update stream set
|
||||
rtsp_path = :rtsp_path,
|
||||
rtsp_url = :rtsp_url,
|
||||
record = :record,
|
||||
flush_if_sec = :flush_if_sec,
|
||||
sample_file_dir_id = :sample_file_dir_id
|
||||
@@ -700,7 +700,7 @@ impl StreamStateChanger {
|
||||
id = :id
|
||||
"#)?;
|
||||
let rows = stmt.execute_named(&[
|
||||
(":rtsp_path", &sc.rtsp_path),
|
||||
(":rtsp_url", &sc.rtsp_url),
|
||||
(":record", &sc.record),
|
||||
(":flush_if_sec", &sc.flush_if_sec),
|
||||
(":sample_file_dir_id", &sc.sample_file_dir_id),
|
||||
@@ -714,22 +714,22 @@ impl StreamStateChanger {
|
||||
streams.push((sid, Some((camera_id, type_, sc))));
|
||||
}
|
||||
} else {
|
||||
if sc.rtsp_path.is_empty() && sc.sample_file_dir_id.is_none() && !sc.record {
|
||||
if sc.rtsp_url.is_empty() && sc.sample_file_dir_id.is_none() && !sc.record {
|
||||
// Do nothing; there is no record and we want to keep it that way.
|
||||
continue;
|
||||
}
|
||||
// Insert stream.
|
||||
let mut stmt = tx.prepare_cached(r#"
|
||||
insert into stream (camera_id, sample_file_dir_id, type, rtsp_path, record,
|
||||
insert into stream (camera_id, sample_file_dir_id, type, rtsp_url, record,
|
||||
retain_bytes, flush_if_sec, next_recording_id)
|
||||
values (:camera_id, :sample_file_dir_id, :type, :rtsp_path, :record,
|
||||
values (:camera_id, :sample_file_dir_id, :type, :rtsp_url, :record,
|
||||
0, :flush_if_sec, 1)
|
||||
"#)?;
|
||||
stmt.execute_named(&[
|
||||
(":camera_id", &camera_id),
|
||||
(":sample_file_dir_id", &sc.sample_file_dir_id),
|
||||
(":type", &type_.as_str()),
|
||||
(":rtsp_path", &sc.rtsp_path),
|
||||
(":rtsp_url", &sc.rtsp_url),
|
||||
(":record", &sc.record),
|
||||
(":flush_if_sec", &sc.flush_if_sec),
|
||||
])?;
|
||||
@@ -757,7 +757,7 @@ impl StreamStateChanger {
|
||||
type_,
|
||||
camera_id,
|
||||
sample_file_dir_id: sc.sample_file_dir_id,
|
||||
rtsp_path: mem::replace(&mut sc.rtsp_path, String::new()),
|
||||
rtsp_url: mem::replace(&mut sc.rtsp_url, String::new()),
|
||||
retain_bytes: 0,
|
||||
flush_if_sec: sc.flush_if_sec,
|
||||
range: None,
|
||||
@@ -778,7 +778,7 @@ impl StreamStateChanger {
|
||||
(Entry::Occupied(e), Some((_, _, sc))) => {
|
||||
let e = e.into_mut();
|
||||
e.sample_file_dir_id = sc.sample_file_dir_id;
|
||||
e.rtsp_path = sc.rtsp_path;
|
||||
e.rtsp_url = sc.rtsp_url;
|
||||
e.record = sc.record;
|
||||
e.flush_if_sec = sc.flush_if_sec;
|
||||
},
|
||||
@@ -1401,7 +1401,7 @@ impl LockedDatabase {
|
||||
uuid,
|
||||
short_name,
|
||||
description,
|
||||
host,
|
||||
onvif_host,
|
||||
username,
|
||||
password
|
||||
from
|
||||
@@ -1416,7 +1416,7 @@ impl LockedDatabase {
|
||||
uuid: uuid.0,
|
||||
short_name: row.get(2)?,
|
||||
description: row.get(3)?,
|
||||
host: row.get(4)?,
|
||||
onvif_host: row.get(4)?,
|
||||
username: row.get(5)?,
|
||||
password: row.get(6)?,
|
||||
streams: Default::default(),
|
||||
@@ -1437,7 +1437,7 @@ impl LockedDatabase {
|
||||
type,
|
||||
camera_id,
|
||||
sample_file_dir_id,
|
||||
rtsp_path,
|
||||
rtsp_url,
|
||||
retain_bytes,
|
||||
flush_if_sec,
|
||||
next_recording_id,
|
||||
@@ -1463,7 +1463,7 @@ impl LockedDatabase {
|
||||
type_,
|
||||
camera_id,
|
||||
sample_file_dir_id: row.get(3)?,
|
||||
rtsp_path: row.get(4)?,
|
||||
rtsp_url: row.get(4)?,
|
||||
retain_bytes: row.get(5)?,
|
||||
flush_if_sec,
|
||||
range: None,
|
||||
@@ -1618,14 +1618,16 @@ impl LockedDatabase {
|
||||
let camera_id;
|
||||
{
|
||||
let mut stmt = tx.prepare_cached(r#"
|
||||
insert into camera (uuid, short_name, description, host, username, password)
|
||||
values (:uuid, :short_name, :description, :host, :username, :password)
|
||||
insert into camera (uuid, short_name, description, onvif_host, username,
|
||||
password)
|
||||
values (:uuid, :short_name, :description, :onvif_host, :username,
|
||||
:password)
|
||||
"#)?;
|
||||
stmt.execute_named(&[
|
||||
(":uuid", &uuid_bytes),
|
||||
(":short_name", &camera.short_name),
|
||||
(":description", &camera.description),
|
||||
(":host", &camera.host),
|
||||
(":onvif_host", &camera.onvif_host),
|
||||
(":username", &camera.username),
|
||||
(":password", &camera.password),
|
||||
])?;
|
||||
@@ -1640,7 +1642,7 @@ impl LockedDatabase {
|
||||
uuid,
|
||||
short_name: camera.short_name,
|
||||
description: camera.description,
|
||||
host: camera.host,
|
||||
onvif_host: camera.onvif_host,
|
||||
username: camera.username,
|
||||
password: camera.password,
|
||||
streams,
|
||||
@@ -1664,7 +1666,7 @@ impl LockedDatabase {
|
||||
update camera set
|
||||
short_name = :short_name,
|
||||
description = :description,
|
||||
host = :host,
|
||||
onvif_host = :onvif_host,
|
||||
username = :username,
|
||||
password = :password
|
||||
where
|
||||
@@ -1674,7 +1676,7 @@ impl LockedDatabase {
|
||||
(":id", &camera_id),
|
||||
(":short_name", &camera.short_name),
|
||||
(":description", &camera.description),
|
||||
(":host", &camera.host),
|
||||
(":onvif_host", &camera.onvif_host),
|
||||
(":username", &camera.username),
|
||||
(":password", &camera.password),
|
||||
])?;
|
||||
@@ -1685,7 +1687,7 @@ impl LockedDatabase {
|
||||
tx.commit()?;
|
||||
c.short_name = camera.short_name;
|
||||
c.description = camera.description;
|
||||
c.host = camera.host;
|
||||
c.onvif_host = camera.onvif_host;
|
||||
c.username = camera.username;
|
||||
c.password = camera.password;
|
||||
c.streams = streams.apply(&mut self.streams_by_id);
|
||||
@@ -2036,11 +2038,11 @@ mod tests {
|
||||
rows += 1;
|
||||
camera_id = row.id;
|
||||
assert_eq!(uuid, row.uuid);
|
||||
assert_eq!("test-camera", row.host);
|
||||
assert_eq!("test-camera", row.onvif_host);
|
||||
assert_eq!("foo", row.username);
|
||||
assert_eq!("bar", row.password);
|
||||
//assert_eq!("/main", row.main_rtsp_path);
|
||||
//assert_eq!("/sub", row.sub_rtsp_path);
|
||||
//assert_eq!("/main", row.main_rtsp_url);
|
||||
//assert_eq!("/sub", row.sub_rtsp_url);
|
||||
//assert_eq!(42, row.retain_bytes);
|
||||
//assert_eq!(None, row.range);
|
||||
//assert_eq!(recording::Duration(0), row.duration);
|
||||
@@ -2225,19 +2227,19 @@ mod tests {
|
||||
let mut c = CameraChange {
|
||||
short_name: "testcam".to_owned(),
|
||||
description: "".to_owned(),
|
||||
host: "test-camera".to_owned(),
|
||||
onvif_host: "test-camera".to_owned(),
|
||||
username: "foo".to_owned(),
|
||||
password: "bar".to_owned(),
|
||||
streams: [
|
||||
StreamChange {
|
||||
sample_file_dir_id: Some(sample_file_dir_id),
|
||||
rtsp_path: "/main".to_owned(),
|
||||
rtsp_url: "rtsp://test-camera/main".to_owned(),
|
||||
record: false,
|
||||
flush_if_sec: 1,
|
||||
},
|
||||
StreamChange {
|
||||
sample_file_dir_id: Some(sample_file_dir_id),
|
||||
rtsp_path: "/sub".to_owned(),
|
||||
rtsp_url: "rtsp://test-camera/sub".to_owned(),
|
||||
record: true,
|
||||
flush_if_sec: 1,
|
||||
},
|
||||
|
||||
@@ -94,8 +94,11 @@ create table camera (
|
||||
-- A short description of the camera.
|
||||
description text,
|
||||
|
||||
-- The host (or IP address) to use in rtsp:// URLs when accessing the camera.
|
||||
host text,
|
||||
-- The host part of the http:// URL when accessing ONVIF, optionally
|
||||
-- including ":<port>". Eg with ONVIF host "192.168.1.110:85", the full URL
|
||||
-- of the devie management service will be
|
||||
-- "http://192.168.1.110:85/device_service".
|
||||
onvif_host text,
|
||||
|
||||
-- The username to use when accessing the camera.
|
||||
-- If empty, no username or password will be supplied.
|
||||
@@ -116,8 +119,9 @@ create table stream (
|
||||
-- will not be deleted.
|
||||
record integer not null check (record in (1, 0)),
|
||||
|
||||
-- The path (starting with "/") to use in rtsp:// URLs to for this stream.
|
||||
rtsp_path text not null,
|
||||
-- The rtsp:// URL to use for this stream, excluding username and password.
|
||||
-- (Those are taken from the camera row's respective fields.)
|
||||
rtsp_url text not null,
|
||||
|
||||
-- The number of bytes of video to retain, excluding the currently-recording
|
||||
-- file. Older files will be deleted as necessary to stay within this limit.
|
||||
|
||||
@@ -96,13 +96,13 @@ impl<C: Clocks + Clone> TestDb<C> {
|
||||
assert_eq!(TEST_CAMERA_ID, l.add_camera(db::CameraChange {
|
||||
short_name: "test camera".to_owned(),
|
||||
description: "".to_owned(),
|
||||
host: "test-camera".to_owned(),
|
||||
onvif_host: "test-camera".to_owned(),
|
||||
username: "foo".to_owned(),
|
||||
password: "bar".to_owned(),
|
||||
streams: [
|
||||
db::StreamChange {
|
||||
sample_file_dir_id: Some(sample_file_dir_id),
|
||||
rtsp_path: "/main".to_owned(),
|
||||
rtsp_url: "rtsp://test-camera/main".to_owned(),
|
||||
record: true,
|
||||
flush_if_sec,
|
||||
},
|
||||
|
||||
@@ -70,6 +70,57 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
-- behavior. Newly created users won't have prepopulated permissions like this.
|
||||
update user set permissions = X'0801';
|
||||
update user_session set permissions = X'0801';
|
||||
|
||||
alter table stream rename to old_stream;
|
||||
create table stream (
|
||||
id integer primary key,
|
||||
camera_id integer not null references camera (id),
|
||||
sample_file_dir_id integer references sample_file_dir (id),
|
||||
type text not null check (type in ('main', 'sub')),
|
||||
record integer not null check (record in (1, 0)),
|
||||
rtsp_url text not null,
|
||||
retain_bytes integer not null check (retain_bytes >= 0),
|
||||
flush_if_sec integer not null,
|
||||
next_recording_id integer not null check (next_recording_id >= 0),
|
||||
unique (camera_id, type)
|
||||
);
|
||||
insert into stream
|
||||
select
|
||||
s.id,
|
||||
s.camera_id,
|
||||
s.sample_file_dir_id,
|
||||
s.type,
|
||||
s.record,
|
||||
'rtsp://' || c.host || s.rtsp_path as rtsp_url,
|
||||
retain_bytes,
|
||||
flush_if_sec,
|
||||
next_recording_id
|
||||
from
|
||||
old_stream s join camera c on (s.camera_id = c.id);
|
||||
drop table old_stream;
|
||||
|
||||
alter table camera rename to old_camera;
|
||||
create table camera (
|
||||
id integer primary key,
|
||||
uuid blob unique not null check (length(uuid) = 16),
|
||||
short_name text not null,
|
||||
description text,
|
||||
onvif_host text,
|
||||
username text,
|
||||
password text
|
||||
);
|
||||
insert into camera
|
||||
select
|
||||
id,
|
||||
uuid,
|
||||
short_name,
|
||||
description,
|
||||
host,
|
||||
username,
|
||||
password
|
||||
from
|
||||
old_camera;
|
||||
drop table old_camera;
|
||||
"#)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user