ZLMediaKit源码分析(三)拉流创建

ZLMediaKit源码分析(一)服务启动
ZLMediaKit源码分析(二)推流创建
ZLMediaKit源码分析(三)拉流创建
ZLMediaKit源码分析(四)重封装
ZLMediaKit源码分析(五)代理服务
ZLMediaKit源码分析(六)http 点播

ZLMediaKit拉流结构体创建是在RtspSession::onRecv()之后。
如何触发onRecv()请参考ZLMediaKit源码分析(一)服务启动这里不在赘述。
RtspSession::onRecv()数据处理参考ZLMediaKit源码分析(二)推流创建这里也不再赘述。

继承关系

RtspMediaSourceImp

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()数据输入

主要由推流调用

RtspSession::onRtpSorted() 数据排序后

数据分发
参考ZLMediaKit源码分析(二)推流创建这里也不再赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值