xref: /xiu/protocol/rtsp/src/sdp/fmtp.rs (revision 4f118a93)
1 use crate::global_trait::{Marshal, Unmarshal};
2 use base64::{engine::general_purpose, Engine as _};
3 use bytes::{BufMut, BytesMut};
4 
5 // pub trait Fmtp: TMsgConverter {}
6 
7 #[derive(Debug, Clone, Default)]
8 pub struct H264Fmtp {
9     pub payload_type: u16,
10     packetization_mode: u8,
11     profile_level_id: BytesMut,
12     pub sps: BytesMut,
13     pub pps: BytesMut,
14 }
15 #[derive(Debug, Clone, Default)]
16 pub struct H265Fmtp {
17     pub payload_type: u16,
18     pub vps: BytesMut,
19     pub sps: BytesMut,
20     pub pps: BytesMut,
21 }
22 #[derive(Debug, Clone, Default)]
23 pub struct Mpeg4Fmtp {
24     pub payload_type: u16,
25     pub asc: BytesMut,
26     profile_level_id: BytesMut,
27     mode: String,
28     size_length: u16,
29     index_length: u16,
30     index_delta_length: u16,
31 }
32 #[derive(Debug, Clone)]
33 pub enum Fmtp {
34     H264(H264Fmtp),
35     H265(H265Fmtp),
36     Mpeg4(Mpeg4Fmtp),
37 }
38 
39 impl Fmtp {
new(codec: &str, raw_data: &str) -> Option<Fmtp>40     pub fn new(codec: &str, raw_data: &str) -> Option<Fmtp> {
41         match codec.to_lowercase().as_str() {
42             "h264" => {
43                 if let Some(h264_fmtp) = H264Fmtp::unmarshal(raw_data) {
44                     return Some(Fmtp::H264(h264_fmtp));
45                 }
46             }
47             "h265" => {
48                 if let Some(h265_fmtp) = H265Fmtp::unmarshal(raw_data) {
49                     return Some(Fmtp::H265(h265_fmtp));
50                 }
51             }
52             "mpeg4-generic" => {
53                 if let Some(mpeg4_fmtp) = Mpeg4Fmtp::unmarshal(raw_data) {
54                     return Some(Fmtp::Mpeg4(mpeg4_fmtp));
55                 }
56             }
57             _ => {}
58         }
59         None
60     }
61 
marshal(&self) -> String62     pub fn marshal(&self) -> String {
63         match self {
64             Fmtp::H264(h264fmtp) => h264fmtp.marshal(),
65             Fmtp::H265(h265fmtp) => h265fmtp.marshal(),
66             Fmtp::Mpeg4(mpeg4fmtp) => mpeg4fmtp.marshal(),
67         }
68     }
69 }
70 
71 // a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAFqyyAUBf8uAiAAADAAIAAAMAPB4sXJA=,aOvDyyLA; profile-level-id=640016
72 impl Unmarshal for H264Fmtp {
unmarshal(raw_data: &str) -> Option<Self>73     fn unmarshal(raw_data: &str) -> Option<Self> {
74         let mut h264_fmtp = H264Fmtp::default();
75         let eles: Vec<&str> = raw_data.splitn(2, ' ').collect();
76         if eles.len() < 2 {
77             log::warn!("H264FmtpSdp parse err: {}", raw_data);
78             return None;
79         }
80 
81         if let Ok(payload_type) = eles[0].parse::<u16>() {
82             h264_fmtp.payload_type = payload_type;
83         }
84 
85         let parameters: Vec<&str> = eles[1].split(';').collect();
86         for parameter in parameters {
87             let kv: Vec<&str> = parameter.trim().splitn(2, '=').collect();
88             if kv.len() < 2 {
89                 log::warn!("H264FmtpSdp parse key=value err: {}", parameter);
90                 continue;
91             }
92             match kv[0] {
93                 "packetization-mode" => {
94                     if let Ok(packetization_mode) = kv[1].parse::<u8>() {
95                         h264_fmtp.packetization_mode = packetization_mode;
96                     }
97                 }
98                 "sprop-parameter-sets" => {
99                     let spspps: Vec<&str> = kv[1].split(',').collect();
100                     let sps = general_purpose::STANDARD.decode(spspps[0]).unwrap();
101                     h264_fmtp.sps.put(&sps[..]);
102                     let pps = general_purpose::STANDARD.decode(spspps[1]).unwrap();
103                     h264_fmtp.pps.put(&pps[..]);
104                 }
105                 "profile-level-id" => {
106                     h264_fmtp.profile_level_id = kv[1].into();
107                 }
108                 _ => {
109                     log::info!("not parsed: {}", kv[0])
110                 }
111             }
112         }
113 
114         Some(h264_fmtp)
115     }
116 }
117 
118 impl Marshal for H264Fmtp {
119     // a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAFqyyAUBf8uAiAAADAAIAAAMAPB4sXJA=,aOvDyyLA; profile-level-id=640016
marshal(&self) -> String120     fn marshal(&self) -> String {
121         let sps_str = general_purpose::STANDARD.encode(&self.sps);
122         let pps_str = general_purpose::STANDARD.encode(&self.pps);
123         let profile_level_id_str = String::from_utf8(self.profile_level_id.to_vec()).unwrap();
124 
125         let h264_fmtp = format!(
126             "{} packetization-mode={}; sprop-parameter-sets={},{}; profile-level-id={}",
127             self.payload_type, self.packetization_mode, sps_str, pps_str, profile_level_id_str
128         );
129 
130         format!("{h264_fmtp}\r\n")
131     }
132 }
133 
134 impl Unmarshal for H265Fmtp {
135     //"a=fmtp:96 sprop-vps=QAEMAf//AWAAAAMAkAAAAwAAAwA/ugJA; sprop-sps=QgEBAWAAAAMAkAAAAwAAAwA/oAUCAXHy5bpKTC8BAQAAAwABAAADAA8I; sprop-pps=RAHAc8GJ"
unmarshal(raw_data: &str) -> Option<Self>136     fn unmarshal(raw_data: &str) -> Option<Self> {
137         let mut h265_fmtp = H265Fmtp::default();
138         let eles: Vec<&str> = raw_data.splitn(2, ' ').collect();
139         if eles.len() < 2 {
140             log::warn!("H265FmtpSdp parse err: {}", raw_data);
141             return None;
142         }
143 
144         if let Ok(payload_type) = eles[0].parse::<u16>() {
145             h265_fmtp.payload_type = payload_type;
146         }
147 
148         let parameters: Vec<&str> = eles[1].split(';').collect();
149         for parameter in parameters {
150             let kv: Vec<&str> = parameter.trim().splitn(2, '=').collect();
151             if kv.len() < 2 {
152                 log::warn!("H265FmtpSdp parse key=value err: {}", parameter);
153                 continue;
154             }
155 
156             match kv[0] {
157                 "sprop-vps" => {
158                     h265_fmtp.vps = kv[1].into();
159                 }
160                 "sprop-sps" => {
161                     h265_fmtp.sps = kv[1].into();
162                 }
163                 "sprop-pps" => {
164                     h265_fmtp.pps = kv[1].into();
165                 }
166                 _ => {
167                     log::info!("not parsed: {}", kv[0])
168                 }
169             }
170         }
171 
172         Some(h265_fmtp)
173     }
174 }
175 
176 impl Marshal for H265Fmtp {
177     //"a=fmtp:96 sprop-vps=QAEMAf//AWAAAAMAkAAAAwAAAwA/ugJA; sprop-sps=QgEBAWAAAAMAkAAAAwAAAwA/oAUCAXHy5bpKTC8BAQAAAwABAAADAA8I; sprop-pps=RAHAc8GJ"
marshal(&self) -> String178     fn marshal(&self) -> String {
179         let sps_str = String::from_utf8(self.sps.to_vec()).unwrap();
180         let pps_str = String::from_utf8(self.pps.to_vec()).unwrap();
181         let vps_str = String::from_utf8(self.vps.to_vec()).unwrap();
182 
183         let h265_fmtp = format!(
184             "{} sprop-vps={}; sprop-sps={}; sprop-pps={}",
185             self.payload_type, vps_str, sps_str, pps_str
186         );
187 
188         format!("{h265_fmtp}\r\n")
189     }
190 }
191 
192 impl Unmarshal for Mpeg4Fmtp {
193     //a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=121056e500
unmarshal(raw_data: &str) -> Option<Self>194     fn unmarshal(raw_data: &str) -> Option<Self> {
195         let mut mpeg4_fmtp = Mpeg4Fmtp::default();
196         let eles: Vec<&str> = raw_data.splitn(2, ' ').collect();
197         if eles.len() < 2 {
198             log::warn!("Mpeg4FmtpSdp parse err: {}", raw_data);
199             return None;
200         }
201 
202         if let Ok(payload_type) = eles[0].parse::<u16>() {
203             mpeg4_fmtp.payload_type = payload_type;
204         }
205 
206         let parameters: Vec<&str> = eles[1].split(';').collect();
207         for parameter in parameters {
208             let kv: Vec<&str> = parameter.trim().splitn(2, '=').collect();
209             if kv.len() < 2 {
210                 log::warn!("Mpeg4FmtpSdp parse key=value err: {}", parameter);
211                 continue;
212             }
213             match kv[0].to_lowercase().as_str() {
214                 "mode" => {
215                     mpeg4_fmtp.mode = kv[1].to_string();
216                 }
217                 "config" => {
218                     let asc = hex::decode(kv[1]).unwrap();
219                     mpeg4_fmtp.asc.put(&asc[..]);
220                 }
221                 "profile-level-id" => {
222                     mpeg4_fmtp.profile_level_id = kv[1].into();
223                 }
224                 "sizelength" => {
225                     if let Ok(size_length) = kv[1].parse::<u16>() {
226                         mpeg4_fmtp.size_length = size_length;
227                     }
228                 }
229                 "indexlength" => {
230                     if let Ok(index_length) = kv[1].parse::<u16>() {
231                         mpeg4_fmtp.index_length = index_length;
232                     }
233                 }
234                 "indexdeltalength" => {
235                     if let Ok(index_delta_length) = kv[1].parse::<u16>() {
236                         mpeg4_fmtp.index_delta_length = index_delta_length;
237                     }
238                 }
239                 _ => {
240                     log::info!("not parsed: {}", kv[0])
241                 }
242             }
243         }
244 
245         Some(mpeg4_fmtp)
246     }
247 }
248 
249 impl Marshal for Mpeg4Fmtp {
250     //a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=121056e500
marshal(&self) -> String251     fn marshal(&self) -> String {
252         let profile_level_id_str = String::from_utf8(self.profile_level_id.to_vec()).unwrap();
253         let asc_str = hex::encode(&self.asc); //String::from_utf8(self.asc.to_vec()).unwrap();
254 
255         let mpeg4_fmtp = format!(
256             "{} profile-level-id={};mode={};sizelength={};indexlength={};indexdeltalength={}; config={}",
257             self.payload_type, profile_level_id_str, self.mode, self.size_length, self.index_length,
258             self.index_delta_length,asc_str);
259 
260         format!("{mpeg4_fmtp}\r\n")
261     }
262 }
263 
264 #[cfg(test)]
265 mod tests {
266 
267     use bytes::BytesMut;
268 
269     use super::H264Fmtp;
270     use super::H265Fmtp;
271     use super::Mpeg4Fmtp;
272     use crate::global_trait::Marshal;
273     use crate::global_trait::Unmarshal;
274     use crate::rtsp_utils;
275 
276     #[test]
test_parse_h264fmtpsdp()277     fn test_parse_h264fmtpsdp() {
278         let parser =  H264Fmtp::unmarshal("96 packetization-mode=1; sprop-parameter-sets=Z2QAFqyyAUBf8uAiAAADAAIAAAMAPB4sXJA=,aOvDyyLA; profile-level-id=640016").unwrap();
279 
280         println!(" parser: {parser:?}");
281 
282         assert_eq!(parser.packetization_mode, 1);
283         assert_eq!(parser.profile_level_id, "640016");
284         // assert_eq!(parser.sps, "Z2QAFqyyAUBf8uAiAAADAAIAAAMAPB4sXJA=");
285         // assert_eq!(parser.pps, "aOvDyyLA");
286         //"96 packetization-mode=1; sprop-parameter-sets=Z2QAFqyyAUBf8uAiAAADAAIAAAMAPB4sXJA=,aOvDyyLA; profile-level-id=640016"
287 
288         print!("264 parser: {}", parser.marshal());
289 
290         let parser2 = H264Fmtp::unmarshal("96 packetization-mode=1;\nsprop-parameter-sets=Z2QAFqyyAUBf8uAiAAADAAIAAAMAPB4sXJA=,aOvDyyLA;\nprofile-level-id=640016").unwrap();
291 
292         println!(" parser: {parser2:?}");
293 
294         assert_eq!(parser2.packetization_mode, 1);
295         assert_eq!(parser2.profile_level_id, "640016");
296         // assert_eq!(parser2.sps, "Z2QAFqyyAUBf8uAiAAADAAIAAAMAPB4sXJA=");
297         // assert_eq!(parser2.pps, "aOvDyyLA");
298 
299         print!("264 parser2: {}", parser2.marshal());
300     }
301     #[test]
test_parse_h265fmtpsdp()302     fn test_parse_h265fmtpsdp() {
303         let parser = H265Fmtp::unmarshal("96 sprop-vps=QAEMAf//AWAAAAMAkAAAAwAAAwA/ugJA; sprop-sps=QgEBAWAAAAMAkAAAAwAAAwA/oAUCAXHy5bpKTC8BAQAAAwABAAADAA8I; sprop-pps=RAHAc8GJ").unwrap();
304 
305         println!(" parser: {parser:?}");
306 
307         assert_eq!(parser.vps, "QAEMAf//AWAAAAMAkAAAAwAAAwA/ugJA");
308         assert_eq!(
309             parser.sps,
310             "QgEBAWAAAAMAkAAAAwAAAwA/oAUCAXHy5bpKTC8BAQAAAwABAAADAA8I"
311         );
312         assert_eq!(parser.pps, "RAHAc8GJ");
313 
314         print!("265 parser: {}", parser.marshal());
315     }
316 
317     #[test]
test_parse_mpeg4fmtpsdp()318     fn test_parse_mpeg4fmtpsdp() {
319         let parser = Mpeg4Fmtp::unmarshal("97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=23; config=121056e500").unwrap();
320 
321         println!(" parser: {parser:?}");
322         let en_asc = hex::encode(parser.asc.clone());
323 
324         assert_eq!(en_asc, "121056e500");
325         assert_eq!(parser.profile_level_id, "1");
326         assert_eq!(parser.mode, "AAC-hbr");
327         assert_eq!(parser.size_length, 13);
328         assert_eq!(parser.index_length, 3);
329         assert_eq!(parser.index_delta_length, 23);
330 
331         print!("mpeg4 parser: {}", parser.marshal());
332     }
333 
334     #[test]
test_string()335     fn test_string() {
336         let s = String::from("119056E500");
337         let ss = hex::decode(s).unwrap();
338         let b = BytesMut::from(&ss[..]);
339 
340         rtsp_utils::print("test", b);
341     }
342 }
343