ZLMediaKit source code analysis (3) pull stream creation

ZLMediaKit source code analysis (1) Service startup
ZLMediaKit source code analysis (2) Push stream creation
ZLMediaKit source code analysis (3) Pull stream creation

The ZLMediaKit streaming structure is created after RtspSession::onRecv().
For how to trigger onRecv(), please refer to ZLMediaKit source code analysis (1) Service startup and I won’t go into details here.
For RtspSession::onRecv() data processing, refer to ZLMediaKit source code analysis (2) Push stream creation, which will not be repeated here.

RtspSession::onRecv()

RtspSession:: onWholeRtspPacket()

RtspSession::handleReq_Options()

RtspSession::handleReq_ANNOUNCE() uplink request

RtspSession::handleReq_SETUP() establishes a connection

RtspSession::handleReq_RECORD() Upstream push

RtspSession::handleReq_Describe() downlink request

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;
}

Create push stream structure 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() Downstream playback

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

Look at the type of RingBuffer::_dispatcher_map, a one-to-many relationship.
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;
};

If the RingReaderDispatcher corresponding to the poller does not exist, construct RingReaderDispatcher::Ptr dispatcher, new RingReaderDispatcher();
if it exists, add a RingReader to RingReaderDispatcher, 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 adds a RingReader

Look at the type of RingReaderDispatcher::_reader_map, a RingReaderDispatcher corresponds to multiple RingReaders.
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 initialization, 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(); };
};

Register RingReader::setGetInfoCB()

Reference: RingReader::setReadCB().

Register RingReader::setDetachCB()

Reference: RingReader::setReadCB().

Register RingReader::setReadCB()

Implementation reference: RingReaderDispatcher adds a RingReader.
transfer:

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);
        });
    }
}

Call RingReader::setReadCB(), and the final registered function is RtspSession::sendRtpPacket(). Tossed to the top again.

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() break link

RtspSession::onRtpPacket() data input

Mainly called by streaming

RtspSession::onRtpSorted() After the data is sorted

Data distribution
Refer to ZLMediaKit source code analysis (2) Push stream creation and will not go into details here.

Guess you like

Origin blog.csdn.net/cliffordl/article/details/131113146