ZLMedia中RTSP协议的处理简要分析(2)--SDP解析函数
通过void SdpParser::load(const string &sdp)解析。
View Code
View Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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")取出每一行,然后解析。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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(附加参数),未对附加参数进一步解析。