1 use super::model::*;
2 use cookie_factory::bytes::*;
3 use cookie_factory::sequence::tuple;
4 use cookie_factory::{combinator::*, gen};
5 use cookie_factory::{GenError, SerializeFn};
6 use err_derive::Error;
7 use log::error;
8 use std::io::Write;
9
10 // PAD_SIZE: Media packets use 8 byte padding
11 const PAD_SIZE: u32 = 8;
12
13 /// The error types used during serialisation
14 #[derive(Debug, Error)]
15 pub enum Error {
16 /// A Cookie Factor GenError
17 #[error(display = "Cookie GenError")]
18 GenError(#[error(source)] GenError),
19 }
20
21 impl BcMedia {
serialize<W: Write>(&self, buf: W) -> Result<W, Error>22 pub(crate) fn serialize<W: Write>(&self, buf: W) -> Result<W, Error> {
23 let (buf, _) = match &self {
24 BcMedia::InfoV1(payload) => gen(bcmedia_info_v1(payload), buf)?,
25 BcMedia::InfoV2(payload) => gen(bcmedia_info_v2(payload), buf)?,
26 BcMedia::Iframe(payload) => {
27 let pad_size = match payload.data.len() as u32 % PAD_SIZE {
28 0 => 0,
29 n => PAD_SIZE - n,
30 };
31 gen(
32 tuple((
33 bcmedia_iframe(payload),
34 slice(&payload.data),
35 slice(&vec![0; pad_size as usize]),
36 )),
37 buf,
38 )?
39 }
40 BcMedia::Pframe(payload) => {
41 let pad_size = match payload.data.len() as u32 % PAD_SIZE {
42 0 => 0,
43 n => PAD_SIZE - n,
44 };
45 gen(
46 tuple((
47 bcmedia_pframe(payload),
48 slice(&payload.data),
49 slice(&vec![0; pad_size as usize]),
50 )),
51 buf,
52 )?
53 }
54 BcMedia::Aac(payload) => {
55 let pad_size = match payload.data.len() as u32 % PAD_SIZE {
56 0 => 0,
57 n => PAD_SIZE - n,
58 };
59 gen(
60 tuple((
61 bcmedia_aac(payload),
62 slice(&payload.data),
63 slice(&vec![0; pad_size as usize]),
64 )),
65 buf,
66 )?
67 }
68 BcMedia::Adpcm(payload) => {
69 let pad_size = match payload.data.len() as u32 % PAD_SIZE {
70 0 => 0,
71 n => PAD_SIZE - n,
72 };
73 gen(
74 tuple((
75 bcmedia_adpcm(payload),
76 slice(&payload.data),
77 slice(&vec![0; pad_size as usize]),
78 )),
79 buf,
80 )?
81 }
82 };
83
84 Ok(buf)
85 }
86 }
87
bcmedia_info_v1<W: Write>(payload: &BcMediaInfoV1) -> impl SerializeFn<W>88 fn bcmedia_info_v1<W: Write>(payload: &BcMediaInfoV1) -> impl SerializeFn<W> {
89 tuple((
90 le_u32(MAGIC_HEADER_BCMEDIA_INFO_V1),
91 le_u32(32),
92 le_u32(payload.video_width),
93 le_u32(payload.video_height),
94 le_u8(0), // unknown. Known values 00/01
95 le_u8(payload.fps),
96 le_u8(payload.start_year),
97 le_u8(payload.start_month),
98 le_u8(payload.start_day),
99 le_u8(payload.start_hour),
100 le_u8(payload.start_min),
101 le_u8(payload.start_seconds),
102 le_u8(payload.end_year),
103 le_u8(payload.end_month),
104 le_u8(payload.end_day),
105 le_u8(payload.end_hour),
106 le_u8(payload.end_min),
107 le_u8(payload.end_seconds),
108 le_u8(0),
109 le_u8(0),
110 ))
111 }
112
bcmedia_info_v2<W: Write>(payload: &BcMediaInfoV2) -> impl SerializeFn<W>113 fn bcmedia_info_v2<W: Write>(payload: &BcMediaInfoV2) -> impl SerializeFn<W> {
114 tuple((
115 le_u32(MAGIC_HEADER_BCMEDIA_INFO_V2),
116 le_u32(32),
117 le_u32(payload.video_width),
118 le_u32(payload.video_height),
119 le_u8(0), // unknown. Known values 00/01
120 le_u8(payload.fps),
121 le_u8(payload.start_year),
122 le_u8(payload.start_month),
123 le_u8(payload.start_day),
124 le_u8(payload.start_hour),
125 le_u8(payload.start_min),
126 le_u8(payload.start_seconds),
127 le_u8(payload.end_year),
128 le_u8(payload.end_month),
129 le_u8(payload.end_day),
130 le_u8(payload.end_hour),
131 le_u8(payload.end_min),
132 le_u8(payload.end_seconds),
133 le_u8(0),
134 le_u8(0),
135 ))
136 }
137
bcmedia_iframe<W: Write>(payload: &BcMediaIframe) -> impl SerializeFn<W>138 fn bcmedia_iframe<W: Write>(payload: &BcMediaIframe) -> impl SerializeFn<W> {
139 // Cookie String needs a static lifetime
140 let vid_string = match payload.video_type {
141 VideoType::H264 => "H264",
142 VideoType::H265 => "H265",
143 };
144 tuple((
145 le_u32(MAGIC_HEADER_BCMEDIA_IFRAME),
146 string(vid_string),
147 le_u32(payload.data.len() as u32),
148 le_u32(0), // unknown. NVR channel count? Known values 1-00/08 2-00 3-00 4-00
149 le_u32(payload.microseconds),
150 le_u32(0), // unknown. Known values 1-00/23/5A 2-00 3-00 4-00
151 le_u32(payload.time),
152 le_u32(0), // unknown. Known values 1-00/06/29 2-00/01 3-00/C3 4-00
153 ))
154 }
155
bcmedia_pframe<W: Write>(payload: &BcMediaPframe) -> impl SerializeFn<W>156 fn bcmedia_pframe<W: Write>(payload: &BcMediaPframe) -> impl SerializeFn<W> {
157 // Cookie String needs a static lifetime
158 let vid_string = match payload.video_type {
159 VideoType::H264 => "H264",
160 VideoType::H265 => "H265",
161 };
162 tuple((
163 le_u32(MAGIC_HEADER_BCMEDIA_PFRAME),
164 string(vid_string),
165 le_u32(payload.data.len() as u32),
166 le_u32(0), // unknown. NVR channel count? Known values 1-00/08 2-00 3-00 4-00
167 le_u32(payload.microseconds),
168 le_u32(0), // unknown. Known values 1-00/23/5A 2-00 3-00 4-00
169 ))
170 }
171
bcmedia_aac<W: Write>(payload: &BcMediaAac) -> impl SerializeFn<W>172 fn bcmedia_aac<W: Write>(payload: &BcMediaAac) -> impl SerializeFn<W> {
173 tuple((
174 le_u32(MAGIC_HEADER_BCMEDIA_AAC),
175 le_u16(payload.data.len() as u16),
176 le_u16(payload.data.len() as u16),
177 ))
178 }
179
bcmedia_adpcm<W: Write>(payload: &BcMediaAdpcm) -> impl SerializeFn<W>180 fn bcmedia_adpcm<W: Write>(payload: &BcMediaAdpcm) -> impl SerializeFn<W> {
181 tuple((
182 le_u32(MAGIC_HEADER_BCMEDIA_ADPCM),
183 le_u16((payload.data.len() + 4) as u16), // Payload + 2 byte magic + 2byte block size
184 le_u16((payload.data.len() + 4) as u16), // Payload + 2 byte magic + 2byte block size
185 le_u16(MAGIC_HEADER_BCMEDIA_ADPCM_DATA), // magic
186 le_u16(((payload.data.len() - 4) / 2) as u16), // Block size without the header halved
187 ))
188 }
189