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