ZLMediaKit源码分析(一)服务启动
ZLMediaKit源码分析(二)推流创建
ZLMediaKit源码分析(三)拉流创建
ZLMediaKit源码分析(四)重封装
ZLMediaKit源码分析(五)代理服务
ZLMediaKit源码分析(六)http 点播
ZLMediaKit拉流结构体创建是在RtspSession::onRecv()之后。
如何触发onRecv()请参考ZLMediaKit源码分析(一)服务启动这里不在赘述。
RtspSession::onRecv()数据处理参考ZLMediaKit源码分析(二)推流创建这里也不再赘述。
继承关系
RtspSession::onRecv()
RtspSession:: onWholeRtspPacket()
RtspSession::handleReq_Options()
RtspSession::handleReq_ANNOUNCE()上行请求
RtspSession::handleReq_SETUP() 建立链接
RtspSession::handleReq_RECORD() 上行推流
RtspSession::handleReq_Describe() 下行请求
src/Rtsp/RtspSession.cpp
void RtspSession::handleReq_Describe(const Parser &parser) {
//该请求中的认证信息
auto authorization = parser["Authorization"];
weak_ptr<RtspSession> weak_self = dynamic_pointer_cast<RtspSession>(shared_from_this());
//rtsp专属鉴权是否开启事件回调
onGetRealm invoker = [weak_self, authorization](const string &realm) {
auto strong_self = weak_self.lock();
if (!strong_self) {
//本对象已经销毁
return;
}
//切换到自己的线程然后执行
strong_self->async([weak_self, realm, authorization]() {
auto strong_self = weak_self.lock();
if (!strong_self) {
//本对象已经销毁
return;
}
if (realm.empty()) {
//无需rtsp专属认证, 那么继续url通用鉴权认证(on_play)
strong_self->emitOnPlay();
return;
}
//该流需要rtsp专属认证,开启rtsp专属认证后,将不再触发url通用鉴权认证(on_play)
strong_self->_rtsp_realm = realm;
strong_self->onAuthUser(realm, authorization);
});
};
if(_rtsp_realm.empty()){
//广播是否需要rtsp专属认证事件
if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm, _media_info, invoker, static_cast<SockInfo &>(*this))) {
//无人监听此事件,说明无需认证
invoker("");
}
}else{
invoker(_rtsp_realm);
}
}
src/Rtsp/RtspSession.cpp
void RtspSession::emitOnPlay(){
weak_ptr<RtspSession> weak_self = dynamic_pointer_cast<RtspSession>(shared_from_this());
//url鉴权回调
auto onRes = [weak_self](const string &err) {
auto strong_self = weak_self.lock();
if (!strong_self) {
return;
}
if (!err.empty()) {
//播放url鉴权失败
strong_self->sendRtspResponse("401 Unauthorized", {"Content-Type", "text/plain"}, err);
strong_self->shutdown(SockException(Err_shutdown, StrPrinter << "401 Unauthorized:" << err));
return;
}
strong_self->onAuthSuccess();
};
Broadcast::AuthInvoker invoker = [weak_self, onRes](const string &err) {
auto strong_self = weak_self.lock();
if (!strong_self) {
return;
}
strong_self->async([onRes, err, weak_self]() {
onRes(err);
});
};
//广播通用播放url鉴权事件
auto flag = _emit_on_play ? false : NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _media_info, invoker, static_cast<SockInfo &>(*this));
if (!flag) {
//该事件无人监听,默认不鉴权
onRes("");
}
//已经鉴权过了
_emit_on_play = true;
}
创建推流结构体RtspMediaSource
src/Rtsp/RtspSession.cpp
void RtspSession::onAuthSuccess() {
TraceP(this);
weak_ptr<RtspSession> weak_self = dynamic_pointer_cast<RtspSession>(shared_from_this());
// 查找流是否存在
// 返回MediaSource::Ptr src
MediaSource::findAsync(_media_info, weak_self.lock(), [weak_self](const MediaSource::Ptr &src){
// RtspSession strong_self
auto strong_self = weak_self.lock();
if(!strong_self){
return;
}
// 转换为派生类的指针
// 派生出RtspMediaSource??
// 打印显示 rtsp_src依然是src的指针内容
auto rtsp_src = dynamic_pointer_cast<RtspMediaSource>(src);
if (!rtsp_src) {
//未找到相应的MediaSource
string err = StrPrinter << "no such stream:" << strong_self->_media_info.shortUrl();
strong_self->send_StreamNotFound();
strong_self->shutdown(SockException(Err_shutdown,err));
return;
}
//找到了相应的rtsp流
// rtsp_src->getSdp() 返回字符串
strong_self->_sdp_track = SdpParser(rtsp_src->getSdp()).getAvailableTrack();
if (strong_self->_sdp_track.empty()) {
//该流无效
WarnL << "sdp中无有效track,该流无效:" << rtsp_src->getSdp();
strong_self->send_StreamNotFound();
strong_self->shutdown(SockException(Err_shutdown,"can not find any available track in sdp"));
return;
}
strong_self->_rtcp_context.clear();
for (auto &track : strong_self->_sdp_track) {
strong_self->_rtcp_context.emplace_back(std::make_shared<RtcpContextForSend>());
}
// 更新sessionid
strong_self->_sessionid = makeRandStr(12);
strong_self->_play_src = rtsp_src;
for(auto &track : strong_self->_sdp_track){
track->_ssrc = rtsp_src->getSsrc(track->_type);
track->_seq = rtsp_src->getSeqence(track->_type);
track->_time_stamp = rtsp_src->getTimeStamp(track->_type);
}
// 返回数据包含sessionid???
// sendRtspResponse 返回时会主动加上 sessionid 具体参考函数实现
// if(!_sessionid.empty()){
// header.emplace("Session", _sessionid);
// }
strong_self->sendRtspResponse("200 OK",
{"Content-Base", strong_self->_content_base + "/",
"x-Accept-Retransmit","our-retransmit",
"x-Accept-Dynamic-Rate","1"
},rtsp_src->getSdp());
});
}
RtspSession::handleReq_Play() 下行播放
src/Rtsp/RtspSession.cpp
void RtspSession::handleReq_Play(const Parser &parser) {
// parser中包含sessionid, 是的。
if (_sdp_track.empty() || parser["Session"] != _sessionid) {
send_SessionNotFound();
throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any available track when play" : "session not found when play");
}
//直播源读取器
// RtspMediaSource::RingType::RingReader::Ptr _play_reader;
//rtsp播放器绑定的直播源
// std::weak_ptr<RtspMediaSource> _play_src;
// _play_src 创建应该在handleReq_Describe()
auto play_src = _play_src.lock();
if(!play_src){
send_StreamNotFound();
shutdown(SockException(Err_shutdown,"rtsp stream released"));
return;
}
bool use_gop = true;
auto &strScale = parser["Scale"];
auto &strRange = parser["Range"];
StrCaseMap res_header;
if (!strScale.empty()) {
//这是设置播放速度
res_header.emplace("Scale", strScale);
auto speed = atof(strScale.data());
play_src->speed(speed);
InfoP(this) << "rtsp set play speed:" << speed;
}
if (!strRange.empty()) {
//这是seek操作
res_header.emplace("Range", strRange);
auto strStart = FindField(strRange.data(), "npt=", "-");
if (strStart == "now") {
strStart = "0";
}
auto iStartTime = 1000 * (float) atof(strStart.data());
use_gop = !play_src->seekTo((uint32_t) iStartTime);
InfoP(this) << "rtsp seekTo(ms):" << iStartTime;
}
vector<TrackType> inited_tracks;
_StrPrinter rtp_info;
for (auto &track : _sdp_track) {
if (track->_inited == false) {
//为支持播放器播放单一track, 不校验没有发setup的track
continue;
}
inited_tracks.emplace_back(track->_type);
track->_ssrc = play_src->getSsrc(track->_type);
track->_seq = play_src->getSeqence(track->_type);
track->_time_stamp = play_src->getTimeStamp(track->_type);
rtp_info << "url=" << track->getControlUrl(_content_base) << ";"
<< "seq=" << track->_seq << ";"
<< "rtptime=" << (int) (track->_time_stamp * (track->_samplerate / 1000)) << ",";
}
rtp_info.pop_back();
res_header.emplace("RTP-Info", rtp_info);
//已存在Range时不覆盖
res_header.emplace("Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << play_src->getTimeStamp(TrackInvalid) / 1000.0);
sendRtspResponse("200 OK", res_header);
//设置播放track
if (inited_tracks.size() == 1) {
_target_play_track = inited_tracks[0];
InfoP(this) << "指定播放track:" << _target_play_track;
}
//在回复rtsp信令后再恢复播放
play_src->pause(false);
setSocketFlags();
//直播源读取器
// RtspMediaSource::RingType::RingReader::Ptr _play_reader;
if (!_play_reader && _rtp_type != Rtsp::RTP_MULTICAST) {
weak_ptr<RtspSession> weak_self = dynamic_pointer_cast<RtspSession>(shared_from_this());
//直播源读取器
// RtspMediaSource::RingType::RingReader::Ptr _play_reader;
//rtsp播放器绑定的直播源
// std::weak_ptr<RtspMediaSource> _play_src;
// RtspMediaSource::getRing()返回 (RingType::Ptr)RtspMediaSource::_ring;
_play_reader = play_src->getRing()->attach(getPoller(), use_gop);
_play_reader->setGetInfoCB([weak_self]() { return weak_self.lock(); });
_play_reader->setDetachCB([weak_self]() {
auto strong_self = weak_self.lock();
if (!strong_self) {
return;
}
strong_self->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
});
// weak_ptr<RtspSession> weak_self = dynamic_pointer_cast<RtspSession>(shared_from_this());
_play_reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pack) {
auto strong_self = weak_self.lock();
if (!strong_self) {
return;
}
strong_self->sendRtpPacket(pack);
});
}
}
RtspSession::_ring添加RingReaderDispatcher
看RingBuffer::_dispatcher_map的类型吧,一对多的关系。
std::unordered_map<EventPoller::Ptr, typename RingReaderDispatcher::Ptr, HashOfPtr> RingBuffer::_dispatcher_map;
src/Rtsp/RtspMediaSource.h
class RtspMediaSource : public MediaSource, public toolkit::RingDelegate<RtpPacket::Ptr>, private PacketCache<RtpPacket> {
public:
using Ptr = std::shared_ptr<RtspMediaSource>;
using RingDataType = std::shared_ptr<toolkit::List<RtpPacket::Ptr> >;
using RingType = toolkit::RingBuffer<RingDataType>;
......
const RingType::Ptr &getRing() const {
return _ring;
}
private:
......
RingType::Ptr _ring;
};
如果poller对应的RingReaderDispatcher不存在,则构造RingReaderDispatcher::Ptr dispatcher,new RingReaderDispatcher();
如果存在则在RingReaderDispatcher添加一个RingReader,dispatcher->attach(poller, use_cache);
3rdpart/ZLToolKit/src/Util/RingBuffer.h
template <typename T>
class RingBuffer : public std::enable_shared_from_this<RingBuffer<T>> {
public:
......
using RingReaderDispatcher = _RingReaderDispatcher<T>;
......
std::shared_ptr<RingReader> attach(const EventPoller::Ptr &poller, bool use_cache = true) {
typename RingReaderDispatcher::Ptr dispatcher;
{
LOCK_GUARD(_mtx_map);
// 数组变量中增加一项。针对poller只会初始化一次
auto &ref = _dispatcher_map[poller];
// 如果不存在则创建RingReaderDispatcher
if (!ref) {
std::weak_ptr<RingBuffer> weak_self = this->shared_from_this();
// 定义回调函数,最终调用RingReader的onSizeChanged()
auto onSizeChanged = [weak_self, poller](int size, bool add_flag) {
if (auto strong_self = weak_self.lock()) {
strong_self->onSizeChanged(poller, size, add_flag);
}
};
auto onDealloc = [poller](RingReaderDispatcher *ptr) { poller->async([ptr]() { delete ptr; }); };
// 初始化
ref.reset(new RingReaderDispatcher(_storage->clone(), std::move(onSizeChanged)), std::move(onDealloc));
}
dispatcher = ref;
}
// 返回ringReader
return dispatcher->attach(poller, use_cache);
}
private:
......
std::unordered_map<EventPoller::Ptr, typename RingReaderDispatcher::Ptr, HashOfPtr> _dispatcher_map;
};
RingReaderDispatcher添加一个RingReader
看RingReaderDispatcher::_reader_map的类型吧,一个RingReaderDispatcher,对应多个RingReader。
std::unordered_map<void *, std::weak_ptr> _reader_map;
template <typename T>
class _RingReaderDispatcher : public std::enable_shared_from_this<_RingReaderDispatcher<T>> {
public:
using Ptr = std::shared_ptr<_RingReaderDispatcher>;
using RingReader = _RingReader<T>;
using RingStorage = _RingStorage<T>;
using onChangeInfoCB = std::function<ReaderInfo(ReaderInfo &&info)>;
......
private:
_RingReaderDispatcher(
const typename RingStorage::Ptr &storage, std::function<void(int, bool)> onSizeChanged) {
_reader_size = 0;
_storage = storage;
_on_size_changed = std::move(onSizeChanged);
assert(_on_size_changed);
}
......
std::shared_ptr<RingReader> attach(const EventPoller::Ptr &poller, bool use_cache) {
if (!poller->isCurrentThread()) {
throw std::runtime_error("You can attach RingBuffer only in it's poller thread");
}
std::weak_ptr<_RingReaderDispatcher> weak_self = this->shared_from_this();
// 回调函数 一个用户退出
auto on_dealloc = [weak_self, poller](RingReader *ptr) {
poller->async([weak_self, ptr]() {
auto strong_self = weak_self.lock();
if (strong_self && strong_self->_reader_map.erase(ptr)) {
--strong_self->_reader_size;
strong_self->onSizeChanged(false);
}
delete ptr;
});
};
// 这个应该是下行用户的追加项了
std::shared_ptr<RingReader> reader(new RingReader(use_cache ? _storage : nullptr), on_dealloc);
// _reader_map中添加reader
_reader_map[reader.get()] = reader;
++_reader_size;
onSizeChanged(true);
return reader;
}
......
private:
std::atomic_int _reader_size;
std::function<void(int, bool)> _on_size_changed;
typename RingStorage::Ptr _storage;
std::unordered_map<void *, std::weak_ptr<RingReader>> _reader_map;
};
RingReader初始化,new RingReader()。
3rdpart/ZLToolKit/src/Util/RingBuffer.h
template <typename T>
class _RingReader {
public:
using Ptr = std::shared_ptr<_RingReader>;
friend class _RingReaderDispatcher<T>;
_RingReader(std::shared_ptr<_RingStorage<T>> storage) { _storage = std::move(storage); }
~_RingReader() = default;
void setReadCB(std::function<void(const T &)> cb) {
if (!cb) {
_read_cb = [](const T &) {};
} else {
_read_cb = std::move(cb);
flushGop();
}
}
void setDetachCB(std::function<void()> cb) {
_detach_cb = cb ? std::move(cb) : []() {};
}
void setGetInfoCB(std::function<ReaderInfo()> cb) {
_get_info = cb ? std::move(cb) : []() { return ReaderInfo(); };
}
private:
void onRead(const T &data, bool /*is_key*/) { _read_cb(data); }
void onDetach() const { _detach_cb(); }
void flushGop() {
if (!_storage) {
return;
}
_storage->getCache().for_each([this](const List<std::pair<bool, T>> &lst) {
lst.for_each([this](const std::pair<bool, T> &pr) { onRead(pr.second, pr.first); });
});
}
ReaderInfo getInfo() { return _get_info(); }
private:
std::shared_ptr<_RingStorage<T>> _storage;
std::function<void(void)> _detach_cb = []() {};
std::function<void(const T &)> _read_cb = [](const T &) {};
std::function<ReaderInfo()> _get_info = []() { return ReaderInfo(); };
};
注册RingReader::setGetInfoCB()
参考:RingReader::setReadCB()。
注册RingReader::setDetachCB()
参考:RingReader::setReadCB()。
注册RingReader::setReadCB()
实现参考:RingReaderDispatcher添加一个RingReader。
调用:
src/Rtsp/RtspSession.cpp
void RtspSession::handleReq_Play(const Parser &parser) {
......
auto play_src = _play_src.lock();
......
//直播源读取器
// RtspMediaSource::RingType::RingReader::Ptr _play_reader;
if (!_play_reader && _rtp_type != Rtsp::RTP_MULTICAST) {
......
_play_reader = play_src->getRing()->attach(getPoller(), use_gop);
_play_reader->setGetInfoCB([weak_self]() { return weak_self.lock(); });
_play_reader->setDetachCB([weak_self]() {
auto strong_self = weak_self.lock();
if (!strong_self) {
return;
}
strong_self->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
});
// weak_ptr<RtspSession> weak_self = dynamic_pointer_cast<RtspSession>(shared_from_this());
_play_reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pack) {
auto strong_self = weak_self.lock();
if (!strong_self) {
return;
}
strong_self->sendRtpPacket(pack);
});
}
}
调用RingReader::setReadCB(),最终注册函数为RtspSession::sendRtpPacket()。又抛到最上层了。
src/Rtsp/RtspSession.cpp
void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) {
switch (_rtp_type) {
case Rtsp::RTP_TCP: {
setSendFlushFlag(false);
pkt->for_each([&](const RtpPacket::Ptr &rtp) {
if (_target_play_track == TrackInvalid || _target_play_track == rtp->type) {
updateRtcpContext(rtp);
send(rtp);
}
});
flushAll();
setSendFlushFlag(true);
}
break;
case Rtsp::RTP_UDP: {
//下标0表示视频,1表示音频
Socket::Ptr rtp_socks[2];
rtp_socks[TrackVideo] = _rtp_socks[getTrackIndexByTrackType(TrackVideo)];
rtp_socks[TrackAudio] = _rtp_socks[getTrackIndexByTrackType(TrackAudio)];
pkt->for_each([&](const RtpPacket::Ptr &rtp) {
if (_target_play_track == TrackInvalid || _target_play_track == rtp->type) {
updateRtcpContext(rtp);
auto &sock = rtp_socks[rtp->type];
if (!sock) {
shutdown(SockException(Err_shutdown, "udp sock not opened yet"));
return;
}
_bytes_usage += rtp->size() - RtpPacket::kRtpTcpHeaderSize;
sock->send(std::make_shared<BufferRtp>(rtp, RtpPacket::kRtpTcpHeaderSize), nullptr, 0, false);
}
});
for (auto &sock : rtp_socks) {
if (sock) {
sock->flushAll();
}
}
}
break;
default:
break;
}
}
RtspSession::handleReq_TEARDOWN() 断开链接
RtspSession:: onRtpPacket()数据输入
主要由推流调用文章来源:https://www.toymoban.com/news/detail-477022.html
RtspSession::onRtpSorted() 数据排序后
数据分发
参考ZLMediaKit源码分析(二)推流创建这里也不再赘述。文章来源地址https://www.toymoban.com/news/detail-477022.html
到了这里,关于ZLMediaKit源码分析(三)拉流创建的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!