1 pub mod fmtp; 2 pub mod rtpmap; 3 4 use crate::global_trait::{Marshal, Unmarshal}; 5 use rtpmap::RtpMap; 6 use std::collections::HashMap; 7 8 use self::fmtp::Fmtp; 9 10 #[derive(Debug, Clone, Default)] 11 pub struct Bandwidth { 12 b_type: String, 13 bandwidth: u16, 14 } 15 16 impl Unmarshal for Bandwidth { 17 // b=AS:284\r\n\ unmarshal(raw_data: &str) -> Option<Self>18 fn unmarshal(raw_data: &str) -> Option<Self> { 19 let mut sdp_bandwidth = Bandwidth::default(); 20 21 let parameters: Vec<&str> = raw_data.split(':').collect(); 22 if let Some(t) = parameters.first() { 23 sdp_bandwidth.b_type = t.to_string(); 24 } 25 26 if let Some(bandwidth) = parameters.get(1) { 27 if let Ok(bandwidth) = bandwidth.parse::<u16>() { 28 sdp_bandwidth.bandwidth = bandwidth; 29 } 30 } 31 32 Some(sdp_bandwidth) 33 } 34 } 35 36 impl Marshal for Bandwidth { marshal(&self) -> String37 fn marshal(&self) -> String { 38 format!("{}:{}\r\n", self.b_type, self.bandwidth) 39 } 40 } 41 42 /* 43 v=0 44 o=- 946685052188730 1 IN IP4 0.0.0.0 45 s=RTSP/RTP Server 46 i=playback/robot=040082d087c335e3bd2b/camera=head/timerang1=1533620879-1533620898 47 t=0 0 48 a=tool:vlc 0.9.8a 49 a=type:broadcast 50 a=control:* 51 a=range:npt=0- 52 m=video 20003 RTP/AVP 97 53 b=RR:0 54 a=rtpmap:97 H264/90000 55 a=fmtp:97 profile-level-id=42C01E;packetization-mode=1;sprop-parameter-sets=Z0LAHtkDxWhAAAADAEAAAAwDxYuSAAAAAQ==,aMuMsgAAAAE= 56 a=control:track1 57 m=audio 11704 RTP/AVP 96 97 98 0 8 18 101 99 100 */ 58 59 #[derive(Default, Debug, Clone)] 60 pub struct SdpMediaInfo { 61 pub media_type: String, 62 port: usize, 63 protocol: String, 64 fmts: Vec<u8>, 65 bandwidth: Option<Bandwidth>, 66 pub rtpmap: RtpMap, 67 pub fmtp: Option<fmtp::Fmtp>, 68 pub attributes: HashMap<String, String>, 69 } 70 71 // impl std::fmt::Debug for dyn TMsgConverter { 72 // fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 73 // write!(fmt, "S2 {{ member: {:?} }}", self.member) 74 // } 75 // } 76 77 // impl Default for SdpMediaInfo { 78 // fn default() -> Self { 79 // Self { 80 // fmtp: Box::new(fmtp::UnknownFmtpSdp::default()), 81 // ..Default::default() 82 // } 83 // } 84 // } 85 86 #[derive(Default, Debug, Clone)] 87 pub struct Sdp { 88 pub raw_string: String, 89 version: u16, 90 origin: String, 91 session: String, 92 connection: String, 93 timing: String, 94 pub medias: Vec<SdpMediaInfo>, 95 attributes: HashMap<String, String>, 96 } 97 98 impl Unmarshal for SdpMediaInfo { 99 //m=audio 11704 RTP/AVP 96 97 98 0 8 18 101 99 100 */ 100 //m=video 20003 RTP/AVP 97 unmarshal(raw_data: &str) -> Option<Self>101 fn unmarshal(raw_data: &str) -> Option<Self> { 102 let mut sdp_media = SdpMediaInfo::default(); 103 let parameters: Vec<&str> = raw_data.split(' ').collect(); 104 105 if let Some(para_0) = parameters.first() { 106 sdp_media.media_type = para_0.to_string(); 107 } 108 109 if let Some(para_1) = parameters.get(1) { 110 if let Ok(port) = para_1.parse::<usize>() { 111 sdp_media.port = port; 112 } 113 } 114 115 if let Some(para_2) = parameters.get(2) { 116 sdp_media.protocol = para_2.to_string(); 117 } 118 119 let mut cur_param_idx = 3; 120 121 while let Some(fmt_str) = parameters.get(cur_param_idx) { 122 if let Ok(fmt) = fmt_str.parse::<u8>() { 123 sdp_media.fmts.push(fmt); 124 } 125 cur_param_idx += 1; 126 } 127 128 Some(sdp_media) 129 } 130 } 131 132 // m=video 0 RTP/AVP 96\r\n\ 133 // b=AS:284\r\n\ 134 // a=rtpmap:96 H264/90000\r\n\ 135 // a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAHqzZQKAv+XARAAADAAEAAAMAMg8WLZY=,aOvjyyLA; profile-level-id=64001E\r\n\ 136 // a=control:streamid=0\r\n\ 137 // m=audio 0 RTP/AVP 97\r\n\ 138 // b=AS:128\r\n\ 139 // a=rtpmap:97 MPEG4-GENERIC/48000/2\r\n\ 140 // a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=119056E500\r\n\ 141 // a=control:streamid=1\r\n" 142 143 impl Marshal for SdpMediaInfo { marshal(&self) -> String144 fn marshal(&self) -> String { 145 let fmts_str = self 146 .fmts 147 .iter() 148 .map(|b| b.to_string()) 149 .collect::<Vec<String>>() 150 .join(" "); 151 152 let bandwidth = if let Some(bandwidth) = &self.bandwidth { 153 format!("b={}", bandwidth.marshal()) 154 } else { 155 String::from("") 156 }; 157 158 let mut sdp_media_info = format!( 159 "m={} {} {} {}\r\n{}a=rtpmap:{}", 160 self.media_type, 161 self.port, 162 self.protocol, 163 fmts_str, 164 bandwidth, 165 self.rtpmap.marshal() 166 ); 167 168 if let Some(fmtp) = &self.fmtp { 169 sdp_media_info = format!("{}a=fmtp:{}", sdp_media_info, fmtp.marshal()); 170 } 171 172 for (k, v) in &self.attributes { 173 sdp_media_info = format!("{sdp_media_info}a={k}:{v}\r\n"); 174 } 175 176 sdp_media_info 177 } 178 } 179 180 impl Unmarshal for Sdp { unmarshal(raw_data: &str) -> Option<Self>181 fn unmarshal(raw_data: &str) -> Option<Self> { 182 let mut sdp = Sdp { 183 raw_string: raw_data.to_string(), 184 ..Default::default() 185 }; 186 187 let lines: Vec<&str> = raw_data.split(|c| c == '\r' || c == '\n').collect(); 188 for line in lines { 189 if line.is_empty() { 190 continue; 191 } 192 let kv: Vec<&str> = line.trim().splitn(2, '=').collect(); 193 if kv.len() < 2 { 194 log::error!("Sdp current line : {} parse error!", line); 195 continue; 196 } 197 198 match kv[0] { 199 //m=audio 11704 RTP/AVP 96 97 98 0 8 18 101 99 100 */ 200 //m=video 20003 RTP/AVP 97 201 202 // v=0\r\n\ 203 // o=- 0 0 IN IP4 127.0.0.1\r\n\ 204 // s=No Name\r\n\ 205 // c=IN IP4 127.0.0.1\r\n\ 206 // t=0 0\r\n\ 207 208 // m=video 0 RTP/AVP 96\r\n\ 209 // b=AS:284\r\n\ 210 // a=rtpmap:96 H264/90000\r\n\ 211 // a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAHqzZQKAv+XARAAADAAEAAAMAMg8WLZY=,aOvjyyLA; profile-level-id=64001E\r\n\ 212 // a=control:streamid=0\r\n\ 213 // m=audio 0 RTP/AVP 97\r\n\ 214 // b=AS:128\r\n\ 215 // a=rtpmap:97 MPEG4-GENERIC/48000/2\r\n\ 216 // a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=119056E500\r\n\ 217 // a=control:streamid=1\r\n"; 218 "v" => { 219 if let Ok(version) = kv[1].parse::<u16>() { 220 sdp.version = version; 221 } 222 } 223 "o" => { 224 sdp.origin = kv[1].to_string(); 225 } 226 "s" => { 227 sdp.session = kv[1].to_string(); 228 } 229 "c" => { 230 sdp.connection = kv[1].to_string(); 231 } 232 "t" => { 233 sdp.timing = kv[1].to_string(); 234 } 235 "m" => { 236 if let Some(sdp_media) = SdpMediaInfo::unmarshal(kv[1]) { 237 sdp.medias.push(sdp_media); 238 } 239 } 240 "b" => { 241 if let Some(cur_media) = sdp.medias.last_mut() { 242 cur_media.bandwidth = Some(Bandwidth::unmarshal(kv[1]).unwrap()); 243 } else { 244 continue; 245 } 246 } 247 // a=rtpmap:96 H264/90000\r\n\ 248 // a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAHqzZQKAv+XARAAADAAEAAAMAMg8WLZY=,aOvjyyLA; profile-level-id=64001E\r\n\ 249 // a=control:streamid=0\r\n\ 250 "a" => { 251 let attribute: Vec<&str> = kv[1].splitn(2, ':').collect(); 252 253 let attr_name = attribute[0]; 254 let attr_value = if let Some(val) = attribute.get(1) { 255 val 256 } else { 257 "" 258 }; 259 260 if let Some(cur_media) = sdp.medias.last_mut() { 261 if attribute.len() == 2 { 262 match attr_name { 263 "rtpmap" => { 264 if let Some(rtpmap) = RtpMap::unmarshal(attr_value) { 265 cur_media.rtpmap = rtpmap; 266 continue; 267 } 268 } 269 "fmtp" => { 270 cur_media.fmtp = 271 Fmtp::new(&cur_media.rtpmap.encoding_name, attr_value); 272 continue; 273 } 274 _ => {} 275 } 276 } 277 cur_media 278 .attributes 279 .insert(attr_name.to_string(), attr_value.to_string()); 280 } else { 281 sdp.attributes 282 .insert(attr_name.to_string(), attr_value.to_string()); 283 } 284 } 285 286 _ => { 287 log::info!("not parsed: {}", line); 288 } 289 } 290 } 291 292 Some(sdp) 293 } 294 } 295 296 // v=0\r\n\ 297 // o=- 0 0 IN IP4 127.0.0.1\r\n\ 298 // s=No Name\r\n\ 299 // c=IN IP4 127.0.0.1\r\n\ 300 // t=0 0\r\n\ 301 // a=tool:libavformat 58.76.100\r\n\ 302 303 impl Marshal for Sdp { marshal(&self) -> String304 fn marshal(&self) -> String { 305 let mut sdp_str = format!( 306 "v={}\r\no={}\r\ns={}\r\nc={}\r\nt={}\r\n", 307 self.version, self.origin, self.session, self.connection, self.timing 308 ); 309 310 for (k, v) in &self.attributes { 311 sdp_str = format!("{sdp_str}a={k}:{v}\r\n"); 312 } 313 314 for media_info in &self.medias { 315 sdp_str = format!("{}{}", sdp_str, media_info.marshal()); 316 } 317 318 sdp_str 319 } 320 } 321 322 #[cfg(test)] 323 mod tests { 324 325 use crate::global_trait::{Marshal, Unmarshal}; 326 327 use super::Sdp; 328 329 #[test] test_parse_sdp()330 fn test_parse_sdp() { 331 let data2 = "ANNOUNCE rtsp://127.0.0.1:5544/stream RTSP/1.0\r\n\ 332 Content-Type: application/sdp\r\n\ 333 CSeq: 2\r\n\ 334 User-Agent: Lavf58.76.100\r\n\ 335 Content-Length: 500\r\n\ 336 \r\n\ 337 v=0\r\n\ 338 o=- 0 0 IN IP4 127.0.0.1\r\n\ 339 s=No Name\r\n\ 340 c=IN IP4 127.0.0.1\r\n\ 341 t=0 0\r\n\ 342 a=tool:libavformat 58.76.100\r\n\ 343 m=video 0 RTP/AVP 96\r\n\ 344 b=AS:284\r\n\ 345 a=rtpmap:96 H264/90000\r\n\ 346 a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAHqzZQKAv+XARAAADAAEAAAMAMg8WLZY=,aOvjyyLA; profile-level-id=64001E\r\n\ 347 a=control:streamid=0\r\n\ 348 m=audio 0 RTP/AVP 97\r\n\ 349 b=AS:128\r\n\ 350 a=rtpmap:97 MPEG4-GENERIC/48000/2\r\n\ 351 a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=119056E500\r\n\ 352 a=control:streamid=1\r\n"; 353 354 // v=0:SDP版本号,通常为0。 355 // o=- 0 0 IN IP4 127.0.0.1:会话的所有者和会话ID,以及会话开始时间和会话结束时间的信息。 356 // s=No Name:会话名称或标题。 357 // c=IN IP4 127.0.0.1:表示会话数据传输的地址类型(IPv4)和地址(127.0.0.1)。 358 // t=0 0:会话时间,包括会话开始时间和结束时间,这里的值都是0,表示会话没有预定义的结束时间。 359 // a=tool:libavformat 58.76.100:会话所使用的工具或软件名称和版本号。 360 361 // m=video 0 RTP/AVP 96:媒体类型(video或audio)、媒体格式(RTP/AVP)、媒体格式编号(96)和媒体流的传输地址。 362 // b=AS:284:视频流所使用的带宽大小。 363 // a=rtpmap:96 H264/90000:视频流所使用的编码方式(H.264)和时钟频率(90000)。 364 // a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAHqzZQKAv+XARAAADAAEAAAMAMg8WLZY=,aOvjyyLA; profile-level-id=64001E:视频流的格式参数,如分片方式、SPS和PPS等。 365 // a=control:streamid=0:指定视频流的流ID。 366 367 // m=audio 0 RTP/AVP 97:媒体类型(audio)、媒体格式(RTP/AVP)、媒体格式编号(97)和媒体流的传输地址。 368 // b=AS:128:音频流所使用的带宽大小。 369 // a=rtpmap:97 MPEG4-GENERIC/48000/2:音频流所使用的编码方式(MPEG4-GENERIC)、采样率(48000Hz)、和通道数(2)。 370 // a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=119056E500:音频流的格式参数,如编码方式、采样长度、索引长度等。 371 // a=control:streamid=1:指定音频流的流ID。 372 373 if let Some(sdp) = Sdp::unmarshal(data2) { 374 println!("sdp : {sdp:?}"); 375 376 println!("sdp str : {}", sdp.marshal()); 377 } 378 } 379 #[test] test_str()380 fn test_str() { 381 let fmts: Vec<u8> = vec![5]; 382 // fmts.push(6); 383 let fmts_str = fmts 384 .iter() 385 .map(|b| b.to_string()) 386 .collect::<Vec<String>>() 387 .join(" "); 388 389 println!("=={fmts_str}=="); 390 } 391 } 392