mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-25 20:27:34 +08:00
兼容一些奇怪的rtsp流:#1031
This commit is contained in:
parent
8b1d1d6e24
commit
07c5341fb0
@ -26,7 +26,18 @@
|
||||
namespace mediakit{
|
||||
|
||||
Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
if (strcasecmp(track->_codec.data(), "mpeg4-generic") == 0) {
|
||||
auto codec = getCodecId(track->_codec);
|
||||
if (codec == CodecInvalid) {
|
||||
//根据传统的payload type 获取编码类型以及采样率等信息
|
||||
codec = RtpPayload::getCodecId(track->_pt);
|
||||
}
|
||||
switch (codec) {
|
||||
case CodecG711A:
|
||||
case CodecG711U: return std::make_shared<G711Track>(codec, track->_samplerate, track->_channel, 16);
|
||||
case CodecL16: return std::make_shared<L16Track>(track->_samplerate, track->_channel);
|
||||
case CodecOpus : return std::make_shared<OpusTrack>();
|
||||
|
||||
case CodecAAC : {
|
||||
string aac_cfg_str = FindField(track->_fmtp.data(), "config=", ";");
|
||||
if (aac_cfg_str.empty()) {
|
||||
aac_cfg_str = FindField(track->_fmtp.data(), "config=", nullptr);
|
||||
@ -36,70 +47,49 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
return nullptr;
|
||||
}
|
||||
string aac_cfg;
|
||||
for(size_t i = 0 ; i < aac_cfg_str.size() / 2 ; ++i ){
|
||||
for (size_t i = 0; i < aac_cfg_str.size() / 2; ++i) {
|
||||
unsigned int cfg;
|
||||
sscanf(aac_cfg_str.substr(i * 2, 2).data(), "%02X", &cfg);
|
||||
cfg &= 0x00FF;
|
||||
aac_cfg.push_back((char)cfg);
|
||||
aac_cfg.push_back((char) cfg);
|
||||
}
|
||||
return std::make_shared<AACTrack>(aac_cfg);
|
||||
}
|
||||
|
||||
if (strcasecmp(track->_codec.data(), "opus") == 0) {
|
||||
return std::make_shared<OpusTrack>();
|
||||
}
|
||||
|
||||
if (strcasecmp(track->_codec.data(), "PCMA") == 0) {
|
||||
return std::make_shared<G711Track>(CodecG711A, track->_samplerate, track->_channel, 16);
|
||||
}
|
||||
|
||||
if (strcasecmp(track->_codec.data(), "PCMU") == 0) {
|
||||
return std::make_shared<G711Track>(CodecG711U, track->_samplerate, track->_channel, 16);
|
||||
}
|
||||
|
||||
if (strcasecmp(track->_codec.data(), "L16") == 0) {
|
||||
return std::make_shared<L16Track>(track->_samplerate, track->_channel);
|
||||
}
|
||||
|
||||
if (strcasecmp(track->_codec.data(), "h264") == 0) {
|
||||
case CodecH264 : {
|
||||
//a=fmtp:96 packetization-mode=1;profile-level-id=42C01F;sprop-parameter-sets=Z0LAH9oBQBboQAAAAwBAAAAPI8YMqA==,aM48gA==
|
||||
auto map = Parser::parseArgs(FindField(track->_fmtp.data()," ", nullptr),";","=");
|
||||
auto map = Parser::parseArgs(track->_fmtp, ";", "=");
|
||||
auto sps_pps = map["sprop-parameter-sets"];
|
||||
string base64_SPS = FindField(sps_pps.data(), NULL, ",");
|
||||
string base64_PPS = FindField(sps_pps.data(), ",", NULL);
|
||||
auto sps = decodeBase64(base64_SPS);
|
||||
auto pps = decodeBase64(base64_PPS);
|
||||
if(sps.empty() || pps.empty()){
|
||||
if (sps.empty() || pps.empty()) {
|
||||
//如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps
|
||||
return std::make_shared<H264Track>();
|
||||
}
|
||||
|
||||
return std::make_shared<H264Track>(sps,pps,0,0);
|
||||
return std::make_shared<H264Track>(sps, pps, 0, 0);
|
||||
}
|
||||
|
||||
if (strcasecmp(track->_codec.data(), "h265") == 0) {
|
||||
case CodecH265: {
|
||||
//a=fmtp:96 sprop-sps=QgEBAWAAAAMAsAAAAwAAAwBdoAKAgC0WNrkky/AIAAADAAgAAAMBlQg=; sprop-pps=RAHA8vA8kAA=
|
||||
auto map = Parser::parseArgs(FindField(track->_fmtp.data()," ", nullptr),";","=");
|
||||
auto map = Parser::parseArgs(track->_fmtp, ";", "=");
|
||||
auto vps = decodeBase64(map["sprop-vps"]);
|
||||
auto sps = decodeBase64(map["sprop-sps"]);
|
||||
auto pps = decodeBase64(map["sprop-pps"]);
|
||||
if(sps.empty() || pps.empty()){
|
||||
if (sps.empty() || pps.empty()) {
|
||||
//如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps
|
||||
return std::make_shared<H265Track>();
|
||||
}
|
||||
return std::make_shared<H265Track>(vps,sps,pps,0,0,0);
|
||||
return std::make_shared<H265Track>(vps, sps, pps, 0, 0, 0);
|
||||
}
|
||||
|
||||
//可以根据传统的payload type 获取编码类型以及采样率等信息
|
||||
CodecId codec_id = RtpPayload::getCodecId(track->_pt);
|
||||
switch (codec_id){
|
||||
case CodecG711A :
|
||||
case CodecG711U : return std::make_shared<G711Track>(codec_id, track->_samplerate, track->_channel, 16);
|
||||
default : break;
|
||||
}
|
||||
|
||||
WarnL << "暂不支持该sdp:" << track->getName();
|
||||
default: {
|
||||
//其他codec不支持
|
||||
WarnL << "暂不支持该rtsp编码类型:" << track->getName();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) {
|
||||
|
@ -12,41 +12,45 @@
|
||||
#include "Rtsp.h"
|
||||
#include "Common/Parser.h"
|
||||
|
||||
namespace mediakit{
|
||||
namespace mediakit {
|
||||
|
||||
int RtpPayload::getClockRate(int pt){
|
||||
switch (pt){
|
||||
int RtpPayload::getClockRate(int pt) {
|
||||
switch (pt) {
|
||||
#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) case value : return clock_rate;
|
||||
RTP_PT_MAP(SWITCH_CASE)
|
||||
#undef SWITCH_CASE
|
||||
default: return 90000;
|
||||
default:
|
||||
return 90000;
|
||||
}
|
||||
}
|
||||
|
||||
TrackType RtpPayload::getTrackType(int pt){
|
||||
switch (pt){
|
||||
TrackType RtpPayload::getTrackType(int pt) {
|
||||
switch (pt) {
|
||||
#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) case value : return type;
|
||||
RTP_PT_MAP(SWITCH_CASE)
|
||||
#undef SWITCH_CASE
|
||||
default: return TrackInvalid;
|
||||
default:
|
||||
return TrackInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
int RtpPayload::getAudioChannel(int pt){
|
||||
switch (pt){
|
||||
int RtpPayload::getAudioChannel(int pt) {
|
||||
switch (pt) {
|
||||
#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) case value : return channel;
|
||||
RTP_PT_MAP(SWITCH_CASE)
|
||||
#undef SWITCH_CASE
|
||||
default: return 1;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const char * RtpPayload::getName(int pt){
|
||||
switch (pt){
|
||||
const char *RtpPayload::getName(int pt) {
|
||||
switch (pt) {
|
||||
#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) case value : return #name;
|
||||
RTP_PT_MAP(SWITCH_CASE)
|
||||
#undef SWITCH_CASE
|
||||
default: return "unknown payload type";
|
||||
default:
|
||||
return "unknown payload type";
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,75 +59,77 @@ CodecId RtpPayload::getCodecId(int pt) {
|
||||
#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) case value : return codec_id;
|
||||
RTP_PT_MAP(SWITCH_CASE)
|
||||
#undef SWITCH_CASE
|
||||
default : return CodecInvalid;
|
||||
default :
|
||||
return CodecInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
static void getAttrSdp(const map<string, string> &attr, _StrPrinter &printer){
|
||||
static void getAttrSdp(const multimap<string, string> &attr, _StrPrinter &printer) {
|
||||
const map<string, string>::value_type *ptr = nullptr;
|
||||
for(auto &pr : attr){
|
||||
if(pr.first == "control"){
|
||||
for (auto &pr : attr) {
|
||||
if (pr.first == "control") {
|
||||
ptr = ≺
|
||||
continue;
|
||||
}
|
||||
if(pr.second.empty()){
|
||||
if (pr.second.empty()) {
|
||||
printer << "a=" << pr.first << "\r\n";
|
||||
}else{
|
||||
} else {
|
||||
printer << "a=" << pr.first << ":" << pr.second << "\r\n";
|
||||
}
|
||||
}
|
||||
if(ptr){
|
||||
if (ptr) {
|
||||
printer << "a=" << ptr->first << ":" << ptr->second << "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
string SdpTrack::getName() const{
|
||||
switch (_pt){
|
||||
string SdpTrack::getName() const {
|
||||
switch (_pt) {
|
||||
#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) case value : return #name;
|
||||
RTP_PT_MAP(SWITCH_CASE)
|
||||
#undef SWITCH_CASE
|
||||
default: return _codec;
|
||||
default:
|
||||
return _codec;
|
||||
}
|
||||
}
|
||||
|
||||
string SdpTrack::getControlUrl(const string &base_url) const{
|
||||
string SdpTrack::getControlUrl(const string &base_url) const {
|
||||
if (_control.find("://") != string::npos) {
|
||||
//以rtsp://开头
|
||||
return _control;
|
||||
}
|
||||
return base_url +"/" + _control;
|
||||
return base_url + "/" + _control;
|
||||
}
|
||||
|
||||
string SdpTrack::toString() const {
|
||||
_StrPrinter _printer;
|
||||
switch (_type){
|
||||
case TrackTitle:{
|
||||
switch (_type) {
|
||||
case TrackTitle: {
|
||||
_printer << "v=" << 0 << "\r\n";
|
||||
if(!_o.empty()){
|
||||
_printer << "o="<< _o << "\r\n";
|
||||
if (!_o.empty()) {
|
||||
_printer << "o=" << _o << "\r\n";
|
||||
}
|
||||
if(!_c.empty()){
|
||||
if (!_c.empty()) {
|
||||
_printer << "c=" << _c << "\r\n";
|
||||
}
|
||||
if(!_t.empty()){
|
||||
if (!_t.empty()) {
|
||||
_printer << "t=" << _t << "\r\n";
|
||||
}
|
||||
|
||||
_printer << "s=Streamed by " << SERVER_NAME << "\r\n";
|
||||
getAttrSdp(_attr,_printer);
|
||||
getAttrSdp(_attr, _printer);
|
||||
}
|
||||
break;
|
||||
case TrackAudio:
|
||||
case TrackVideo:{
|
||||
if(_type == TrackAudio){
|
||||
case TrackVideo: {
|
||||
if (_type == TrackAudio) {
|
||||
_printer << "m=audio 0 RTP/AVP " << _pt << "\r\n";
|
||||
}else{
|
||||
} else {
|
||||
_printer << "m=video 0 RTP/AVP " << _pt << "\r\n";
|
||||
}
|
||||
if(!_b.empty()){
|
||||
_printer << "b=" <<_b << "\r\n";
|
||||
if (!_b.empty()) {
|
||||
_printer << "b=" << _b << "\r\n";
|
||||
}
|
||||
getAttrSdp(_attr,_printer);
|
||||
getAttrSdp(_attr, _printer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -200,9 +206,9 @@ void SdpParser::load(const string &sdp) {
|
||||
case 'a': {
|
||||
string attr = FindField(opt_val.data(), nullptr, ":");
|
||||
if (attr.empty()) {
|
||||
track->_attr[opt_val] = "";
|
||||
track->_attr.emplace(opt_val, "");
|
||||
} else {
|
||||
track->_attr[attr] = FindField(opt_val.data(), ":", nullptr);
|
||||
track->_attr.emplace(attr, FindField(opt_val.data(), ":", nullptr));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -229,13 +235,18 @@ void SdpParser::load(const string &sdp) {
|
||||
}
|
||||
}
|
||||
|
||||
it = track._attr.find("rtpmap");
|
||||
if (it != track._attr.end()) {
|
||||
auto rtpmap = it->second;
|
||||
for (it = track._attr.find("rtpmap"); it != track._attr.end();) {
|
||||
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._pt = pt;
|
||||
track._codec = codec;
|
||||
track._samplerate = samplerate;
|
||||
track._channel = channel;
|
||||
@ -248,11 +259,20 @@ void SdpParser::load(const string &sdp) {
|
||||
//未设置视频采样率时,赋值为90000
|
||||
track._samplerate = 90000;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
it = track._attr.find("fmtp");
|
||||
if (it != track._attr.end()) {
|
||||
track._fmtp = it->second;
|
||||
for (it = track._attr.find("fmtp"); it != track._attr.end(); ) {
|
||||
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");
|
||||
@ -267,8 +287,8 @@ bool SdpParser::available() const {
|
||||
}
|
||||
|
||||
SdpTrack::Ptr SdpParser::getTrack(TrackType type) const {
|
||||
for (auto &track : _track_vec){
|
||||
if(track->_type == type){
|
||||
for (auto &track : _track_vec) {
|
||||
if (track->_type == type) {
|
||||
return track;
|
||||
}
|
||||
}
|
||||
@ -279,17 +299,17 @@ vector<SdpTrack::Ptr> SdpParser::getAvailableTrack() const {
|
||||
vector<SdpTrack::Ptr> ret;
|
||||
bool audio_added = false;
|
||||
bool video_added = false;
|
||||
for (auto &track : _track_vec){
|
||||
if(track->_type == TrackAudio ){
|
||||
if(!audio_added){
|
||||
for (auto &track : _track_vec) {
|
||||
if (track->_type == TrackAudio) {
|
||||
if (!audio_added) {
|
||||
ret.emplace_back(track);
|
||||
audio_added = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(track->_type == TrackVideo ){
|
||||
if(!video_added){
|
||||
if (track->_type == TrackVideo) {
|
||||
if (!video_added) {
|
||||
ret.emplace_back(track);
|
||||
video_added = true;
|
||||
}
|
||||
@ -300,18 +320,18 @@ vector<SdpTrack::Ptr> SdpParser::getAvailableTrack() const {
|
||||
}
|
||||
|
||||
string SdpParser::toString() const {
|
||||
string title,audio,video;
|
||||
for(auto &track : _track_vec){
|
||||
switch (track->_type){
|
||||
case TrackTitle:{
|
||||
string title, audio, video;
|
||||
for (auto &track : _track_vec) {
|
||||
switch (track->_type) {
|
||||
case TrackTitle: {
|
||||
title = track->toString();
|
||||
}
|
||||
break;
|
||||
case TrackVideo:{
|
||||
case TrackVideo: {
|
||||
video = track->toString();
|
||||
}
|
||||
break;
|
||||
case TrackAudio:{
|
||||
case TrackAudio: {
|
||||
audio = track->toString();
|
||||
}
|
||||
break;
|
||||
@ -375,7 +395,7 @@ bool RtspUrl::setup(bool isSSL, const string &strUrl, const string &strUser, con
|
||||
return true;
|
||||
}
|
||||
|
||||
static void makeSockPair_l(std::pair<Socket::Ptr, Socket::Ptr> &pair, const string &local_ip){
|
||||
static void makeSockPair_l(std::pair<Socket::Ptr, Socket::Ptr> &pair, const string &local_ip) {
|
||||
auto &pSockRtp = pair.first;
|
||||
auto &pSockRtcp = pair.second;
|
||||
|
||||
@ -399,7 +419,7 @@ static void makeSockPair_l(std::pair<Socket::Ptr, Socket::Ptr> &pair, const stri
|
||||
}
|
||||
}
|
||||
|
||||
void makeSockPair(std::pair<Socket::Ptr, Socket::Ptr> &pair, const string &local_ip){
|
||||
void makeSockPair(std::pair<Socket::Ptr, Socket::Ptr> &pair, const string &local_ip) {
|
||||
int try_count = 0;
|
||||
while (true) {
|
||||
try {
|
||||
@ -415,7 +435,7 @@ static void makeSockPair_l(std::pair<Socket::Ptr, Socket::Ptr> &pair, const stri
|
||||
}
|
||||
|
||||
string printSSRC(uint32_t ui32Ssrc) {
|
||||
char tmp[9] = { 0 };
|
||||
char tmp[9] = {0};
|
||||
ui32Ssrc = htonl(ui32Ssrc);
|
||||
uint8_t *pSsrc = (uint8_t *) &ui32Ssrc;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@ -424,7 +444,7 @@ string printSSRC(uint32_t ui32Ssrc) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Buffer::Ptr makeRtpOverTcpPrefix(uint16_t size, uint8_t interleaved){
|
||||
Buffer::Ptr makeRtpOverTcpPrefix(uint16_t size, uint8_t interleaved) {
|
||||
auto rtp_tcp = BufferRaw::create();
|
||||
rtp_tcp->setCapacity(RtpPacket::kRtpTcpHeaderSize);
|
||||
rtp_tcp->setSize(RtpPacket::kRtpTcpHeaderSize);
|
||||
@ -463,7 +483,7 @@ size_t RtpHeader::getExtSize() const {
|
||||
return AV_RB16(ext_ptr + 2) << 2;
|
||||
}
|
||||
|
||||
uint16_t RtpHeader::getExtReserved() const{
|
||||
uint16_t RtpHeader::getExtReserved() const {
|
||||
//rtp有ext
|
||||
if (!ext) {
|
||||
return 0;
|
||||
@ -498,7 +518,7 @@ size_t RtpHeader::getPaddingSize(size_t rtp_size) const {
|
||||
return *end;
|
||||
}
|
||||
|
||||
size_t RtpHeader::getPayloadSize(size_t rtp_size) const{
|
||||
size_t RtpHeader::getPayloadSize(size_t rtp_size) const {
|
||||
auto invalid_size = getPayloadOffset() + getPaddingSize(rtp_size);
|
||||
if (invalid_size + RtpPacket::kRtpHeaderSize >= rtp_size) {
|
||||
return 0;
|
||||
@ -506,14 +526,14 @@ size_t RtpHeader::getPayloadSize(size_t rtp_size) const{
|
||||
return rtp_size - invalid_size - RtpPacket::kRtpHeaderSize;
|
||||
}
|
||||
|
||||
string RtpHeader::dumpString(size_t rtp_size) const{
|
||||
string RtpHeader::dumpString(size_t rtp_size) const {
|
||||
_StrPrinter printer;
|
||||
printer << "version:" << (int)version << "\r\n";
|
||||
printer << "version:" << (int) version << "\r\n";
|
||||
printer << "padding:" << getPaddingSize(rtp_size) << "\r\n";
|
||||
printer << "ext:" << getExtSize() << "\r\n";
|
||||
printer << "csrc:" << getCsrcSize() << "\r\n";
|
||||
printer << "mark:" << (int)mark << "\r\n";
|
||||
printer << "pt:" << (int)pt << "\r\n";
|
||||
printer << "mark:" << (int) mark << "\r\n";
|
||||
printer << "pt:" << (int) pt << "\r\n";
|
||||
printer << "seq:" << ntohs(seq) << "\r\n";
|
||||
printer << "stamp:" << ntohl(stamp) << "\r\n";
|
||||
printer << "ssrc:" << ntohl(ssrc) << "\r\n";
|
||||
@ -563,7 +583,7 @@ size_t RtpPacket::getPayloadSize() const {
|
||||
return getHeader()->getPayloadSize(size() - kRtpTcpHeaderSize);
|
||||
}
|
||||
|
||||
RtpPacket::Ptr RtpPacket::create(){
|
||||
RtpPacket::Ptr RtpPacket::create() {
|
||||
#if 0
|
||||
static ResourcePool<RtpPacket> packet_pool;
|
||||
static onceToken token([]() {
|
||||
@ -580,5 +600,5 @@ RtpPacket::Ptr RtpPacket::create(){
|
||||
}//namespace mediakit
|
||||
|
||||
namespace toolkit {
|
||||
StatisticImp(mediakit::RtpPacket);
|
||||
StatisticImp(mediakit::RtpPacket);
|
||||
}
|
@ -220,7 +220,7 @@ public:
|
||||
float _end = 0;
|
||||
|
||||
map<char, string> _other;
|
||||
map<string, string> _attr;
|
||||
multimap<string, string> _attr;
|
||||
|
||||
string toString() const;
|
||||
string getName() const;
|
||||
|
Loading…
Reference in New Issue
Block a user