xref: /xiu/protocol/rtsp/src/rtsp_range.rs (revision b36cf5da)
1 use crate::global_trait::Marshal;
2 
3 use super::global_trait::Unmarshal;
4 use super::rtsp_utils;
5 
6 #[derive(Debug, Clone, Default, PartialEq)]
7 pub enum RtspRangeType {
8     #[default]
9     NPT,
10     CLOCK,
11 }
12 
13 #[derive(Debug, Clone, Default)]
14 pub struct RtspRange {
15     range_type: RtspRangeType,
16     begin: i64,
17     end: Option<i64>,
18 }
19 
20 impl Unmarshal for RtspRange {
unmarshal(raw_data: &str) -> Option<Self>21     fn unmarshal(raw_data: &str) -> Option<Self> {
22         let mut rtsp_range = RtspRange::default();
23 
24         let kv: Vec<&str> = raw_data.splitn(2, '=').collect();
25         if kv.len() < 2 {
26             return None;
27         }
28 
29         match kv[0] {
30             "clock" => {
31                 rtsp_range.range_type = RtspRangeType::CLOCK;
32                 let ranges: Vec<&str> = kv[1].split('-').collect();
33 
34                 let get_clock_time = |range_time: &str| -> i64 {
35                     let datetime =
36                         match chrono::NaiveDateTime::parse_from_str(range_time, "%Y%m%dT%H%M%SZ") {
37                             Ok(dt) => dt,
38                             Err(err) => {
39                                 println!("get_clock_time error: {err}");
40                                 return -1;
41                             }
42                         };
43                     datetime.timestamp()
44                 };
45 
46                 rtsp_range.begin = get_clock_time(ranges[0]);
47                 if ranges.len() > 1 {
48                     rtsp_range.end = Some(get_clock_time(ranges[1]));
49                 }
50             }
51             "npt" => {
52                 rtsp_range.range_type = RtspRangeType::NPT;
53                 let ranges: Vec<&str> = kv[1].split('-').collect();
54 
55                 let get_npt_time = |range_time: &str| -> i64 {
56                     if let (Some(hour), Some(minute), Some(second), mill) =
57                         rtsp_utils::scanf!(range_time, |c| c == ':' || c == '.', i64, i64, i64, i64)
58                     {
59                         let mut result = (hour * 3600 + minute * 60 + second) * 1000;
60                         if let Some(m) = mill {
61                             result += m;
62                         }
63                         result
64                     } else {
65                         0
66                     }
67                 };
68 
69                 match ranges[0] {
70                     "now" => {
71                         rtsp_range.begin = 0;
72                     }
73                     _ => {
74                         rtsp_range.begin = get_npt_time(ranges[0]);
75                     }
76                 }
77 
78                 if ranges.len() == 2 && !ranges[1].is_empty() {
79                     rtsp_range.end = Some(get_npt_time(ranges[1]));
80                 }
81             }
82             _ => {
83                 log::info!("{} not parsed..", kv[0]);
84             }
85         }
86 
87         Some(rtsp_range)
88     }
89 }
90 
91 impl Marshal for RtspRange {
marshal(&self) -> String92     fn marshal(&self) -> String {
93         String::default()
94     }
95 }
96 
97 #[cfg(test)]
98 mod tests {
99 
100     use super::RtspRange;
101     use crate::global_trait::Unmarshal;
102 
103     #[test]
test_parse_transport()104     fn test_parse_transport() {
105         //a=range:
106         //a=range:npt=now-
107         //a=range:npt=0-
108         let parser = RtspRange::unmarshal("clock=20220520T064812Z-20230520T064816Z").unwrap();
109 
110         println!(" parser: {parser:?}");
111 
112         let parser1 = RtspRange::unmarshal("npt=now-").unwrap();
113 
114         println!(" parser1: {:?}, {}", parser1, parser1.end.is_none());
115 
116         let parser2 = RtspRange::unmarshal("npt=0-").unwrap();
117         println!(" parser2: {:?}, {}", parser2, parser2.end.is_none());
118     }
119 }
120