mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2024-12-27 15:45:55 -05:00
fix panic when requesting zero segment duration
The recording::Segment was constructing a segment with no frames in it, which was causing a panic when appending a zero-length stts to the Slices. Fix this in a couple ways: * Slices::append should return Err rather than panic. No reason to crash the whole program when we have trouble serving a single .mp4 request. * recording::Segment shouldn't produce zero-frame segments
This commit is contained in:
parent
1d08698d0c
commit
9041eeb907
@ -1405,8 +1405,7 @@ impl BodyState {
|
|||||||
|
|
||||||
fn append_slice(&mut self, len: u64, t: SliceType, p: usize) -> Result<(), Error> {
|
fn append_slice(&mut self, len: u64, t: SliceType, p: usize) -> Result<(), Error> {
|
||||||
let l = self.slices.len();
|
let l = self.slices.len();
|
||||||
self.slices.append(Slice::new(l + len, t, p)?);
|
self.slices.append(Slice::new(l + len, t, p)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a static bytestring, flushing the buffer if necessary.
|
/// Appends a static bytestring, flushing the buffer if necessary.
|
||||||
|
@ -406,10 +406,13 @@ impl Segment {
|
|||||||
if self_.desired_range_90k.start == 0 &&
|
if self_.desired_range_90k.start == 0 &&
|
||||||
self_.desired_range_90k.end == recording.duration_90k {
|
self_.desired_range_90k.end == recording.duration_90k {
|
||||||
// Fast path. Existing entry is fine.
|
// Fast path. Existing entry is fine.
|
||||||
|
trace!("recording::Segment::new fast path, recording={:#?}", recording);
|
||||||
return Ok(self_)
|
return Ok(self_)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slow path. Need to iterate through the index.
|
// Slow path. Need to iterate through the index.
|
||||||
|
trace!("recording::Segment::new slow path, desired_range_90k={:?}, recording={:#?}",
|
||||||
|
self_.desired_range_90k, recording);
|
||||||
db.with_recording_playback(self_.camera_id, self_.recording_id, |playback| {
|
db.with_recording_playback(self_.camera_id, self_.recording_id, |playback| {
|
||||||
let mut begin = Box::new(SampleIndexIterator::new());
|
let mut begin = Box::new(SampleIndexIterator::new());
|
||||||
let data = &(&playback).video_index;
|
let data = &(&playback).video_index;
|
||||||
@ -441,7 +444,7 @@ impl Segment {
|
|||||||
self_.frames = 0;
|
self_.frames = 0;
|
||||||
self_.key_frames = 0;
|
self_.key_frames = 0;
|
||||||
}
|
}
|
||||||
if it.start_90k >= end_90k {
|
if it.start_90k >= end_90k && self_.frames > 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self_.frames += 1;
|
self_.frames += 1;
|
||||||
@ -709,6 +712,18 @@ mod tests {
|
|||||||
assert_eq!(&get_frames(&db.db, &segment, |it| it.bytes), &[2, 3]);
|
assert_eq!(&get_frames(&db.db, &segment, |it| it.bytes), &[2, 3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Even if the desired duration is 0, there should still be a frame.
|
||||||
|
#[test]
|
||||||
|
fn test_segment_zero_desired_duration() {
|
||||||
|
testutil::init();
|
||||||
|
let mut encoder = SampleIndexEncoder::new();
|
||||||
|
encoder.add_sample(1, 1, true);
|
||||||
|
let db = TestDb::new();
|
||||||
|
let row = db.create_recording_from_encoder(encoder);
|
||||||
|
let segment = Segment::new(&db.db.lock(), &row, 0 .. 0).unwrap();
|
||||||
|
assert_eq!(&get_frames(&db.db, &segment, |it| it.bytes), &[1]);
|
||||||
|
}
|
||||||
|
|
||||||
/// Test a `Segment` which uses the whole recording.
|
/// Test a `Segment` which uses the whole recording.
|
||||||
/// This takes a fast path which skips scanning the index in `new()`.
|
/// This takes a fast path which skips scanning the index in `new()`.
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
//! Tools for implementing a `http_entity::Entity` body composed from many "slices".
|
//! Tools for implementing a `http_entity::Entity` body composed from many "slices".
|
||||||
|
|
||||||
|
use error::Error;
|
||||||
use reffers::ARefs;
|
use reffers::ARefs;
|
||||||
use futures::stream;
|
use futures::stream;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
@ -92,12 +93,16 @@ impl<S> Slices<S> where S: Slice {
|
|||||||
self.slices.reserve(additional)
|
self.slices.reserve(additional)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends the given slice.
|
/// Appends the given slice, which must have end > the Slice's current len.
|
||||||
pub fn append(&mut self, slice: S) {
|
pub fn append(&mut self, slice: S) -> Result<(), Error> {
|
||||||
assert!(slice.end() > self.len, "end {} <= len {} while adding slice {:?} to slices:\n{:?}",
|
if slice.end() <= self.len {
|
||||||
slice.end(), self.len, slice, self);
|
return Err(Error::new(
|
||||||
|
format!("end {} <= len {} while adding slice {:?} to slices:\n{:?}",
|
||||||
|
slice.end(), self.len, slice, self)));
|
||||||
|
}
|
||||||
self.len = slice.end();
|
self.len = slice.end();
|
||||||
self.slices.push(slice);
|
self.slices.push(slice);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the total byte length of all slices.
|
/// Returns the total byte length of all slices.
|
||||||
@ -182,11 +187,11 @@ mod tests {
|
|||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref SLICES: Slices<FakeSlice> = {
|
static ref SLICES: Slices<FakeSlice> = {
|
||||||
let mut s = Slices::new();
|
let mut s = Slices::new();
|
||||||
s.append(FakeSlice{end: 5, name: "a"});
|
s.append(FakeSlice{end: 5, name: "a"}).unwrap();
|
||||||
s.append(FakeSlice{end: 5+13, name: "b"});
|
s.append(FakeSlice{end: 5+13, name: "b"}).unwrap();
|
||||||
s.append(FakeSlice{end: 5+13+7, name: "c"});
|
s.append(FakeSlice{end: 5+13+7, name: "c"}).unwrap();
|
||||||
s.append(FakeSlice{end: 5+13+7+17, name: "d"});
|
s.append(FakeSlice{end: 5+13+7+17, name: "d"}).unwrap();
|
||||||
s.append(FakeSlice{end: 5+13+7+17+19, name: "e"});
|
s.append(FakeSlice{end: 5+13+7+17+19, name: "e"}).unwrap();
|
||||||
s
|
s
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user