From 6da3a577a6da6f8cb4be9cd99f1bb700ee8f956c Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Fri, 2 Feb 2018 18:19:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E6=8F=90=E4=BA=A42.0?= =?UTF-8?q?=E7=89=88=E6=9C=AC=EF=BC=8C=E6=94=AF=E6=8C=81=E8=99=9A=E6=8B=9F?= =?UTF-8?q?=E4=B8=BB=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/MediaSource.cpp | 177 +++++++++++++++++++++++++++++++ src/Common/MediaSource.h | 212 +++++++++++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 src/Common/MediaSource.cpp create mode 100644 src/Common/MediaSource.h diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp new file mode 100644 index 00000000..0b1edd47 --- /dev/null +++ b/src/Common/MediaSource.cpp @@ -0,0 +1,177 @@ +/* + * MIT License + * + * Copyright (c) 2016 xiongziliang <771730766@qq.com> + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "MediaSource.h" +#include "MediaFile/MediaReader.h" +#include "Util/util.h" +#include "Rtsp/Rtsp.h" + +using namespace ZL::Util; +using namespace ZL::MediaFile; + + +namespace ZL { +namespace Media { + +recursive_mutex MediaSource::g_mtxMediaSrc; +MediaSource::SchemaVhostAppStreamMap MediaSource::g_mapMediaSrc; + +MediaSource::Ptr MediaSource::find( + const string &schema, + const string &vhost_tmp, + const string &app, + const string &id, + bool bMake) { + string vhost = vhost_tmp; + if(vhost.empty()){ + vhost = DEFAULT_VHOST; + } + lock_guard lock(g_mtxMediaSrc); + MediaSource::Ptr ret; + searchMedia(schema, vhost, app, id, + [&](SchemaVhostAppStreamMap::iterator &it0 , + VhostAppStreamMap::iterator &it1, + AppStreamMap::iterator &it2, + StreamMap::iterator &it3){ + ret = it3->second.lock(); + if(!ret){ + //该对象已经销毁 + it2->second.erase(it3); + eraseIfEmpty(it0,it1,it2); + return false; + } + return true; + }); + if(!ret && bMake){ + //查找某一媒体源,找到后返回 + ret = MediaReader::onMakeMediaSource(schema, vhost,app,id); + } + return ret; + +} +bool MediaSource::regist() { + //注册该源,注册后服务器才能找到该源 + lock_guard lock(g_mtxMediaSrc); + auto pr = g_mapMediaSrc[m_strSchema][m_strVhost][m_strApp].emplace(m_strId,shared_from_this()); + auto success = pr.second; + if(success){ + InfoL << m_strSchema << " " << m_strVhost << " " << m_strApp << " " << m_strId; + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaChanged, + true, + m_strSchema.data(), + m_strVhost.data(), + m_strApp.data(), + m_strId.data()); + } + return success; +} +bool MediaSource::unregist() { + //反注册该源 + lock_guard lock(g_mtxMediaSrc); + return searchMedia(m_strSchema, m_strVhost, m_strApp, m_strId, [&](SchemaVhostAppStreamMap::iterator &it0 , + VhostAppStreamMap::iterator &it1, + AppStreamMap::iterator &it2, + StreamMap::iterator &it3){ + auto strongMedia = it3->second.lock(); + if(strongMedia && this != strongMedia.get()){ + //不是自己,不允许反注册 + return false; + } + it2->second.erase(it3); + eraseIfEmpty(it0,it1,it2); + unregisted(); + return true; + }); +} +void MediaSource::unregisted(){ + InfoL << "" << m_strSchema << " " << m_strVhost << " " << m_strApp << " " << m_strId; + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaChanged, + false, + m_strSchema.data(), + m_strVhost.data(), + m_strApp.data(), + m_strId.data()); +} + +void MediaInfo::parse(const string &url){ + //string url = "rtsp://127.0.0.1:8554/live/id?key=val&a=1&&b=2&vhost=vhost.com"; + auto schema_pos = url.find("://"); + if(schema_pos != string::npos){ + m_schema = url.substr(0,schema_pos); + }else{ + schema_pos = -3; + } + auto split_vec = split(url.substr(schema_pos + 3),"/"); + if(split_vec.size() > 0){ + auto vhost = split_vec[0]; + auto pos = vhost.find(":"); + if(pos != string::npos){ + m_host = m_vhost = vhost.substr(0,pos); + m_port = vhost.substr(pos + 1); + } else{ + m_host = m_vhost = vhost; + } + } + if(split_vec.size() > 1){ + m_app = split_vec[1]; + } + if(split_vec.size() > 2){ + string steamid; + for(int i = 2 ; i < split_vec.size() ; ++i){ + steamid.append(split_vec[i] + "/"); + } + if(steamid.back() == '/'){ + steamid.pop_back(); + } + auto pos = steamid.find("?"); + if(pos != string::npos){ + m_streamid = steamid.substr(0,pos); + auto params = steamid.substr(pos + 1); + m_params = Parser::parseArgs(params); + if(m_params.find(VHOST_KEY) != m_params.end()){ + m_vhost = m_params[VHOST_KEY]; + } + } else{ + m_streamid = steamid; + } + } + if(m_vhost.empty()){ + //无效vhost + m_vhost = DEFAULT_VHOST; + }else{ + struct in_addr addr; + if(0 != inet_aton(m_vhost.data(),&addr)){ + //这是ip,未指定vhost;使用默认vhost + m_vhost = DEFAULT_VHOST; + } + } + +} + + +} /* namespace Media */ +} /* namespace ZL */ \ No newline at end of file diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h new file mode 100644 index 00000000..1ca636f2 --- /dev/null +++ b/src/Common/MediaSource.h @@ -0,0 +1,212 @@ +/* + * MIT License + * + * Copyright (c) 2016 xiongziliang <771730766@qq.com> + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#ifndef ZLMEDIAKIT_MEDIASOURCE_H +#define ZLMEDIAKIT_MEDIASOURCE_H + +#include +#include +#include +#include +#include +#include "Common/config.h" +#include "Util/logger.h" +#include "Util/TimeTicker.h" +#include "Util/NoticeCenter.h" +#include "Rtsp/Rtsp.h" +#include + + +using namespace std; +using namespace Config; +using namespace ZL::Util; + +namespace ZL { +namespace Media { + +class MediaSourceEvent +{ +public: + MediaSourceEvent(){}; + virtual ~MediaSourceEvent(){}; +public: + virtual bool seekTo(uint32_t ui32Stamp){ + return false; + } + virtual uint32_t getStamp() { + return 0; + } +}; +class MediaInfo +{ +public: + MediaInfo(){} + MediaInfo(const string &url){ + parse(url); + } + ~MediaInfo(){} + + void parse(const string &url); + + string &operator[](const string &key){ + return m_params[key]; + } +public: + string m_schema; + string m_host; + string m_port; + string m_vhost; + string m_app; + string m_streamid; + StrCaseMap m_params; +}; + + +class MediaSource: public enable_shared_from_this { +public: + typedef std::shared_ptr Ptr; + typedef unordered_map > StreamMap; + typedef unordered_map AppStreamMap; + typedef unordered_map VhostAppStreamMap; + typedef unordered_map SchemaVhostAppStreamMap; + + MediaSource(const string &strSchema, + const string &strVhost, + const string &strApp, + const string &strId) : + m_strSchema(strSchema), + m_strApp(strApp), + m_strId(strId) { + if(strVhost.empty()){ + m_strVhost = DEFAULT_VHOST; + }else{ + m_strVhost = strVhost; + } + } + virtual ~MediaSource() { + unregist(); + } + + virtual bool regist() ; + virtual bool unregist() ; + + static Ptr find(const string &schema, + const string &vhost, + const string &app, + const string &id, + bool bMake = true) ; + + const string& getSchema() const { + return m_strSchema; + } + const string& getVhost() const { + return m_strVhost; + } + const string& getApp() const { + //获取该源的id + return m_strApp; + } + const string& getId() const { + return m_strId; + } + + bool seekTo(uint32_t ui32Stamp) { + auto listener = m_listener.lock(); + if(!listener){ + return false; + } + return listener->seekTo(ui32Stamp); + } + + uint32_t getStamp() { + auto listener = m_listener.lock(); + if(!listener){ + return 0; + } + return listener->getStamp(); + } + void setListener(const std::weak_ptr &listener){ + m_listener = listener; + } +private: + template + static bool searchMedia(const string &schema, + const string &vhost, + const string &app, + const string &id, + FUN &&fun){ + auto it0 = g_mapMediaSrc.find(schema); + if (it0 == g_mapMediaSrc.end()) { + //未找到协议 + return false; + } + auto it1 = it0->second.find(vhost); + if(it1 == it0->second.end()){ + //未找到vhost + return false; + } + auto it2 = it1->second.find(app); + if(it2 == it1->second.end()){ + //未找到app + return false; + } + auto it3 = it2->second.find(id); + if(it3 == it2->second.end()){ + //未找到streamId + return false; + } + return fun(it0,it1,it2,it3); + } + template + static void eraseIfEmpty(IT0 it0,IT1 it1,IT2 it2){ + if(it2->second.empty()){ + it1->second.erase(it2); + if(it1->second.empty()){ + it0->second.erase(it1); + if(it0->second.empty()){ + g_mapMediaSrc.erase(it0); + } + } + } + }; + void unregisted(); +protected: + std::weak_ptr m_listener; +private: + string m_strSchema;//协议类型 + string m_strVhost; //vhost + string m_strApp; //媒体app + string m_strId; //媒体id + static SchemaVhostAppStreamMap g_mapMediaSrc; //静态的媒体源表 + static recursive_mutex g_mtxMediaSrc; //访问静态的媒体源表的互斥锁 +}; + +} /* namespace Media */ +} /* namespace ZL */ + + +#endif //ZLMEDIAKIT_MEDIASOURCE_H