mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2024-12-25 22:55:55 -05:00
increment sequence number on live stream endpoint
This is an experiment to see if helps with #203.
This commit is contained in:
parent
a6bdf0bd80
commit
28cd864f94
@ -864,7 +864,7 @@ macro_rules! write_length {
|
||||
pub enum Type {
|
||||
Normal,
|
||||
InitSegment,
|
||||
MediaSegment,
|
||||
MediaSegment { sequence_number: u32 },
|
||||
}
|
||||
|
||||
impl FileBuilder {
|
||||
@ -891,7 +891,7 @@ impl FileBuilder {
|
||||
/// Sets if the generated `.mp4` should include a subtitle track with second-level timestamps.
|
||||
/// Default is false.
|
||||
pub fn include_timestamp_subtitle_track(&mut self, b: bool) -> Result<(), Error> {
|
||||
if b && self.type_ == Type::MediaSegment {
|
||||
if b && matches!(self.type_, Type::MediaSegment { .. }) {
|
||||
// There's no support today for timestamp truns or for timestamps without edit lists.
|
||||
// The latter would invalidate the code's assumption that desired timespan == actual
|
||||
// timespan in the timestamp track.
|
||||
@ -992,8 +992,9 @@ impl FileBuilder {
|
||||
Type::InitSegment => {
|
||||
etag.update(b":init:");
|
||||
}
|
||||
Type::MediaSegment => {
|
||||
Type::MediaSegment { sequence_number } => {
|
||||
etag.update(b":media:");
|
||||
etag.update(&sequence_number.to_be_bytes()[..]);
|
||||
}
|
||||
};
|
||||
for s in &mut self.segments {
|
||||
@ -1002,7 +1003,7 @@ impl FileBuilder {
|
||||
// Add the media time for this segment. If edit lists are supported (not media
|
||||
// segments), this shouldn't include the portion they skip.
|
||||
let start = match self.type_ {
|
||||
Type::MediaSegment => s.s.actual_start_90k(),
|
||||
Type::MediaSegment { .. } => s.s.actual_start_90k(),
|
||||
_ => md.start,
|
||||
};
|
||||
self.media_duration_90k += u64::try_from(md.end - start).unwrap();
|
||||
@ -1055,8 +1056,8 @@ impl FileBuilder {
|
||||
const EST_BUF_LEN: usize = 2048;
|
||||
self.body.buf.reserve(EST_BUF_LEN);
|
||||
let initial_sample_byte_pos = match self.type_ {
|
||||
Type::MediaSegment => {
|
||||
self.append_moof()?;
|
||||
Type::MediaSegment { sequence_number } => {
|
||||
self.append_moof(sequence_number)?;
|
||||
let p = self.append_media_mdat()?;
|
||||
|
||||
// If the segment is > 4 GiB, the 32-bit trun data offsets are untrustworthy.
|
||||
@ -1240,14 +1241,14 @@ impl FileBuilder {
|
||||
}
|
||||
|
||||
/// Appends a `MovieFragmentBox` (ISO/IEC 14496-12 section 8.8.4).
|
||||
fn append_moof(&mut self) -> Result<(), Error> {
|
||||
fn append_moof(&mut self, sequence_number: u32) -> Result<(), Error> {
|
||||
write_length!(self, {
|
||||
self.body.buf.extend_from_slice(b"moof");
|
||||
|
||||
// MovieFragmentHeaderBox (ISO/IEC 14496-12 section 8.8.5).
|
||||
write_length!(self, {
|
||||
self.body.buf.extend_from_slice(b"mfhd\x00\x00\x00\x00");
|
||||
self.body.append_u32(1); // sequence_number
|
||||
self.body.append_u32(sequence_number);
|
||||
})?;
|
||||
|
||||
// TrackFragmentBox (ISO/IEC 14496-12 section 8.8.6).
|
||||
@ -1908,7 +1909,7 @@ 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 matches!(self.0.type_, Type::MediaSegment { .. }) {
|
||||
if let Some((d, r)) = self.0.prev_media_duration_and_cur_runs {
|
||||
hdrs.insert(
|
||||
"X-Prev-Media-Duration",
|
||||
@ -2744,7 +2745,7 @@ mod tests {
|
||||
// Time range [2+4+6, 2+4+6+8+1) means the 4th sample and part of the 5th are included.
|
||||
// The 3rd gets pulled in also because it's a sync frame and the 4th isn't.
|
||||
let mp4 = make_mp4_from_encoders(
|
||||
Type::MediaSegment,
|
||||
Type::MediaSegment { sequence_number: 1 },
|
||||
&db,
|
||||
vec![r],
|
||||
2 + 4 + 6..2 + 4 + 6 + 8 + 1,
|
||||
@ -2799,7 +2800,7 @@ mod tests {
|
||||
for i in 1..6 {
|
||||
let duration_90k = 2 * i;
|
||||
let mp4 = make_mp4_from_encoders(
|
||||
Type::MediaSegment,
|
||||
Type::MediaSegment { sequence_number: 1 },
|
||||
&db,
|
||||
vec![r.clone()],
|
||||
pos..pos + duration_90k,
|
||||
|
@ -162,6 +162,7 @@ impl Service {
|
||||
// On the first LiveSegment, send all the data from the previous key frame onward.
|
||||
// For LiveSegments, it's okay to send a single non-key frame at a time.
|
||||
let mut start_at_key = true;
|
||||
let mut sequence_number = 1;
|
||||
loop {
|
||||
let next = combo
|
||||
.next()
|
||||
@ -169,9 +170,17 @@ impl Service {
|
||||
.unwrap_or_else(|| unreachable!("timer stream never ends"));
|
||||
match next {
|
||||
Either::Left(live) => {
|
||||
self.stream_live_m4s_chunk(open_id, stream_id, &mut ws, live, start_at_key)
|
||||
self.stream_live_m4s_chunk(
|
||||
open_id,
|
||||
stream_id,
|
||||
&mut ws,
|
||||
live,
|
||||
start_at_key,
|
||||
sequence_number,
|
||||
)
|
||||
.await?;
|
||||
start_at_key = false;
|
||||
sequence_number = sequence_number.wrapping_add(1);
|
||||
}
|
||||
Either::Right(_) => {
|
||||
ws.send(tungstenite::Message::Ping(Vec::new())).await?;
|
||||
@ -188,8 +197,9 @@ impl Service {
|
||||
ws: &mut tokio_tungstenite::WebSocketStream<hyper::upgrade::Upgraded>,
|
||||
live: db::LiveSegment,
|
||||
start_at_key: bool,
|
||||
sequence_number: u32,
|
||||
) -> Result<(), Error> {
|
||||
let mut builder = mp4::FileBuilder::new(mp4::Type::MediaSegment);
|
||||
let mut builder = mp4::FileBuilder::new(mp4::Type::MediaSegment { sequence_number });
|
||||
let mut row = None;
|
||||
{
|
||||
let db = self.db.lock();
|
||||
|
@ -254,7 +254,14 @@ impl Service {
|
||||
),
|
||||
Path::StreamViewMp4Segment(uuid, type_, debug) => (
|
||||
CacheControl::PrivateStatic,
|
||||
self.stream_view_mp4(&req, caller, uuid, type_, mp4::Type::MediaSegment, debug)?,
|
||||
self.stream_view_mp4(
|
||||
&req,
|
||||
caller,
|
||||
uuid,
|
||||
type_,
|
||||
mp4::Type::MediaSegment { sequence_number: 1 },
|
||||
debug,
|
||||
)?,
|
||||
),
|
||||
Path::StreamLiveMp4Segments(uuid, type_) => (
|
||||
CacheControl::PrivateDynamic,
|
||||
|
Loading…
Reference in New Issue
Block a user