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)
|
insert into video_sample_entry (id, sha1, width, height, data)
|
||||||
values (3, X'0000000000000000000000000000000000000002', 704, 480, ?);
|
values (3, X'0000000000000000000000000000000000000002', 704, 480, ?);
|
||||||
"#, params![GOOD_ANAMORPHIC_VIDEO_SAMPLE_ENTRY])?;
|
"#, 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#"
|
upgraded.execute_batch(r#"
|
||||||
insert into recording (id, camera_id, sample_file_bytes, start_time_90k, duration_90k,
|
insert into recording (id, camera_id, sample_file_bytes, start_time_90k, duration_90k,
|
||||||
local_time_delta_90k, video_samples, video_sync_samples,
|
local_time_delta_90k, video_samples, video_sync_samples,
|
||||||
video_sample_entry_id, sample_file_uuid, sample_file_sha1,
|
video_sample_entry_id, sample_file_uuid, sample_file_sha1,
|
||||||
video_index)
|
video_index)
|
||||||
values (1, 1, 42, 140063580000000, 90000, 0, 1, 1, 1,
|
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),
|
insert into reserved_sample_files values (X'51EF700C933E4197AAE4EE8161E94221', 0),
|
||||||
(X'E69D45E8CBA64DC1BA2ECB1585983A10', 1);
|
(X'E69D45E8CBA64DC1BA2ECB1585983A10', 1);
|
||||||
"#)?;
|
"#)?;
|
||||||
let rec1 = tmpdir.path().join("e69d45e8-cba6-4dc1-ba2e-cb1585983a10");
|
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");
|
let garbage = tmpdir.path().join("51ef700c-933e-4197-aae4-ee8161e94221");
|
||||||
std::fs::File::create(&rec1)?;
|
std::fs::File::create(&rec1)?;
|
||||||
|
std::fs::File::create(&rec2)?;
|
||||||
|
std::fs::File::create(&rec3)?;
|
||||||
std::fs::File::create(&garbage)?;
|
std::fs::File::create(&garbage)?;
|
||||||
|
|
||||||
for (ver, fresh_sql) in &[(1, Some(include_str!("v1.sql"))),
|
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(&1), Some(&(1, 1)));
|
||||||
assert_eq!(pasp_by_id.get(&2), Some(&(4, 3)));
|
assert_eq!(pasp_by_id.get(&2), Some(&(4, 3)));
|
||||||
assert_eq!(pasp_by_id.get(&3), Some(&(40, 33)));
|
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.
|
/// Upgrades a version 4 schema to a version 5 schema.
|
||||||
|
|
||||||
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
|
||||||
use failure::{Error, bail, format_err};
|
use failure::{Error, ResultExt, bail, format_err};
|
||||||
use h264_reader::avcc::AvcDecoderConfigurationRecord;
|
use h264_reader::avcc::AvcDecoderConfigurationRecord;
|
||||||
use rusqlite::{named_params, params};
|
use rusqlite::{named_params, params};
|
||||||
use std::convert::{TryFrom, TryInto};
|
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,
|
values (:id, :width, :height, :rfc6381_codec, :data,
|
||||||
:pasp_h_spacing, :pasp_v_spacing)
|
: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#"
|
let mut stmt = tx.prepare(r#"
|
||||||
select
|
select
|
||||||
id,
|
id,
|
||||||
@ -101,7 +105,15 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
|||||||
rfc6381_codec,
|
rfc6381_codec,
|
||||||
data
|
data
|
||||||
from
|
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![])?;
|
let mut rows = stmt.query(params![])?;
|
||||||
while let Some(row) = rows.next()? {
|
while let Some(row) = rows.next()? {
|
||||||
@ -115,9 +127,10 @@ pub fn run(_args: &super::Args, tx: &rusqlite::Transaction) -> Result<(), Error>
|
|||||||
bail!("Multiple SPSs!");
|
bail!("Multiple SPSs!");
|
||||||
}
|
}
|
||||||
let ctx = avcc.create_context(())
|
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())
|
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()
|
let pasp = sps.vui_parameters.as_ref()
|
||||||
.and_then(|v| v.aspect_ratio_info.as_ref())
|
.and_then(|v| v.aspect_ratio_info.as_ref())
|
||||||
.and_then(|a| a.clone().get())
|
.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_samples": video_samples,
|
||||||
":video_sync_samples": video_sync_samples,
|
":video_sync_samples": video_sync_samples,
|
||||||
":video_sample_entry_id": video_sample_entry_id,
|
":video_sample_entry_id": video_sample_entry_id,
|
||||||
})?;
|
}).with_context(|_| format!("Unable to insert composite_id {}", composite_id))?;
|
||||||
cum_duration_90k += duration_90k;
|
cum_duration_90k += i64::from(duration_90k);
|
||||||
cum_runs += if run_offset == 0 { 1 } else { 0 };
|
cum_runs += if run_offset == 0 { 1 } else { 0 };
|
||||||
}
|
}
|
||||||
tx.execute_batch(r#"
|
tx.execute_batch(r#"
|
||||||
|
Loading…
Reference in New Issue
Block a user