mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-12-04 14:37:19 -05:00
pass prev duration and runs through API layer
Builds on f3ddbfe, for #32 and #59.
This commit is contained in:
29
src/mp4.rs
29
src/mp4.rs
@@ -550,6 +550,7 @@ pub struct FileBuilder {
|
||||
subtitle_co64_pos: Option<usize>,
|
||||
body: BodyState,
|
||||
type_: Type,
|
||||
prev_duration_and_cur_runs: Option<(recording::Duration, i32)>,
|
||||
include_timestamp_subtitle_track: bool,
|
||||
content_disposition: Option<HeaderValue>,
|
||||
}
|
||||
@@ -736,6 +737,7 @@ impl FileBuilder {
|
||||
type_: type_,
|
||||
include_timestamp_subtitle_track: false,
|
||||
content_disposition: None,
|
||||
prev_duration_and_cur_runs: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,6 +765,11 @@ impl FileBuilder {
|
||||
"unable to append recording {} after recording {} with trailing zero",
|
||||
row.id, prev.s.id);
|
||||
}
|
||||
} else {
|
||||
// Include the current run in this count here, as we're not propagating the
|
||||
// run_offset_id further.
|
||||
self.prev_duration_and_cur_runs = row.prev_duration_and_runs
|
||||
.map(|(d, r)| (d, r + if row.open_id == 0 { 1 } else { 0 }));
|
||||
}
|
||||
let s = Segment::new(db, &row, rel_range_90k, self.next_frame_num)?;
|
||||
|
||||
@@ -899,6 +906,8 @@ impl FileBuilder {
|
||||
etag: HeaderValue::try_from(format!("\"{}\"", etag.to_hex().as_str()))
|
||||
.expect("hex string should be valid UTF-8"),
|
||||
content_disposition: self.content_disposition,
|
||||
prev_duration_and_cur_runs: self.prev_duration_and_cur_runs,
|
||||
type_: self.type_,
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -1447,6 +1456,8 @@ struct FileInner {
|
||||
last_modified: SystemTime,
|
||||
etag: HeaderValue,
|
||||
content_disposition: Option<HeaderValue>,
|
||||
prev_duration_and_cur_runs: Option<(recording::Duration, i32)>,
|
||||
type_: Type,
|
||||
}
|
||||
|
||||
impl FileInner {
|
||||
@@ -1553,6 +1564,24 @@ impl http_serve::Entity for File {
|
||||
if let Some(cd) = self.0.content_disposition.as_ref() {
|
||||
hdrs.insert(http::header::CONTENT_DISPOSITION, cd.clone());
|
||||
}
|
||||
if self.0.type_ == Type::MediaSegment {
|
||||
if let Some((d, r)) = self.0.prev_duration_and_cur_runs {
|
||||
hdrs.insert(
|
||||
"X-Prev-Duration",
|
||||
HeaderValue::try_from(d.0.to_string()).expect("ints are valid headers"));
|
||||
hdrs.insert(
|
||||
"X-Runs",
|
||||
HeaderValue::try_from(r.to_string()).expect("ints are valid headers"));
|
||||
}
|
||||
if let Some(s) = self.0.segments.first() {
|
||||
let skip = s.s.desired_range_90k.start - s.s.actual_start_90k();
|
||||
if skip > 0 {
|
||||
hdrs.insert(
|
||||
"X-Leading-Duration",
|
||||
HeaderValue::try_from(skip.to_string()).expect("ints are valid headers"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn last_modified(&self) -> Option<SystemTime> { Some(self.0.last_modified) }
|
||||
fn etag(&self) -> Option<HeaderValue> { Some(self.0.etag.clone()) }
|
||||
|
||||
21
src/web.rs
21
src/web.rs
@@ -440,15 +440,13 @@ impl Service {
|
||||
ws: &mut tokio_tungstenite::WebSocketStream<hyper::upgrade::Upgraded>,
|
||||
live: db::LiveSegment) -> Result<(), Error> {
|
||||
let mut builder = mp4::FileBuilder::new(mp4::Type::MediaSegment);
|
||||
let mut vse_id = None;
|
||||
let mut start = None;
|
||||
let mut row = None;
|
||||
{
|
||||
let db = self.db.lock();
|
||||
let mut rows = 0;
|
||||
db.list_recordings_by_id(stream_id, live.recording .. live.recording+1, &mut |r| {
|
||||
rows += 1;
|
||||
vse_id = Some(r.video_sample_entry_id);
|
||||
start = Some(r.start);
|
||||
row = Some(r);
|
||||
builder.append(&db, r, live.off_90k.clone())?;
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -456,29 +454,32 @@ impl Service {
|
||||
bail_t!(Internal, "unable to find {:?}", live);
|
||||
}
|
||||
}
|
||||
let vse_id = vse_id.unwrap();
|
||||
let start = start.unwrap();
|
||||
let row = row.unwrap();
|
||||
use http_serve::Entity;
|
||||
let mp4 = builder.build(self.db.clone(), self.dirs_by_stream_id.clone())?;
|
||||
let mut hdrs = header::HeaderMap::new();
|
||||
mp4.add_headers(&mut hdrs);
|
||||
let mime_type = hdrs.get(header::CONTENT_TYPE).unwrap();
|
||||
let (prev_duration, prev_runs) = row.prev_duration_and_runs.unwrap();
|
||||
let hdr = format!(
|
||||
"Content-Type: {}\r\n\
|
||||
X-Recording-Start: {}\r\n\
|
||||
X-Recording-Id: {}.{}\r\n\
|
||||
X-Time-Range: {}-{}\r\n\
|
||||
X-Prev-Duration: {}\r\n\
|
||||
X-Runs: {}\r\n\
|
||||
X-Video-Sample-Entry-Id: {}\r\n\r\n",
|
||||
mime_type.to_str().unwrap(),
|
||||
start.0,
|
||||
row.start.0,
|
||||
open_id,
|
||||
live.recording,
|
||||
live.off_90k.start,
|
||||
live.off_90k.end,
|
||||
&vse_id);
|
||||
let mut v = /*Pin::from(*/hdr.into_bytes()/*)*/;
|
||||
prev_duration.0,
|
||||
prev_runs + if row.run_offset == 0 { 1 } else { 0 },
|
||||
&row.video_sample_entry_id);
|
||||
let mut v = hdr.into_bytes();
|
||||
mp4.append_into_vec(&mut v).await?;
|
||||
//let v = Pin::into_inner();
|
||||
ws.send(tungstenite::Message::Binary(v)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user