mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2024-12-25 22:55:55 -05:00
fix a couple v5->v6 schema upgrade problems
* Get rid of unused video_sample_entry rows. h264_reader rejected some of these; perhaps they were corrupted by some long-fixed bug. * Use an i64 for cum_duration_90k (oops); an i32 overflows with only 6.6 hours of recording, so this was guaranteed to fail on any real setup. * Add some context to those errors for debugging. For posterity, a video_sample_entry that failed: sqlite> select id, hex(sha1), width, height, rfc6381_codec, hex(data) from video_sample_entry where id = 9; 9|B3607B06107E779F57D062331FB54B59E964B9BC|1920|1080|avc1.640028|000000B26176633100000000000000010000000000000000000000000000000007800438004800000048000000000000000100000000000000000000000000000000000000000000000000000000000000000018FFFF0000005C6176634301640028FFE1002967640028AC1B1A80780227E5C05B808080A000007D0000186A1D0C0029FF5DE5C6860014FFAEF2E140010020A886052ACA0500769C28476EFE104A8000F08781320819888E894B5200000000
This commit is contained in:
parent
6f9612738c
commit
840524ec83
@ -230,19 +230,31 @@ mod tests {
|
||||
insert into video_sample_entry (id, sha1, width, height, data)
|
||||
values (3, X'0000000000000000000000000000000000000002', 704, 480, ?);
|
||||
"#, params![GOOD_ANAMORPHIC_VIDEO_SAMPLE_ENTRY])?;
|
||||
upgraded.execute(r#"
|
||||
insert into video_sample_entry (id, sha1, width, height, data)
|
||||
values (4, X'0000000000000000000000000000000000000003', 704, 480, ?);
|
||||
"#, params![GOOD_ANAMORPHIC_VIDEO_SAMPLE_ENTRY])?;
|
||||
upgraded.execute_batch(r#"
|
||||
insert into recording (id, camera_id, sample_file_bytes, start_time_90k, duration_90k,
|
||||
local_time_delta_90k, video_samples, video_sync_samples,
|
||||
video_sample_entry_id, sample_file_uuid, sample_file_sha1,
|
||||
video_index)
|
||||
values (1, 1, 42, 140063580000000, 90000, 0, 1, 1, 1,
|
||||
X'E69D45E8CBA64DC1BA2ECB1585983A10', zeroblob(20), X'00');
|
||||
X'E69D45E8CBA64DC1BA2ECB1585983A10', zeroblob(20), X'00'),
|
||||
(2, 1, 42, 140063580090000, 90000, 0, 1, 1, 2,
|
||||
X'94DE8484FF874A5295D488C8038A0312', zeroblob(20), X'00'),
|
||||
(3, 1, 42, 140063580180000, 90000, 0, 1, 1, 3,
|
||||
X'C94D4D0B533746059CD40B29039E641E', zeroblob(20), X'00');
|
||||
insert into reserved_sample_files values (X'51EF700C933E4197AAE4EE8161E94221', 0),
|
||||
(X'E69D45E8CBA64DC1BA2ECB1585983A10', 1);
|
||||
"#)?;
|
||||
let rec1 = tmpdir.path().join("e69d45e8-cba6-4dc1-ba2e-cb1585983a10");
|
||||
let rec2 = tmpdir.path().join("94de8484-ff87-4a52-95d4-88c8038a0312");
|
||||
let rec3 = tmpdir.path().join("c94d4d0b-5337-4605-9cd4-0b29039e641e");
|
||||
let garbage = tmpdir.path().join("51ef700c-933e-4197-aae4-ee8161e94221");
|
||||
std::fs::File::create(&rec1)?;
|
||||
std::fs::File::create(&rec2)?;
|
||||
std::fs::File::create(&rec3)?;
|
||||
std::fs::File::create(&garbage)?;
|
||||
|
||||
for (ver, fresh_sql) in &[(1, Some(include_str!("v1.sql"))),
|
||||
@ -287,6 +299,9 @@ mod tests {
|
||||
assert_eq!(pasp_by_id.get(&1), Some(&(1, 1)));
|
||||
assert_eq!(pasp_by_id.get(&2), Some(&(4, 3)));
|
||||
assert_eq!(pasp_by_id.get(&3), Some(&(40, 33)));
|
||||
|
||||
// No recording references this video_sample_entry, so it gets dropped on upgrade.
|
||||
assert_eq!(pasp_by_id.get(&4), None);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
/// Upgrades a version 4 schema to a version 5 schema.
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
||||
use failure::{Error, bail, format_err};
|
||||
use failure::{Error, ResultExt, bail, format_err};
|
||||
use h264_reader::avcc::AvcDecoderConfigurationRecord;
|
||||
use rusqlite::{named_params, params};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
@ -93,6 +93,10 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
values (:id, :width, :height, :rfc6381_codec, :data,
|
||||
:pasp_h_spacing, :pasp_v_spacing)
|
||||
"#)?;
|
||||
|
||||
// Only insert still-referenced video sample entries. I've had problems with
|
||||
// no-longer-referenced ones (perhaps from some ancient, buggy version of Moonfire NVR) for
|
||||
// which avcc.create_context(()) fails.
|
||||
let mut stmt = tx.prepare(r#"
|
||||
select
|
||||
id,
|
||||
@ -101,7 +105,15 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
rfc6381_codec,
|
||||
data
|
||||
from
|
||||
old_video_sample_entry
|
||||
old_video_sample_entry v
|
||||
where
|
||||
exists (
|
||||
select
|
||||
'x'
|
||||
from
|
||||
recording r
|
||||
where
|
||||
r.video_sample_entry_id = v.id)
|
||||
"#)?;
|
||||
let mut rows = stmt.query(params![])?;
|
||||
while let Some(row) = rows.next()? {
|
||||
@ -115,9 +127,10 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
bail!("Multiple SPSs!");
|
||||
}
|
||||
let ctx = avcc.create_context(())
|
||||
.map_err(|e| format_err!("Can't load SPS+PPS: {:?}", e))?;
|
||||
.map_err(|e| format_err!("Can't load SPS+PPS for video_sample_entry_id {}: {:?}",
|
||||
id, e))?;
|
||||
let sps = ctx.sps_by_id(h264_reader::nal::pps::ParamSetId::from_u32(0).unwrap())
|
||||
.ok_or_else(|| format_err!("No SPS 0"))?;
|
||||
.ok_or_else(|| format_err!("No SPS 0 for video_sample_entry_id {}", id))?;
|
||||
let pasp = sps.vui_parameters.as_ref()
|
||||
.and_then(|v| v.aspect_ratio_info.as_ref())
|
||||
.and_then(|a| a.clone().get())
|
||||
@ -257,8 +270,8 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
||||
":video_samples": video_samples,
|
||||
":video_sync_samples": video_sync_samples,
|
||||
":video_sample_entry_id": video_sample_entry_id,
|
||||
})?;
|
||||
cum_duration_90k += duration_90k;
|
||||
}).with_context(|_| format!("Unable to insert composite_id {}", composite_id))?;
|
||||
cum_duration_90k += i64::from(duration_90k);
|
||||
cum_runs += if run_offset == 0 { 1 } else { 0 };
|
||||
}
|
||||
tx.execute_batch(r#"
|
||||
|
Loading…
Reference in New Issue
Block a user