webrtc 開啟Simulcast功能
阿新 • • 發佈:2018-12-18
webrtc 開啟Simulcast功能
webrtc自帶了Simulcast功能,可以將一個解析度的流編碼成多個解析度併發送,觀看端可以根據頻寬去動態的選擇某個解析度,也可以自己選擇某個解析度,據說在webrtc M70版本提供了對外的介面開啟Simulcast,並 vp8,vp9,h264三種編碼器都支援Simulcast功能,但是在M70版本以下並不支援h264編碼器的Simulcast功能,如果在M70版本以下使用Simulcast功能,需要通過修改SDP來開啟,話不多說,直接上程式碼:
- 標頭檔案
// // sdp_helpers.h // // Created by ilong on 2018/10/29. // Copyright © 2018 ilong. All rights reserved. // #ifndef sdp_helpers_h #define sdp_helpers_h #include <stdio.h> #include <string> #include <vector> class SdpHelpers { public: template<typename T> static T StringTo(std::string str); template<typename T> static std::string ToString(T arg); // return sdp ,numSpatialLayers 表示開啟幾路流,一般是2 static std::string EnableSimulcast(const std::string &sdp, const int numSpatialLayers); private: SdpHelpers(); ~SdpHelpers(); static std::vector<std::string> GetFID(const std::string &sdp); static std::string GetSsrcTagValue(const std::string &sdp, uint64_t fid, std::string &tag); static std::string AddSim(std::vector<uint64_t> &spatialLayers); static std::string AddGroup(uint64_t spatialLayerId, uint64_t spatialLayerIdRtx); static std::string AddSpatialLayer(std::string &cname, std::string &msid, std::string &mslabel, std::string &label, uint64_t spatialLayerId, uint64_t spatialLayerIdRtx); static void StrReplace(std::string &baseString, std::string &src, std::string &dst); static std::string RemoveSsrcLine(std::string &sdp ,uint64_t fid); static void StringReplace( std::string &strBig, const std::string &strsrc, const std::string &strdst); }; #endif /* sdp_helpers_h */
- 實現檔案
// // sdp_helpers.cpp // // Created by ilong on 2018/10/29. // Copyright © 2018 ilong. All rights reserved. // #include "sdp_helpers.h" #include <sstream> #include <regex> SdpHelpers::SdpHelpers(){ } SdpHelpers::~SdpHelpers(){ } template <typename T> T SdpHelpers::StringTo(std::string str) { T tmp; std::stringstream ss; ss << str; ss >> tmp; return tmp; } template<typename T> std::string SdpHelpers::ToString(T arg){ std::stringstream ss; ss << arg; return ss.str(); } std::string SdpHelpers::EnableSimulcast(const std::string &sdp, const int numSpatialLayers){ std::string sdpStr = sdp; uint64_t baseSsrc = 0, baseSsrcRtx = 0; std::vector<std::string> results = SdpHelpers::GetFID(sdp); if (results.size()>2) { baseSsrc = SdpHelpers::StringTo<uint64_t>(results[1]); baseSsrcRtx = SdpHelpers::StringTo<uint64_t>(results[2]); }else{ //LOGW("fid is empty."); return ""; } std::string tag = "cname"; std::string cname = SdpHelpers::GetSsrcTagValue(sdp, baseSsrc, tag); if (cname.length()<=0) { //LOGW("cname length is 0."); return ""; } tag = "msid"; std::string msid = SdpHelpers::GetSsrcTagValue(sdp, baseSsrc, tag); if (msid.length()<=0) { //LOGW("msid length is 0."); return ""; } tag = "mslabel"; std::string mslabel = SdpHelpers::GetSsrcTagValue(sdp, baseSsrc, tag); if (mslabel.length()<=0) { //LOGW("mslabel length is 0."); return ""; } tag = "label"; std::string label = SdpHelpers::GetSsrcTagValue(sdp, baseSsrc, tag); if (label.length()<=0) { //LOGW("label length is 0."); return ""; } sdpStr = SdpHelpers::RemoveSsrcLine(sdpStr, baseSsrc); sdpStr = SdpHelpers::RemoveSsrcLine(sdpStr, baseSsrcRtx); std::vector<uint64_t> spatialLayers; spatialLayers.push_back(baseSsrc); std::vector<uint64_t> spatialLayersRtx; spatialLayersRtx.push_back(baseSsrcRtx); for (int i = 1; i<numSpatialLayers; i++) { spatialLayers.push_back(baseSsrc+i*1000); spatialLayersRtx.push_back(baseSsrcRtx+i*1000); } std::string result = SdpHelpers::AddSim(spatialLayers); for (int i = 0; i < spatialLayers.size(); i++) { result += SdpHelpers::AddGroup(spatialLayers[i], spatialLayersRtx[i]); } for (int i = 0; i < spatialLayers.size(); i++) { result += SdpHelpers::AddSpatialLayer(cname, msid, mslabel, label, spatialLayers[i], spatialLayersRtx[i]); } result += "a=x-google-flag:conference\r\n"; SdpHelpers::StrReplace(sdpStr, results[0], result); return sdpStr; } std::vector<std::string> SdpHelpers::GetFID(const std::string &sdp){ std::string pattern{ "a=ssrc-group:FID ([0-9]*) ([0-9]*)\r?\n" }; // id card std::regex re(pattern); std::smatch results; std::vector<std::string> res; res.clear(); bool ret = std::regex_search(sdp, results, re); if (ret) { for (auto item:results) { res.push_back(item.str()); } } return res; } std::string SdpHelpers::GetSsrcTagValue(const std::string &sdp, uint64_t fid, std::string &tag){ std::stringstream ss; ss << "a=ssrc:" << fid <<" "<< tag <<":(.*)\r?\n"; std::regex re(ss.str()); std::smatch results; bool ret = std::regex_search(sdp, results, re); if (ret) { return results[1].str(); } return ""; } std::string SdpHelpers::AddSim(std::vector<uint64_t> &spatialLayers){ std::string line{"a=ssrc-group:SIM"}; for (auto item:spatialLayers) { line+=" "+SdpHelpers::ToString(item); } return line+"\r\n"; } std::string SdpHelpers::AddGroup(uint64_t spatialLayerId, uint64_t spatialLayerIdRtx){ return "a=ssrc-group:FID "+SdpHelpers::ToString(spatialLayerId)+" "+SdpHelpers::ToString(spatialLayerIdRtx)+"\r\n"; } std::string SdpHelpers::AddSpatialLayer(std::string &cname, std::string &msid, std::string &mslabel, std::string &label, uint64_t spatialLayerId, uint64_t spatialLayerIdRtx){ return "a=ssrc:"+SdpHelpers::ToString(spatialLayerId)+" cname:"+cname+"\r\n"+ "a=ssrc:"+SdpHelpers::ToString(spatialLayerId)+" msid:"+msid+"\r\n"+ "a=ssrc:"+SdpHelpers::ToString(spatialLayerId)+" mslabel:"+mslabel+"\r\n"+ "a=ssrc:"+SdpHelpers::ToString(spatialLayerId)+" label:"+label+"\r\n"+ "a=ssrc:"+SdpHelpers::ToString(spatialLayerIdRtx)+" cname:"+cname+"\r\n"+ "a=ssrc:"+SdpHelpers::ToString(spatialLayerIdRtx)+" msid:"+msid+"\r\n"+ "a=ssrc:"+SdpHelpers::ToString(spatialLayerIdRtx)+" mslabel:"+mslabel+"\r\n"+ "a=ssrc:"+SdpHelpers::ToString(spatialLayerIdRtx)+" label:"+label+"\r\n"; } void SdpHelpers::StrReplace(std::string &baseString, std::string &src, std::string &dst){ SdpHelpers::StringReplace(baseString, src, dst); } void SdpHelpers::StringReplace( std::string &strBig, const std::string &strsrc, const std::string &strdst){ std::string::size_type pos = 0; std::string::size_type srclen = strsrc.size(); std::string::size_type dstlen = strdst.size(); while( (pos=strBig.find(strsrc, pos)) != std::string::npos ){ strBig.replace( pos, srclen, strdst ); pos += dstlen; } } std::string SdpHelpers::RemoveSsrcLine(std::string &sdp ,uint64_t fid){ std::string retStr = sdp; std::stringstream ss; ss << "a=ssrc:" << fid <<".*\r?\n"; std::regex re(ss.str()); std::smatch results; //多次匹配 while (std::regex_search(retStr, results, re)) { for (auto item:results) { SdpHelpers::StringReplace(retStr, item.str(), std::string("")); } } return retStr; }