ZLMedia中RTSP协议的处理简要分析(2)--SDP解析函数

void SdpParser::load(const string &sdp) { { _track_vec.clear(); SdpTrack::Ptr track = std::make_shared<SdpTrack>(); track->_type = TrackTitle; _track_vec.emplace_back(track); auto lines = split(sdp, "\n"); for (auto &line : lines) { trim(line); if (line.size() < 2 || line[1] != '=') { continue; } char opt = line[0]; string opt_val = line.substr(2); switch (opt) { case 't': track->_t = opt_val; break; case 'b': track->_b = opt_val; break; case 'm': { track = std::make_shared<SdpTrack>(); int pt, port; char rtp[16] = {0}, type[16]; if (4 == sscanf(opt_val.data(), " %15[^ ] %d %15[^ ] %d", type, &port, rtp, &pt)) { track->_pt = pt; track->_samplerate = RtpPayload::getClockRate(pt); track->_channel = RtpPayload::getAudioChannel(pt); track->_type = toTrackType(type); track->_port = port; _track_vec.emplace_back(track); } break; } case 'a': { string attr = FindField(opt_val.data(), nullptr, ":"); if (attr.empty()) { track->_attr.emplace(opt_val, ""); } else { track->_attr.emplace(attr, FindField(opt_val.data(), ":", nullptr)); } break; } default: track->_other[opt] = opt_val; break; } } } for (auto &track_ptr : _trackn_vec) { auto &track = *track_ptr; auto it = track._attr.find("range"); if (it != track._attr.end()) { char name[16] = {0}, start[16] = {0}, end[16] = {0}; int ret = sscanf(it->second.data(), "%15[^=]=%15[^-]-%15s", name, start, end); if (3 == ret || 2 == ret) { if (strcmp(start, "now") == 0) { strcpy(start, "0"); } track._start = (float) atof(start); track._end = (float) atof(end); track._duration = track._end - track._start; } } for (it = track._attr.find("rtpmap"); it != track._attr.end() && it->first == "rtpmap";) { auto &rtpmap = it->second; int pt, samplerate, channel; char codec[16] = {0}; sscanf(rtpmap.data(), "%d", &pt); if (track._pt != pt) { //pt不匹配 it = track._attr.erase(it); continue; } if (4 == sscanf(rtpmap.data(), "%d %15[^/]/%d/%d", &pt, codec, &samplerate, &channel)) { track._codec = codec; track._samplerate = samplerate; track._channel = channel; } else if (3 == sscanf(rtpmap.data(), "%d %15[^/]/%d", &pt, codec, &samplerate)) { track._pt = pt; track._codec = codec; track._samplerate = samplerate; } if (!track._samplerate && track._type == TrackVideo) { //未设置视频采样率时,赋值为90000 track._samplerate = 90000; } ++it; } for (it = track._attr.find("fmtp"); it != track._attr.end() && it->first == "fmtp"; ) { auto &fmtp = it->second; int pt; sscanf(fmtp.data(), "%d", &pt); if (track._pt != pt) { //pt不匹配 it = track._attr.erase(it); continue; } track._fmtp = FindField(fmtp.data(), " ", nullptr); ++it; } it = track._attr.find("control"); if (it != track._attr.end()) { track._control = it->second; } } }
1、track包括三部分:session、audio、video。
2、 auto lines = split(sdp, "\n")取出每一行,然后解析。

vector<string> split(const string &s, const char *delim) { vector<string> ret; size_t last = 0; auto index = s.find(delim, last); while (index != string::npos) { if (index - last > 0) { ret.push_back(s.substr(last, index - last)); } last = index + strlen(delim); index = s.find(delim, last); } if (!s.size() || s.size() - last > 0) { ret.push_back(s.substr(last)); } return ret; }
3、track->_t 表示开始和结束的时间。
4、track->_b 表示带宽
5、if (4 == sscanf(opt_val.data (), " %15[^ ] %d %15[^ ] %d", type, &port, rtp, &pt))处理一个媒体信息。m=video 0 RTP/AVP 96
6、'a'的属性值存入到track->_attr。
7、其他的属性值存入到track->_other中。
8、for (it = track._attr.find("rtpmap"); it != track._attr.end() && it->first == "rtpmap";)解析
(1)sscanf(rtpmap.data(), "%d", &pt);可以得到动态负载类型。
(2) if (4 == sscanf(rtpmap.data(), "%d %15[^/]/%d/%d", &pt, codec, &samplerate, &channel))或else if (3 == sscanf(rtpmap.data(), "%d %15[^/]/%d", &pt, codec, &samplerate)。可以得到动态负载类型、编码名称、时钟频率、及通过号。
9、for (it = track._attr.find("fmtp"); it != track._attr.end() && it->first == "fmtp"; )解fmtp(附加参数),未对附加参数进一步解析。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!