From bb00759ce0dc2f28eb5168f7d36208d5ef9e11c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=8F=E6=A5=9A?= <771730766@qq.com> Date: Wed, 17 Jun 2020 16:15:15 +0800 Subject: [PATCH 01/59] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0b022a90..66dfd26b 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,6 @@ bash build_docker_images.sh 欢迎捐赠以便更好的推动项目的发展,谢谢您的支持! -[支付宝](https://raw.githubusercontent.com/xiongziliang/other/master/IMG_3919.JPG) +[支付宝](https://gitee.com/xiahcu/other/raw/master/IMG_3919.JPG) -[微信](https://raw.githubusercontent.com/xiongziliang/other/master/IMG_3920.JPG) +[微信](https://gitee.com/xiahcu/other/raw/master/IMG_3920.JPG) From e76bc652437c0fc1b3be3fb564fb4a642836d271 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Fri, 19 Jun 2020 10:19:42 +0800 Subject: [PATCH 02/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BC=80=E5=90=AF?= =?UTF-8?q?=E8=BD=AC=E5=8D=8F=E8=AE=AE=E5=90=8E=EF=BC=8C=E6=97=A0=E4=BA=BA?= =?UTF-8?q?=E8=A7=82=E7=9C=8B=E6=8E=90=E6=B5=81=E5=BB=B6=E6=97=B6=E4=B8=8D?= =?UTF-8?q?=E5=AE=9A=E6=9C=9F=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/FFmpegSource.cpp | 9 +++++++++ server/FFmpegSource.h | 2 ++ src/Common/MediaSource.h | 4 ++-- src/Common/MultiMediaSourceMuxer.cpp | 9 +++++++++ src/Common/MultiMediaSourceMuxer.h | 6 ++++++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/server/FFmpegSource.cpp b/server/FFmpegSource.cpp index 50492f22..b6a7ef7e 100644 --- a/server/FFmpegSource.cpp +++ b/server/FFmpegSource.cpp @@ -240,6 +240,15 @@ int FFmpegSource::totalReaderCount(MediaSource &sender) { return sender.readerCount(); } +void FFmpegSource::onNoneReader(MediaSource &sender){ + auto listener = _listener.lock(); + if(listener){ + listener->onNoneReader(sender); + return; + } + MediaSourceEvent::onNoneReader(sender); +} + void FFmpegSource::onGetMediaSource(const MediaSource::Ptr &src) { _listener = src->getListener(); src->setListener(shared_from_this()); diff --git a/server/FFmpegSource.h b/server/FFmpegSource.h index b32ec8f8..06bcf410 100644 --- a/server/FFmpegSource.h +++ b/server/FFmpegSource.h @@ -61,6 +61,8 @@ private: //MediaSourceEvent override bool close(MediaSource &sender,bool force) override; int totalReaderCount(MediaSource &sender) override; + void onNoneReader(MediaSource &sender) override; + private: Process _process; Timer::Ptr _timer; diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h index 6c775934..28330166 100644 --- a/src/Common/MediaSource.h +++ b/src/Common/MediaSource.h @@ -53,9 +53,9 @@ public: virtual bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path) { return false; }; // 获取录制状态 virtual bool isRecording(MediaSource &sender, Recorder::type type) { return false; }; -private: // 通知无人观看 - void onNoneReader(MediaSource &sender); + virtual void onNoneReader(MediaSource &sender); + private: Timer::Ptr _async_close_timer; }; diff --git a/src/Common/MultiMediaSourceMuxer.cpp b/src/Common/MultiMediaSourceMuxer.cpp index 70a20413..b5f10da8 100644 --- a/src/Common/MultiMediaSourceMuxer.cpp +++ b/src/Common/MultiMediaSourceMuxer.cpp @@ -278,6 +278,15 @@ int MultiMediaSourceMuxer::totalReaderCount(MediaSource &sender) { return listener->totalReaderCount(sender); } +void MultiMediaSourceMuxer::onNoneReader(MediaSource &sender){ + auto listener = _listener.lock(); + if (!listener) { + MediaSourceEvent::onNoneReader(sender); + return; + } + listener->onNoneReader(sender); +} + bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path) { return _muxer->setupRecord(sender,type,start,custom_path); } diff --git a/src/Common/MultiMediaSourceMuxer.h b/src/Common/MultiMediaSourceMuxer.h index 2ba2aa99..679906ba 100644 --- a/src/Common/MultiMediaSourceMuxer.h +++ b/src/Common/MultiMediaSourceMuxer.h @@ -131,6 +131,12 @@ public: */ int totalReaderCount(MediaSource &sender) override; + /** + * 触发无人观看事件 + * @param sender 触发者 + */ + void onNoneReader(MediaSource &sender) override; + /** * 设置录制状态 * @param type 录制类型 From 791c773ae04f2a3f2cc181dc597bb1bc62efa36c Mon Sep 17 00:00:00 2001 From: lyg1949 Date: Wed, 24 Jun 2020 08:52:45 +0800 Subject: [PATCH 03/59] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BE=93=E5=85=A5PCM?= =?UTF-8?q?=E5=B8=A7=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在使用faac库的前提下,增加输入PCM帧的接口 --- api/include/mk_media.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/api/include/mk_media.h b/api/include/mk_media.h index c221053b..ff85cf47 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -98,6 +98,16 @@ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len, */ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, void *adts); +#ifdef ENABLE_FAAC +/** + * 输入单帧PCM音频 + * @param ctx 对象指针 + * @param data 单帧PCM数据 + * @param len 单帧PCM数据字节数 + * @param dts 时间戳,毫秒 + */ +API_EXPORT void API_CALL mk_media_input_PCM(mk_media ctx, void *Data, int len, uint32_t pts); +#endif //ENABLE_FAAC /** * 输入单帧G711音频 * @param ctx 对象指针 From f0a538d37de356b823634d42813e07cb41da377a Mon Sep 17 00:00:00 2001 From: lyg1949 Date: Wed, 24 Jun 2020 08:54:15 +0800 Subject: [PATCH 04/59] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=BE=93=E5=85=A5PCM?= =?UTF-8?q?=E5=B8=A7=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现输入PCM帧的接口 --- api/source/mk_media.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/source/mk_media.cpp b/api/source/mk_media.cpp index c3309c5d..c6bdaf19 100755 --- a/api/source/mk_media.cpp +++ b/api/source/mk_media.cpp @@ -157,6 +157,15 @@ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, u (*obj)->getChannel()->inputAAC((char *) data, len, dts, (char *) adts); } +#ifdef ENABLE_FAAC +API_EXPORT void API_CALL mk_media_input_PCM(mk_media ctx, void *data , int len, uint32_t pts) +{ + assert(ctx && data && len > 0); + MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx; + (*obj)->getChannel()->inputPCM((char*)data, len, pts); +} +#endif //ENABLE_FAAC + API_EXPORT void API_CALL mk_media_input_g711(mk_media ctx, void* data, int len, uint32_t dts){ assert(ctx && data && len > 0); MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx; From 3d25ede46fe4d17a467d3630ef1780aecae9d955 Mon Sep 17 00:00:00 2001 From: zhlong Date: Wed, 24 Jun 2020 09:50:35 +0800 Subject: [PATCH 05/59] =?UTF-8?q?=E4=B8=BAAPI=E6=B7=BB=E5=8A=A0=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E9=85=8D=E7=BD=AE=E5=9E=8B=E5=86=85=E5=AE=B9=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/include/mk_common.h | 7 +++++++ api/source/mk_common.cpp | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/api/include/mk_common.h b/api/include/mk_common.h index 6363d22e..d93f1124 100755 --- a/api/include/mk_common.h +++ b/api/include/mk_common.h @@ -101,6 +101,13 @@ API_EXPORT void API_CALL mk_env_init1(int thread_num, */ API_EXPORT void API_CALL mk_set_option(const char *key, const char *val); +/** + * 获取配置项的值 + * @param key 配置项名 + */ +API_EXPORT const char * API_CALL mk_get_option(const char *key); + + /** * 创建http[s]服务器 * @param port htt监听端口,推荐80,传入0则随机分配 diff --git a/api/source/mk_common.cpp b/api/source/mk_common.cpp index 0baa311c..ce36924e 100644 --- a/api/source/mk_common.cpp +++ b/api/source/mk_common.cpp @@ -119,6 +119,17 @@ API_EXPORT void API_CALL mk_set_option(const char *key, const char *val) { mINI::Instance()[key] = val; } +API_EXPORT const char * API_CALL mk_get_option(const char *key) +{ + assert(key); + if (mINI::Instance().find(key) == mINI::Instance().end()) { + WarnL << "key:" << key << " not existed!"; + return nullptr; + } + return mINI::Instance()[key].data(); +} + + API_EXPORT uint16_t API_CALL mk_http_server_start(uint16_t port, int ssl) { ssl = MAX(0,MIN(ssl,1)); try { From 66c5a7169a1377282edff0b8e0f7a33393ce8797 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 24 Jun 2020 11:02:35 +0800 Subject: [PATCH 06/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dmetadata=E4=B8=AD?= =?UTF-8?q?=E6=B2=A1duration=E5=AF=BC=E8=87=B4=E6=92=AD=E6=94=BE=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E7=9A=84bug:#362?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtmp/RtmpSession.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index 95076682..d52b0943 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -257,8 +257,8 @@ void RtmpSession::sendPlayResponse(const string &err,const RtmpMediaSource::Ptr invoke.clear(); invoke << "onMetaData" << metadata; sendResponse(MSG_DATA, invoke.data()); - auto duration = metadata["duration"].as_number(); - if(duration > 0){ + auto duration = metadata["duration"]; + if(duration && duration.as_number() > 0){ //这是点播,使用绝对时间戳 _stamp[0].setPlayBack(); _stamp[1].setPlayBack(); From e89caa23851dd7fc763115347deb59562cf97375 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 24 Jun 2020 11:18:04 +0800 Subject: [PATCH 07/59] =?UTF-8?q?c=20sdk=E6=94=AF=E6=8C=81pcm=E8=BE=93?= =?UTF-8?q?=E5=85=A5:#363?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/include/mk_media.h | 7 +++---- api/source/mk_media.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/include/mk_media.h b/api/include/mk_media.h index ff85cf47..3337b59f 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -98,16 +98,15 @@ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len, */ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, void *adts); -#ifdef ENABLE_FAAC /** - * 输入单帧PCM音频 + * 输入单帧PCM音频,启用ENABLE_FAAC编译时,该函数才有效 * @param ctx 对象指针 * @param data 单帧PCM数据 * @param len 单帧PCM数据字节数 * @param dts 时间戳,毫秒 */ -API_EXPORT void API_CALL mk_media_input_PCM(mk_media ctx, void *Data, int len, uint32_t pts); -#endif //ENABLE_FAAC +API_EXPORT void API_CALL mk_media_input_pcm(mk_media ctx, void *data, int len, uint32_t pts); + /** * 输入单帧G711音频 * @param ctx 对象指针 diff --git a/api/source/mk_media.cpp b/api/source/mk_media.cpp index c6bdaf19..91761829 100755 --- a/api/source/mk_media.cpp +++ b/api/source/mk_media.cpp @@ -157,14 +157,15 @@ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, u (*obj)->getChannel()->inputAAC((char *) data, len, dts, (char *) adts); } +API_EXPORT void API_CALL mk_media_input_pcm(mk_media ctx, void *data , int len, uint32_t pts){ #ifdef ENABLE_FAAC -API_EXPORT void API_CALL mk_media_input_PCM(mk_media ctx, void *data , int len, uint32_t pts) -{ assert(ctx && data && len > 0); MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx; (*obj)->getChannel()->inputPCM((char*)data, len, pts); -} +#else + WarnL << "aac编码未启用,该方法无效,编译时请打开ENABLE_FAAC选项"; #endif //ENABLE_FAAC +} API_EXPORT void API_CALL mk_media_input_g711(mk_media ctx, void* data, int len, uint32_t dts){ assert(ctx && data && len > 0); From f67e9fce9aa83f1ae9425f8f60252eef62a67ceb Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sun, 28 Jun 2020 15:21:41 +0800 Subject: [PATCH 08/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=82=AC=E5=9E=82=E6=8C=87=E9=92=88=E7=9A=84=E5=8F=AF=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtp/RtpProcess.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Rtp/RtpProcess.cpp b/src/Rtp/RtpProcess.cpp index 7deb0e0a..08923216 100644 --- a/src/Rtp/RtpProcess.cpp +++ b/src/Rtp/RtpProcess.cpp @@ -73,11 +73,6 @@ RtpProcess::RtpProcess(uint32_t ssrc) { } RtpProcess::~RtpProcess() { - DebugP(this); - if (_addr) { - delete _addr; - } - uint64_t duration = (_last_rtp_time.createdTime() - _last_rtp_time.elapsedTime()) / 1000; WarnP(this) << "RTP推流器(" << _media_info._vhost << "/" @@ -90,6 +85,11 @@ RtpProcess::~RtpProcess() { if (_total_bytes > iFlowThreshold * 1024) { NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _total_bytes, duration, false, static_cast(*this)); } + + if (_addr) { + delete _addr; + _addr = nullptr; + } } bool RtpProcess::inputRtp(const Socket::Ptr &sock, const char *data, int data_len,const struct sockaddr *addr,uint32_t *dts_out) { From fd7739829110308f96c28842e0b04f4bc1498c58 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sun, 28 Jun 2020 15:24:08 +0800 Subject: [PATCH 09/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8Ddts=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E5=AF=BC=E8=87=B4=E4=B8=8D=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=9A#369?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/Stamp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index e5fd631c..d9ab1823 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -176,6 +176,8 @@ bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){ _sorter_max_size = _frames_since_last_max_pts; //我们记录P帧间时间间隔(也就是多个B帧时间戳增量累计) _dts_pts_offset = (pts - _last_max_pts); + //除以2,防止dts大于pts + _dts_pts_offset /= 2; } //遇到P帧或关键帧,连续B帧计数清零 _frames_since_last_max_pts = 0; From 038979b71626f157ad98bba18de6920e6e706a37 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sun, 28 Jun 2020 21:49:08 +0800 Subject: [PATCH 10/59] =?UTF-8?q?=E4=BF=AE=E6=94=B9rtmp=20metadata=20codec?= =?UTF-8?q?=E7=94=B1=E5=AD=97=E7=AC=A6=E4=B8=BA=E6=95=B4=E5=BD=A2,?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=AF=94=E8=BE=83=E8=80=81=E7=9A=84rtmp?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Extension/Factory.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Extension/Factory.cpp b/src/Extension/Factory.cpp index 3a8fce31..1e7a6284 100644 --- a/src/Extension/Factory.cpp +++ b/src/Extension/Factory.cpp @@ -243,9 +243,8 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc AMFValue Factory::getAmfByCodecId(CodecId codecId) { switch (codecId){ - //此处用string标明rtmp编码类型目的是为了兼容某些android系统 - case CodecAAC: return AMFValue("mp4a"); - case CodecH264: return AMFValue("avc1"); + case CodecAAC: return AMFValue(FLV_CODEC_AAC); + case CodecH264: return AMFValue(FLV_CODEC_H264); case CodecH265: return AMFValue(FLV_CODEC_H265); case CodecG711A: return AMFValue(FLV_CODEC_G711A); case CodecG711U: return AMFValue(FLV_CODEC_G711U); From bbcb4d41f7e55ca971b57d3dbbe555b3ba34d392 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Mon, 29 Jun 2020 11:55:13 +0800 Subject: [PATCH 11/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dps=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E8=AF=AF=E5=88=A4=E4=B8=BAaac=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtp/Decoder.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Rtp/Decoder.cpp b/src/Rtp/Decoder.cpp index cd8e566d..92402a95 100644 --- a/src/Rtp/Decoder.cpp +++ b/src/Rtp/Decoder.cpp @@ -158,6 +158,11 @@ void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d } case PSI_STREAM_AAC: { + uint8_t *ptr = (uint8_t *)data; + if(!(bytes > 7 && ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0)){ + //这不是aac + break; + } if (!_codecid_audio) { //获取到音频 _codecid_audio = codecid; From 41c75fb66a235ddf1f282b7c067376a99347c9a6 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 30 Jun 2020 09:16:02 +0800 Subject: [PATCH 12/59] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=BC=80=E5=90=AF=E6=B5=8F=E8=A7=88http=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E7=9A=84=E9=85=8D=E7=BD=AE=E9=80=89=E9=A1=B9:#367?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/config.ini | 2 ++ src/Common/config.cpp | 4 ++++ src/Common/config.h | 2 ++ src/Http/HttpFileManager.cpp | 5 +++++ 4 files changed, 13 insertions(+) diff --git a/conf/config.ini b/conf/config.ini index 8f5fe93f..5964342f 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -122,6 +122,8 @@ rootPath=./www sendBufSize=65536 #https服务器监听端口 sslport=443 +#是否显示文件夹菜单,开启后可以浏览文件夹 +dirMenu=1 [multicast] #rtp组播截止组播ip地址 diff --git a/src/Common/config.cpp b/src/Common/config.cpp index b2e00ba5..90e171ab 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -100,11 +100,15 @@ const string kCharSet = HTTP_FIELD"charSet"; const string kRootPath = HTTP_FIELD"rootPath"; //http 404错误提示内容 const string kNotFound = HTTP_FIELD"notFound"; +//是否显示文件夹菜单 +const string kDirMenu = HTTP_FIELD"dirMenu"; onceToken token([](){ mINI::Instance()[kSendBufSize] = 64 * 1024; mINI::Instance()[kMaxReqSize] = 4*1024; mINI::Instance()[kKeepAliveSecond] = 15; + mINI::Instance()[kDirMenu] = true; + #if defined(_WIN32) mINI::Instance()[kCharSet] = "gb2312"; #else diff --git a/src/Common/config.h b/src/Common/config.h index 27b4cefa..5d210ce5 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -193,6 +193,8 @@ extern const string kCharSet; extern const string kRootPath; //http 404错误提示内容 extern const string kNotFound; +//是否显示文件夹菜单 +extern const string kDirMenu; }//namespace Http ////////////SHELL配置/////////// diff --git a/src/Http/HttpFileManager.cpp b/src/Http/HttpFileManager.cpp index 584b6f25..5d6464db 100644 --- a/src/Http/HttpFileManager.cpp +++ b/src/Http/HttpFileManager.cpp @@ -195,6 +195,11 @@ static string searchIndexFile(const string &dir){ } static bool makeFolderMenu(const string &httpPath, const string &strFullPath, string &strRet) { + GET_CONFIG(bool, dirMenu, Http::kDirMenu); + if(!dirMenu){ + //不允许浏览文件夹 + return false; + } string strPathPrefix(strFullPath); string last_dir_name; if(strPathPrefix.back() == '/'){ From 2b276efaddc36f8211d779d502132ac24674f43d Mon Sep 17 00:00:00 2001 From: Xiaofeng Wang <1237906+wasphin@users.noreply.github.com> Date: Tue, 30 Jun 2020 20:15:22 +0800 Subject: [PATCH 13/59] Remove self-included header --- src/Rtp/Decoder.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Rtp/Decoder.h b/src/Rtp/Decoder.h index a74ee9f2..5552500f 100644 --- a/src/Rtp/Decoder.h +++ b/src/Rtp/Decoder.h @@ -14,7 +14,6 @@ #include #include #include -#include "Decoder.h" #include "Common/MediaSink.h" using namespace std; From 29077dcef4d9dba2a1b63c84825dc20a9717bd43 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 30 Jun 2020 21:00:45 +0800 Subject: [PATCH 14/59] =?UTF-8?q?rtmp=E6=92=AD=E6=94=BE=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E6=97=B6=E7=A1=AE=E4=BF=9Daac=20track=E5=A4=84=E4=BA=8Eready?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Extension/AAC.h | 8 ++++++-- src/Extension/AACRtmp.cpp | 16 +++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Extension/AAC.h b/src/Extension/AAC.h index e024bb90..aa9dbb1e 100644 --- a/src/Extension/AAC.h +++ b/src/Extension/AAC.h @@ -138,14 +138,18 @@ public: if (_cfg.empty()) { //未获取到aac_cfg信息 if (frame->prefixSize()) { - //7个字节的adts头 + //根据7个字节的adts头生成aac config _cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize()); onReady(); } else { WarnL << "无法获取adts头!"; } } - AudioTrack::inputFrame(frame); + + if (frame->size() > frame->prefixSize()) { + //除adts头外,有实际负载 + AudioTrack::inputFrame(frame); + } } private: /** diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index 48102a2d..d58cdfb4 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -32,7 +32,6 @@ static string getAacCfg(const RtmpPacket &thiz) { bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) { if (pkt->isCfgFrame()) { _aac_cfg = getAacCfg(*pkt); - return false; } if (!_aac_cfg.empty()) { onGetAAC(pkt->strBuf.data() + 2, pkt->strBuf.size() - 2, pkt->timeStamp); @@ -42,7 +41,6 @@ bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) { void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) { auto frame = ResourcePoolHelper::obtainObj(); - //生成adts头 char adts_header[32] = {0}; auto size = dumpAacConfig(_aac_cfg, len, (uint8_t *) adts_header, sizeof(adts_header)); @@ -54,12 +52,16 @@ void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) { frame->_prefix_size = 0; } - //追加负载数据 - frame->_buffer.append(data, len); - frame->_dts = stamp; + if(len){ + //追加负载数据 + frame->_buffer.append(data, len); + frame->_dts = stamp; + } - //写入环形缓存 - RtmpCodec::inputFrame(frame); + if(size || len){ + //有adts头或者实际aac负载 + RtmpCodec::inputFrame(frame); + } } ///////////////////////////////////////////////////////////////////////////////////// From 9e42772b482a9a42e01728d17e4037acc7eadc11 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 30 Jun 2020 21:08:52 +0800 Subject: [PATCH 15/59] =?UTF-8?q?rtmp=20aac=20config=E5=8C=85=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E8=B4=9F=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Extension/AACRtmp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index d58cdfb4..5355146b 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -32,7 +32,10 @@ static string getAacCfg(const RtmpPacket &thiz) { bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) { if (pkt->isCfgFrame()) { _aac_cfg = getAacCfg(*pkt); + onGetAAC(nullptr, 0, 0); + return false; } + if (!_aac_cfg.empty()) { onGetAAC(pkt->strBuf.data() + 2, pkt->strBuf.size() - 2, pkt->timeStamp); } From d2c052a67353a33dcd53130a9a841682d3a8de2b Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 30 Jun 2020 21:11:59 +0800 Subject: [PATCH 16/59] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Extension/AACRtmp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index 5355146b..c2e5de6c 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -55,13 +55,13 @@ void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) { frame->_prefix_size = 0; } - if(len){ + if(len > 0){ //追加负载数据 frame->_buffer.append(data, len); frame->_dts = stamp; } - if(size || len){ + if(size > 0 || len > 0){ //有adts头或者实际aac负载 RtmpCodec::inputFrame(frame); } From bc606cf76793c3c8fba94d51d7e9a1e565320ff3 Mon Sep 17 00:00:00 2001 From: Xiaofeng Wang <1237906+wasphin@users.noreply.github.com> Date: Tue, 30 Jun 2020 21:13:52 +0800 Subject: [PATCH 17/59] =?UTF-8?q?=E5=AD=90=E6=A8=A1=E5=9D=97=E5=9C=B0?= =?UTF-8?q?=E5=9D=80=E4=BD=BF=E7=94=A8=E7=9B=B8=E5=AF=B9=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 子模块地址使用相对路径。 * 统一服务器,即主库通过 github 下载则子库也通过 github 下载; * 也方便做 git 镜像,在自建 git 服务器上镜像后访问也更方便; --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 54226a7f..442daee9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "ZLToolKit"] path = 3rdpart/ZLToolKit - url = https://gitee.com/xiahcu/ZLToolKit + url = ../ZLToolKit [submodule "3rdpart/media-server"] path = 3rdpart/media-server - url = https://gitee.com/xiahcu/media-server + url = ../media-server From e679e746958452980ea0f7ebf26a8ea40a6c1140 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 30 Jun 2020 21:14:51 +0800 Subject: [PATCH 18/59] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E5=A4=9A=E4=BD=99#incl?= =?UTF-8?q?ude?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtp/Decoder.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Rtp/Decoder.h b/src/Rtp/Decoder.h index a74ee9f2..5552500f 100644 --- a/src/Rtp/Decoder.h +++ b/src/Rtp/Decoder.h @@ -14,7 +14,6 @@ #include #include #include -#include "Decoder.h" #include "Common/MediaSink.h" using namespace std; From e24adfe995c353cf8b7304536f9a44014cceb31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=8F=E6=A5=9A?= <771730766@qq.com> Date: Thu, 2 Jul 2020 15:26:40 +0800 Subject: [PATCH 19/59] Update README_en.md --- README_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_en.md b/README_en.md index 485bd5ce..6eae5565 100644 --- a/README_en.md +++ b/README_en.md @@ -128,7 +128,7 @@ It is recommended to compile on Ubuntu or MacOS,compiling on windows is cumber ### Before build - **You must use git to clone the complete code. Do not download the source code by downloading zip package. Otherwise, the sub-module code will not be downloaded by default.You can do it like this:** ``` -git clone https://github.com/zlmediakit/ZLMediaKit.git +git clone https://github.com/xiongziliang/ZLMediaKit.git cd ZLMediaKit git submodule update --init ``` From 2fee173d7a12df64bb643e4d73420c8282dea13b Mon Sep 17 00:00:00 2001 From: wxf Date: Tue, 30 Jun 2020 21:45:17 +0800 Subject: [PATCH 20/59] =?UTF-8?q?=E4=BC=98=E5=85=88=E4=BD=BF=E7=94=A8=20pk?= =?UTF-8?q?g-config=20=E6=9D=A5=E6=9F=A5=E6=89=BE=20AV*=20=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 部分主机上 ffmpeg 安装路径不标准, 默认查找方式不方便适应该方式 --- tests/CMakeLists.txt | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ee75592c..4458b8d1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,20 +8,38 @@ if (SDL2_FOUND) message(STATUS "found library:${SDL2_LIBRARY}") endif (SDL2_FOUND) +find_package(PkgConfig QUIET) + #查找ffmpeg/libutil是否安装 -find_package(AVUTIL QUIET) -if(AVUTIL_FOUND) - include_directories(${AVUTIL_INCLUDE_DIR}) - list(APPEND LINK_LIB_LIST ${AVUTIL_LIBRARIES}) - message(STATUS "found library:${AVUTIL_LIBRARIES}") +if(PKG_CONFIG_FOUND) + pkg_check_modules(AVUTIL QUIET IMPORTED_TARGET libavutil) + if(AVUTIL_FOUND) + list(APPEND LINK_LIB_LIST PkgConfig::AVUTIL) + message(STATUS "found library:${AVUTIL_LIBRARY}") + endif() +else() + find_package(AVUTIL QUIET) + if(AVUTIL_FOUND) + include_directories(${AVUTIL_INCLUDE_DIR}) + list(APPEND LINK_LIB_LIST ${AVUTIL_LIBRARIES}) + message(STATUS "found library:${AVUTIL_LIBRARIES}") + endif() endif() #查找ffmpeg/libavcodec是否安装 -find_package(AVCODEC QUIET) -if(AVCODEC_FOUND) - include_directories(${AVCODEC_INCLUDE_DIR}) - list(APPEND LINK_LIB_LIST ${AVCODEC_LIBRARIES}) - message(STATUS "found library:${AVCODEC_LIBRARIES}") +if(PKG_CONFIG_FOUND) + pkg_check_modules(AVCODEC QUIET IMPORTED_TARGET libavcodec) + if(AVCODEC_FOUND) + list(APPEND LINK_LIB_LIST PkgConfig::AVCODEC) + message(STATUS "found library:${AVCODEC_LIBRARY}") + endif() +else() + find_package(AVCODEC QUIET) + if(AVCODEC_FOUND) + include_directories(${AVCODEC_INCLUDE_DIR}) + list(APPEND LINK_LIB_LIST ${AVCODEC_LIBRARIES}) + message(STATUS "found library:${AVCODEC_LIBRARIES}") + endif() endif() aux_source_directory(. TEST_SRC_LIST) From 21edbb0ebe6d5ab5d4238230200cac3a0b962739 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 2 Jul 2020 17:44:53 +0800 Subject: [PATCH 21/59] =?UTF-8?q?=E6=9B=B4=E6=96=B0ZLToolKit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdpart/ZLToolKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 5030af90..ed47015f 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 5030af90126ea8f01ded6744ae8abdf549d00a81 +Subproject commit ed47015f92cc79dfe3344b3666aafb54f1bbc2f4 From ac320ddc092c976df31d15a48ca7c0f0b85f266e Mon Sep 17 00:00:00 2001 From: wxf Date: Thu, 2 Jul 2020 16:58:21 +0800 Subject: [PATCH 22/59] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=9C=A8=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E6=97=B6=E5=BC=80=E5=90=AF/=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E9=83=A8=E5=88=86=E7=89=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c23279c7..4cb5f70e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,13 +41,13 @@ INCLUDE_DIRECTORIES(${ToolKit_Root}) INCLUDE_DIRECTORIES(${MediaKit_Root}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/3rdpart) -set(ENABLE_HLS true) -set(ENABLE_OPENSSL true) -set(ENABLE_MYSQL false) -set(ENABLE_FAAC false) -set(ENABLE_X264 false) -set(ENABLE_MP4 true) -set(ENABLE_RTPPROXY true) +option(ENABLE_HLS "Enable HLS" true) +option(ENABLE_OPENSSL "Enable OpenSSL" true) +option(ENABLE_MYSQL "Enable MySQL" false) +option(ENABLE_FAAC "Enable FAAC" false) +option(ENABLE_X264 "Enable x264" false) +option(ENABLE_MP4 "Enable MP4" true) +option(ENABLE_RTPPROXY "Enable RTPPROXY" true) set(LINK_LIB_LIST zlmediakit zltoolkit) From e89e39704f937d53ec07ee46d717ab1076c18ace Mon Sep 17 00:00:00 2001 From: wxf Date: Thu, 2 Jul 2020 17:55:32 +0800 Subject: [PATCH 23/59] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E7=BC=96=E8=AF=91=20api/tests/server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cb5f70e..2173561b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,9 @@ option(ENABLE_FAAC "Enable FAAC" false) option(ENABLE_X264 "Enable x264" false) option(ENABLE_MP4 "Enable MP4" true) option(ENABLE_RTPPROXY "Enable RTPPROXY" true) +option(ENABLE_API "Enable C API SDK" true) +option(ENABLE_TESTS "Enable Tests" true) +option(ENABLE_SERVER "Enable Server" true) set(LINK_LIB_LIST zlmediakit zltoolkit) @@ -188,11 +191,17 @@ execute_process(COMMAND cp -r ${CMAKE_CURRENT_SOURCE_DIR}/www ${EXECUTABLE_OUTPU execute_process(COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/conf/config.ini ${EXECUTABLE_OUTPUT_PATH}/) #添加c库 -add_subdirectory(api) +if(ENABLE_API) + add_subdirectory(api) +endif() if (NOT IOS) #测试程序 - add_subdirectory(tests) + if(ENABLE_TESTS) + add_subdirectory(tests) + endif() #主服务器 - add_subdirectory(server) + if(ENABLE_SERVER) + add_subdirectory(server) + endif() endif () From dccb1e2a428058947f40327a6b54d01133646b7f Mon Sep 17 00:00:00 2001 From: wxf Date: Thu, 2 Jul 2020 17:56:18 +0800 Subject: [PATCH 24/59] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AE=89=E8=A3=85=20C+?= =?UTF-8?q?+=20=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 17 +++++++++++++++++ api/CMakeLists.txt | 9 --------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2173561b..6a6fe11b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ option(ENABLE_X264 "Enable x264" false) option(ENABLE_MP4 "Enable MP4" true) option(ENABLE_RTPPROXY "Enable RTPPROXY" true) option(ENABLE_API "Enable C API SDK" true) +option(ENABLE_CXX_API "Enable C++ API SDK" false) option(ENABLE_TESTS "Enable Tests" true) option(ENABLE_SERVER "Enable Server" true) @@ -178,6 +179,22 @@ endif () add_library(zltoolkit STATIC ${ToolKit_src_list}) add_library(zlmediakit STATIC ${MediaKit_src_list}) +#安装目录 +if (WIN32) + set(INSTALL_PATH_LIB $ENV{HOME}/${CMAKE_PROJECT_NAME}/lib) + set(INSTALL_PATH_INCLUDE $ENV{HOME}/${CMAKE_PROJECT_NAME}/include) +else () + set(INSTALL_PATH_LIB lib) + set(INSTALL_PATH_INCLUDE include) +endif () + +if(ENABLE_CXX_API) + # 保留目录结构 + install(DIRECTORY ${ToolKit_Root}/ DESTINATION ${INSTALL_PATH_INCLUDE}/ZLToolKit REGEX "(.*[.](md|cpp)|win32)$" EXCLUDE) + install(DIRECTORY ${MediaKit_Root}/ DESTINATION ${INSTALL_PATH_INCLUDE}/ZLMediaKit REGEX ".*[.](md|cpp)$" EXCLUDE) + install(TARGETS zltoolkit zlmediakit DESTINATION ${INSTALL_PATH_LIB}) +endif() + if (WIN32) list(APPEND LINK_LIB_LIST WS2_32 Iphlpapi shlwapi) set_target_properties(zltoolkit PROPERTIES COMPILE_FLAGS ${VS_FALGS} ) diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index 6169e0f5..6f460300 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -22,15 +22,6 @@ else () target_link_libraries(mk_api ${LINK_LIB_LIST}) add_subdirectory(tests) - #安装目录 - if (WIN32) - set(INSTALL_PATH_LIB $ENV{HOME}/${CMAKE_PROJECT_NAME}/lib) - set(INSTALL_PATH_INCLUDE $ENV{HOME}/${CMAKE_PROJECT_NAME}/include) - else () - set(INSTALL_PATH_LIB lib) - set(INSTALL_PATH_INCLUDE include) - endif () - file(GLOB api_header_list include/*.h) install(FILES ${api_header_list} DESTINATION ${INSTALL_PATH_INCLUDE}) install(TARGETS mk_api ARCHIVE DESTINATION ${INSTALL_PATH_LIB} LIBRARY DESTINATION ${INSTALL_PATH_LIB}) From 3c858a835175f6d7f1c66b62a6cc0db2ed511156 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 2 Jul 2020 18:14:39 +0800 Subject: [PATCH 25/59] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AA=92=E4=BD=93?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=9B=9E=E8=B0=83=E4=BA=8B=E4=BB=B6:#373?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/include/mk_media.h | 17 +++++++++++++++++ api/source/mk_media.cpp | 21 +++++++++++++++++++++ server/FFmpegSource.cpp | 7 +++++++ server/FFmpegSource.h | 1 + src/Common/MediaSource.cpp | 12 +++++++++++- src/Common/MediaSource.h | 2 ++ src/Common/MultiMediaSourceMuxer.cpp | 7 +++++++ src/Common/MultiMediaSourceMuxer.h | 7 +++++++ 8 files changed, 73 insertions(+), 1 deletion(-) diff --git a/api/include/mk_media.h b/api/include/mk_media.h index 3337b59f..87b8836d 100755 --- a/api/include/mk_media.h +++ b/api/include/mk_media.h @@ -12,6 +12,7 @@ #define MK_MEDIA_H_ #include "mk_common.h" +#include "mk_events_objects.h" #ifdef __cplusplus extern "C" { @@ -158,6 +159,22 @@ API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, */ API_EXPORT int API_CALL mk_media_total_reader_count(mk_media ctx); +/** + * 生成的MediaSource注册或注销事件 + * @param user_data 设置回调时的用户数据指针 + * @param sender 生成的MediaSource对象 + * @param regist 1为注册事件,0为注销事件 + */ +typedef void(API_CALL *on_mk_media_source_regist)(void *user_data, mk_media_source sender, int regist); + +/** + * 设置MediaSource注册或注销事件回调函数 + * @param ctx 对象指针 + * @param cb 回调指针 + * @param user_data 用户数据指针 + */ +API_EXPORT void API_CALL mk_media_set_on_regist(mk_media ctx, on_mk_media_source_regist cb, void *user_data); + #ifdef __cplusplus } #endif diff --git a/api/source/mk_media.cpp b/api/source/mk_media.cpp index 91761829..bad5bf51 100755 --- a/api/source/mk_media.cpp +++ b/api/source/mk_media.cpp @@ -42,6 +42,12 @@ public: _on_seek = cb; _on_seek_data = user_data; } + + void setOnRegist(on_mk_media_source_regist cb, void *user_data){ + _on_regist = cb; + _on_regist_data = user_data; + } + protected: // 通知其停止推流 bool close(MediaSource &sender,bool force) override{ @@ -70,12 +76,21 @@ protected: int totalReaderCount(MediaSource &sender) override{ return _channel->totalReaderCount(); } + + void onRegist(MediaSource &sender, bool regist) override{ + if (_on_regist) { + _on_regist(_on_regist_data, &sender, regist); + } + } + private: DevChannel::Ptr _channel; on_mk_media_close _on_close = nullptr; on_mk_media_seek _on_seek = nullptr; + on_mk_media_source_regist _on_regist = nullptr; void *_on_seek_data; void *_on_close_data; + void *_on_regist_data; }; API_EXPORT void API_CALL mk_media_set_on_close(mk_media ctx, on_mk_media_close cb, void *user_data){ @@ -90,6 +105,12 @@ API_EXPORT void API_CALL mk_media_set_on_seek(mk_media ctx, on_mk_media_seek cb, (*obj)->setOnSeek(cb, user_data); } +API_EXPORT void API_CALL mk_media_set_on_regist(mk_media ctx, on_mk_media_source_regist cb, void *user_data){ + assert(ctx); + MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; + (*obj)->setOnRegist(cb, user_data); +} + API_EXPORT int API_CALL mk_media_total_reader_count(mk_media ctx){ assert(ctx); MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; diff --git a/server/FFmpegSource.cpp b/server/FFmpegSource.cpp index b6a7ef7e..fdf9b7f2 100644 --- a/server/FFmpegSource.cpp +++ b/server/FFmpegSource.cpp @@ -249,6 +249,13 @@ void FFmpegSource::onNoneReader(MediaSource &sender){ MediaSourceEvent::onNoneReader(sender); } +void FFmpegSource::onRegist(MediaSource &sender, bool regist){ + auto listener = _listener.lock(); + if(listener){ + listener->onRegist(sender, regist); + } +} + void FFmpegSource::onGetMediaSource(const MediaSource::Ptr &src) { _listener = src->getListener(); src->setListener(shared_from_this()); diff --git a/server/FFmpegSource.h b/server/FFmpegSource.h index 06bcf410..00635ac5 100644 --- a/server/FFmpegSource.h +++ b/server/FFmpegSource.h @@ -62,6 +62,7 @@ private: bool close(MediaSource &sender,bool force) override; int totalReaderCount(MediaSource &sender) override; void onNoneReader(MediaSource &sender) override; + void onRegist(MediaSource &sender, bool regist) override; private: Process _process; diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp index 7d9ba2f8..e7bc6b14 100644 --- a/src/Common/MediaSource.cpp +++ b/src/Common/MediaSource.cpp @@ -295,7 +295,7 @@ void MediaSource::regist() { //注册该源,注册后服务器才能找到该源 { lock_guard lock(g_mtxMediaSrc); - g_mapMediaSrc[_strSchema][_strVhost][_strApp][_strId] = shared_from_this(); + g_mapMediaSrc[_strSchema][_strVhost][_strApp][_strId] = shared_from_this(); } _StrPrinter codec_info; auto tracks = getTracks(true); @@ -326,6 +326,11 @@ void MediaSource::regist() { InfoL << _strSchema << " " << _strVhost << " " << _strApp << " " << _strId << " " << codec_info; NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaChanged, true, *this); + + auto listener = _listener.lock(); + if (listener) { + listener->onRegist(*this, true); + } } //反注册该源 @@ -352,6 +357,11 @@ bool MediaSource::unregist() { if(ret){ InfoL << _strSchema << " " << _strVhost << " " << _strApp << " " << _strId; NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaChanged, false, *this); + + auto listener = _listener.lock(); + if (listener) { + listener->onRegist(*this, false); + } } return ret; } diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h index 28330166..d4e44d4e 100644 --- a/src/Common/MediaSource.h +++ b/src/Common/MediaSource.h @@ -55,6 +55,8 @@ public: virtual bool isRecording(MediaSource &sender, Recorder::type type) { return false; }; // 通知无人观看 virtual void onNoneReader(MediaSource &sender); + //流注册或注销事件 + virtual void onRegist(MediaSource &sender, bool regist) {}; private: Timer::Ptr _async_close_timer; diff --git a/src/Common/MultiMediaSourceMuxer.cpp b/src/Common/MultiMediaSourceMuxer.cpp index b5f10da8..aeaa84bc 100644 --- a/src/Common/MultiMediaSourceMuxer.cpp +++ b/src/Common/MultiMediaSourceMuxer.cpp @@ -287,6 +287,13 @@ void MultiMediaSourceMuxer::onNoneReader(MediaSource &sender){ listener->onNoneReader(sender); } +void MultiMediaSourceMuxer::onRegist(MediaSource &sender, bool regist){ + auto listener = _listener.lock(); + if (listener) { + listener->onRegist(sender, regist); + } +} + bool MultiMediaSourceMuxer::setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path) { return _muxer->setupRecord(sender,type,start,custom_path); } diff --git a/src/Common/MultiMediaSourceMuxer.h b/src/Common/MultiMediaSourceMuxer.h index 679906ba..216ba443 100644 --- a/src/Common/MultiMediaSourceMuxer.h +++ b/src/Common/MultiMediaSourceMuxer.h @@ -137,6 +137,13 @@ public: */ void onNoneReader(MediaSource &sender) override; + /** + * 媒体注册注销事件 + * @param sender 触发者 + * @param regist 是否为注册事件 + */ + void onRegist(MediaSource &sender, bool regist) override; + /** * 设置录制状态 * @param type 录制类型 From b603b8a68d772099ce8b542bd4c9780bc8f33497 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 2 Jul 2020 22:23:43 +0800 Subject: [PATCH 26/59] =?UTF-8?q?=E6=94=AF=E6=8C=81http=20api=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E6=B7=BB=E5=8A=A0=E6=88=96=E5=85=B3=E9=97=ADrtp?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/source/mk_common.cpp | 25 +++++----------- server/WebApi.cpp | 47 +++++++++++++++++++++++++++-- server/main.cpp | 15 +++------- src/Rtp/RtpServer.cpp | 64 ++++++++++++++++++++++++++++++++++++++++ src/Rtp/RtpServer.h | 61 ++++++++++++++++++++++++++++++++++++++ src/Rtp/UdpRecver.cpp | 44 --------------------------- src/Rtp/UdpRecver.h | 40 ------------------------- 7 files changed, 181 insertions(+), 115 deletions(-) create mode 100644 src/Rtp/RtpServer.cpp create mode 100644 src/Rtp/RtpServer.h delete mode 100644 src/Rtp/UdpRecver.cpp delete mode 100644 src/Rtp/UdpRecver.h diff --git a/api/source/mk_common.cpp b/api/source/mk_common.cpp index ce36924e..1b84707e 100644 --- a/api/source/mk_common.cpp +++ b/api/source/mk_common.cpp @@ -30,10 +30,8 @@ static TcpServer::Ptr http_server[2]; static TcpServer::Ptr shell_server; #ifdef ENABLE_RTPPROXY -#include "Rtp/UdpRecver.h" -#include "Rtp/RtpSession.h" -static std::shared_ptr udpRtpServer; -static TcpServer::Ptr tcpRtpServer; +#include "Rtp/RtpServer.h" +static std::shared_ptr rtpServer; #endif //////////////////////////environment init/////////////////////////// @@ -57,8 +55,7 @@ API_EXPORT void API_CALL mk_stop_all_server(){ CLEAR_ARR(rtmp_server); CLEAR_ARR(http_server); #ifdef ENABLE_RTPPROXY - udpRtpServer = nullptr; - tcpRtpServer = nullptr; + rtpServer = nullptr; #endif stopAllTcpServer(); } @@ -184,18 +181,12 @@ API_EXPORT uint16_t API_CALL mk_rtmp_server_start(uint16_t port, int ssl) { API_EXPORT uint16_t API_CALL mk_rtp_server_start(uint16_t port){ #ifdef ENABLE_RTPPROXY try { - //创建rtp tcp服务器 - tcpRtpServer = std::make_shared(); - tcpRtpServer->start(port); - - //创建rtp udp服务器 - auto ret = tcpRtpServer->getPort(); - udpRtpServer = std::make_shared(); - udpRtpServer->initSock(port); - return ret; + //创建rtp 服务器 + rtpServer = std::make_shared(); + rtpServer->start(port); + return rtpServer->getPort(); } catch (std::exception &ex) { - tcpRtpServer.reset(); - udpRtpServer.reset(); + rtpServer.reset(); WarnL << ex.what(); return 0; } diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 20a653aa..cc98d596 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -34,6 +34,9 @@ #include "Thread/WorkThreadPool.h" #include "Rtp/RtpSelector.h" #include "FFmpegSource.h" +#if defined(ENABLE_RTPPROXY) +#include "Rtp/RtpServer.h" +#endif using namespace Json; using namespace toolkit; using namespace mediakit; @@ -244,15 +247,24 @@ bool checkArgs(Args &&args,First &&first,KeyTypes && ...keys){ } \ } +//拉流代理器列表 static unordered_map s_proxyMap; static recursive_mutex s_proxyMapMtx; + +//FFmpeg拉流代理器列表 +static unordered_map s_ffmpegMap; +static recursive_mutex s_ffmpegMapMtx; + +#if defined(ENABLE_RTPPROXY) +//rtp服务器列表 +static unordered_map s_rtpServerMap; +static recursive_mutex s_rtpServerMapMtx; +#endif + static inline string getProxyKey(const string &vhost,const string &app,const string &stream){ return vhost + "/" + app + "/" + stream; } -static unordered_map s_ffmpegMap; -static recursive_mutex s_ffmpegMapMtx; - /** * 安装api接口 * 所有api都支持GET和POST两种方式 @@ -745,6 +757,29 @@ void installWebApi() { val["peer_ip"] = process->get_peer_ip(); val["peer_port"] = process->get_peer_port(); }); + + api_regist1("/index/api/openRtpServer",[](API_ARGS1){ + CHECK_SECRET(); + CHECK_ARGS("port", "enable_tcp"); + + RtpServer::Ptr server = std::make_shared(); + server->start(allArgs["port"], allArgs["enable_tcp"].as()); + val["port"] = server->getPort(); + + //保存对象 + lock_guard lck(s_rtpServerMapMtx); + s_rtpServerMap.emplace(server->getPort(), server); + }); + + api_regist1("/index/api/closeRtpServer",[](API_ARGS1){ + CHECK_SECRET(); + CHECK_ARGS("port"); + + lock_guard lck(s_rtpServerMapMtx); + val["hit"] = (int)s_rtpServerMap.erase(allArgs["port"].as()); + }); + + #endif//ENABLE_RTPPROXY // 开始录制hls或MP4 @@ -1045,4 +1080,10 @@ void unInstallWebApi(){ lock_guard lck(s_ffmpegMapMtx); s_ffmpegMap.clear(); } + { +#if defined(ENABLE_RTPPROXY) + lock_guard lck(s_rtpServerMapMtx); + s_rtpServerMap.clear(); +#endif + } } \ No newline at end of file diff --git a/server/main.cpp b/server/main.cpp index cd1ee8a0..705092c4 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -20,13 +20,11 @@ #include "Network/TcpServer.h" #include "Poller/EventPoller.h" #include "Common/config.h" -#include "Rtsp/UDPServer.h" #include "Rtsp/RtspSession.h" -#include "Rtp/RtpSession.h" #include "Rtmp/RtmpSession.h" #include "Shell/ShellSession.h" #include "Http/WebSocketSession.h" -#include "Rtp/UdpRecver.h" +#include "Rtp/RtpServer.h" #include "WebApi.h" #include "WebHook.h" @@ -283,8 +281,7 @@ int start_main(int argc,char *argv[]) { #if defined(ENABLE_RTPPROXY) //GB28181 rtp推流端口,支持UDP/TCP - UdpRecver recver; - TcpServer::Ptr tcpRtpServer(new TcpServer()); + RtpServer::Ptr rtpServer = std::make_shared(); #endif//defined(ENABLE_RTPPROXY) try { @@ -307,12 +304,8 @@ int start_main(int argc,char *argv[]) { if(shellPort) { shellSrv->start(shellPort); } #if defined(ENABLE_RTPPROXY) - if(rtpPort){ - //创建rtp udp服务器 - recver.initSock(rtpPort); - //创建rtp tcp服务器 - tcpRtpServer->start(rtpPort); - } + //创建rtp服务器 + if(rtpPort){ rtpServer->start(rtpPort); } #endif//defined(ENABLE_RTPPROXY) }catch (std::exception &ex){ diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp new file mode 100644 index 00000000..5e90c1f7 --- /dev/null +++ b/src/Rtp/RtpServer.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#if defined(ENABLE_RTPPROXY) +#include "RtpServer.h" +#include "RtpSelector.h" +namespace mediakit{ + +RtpServer::RtpServer() { +} + +RtpServer::~RtpServer() { + if(_udp_server){ + _udp_server->setOnRead(nullptr); + } +} + +void RtpServer::start(uint16_t local_port, bool enable_tcp, const char *local_ip) { + _udp_server.reset(new Socket(nullptr, false)); + auto &ref = RtpSelector::Instance(); + auto sock = _udp_server; + _udp_server->setOnRead([&ref, sock](const Buffer::Ptr &buf, struct sockaddr *addr, int) { + ref.inputRtp(sock, buf->data(), buf->size(), addr); + }); + + //创建udp服务器 + if (!_udp_server->bindUdpSock(local_port, local_ip)) { + _udp_server = nullptr; + string err = (StrPrinter << "bindUdpSock on " << local_ip << ":" << local_port << " failed:" << get_uv_errmsg(true)); + throw std::runtime_error(err); + } + //设置udp socket读缓存 + SockUtil::setRecvBuf(_udp_server->rawFD(), 4 * 1024 * 1024); + + if (enable_tcp) { + try { + //创建tcp服务器 + _tcp_server = std::make_shared(_udp_server->getPoller()); + _tcp_server->start(_udp_server->get_local_port(), local_ip); + } catch (...) { + _tcp_server = nullptr; + _udp_server = nullptr; + throw; + } + } +} + +EventPoller::Ptr RtpServer::getPoller() { + return _udp_server->getPoller(); +} + +uint16_t RtpServer::getPort() { + return _udp_server ? _udp_server->get_local_port() : 0; +} + +}//namespace mediakit +#endif//defined(ENABLE_RTPPROXY) \ No newline at end of file diff --git a/src/Rtp/RtpServer.h b/src/Rtp/RtpServer.h new file mode 100644 index 00000000..c81f9513 --- /dev/null +++ b/src/Rtp/RtpServer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef ZLMEDIAKIT_RTPSERVER_H +#define ZLMEDIAKIT_RTPSERVER_H + +#if defined(ENABLE_RTPPROXY) +#include +#include "Network/Socket.h" +#include "Network/TcpServer.h" +#include "RtpSession.h" + +using namespace std; +using namespace toolkit; + +namespace mediakit{ + +/** + * RTP服务器,支持UDP/TCP + */ +class RtpServer { +public: + typedef std::shared_ptr Ptr; + typedef function onRecv; + + RtpServer(); + ~RtpServer(); + + /** + * 开启服务器,可能抛异常 + * @param local_port 本地端口,0时为随机端口 + * @param enable_tcp 是否启用tcp服务器 + * @param local_ip 绑定的本地网卡ip + */ + void start(uint16_t local_port, bool enable_tcp = true, const char *local_ip = "0.0.0.0"); + + /** + * 获取绑定的本地端口 + */ + uint16_t getPort(); + + /** + * 获取绑定的线程 + */ + EventPoller::Ptr getPoller(); + +protected: + Socket::Ptr _udp_server; + TcpServer::Ptr _tcp_server; +}; + +}//namespace mediakit +#endif//defined(ENABLE_RTPPROXY) +#endif //ZLMEDIAKIT_RTPSERVER_H diff --git a/src/Rtp/UdpRecver.cpp b/src/Rtp/UdpRecver.cpp deleted file mode 100644 index 2b4a6f3b..00000000 --- a/src/Rtp/UdpRecver.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#if defined(ENABLE_RTPPROXY) -#include "UdpRecver.h" -#include "RtpSelector.h" -namespace mediakit{ - -UdpRecver::UdpRecver() { -} - -UdpRecver::~UdpRecver() { - if(_sock){ - _sock->setOnRead(nullptr); - } -} - -bool UdpRecver::initSock(uint16_t local_port,const char *local_ip) { - _sock.reset(new Socket(nullptr, false)); - onceToken token(nullptr,[&](){ - SockUtil::setRecvBuf(_sock->rawFD(),4 * 1024 * 1024); - }); - - auto &ref = RtpSelector::Instance(); - auto sock = _sock; - _sock->setOnRead([&ref, sock](const Buffer::Ptr &buf, struct sockaddr *addr, int ){ - ref.inputRtp(sock, buf->data(),buf->size(),addr); - }); - return _sock->bindUdpSock(local_port,local_ip); -} - -EventPoller::Ptr UdpRecver::getPoller() { - return _sock->getPoller(); -} - -}//namespace mediakit -#endif//defined(ENABLE_RTPPROXY) \ No newline at end of file diff --git a/src/Rtp/UdpRecver.h b/src/Rtp/UdpRecver.h deleted file mode 100644 index 98361064..00000000 --- a/src/Rtp/UdpRecver.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef ZLMEDIAKIT_UDPRECVER_H -#define ZLMEDIAKIT_UDPRECVER_H - -#if defined(ENABLE_RTPPROXY) -#include -#include "Network/Socket.h" -using namespace std; -using namespace toolkit; - -namespace mediakit{ - -/** - * 组播接收器 - */ -class UdpRecver { -public: - typedef std::shared_ptr Ptr; - typedef function onRecv; - - UdpRecver(); - virtual ~UdpRecver(); - bool initSock(uint16_t local_port,const char *local_ip = "0.0.0.0"); - EventPoller::Ptr getPoller(); -protected: - Socket::Ptr _sock; -}; - -}//namespace mediakit -#endif//defined(ENABLE_RTPPROXY) -#endif //ZLMEDIAKIT_UDPRECVER_H From 2be19ffb31b60415cdbae87a2173aec1354c76f5 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 2 Jul 2020 22:26:38 +0800 Subject: [PATCH 27/59] =?UTF-8?q?=E6=B7=BB=E5=8A=A0listRtpServer=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index cc98d596..80de4984 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -779,6 +779,14 @@ void installWebApi() { val["hit"] = (int)s_rtpServerMap.erase(allArgs["port"].as()); }); + api_regist1("/index/api/listRtpServer",[](API_ARGS1){ + CHECK_SECRET(); + + lock_guard lck(s_rtpServerMapMtx); + for(auto &pr : s_rtpServerMap){ + val["data"].append(pr.first); + } + }); #endif//ENABLE_RTPPROXY From cd5dd6ffd01fc03fdbcbca4b955bb35f32a1e93c Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sat, 4 Jul 2020 19:30:03 +0800 Subject: [PATCH 28/59] =?UTF-8?q?=E6=9B=B4=E6=96=B0ps=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E5=BA=93=EF=BC=8C=E4=BF=AE=E5=A4=8D=E7=8C=9C=E6=B5=8B=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F=E9=94=99=E8=AF=AF=E7=9A=84bug:#359?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdpart/media-server | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdpart/media-server b/3rdpart/media-server index 576216c6..037571ec 160000 --- a/3rdpart/media-server +++ b/3rdpart/media-server @@ -1 +1 @@ -Subproject commit 576216c64bf3bcdc5e787da2adb3e169bdd97118 +Subproject commit 037571ecbf47085f39f4f208bfbf261570b6412f From 80d9f8ccaae99736a6b6116353fb0fcc12ebf70e Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sat, 4 Jul 2020 21:44:44 +0800 Subject: [PATCH 29/59] =?UTF-8?q?=E6=9B=B4=E6=96=B0ps=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E5=BA=93=EF=BC=8C=E5=85=BC=E5=AE=B9=E4=B8=8D=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E7=9A=84ps=E6=B5=81:#359?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdpart/media-server | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdpart/media-server b/3rdpart/media-server index 037571ec..7f7906b0 160000 --- a/3rdpart/media-server +++ b/3rdpart/media-server @@ -1 +1 @@ -Subproject commit 037571ecbf47085f39f4f208bfbf261570b6412f +Subproject commit 7f7906b05d84c5efeceecb8d6f540a71c8153431 From 30260e5414d71922b7d4a5a2c2eff146e1e81540 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 7 Jul 2020 09:58:08 +0800 Subject: [PATCH 30/59] =?UTF-8?q?=E5=A4=8D=E7=94=A8printSSRC=E5=87=BD?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtsp/Rtsp.cpp | 10 ++++++++++ src/Rtsp/Rtsp.h | 1 + src/Rtsp/RtspSession.cpp | 9 --------- src/Rtsp/RtspSession.h | 2 -- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Rtsp/Rtsp.cpp b/src/Rtsp/Rtsp.cpp index b55c1d0e..c93331d6 100644 --- a/src/Rtsp/Rtsp.cpp +++ b/src/Rtsp/Rtsp.cpp @@ -404,4 +404,14 @@ std::pair makeSockPair(const EventPoller::Ptr &poller, } } +string printSSRC(uint32_t ui32Ssrc) { + char tmp[9] = { 0 }; + ui32Ssrc = htonl(ui32Ssrc); + uint8_t *pSsrc = (uint8_t *) &ui32Ssrc; + for (int i = 0; i < 4; i++) { + sprintf(tmp + 2 * i, "%02X", pSsrc[i]); + } + return tmp; +} + }//namespace mediakit \ No newline at end of file diff --git a/src/Rtsp/Rtsp.h b/src/Rtsp/Rtsp.h index 3e7a22e7..ff31295c 100644 --- a/src/Rtsp/Rtsp.h +++ b/src/Rtsp/Rtsp.h @@ -272,6 +272,7 @@ private: }; std::pair makeSockPair(const EventPoller::Ptr &poller, const string &local_ip); +string printSSRC(uint32_t ui32Ssrc); } //namespace mediakit #endif //RTSP_RTSP_H_ diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index d73b11f1..d60941b4 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -1068,15 +1068,6 @@ bool RtspSession::sendRtspResponse(const string &res_code, return sendRtspResponse(res_code,header_map,sdp,protocol); } -inline string RtspSession::printSSRC(uint32_t ui32Ssrc) { - char tmp[9] = { 0 }; - ui32Ssrc = htonl(ui32Ssrc); - uint8_t *pSsrc = (uint8_t *) &ui32Ssrc; - for (int i = 0; i < 4; i++) { - sprintf(tmp + 2 * i, "%02X", pSsrc[i]); - } - return tmp; -} inline int RtspSession::getTrackIndexByTrackType(TrackType type) { for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { if (type == _aTrackInfo[i]->_type) { diff --git a/src/Rtsp/RtspSession.h b/src/Rtsp/RtspSession.h index c7e3160c..eeba0d85 100644 --- a/src/Rtsp/RtspSession.h +++ b/src/Rtsp/RtspSession.h @@ -136,8 +136,6 @@ private: void inline send_SessionNotFound(); //一般rtsp服务器打开端口失败时触发 void inline send_NotAcceptable(); - //ssrc转字符串 - inline string printSSRC(uint32_t ui32Ssrc); //获取track下标 inline int getTrackIndexByTrackType(TrackType type); From 477f99b756782e40fd67d769bc8d7eea768922d0 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 7 Jul 2020 10:01:12 +0800 Subject: [PATCH 31/59] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E5=88=9B=E5=BB=BAGB28181=E6=94=B6=E6=B5=81=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E5=B9=B6=E5=8F=AF=E6=8C=87=E5=AE=9Astream=5Fid:#338?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 15 ++++------ src/Rtp/RtpProcess.cpp | 17 ++--------- src/Rtp/RtpProcess.h | 4 +-- src/Rtp/RtpSelector.cpp | 63 ++++++++++++++++++++++------------------- src/Rtp/RtpSelector.h | 21 +++++++++----- src/Rtp/RtpServer.cpp | 7 +++-- src/Rtp/RtpServer.h | 3 +- src/Rtp/RtpSession.cpp | 23 +++++++++++---- src/Rtp/RtpSession.h | 6 +++- tests/test_rtp.cpp | 3 +- 10 files changed, 89 insertions(+), 73 deletions(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 80de4984..1980ee02 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -741,15 +741,12 @@ void installWebApi() { }); #if defined(ENABLE_RTPPROXY) - api_regist1("/index/api/getSsrcInfo",[](API_ARGS1){ + api_regist1("/index/api/getRtpInfo",[](API_ARGS1){ CHECK_SECRET(); - CHECK_ARGS("ssrc"); - uint32_t ssrc = 0; - stringstream ss(allArgs["ssrc"]); - ss >> std::hex >> ssrc; + CHECK_ARGS("stream_id"); - auto process = RtpSelector::Instance().getProcess(ssrc,false); - if(!process){ + auto process = RtpSelector::Instance().getProcess(allArgs["stream_id"], false); + if (!process) { val["exist"] = false; return; } @@ -760,10 +757,10 @@ void installWebApi() { api_regist1("/index/api/openRtpServer",[](API_ARGS1){ CHECK_SECRET(); - CHECK_ARGS("port", "enable_tcp"); + CHECK_ARGS("port", "enable_tcp", "stream_id"); RtpServer::Ptr server = std::make_shared(); - server->start(allArgs["port"], allArgs["enable_tcp"].as()); + server->start(allArgs["port"], allArgs["stream_id"], allArgs["enable_tcp"].as()); val["port"] = server->getPort(); //保存对象 diff --git a/src/Rtp/RtpProcess.cpp b/src/Rtp/RtpProcess.cpp index 08923216..b3f32d19 100644 --- a/src/Rtp/RtpProcess.cpp +++ b/src/Rtp/RtpProcess.cpp @@ -16,32 +16,21 @@ namespace mediakit{ -string printSSRC(uint32_t ui32Ssrc) { - char tmp[9] = { 0 }; - ui32Ssrc = htonl(ui32Ssrc); - uint8_t *pSsrc = (uint8_t *) &ui32Ssrc; - for (int i = 0; i < 4; i++) { - sprintf(tmp + 2 * i, "%02X", pSsrc[i]); - } - return tmp; -} - static string printAddress(const struct sockaddr *addr){ return StrPrinter << SockUtil::inet_ntoa(((struct sockaddr_in *) addr)->sin_addr) << ":" << ntohs(((struct sockaddr_in *) addr)->sin_port); } -RtpProcess::RtpProcess(uint32_t ssrc) { - _ssrc = ssrc; +RtpProcess::RtpProcess(const string &stream_id) { _track = std::make_shared(); _track->_interleaved = 0; _track->_samplerate = 90000; _track->_type = TrackVideo; - _track->_ssrc = _ssrc; + _track->_ssrc = 0; _media_info._schema = RTP_APP_NAME; _media_info._vhost = DEFAULT_VHOST; _media_info._app = RTP_APP_NAME; - _media_info._streamid = printSSRC(_ssrc); + _media_info._streamid = stream_id; GET_CONFIG(string,dump_dir,RtpProxy::kDumpDir); { diff --git a/src/Rtp/RtpProcess.h b/src/Rtp/RtpProcess.h index 7b054292..0c55e375 100644 --- a/src/Rtp/RtpProcess.h +++ b/src/Rtp/RtpProcess.h @@ -22,11 +22,10 @@ using namespace mediakit; namespace mediakit{ -string printSSRC(uint32_t ui32Ssrc); class RtpProcess : public RtpReceiver , public RtpDecoder, public SockInfo, public MediaSinkInterface, public std::enable_shared_from_this{ public: typedef std::shared_ptr Ptr; - RtpProcess(uint32_t ssrc); + RtpProcess(const string &stream_id); ~RtpProcess(); bool inputRtp(const Socket::Ptr &sock, const char *data,int data_len, const struct sockaddr *addr , uint32_t *dts_out = nullptr); bool alive(); @@ -54,7 +53,6 @@ private: std::shared_ptr _save_file_rtp; std::shared_ptr _save_file_ps; std::shared_ptr _save_file_video; - uint32_t _ssrc; SdpTrack::Ptr _track; struct sockaddr *_addr = nullptr; uint16_t _sequence = 0; diff --git a/src/Rtp/RtpSelector.cpp b/src/Rtp/RtpSelector.cpp index d40e5ceb..36d8f8bc 100644 --- a/src/Rtp/RtpSelector.cpp +++ b/src/Rtp/RtpSelector.cpp @@ -15,37 +15,44 @@ namespace mediakit{ INSTANCE_IMP(RtpSelector); -bool RtpSelector::inputRtp(const Socket::Ptr &sock, const char *data, int data_len,const struct sockaddr *addr,uint32_t *dts_out) { - uint32_t ssrc = 0; - if(!getSSRC(data,data_len,ssrc)){ - WarnL << "get ssrc from rtp failed:" << data_len; - return false; +bool RtpSelector::inputRtp(const Socket::Ptr &sock, string &stream_id, const char *data, int data_len, + const struct sockaddr *addr,uint32_t *dts_out) { + if (stream_id.empty()) { + //未指定流id,那么使用ssrc为流id + uint32_t ssrc = 0; + if (!getSSRC(data, data_len, ssrc)) { + WarnL << "get ssrc from rtp failed:" << data_len; + return false; + } + stream_id = printSSRC(ssrc); } - auto process = getProcess(ssrc, true); - if(process){ - return process->inputRtp(sock, data,data_len, addr,dts_out); + + //假定指定了流id,那么通过流id来区分是否为一路流(哪怕可能同时收到多路流) + auto process = getProcess(stream_id, true); + if (process) { + return process->inputRtp(sock, data, data_len, addr, dts_out); } return false; } bool RtpSelector::getSSRC(const char *data,int data_len, uint32_t &ssrc){ - if(data_len < 12){ + if (data_len < 12) { return false; } - uint32_t *ssrc_ptr = (uint32_t *)(data + 8); + uint32_t *ssrc_ptr = (uint32_t *) (data + 8); ssrc = ntohl(*ssrc_ptr); return true; } -RtpProcess::Ptr RtpSelector::getProcess(uint32_t ssrc,bool makeNew) { +RtpProcess::Ptr RtpSelector::getProcess(const string &stream_id,bool makeNew) { lock_guard lck(_mtx_map); - auto it = _map_rtp_process.find(ssrc); - if(it == _map_rtp_process.end() && !makeNew){ + auto it = _map_rtp_process.find(stream_id); + if (it == _map_rtp_process.end() && !makeNew) { return nullptr; } - RtpProcessHelper::Ptr &ref = _map_rtp_process[ssrc]; - if(!ref){ - ref = std::make_shared(ssrc,shared_from_this()); + RtpProcessHelper::Ptr &ref = _map_rtp_process[stream_id]; + if (!ref) { + ref = std::make_shared(stream_id, shared_from_this()); ref->attachEvent(); createTimer(); } @@ -67,17 +74,15 @@ void RtpSelector::createTimer() { } } -void RtpSelector::delProcess(uint32_t ssrc,const RtpProcess *ptr) { +void RtpSelector::delProcess(const string &stream_id,const RtpProcess *ptr) { lock_guard lck(_mtx_map); - auto it = _map_rtp_process.find(ssrc); - if(it == _map_rtp_process.end()){ + auto it = _map_rtp_process.find(stream_id); + if (it == _map_rtp_process.end()) { return; } - - if(it->second->getProcess().get() != ptr){ + if (it->second->getProcess().get() != ptr) { return; } - _map_rtp_process.erase(it); } @@ -88,7 +93,7 @@ void RtpSelector::onManager() { ++it; continue; } - WarnL << "RtpProcess timeout:" << printSSRC(it->first); + WarnL << "RtpProcess timeout:" << it->first; it = _map_rtp_process.erase(it); } } @@ -99,10 +104,10 @@ RtpSelector::RtpSelector() { RtpSelector::~RtpSelector() { } -RtpProcessHelper::RtpProcessHelper(uint32_t ssrc, const weak_ptr &parent) { - _ssrc = ssrc; +RtpProcessHelper::RtpProcessHelper(const string &stream_id, const weak_ptr &parent) { + _stream_id = stream_id; _parent = parent; - _process = std::make_shared(_ssrc); + _process = std::make_shared(stream_id); } RtpProcessHelper::~RtpProcessHelper() { @@ -114,14 +119,14 @@ void RtpProcessHelper::attachEvent() { bool RtpProcessHelper::close(MediaSource &sender, bool force) { //此回调在其他线程触发 - if(!_process || (!force && _process->totalReaderCount())){ + if (!_process || (!force && _process->totalReaderCount())) { return false; } auto parent = _parent.lock(); - if(!parent){ + if (!parent) { return false; } - parent->delProcess(_ssrc,_process.get()); + parent->delProcess(_stream_id, _process.get()); WarnL << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; return true; } diff --git a/src/Rtp/RtpSelector.h b/src/Rtp/RtpSelector.h index d6354f48..adb6f1a5 100644 --- a/src/Rtp/RtpSelector.h +++ b/src/Rtp/RtpSelector.h @@ -24,19 +24,21 @@ class RtpSelector; class RtpProcessHelper : public MediaSourceEvent , public std::enable_shared_from_this { public: typedef std::shared_ptr Ptr; - RtpProcessHelper(uint32_t ssrc,const weak_ptr &parent); + RtpProcessHelper(const string &stream_id, const weak_ptr &parent); ~RtpProcessHelper(); void attachEvent(); RtpProcess::Ptr & getProcess(); + protected: // 通知其停止推流 bool close(MediaSource &sender,bool force) override; // 观看总人数 int totalReaderCount(MediaSource &sender) override; + private: weak_ptr _parent; RtpProcess::Ptr _process; - uint32_t _ssrc = 0; + string _stream_id; }; class RtpSelector : public std::enable_shared_from_this{ @@ -44,16 +46,21 @@ public: RtpSelector(); ~RtpSelector(); - static RtpSelector &Instance(); - bool inputRtp(const Socket::Ptr &sock, const char *data,int data_len,const struct sockaddr *addr ,uint32_t *dts_out = nullptr ); static bool getSSRC(const char *data,int data_len, uint32_t &ssrc); - RtpProcess::Ptr getProcess(uint32_t ssrc,bool makeNew); - void delProcess(uint32_t ssrc,const RtpProcess *ptr); + static RtpSelector &Instance(); + + bool inputRtp(const Socket::Ptr &sock, string &stream_id, const char *data, int data_len, + const struct sockaddr *addr, uint32_t *dts_out = nullptr); + + RtpProcess::Ptr getProcess(const string &stream_id, bool makeNew); + void delProcess(const string &stream_id, const RtpProcess *ptr); + private: void onManager(); void createTimer(); + private: - unordered_map _map_rtp_process; + unordered_map _map_rtp_process; recursive_mutex _mtx_map; Timer::Ptr _timer; }; diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp index 5e90c1f7..466b6a0c 100644 --- a/src/Rtp/RtpServer.cpp +++ b/src/Rtp/RtpServer.cpp @@ -22,12 +22,12 @@ RtpServer::~RtpServer() { } } -void RtpServer::start(uint16_t local_port, bool enable_tcp, const char *local_ip) { +void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_tcp, const char *local_ip) { _udp_server.reset(new Socket(nullptr, false)); auto &ref = RtpSelector::Instance(); auto sock = _udp_server; - _udp_server->setOnRead([&ref, sock](const Buffer::Ptr &buf, struct sockaddr *addr, int) { - ref.inputRtp(sock, buf->data(), buf->size(), addr); + _udp_server->setOnRead([&ref, sock, stream_id](const Buffer::Ptr &buf, struct sockaddr *addr, int) { + ref.inputRtp(sock, const_cast(stream_id), buf->data(), buf->size(), addr); }); //创建udp服务器 @@ -43,6 +43,7 @@ void RtpServer::start(uint16_t local_port, bool enable_tcp, const char *local_i try { //创建tcp服务器 _tcp_server = std::make_shared(_udp_server->getPoller()); + (*_tcp_server)[RtpSession::kStreamID] = stream_id; _tcp_server->start(_udp_server->get_local_port(), local_ip); } catch (...) { _tcp_server = nullptr; diff --git a/src/Rtp/RtpServer.h b/src/Rtp/RtpServer.h index c81f9513..7c406903 100644 --- a/src/Rtp/RtpServer.h +++ b/src/Rtp/RtpServer.h @@ -36,10 +36,11 @@ public: /** * 开启服务器,可能抛异常 * @param local_port 本地端口,0时为随机端口 + * @param stream_id 流id,置空则使用ssrc * @param enable_tcp 是否启用tcp服务器 * @param local_ip 绑定的本地网卡ip */ - void start(uint16_t local_port, bool enable_tcp = true, const char *local_ip = "0.0.0.0"); + void start(uint16_t local_port, const string &stream_id = "", bool enable_tcp = true, const char *local_ip = "0.0.0.0"); /** * 获取绑定的本地端口 diff --git a/src/Rtp/RtpSession.cpp b/src/Rtp/RtpSession.cpp index b51bbda4..2e3f63fe 100644 --- a/src/Rtp/RtpSession.cpp +++ b/src/Rtp/RtpSession.cpp @@ -11,8 +11,15 @@ #if defined(ENABLE_RTPPROXY) #include "RtpSession.h" #include "RtpSelector.h" +#include "Network/TcpServer.h" namespace mediakit{ +const string RtpSession::kStreamID = "stream_id"; + +void RtpSession::attachServer(const TcpServer &server) { + _stream_id = const_cast(server)[kStreamID]; +} + RtpSession::RtpSession(const Socket::Ptr &sock) : TcpSession(sock) { DebugP(this); socklen_t addr_len = sizeof(addr); @@ -21,7 +28,7 @@ RtpSession::RtpSession(const Socket::Ptr &sock) : TcpSession(sock) { RtpSession::~RtpSession() { DebugP(this); if(_process){ - RtpSelector::Instance().delProcess(_ssrc,_process.get()); + RtpSelector::Instance().delProcess(_stream_id,_process.get()); } } @@ -36,7 +43,7 @@ void RtpSession::onRecv(const Buffer::Ptr &data) { } void RtpSession::onError(const SockException &err) { - WarnL << _ssrc << " " << err.what(); + WarnL << _stream_id << " " << err.what(); } void RtpSession::onManager() { @@ -51,13 +58,19 @@ void RtpSession::onManager() { void RtpSession::onRtpPacket(const char *data, uint64_t len) { if (!_process) { - if (!RtpSelector::getSSRC(data + 2, len - 2, _ssrc)) { + uint32_t ssrc; + if (!RtpSelector::getSSRC(data + 2, len - 2, ssrc)) { return; } - _process = RtpSelector::Instance().getProcess(_ssrc, true); + if (_stream_id.empty()) { + //未指定流id就使用ssrc为流id + _stream_id = printSSRC(ssrc); + } + //tcp情况下,一个tcp链接只可能是一路流,不需要通过多个ssrc来区分,所以不需要频繁getProcess + _process = RtpSelector::Instance().getProcess(_stream_id, true); _process->setListener(dynamic_pointer_cast(shared_from_this())); } - _process->inputRtp(_sock,data + 2, len - 2, &addr); + _process->inputRtp(_sock, data + 2, len - 2, &addr); _ticker.resetTime(); } diff --git a/src/Rtp/RtpSession.h b/src/Rtp/RtpSession.h index a3557029..07c9166b 100644 --- a/src/Rtp/RtpSession.h +++ b/src/Rtp/RtpSession.h @@ -22,22 +22,26 @@ namespace mediakit{ class RtpSession : public TcpSession , public RtpSplitter , public MediaSourceEvent{ public: + static const string kStreamID; RtpSession(const Socket::Ptr &sock); ~RtpSession() override; void onRecv(const Buffer::Ptr &) override; void onError(const SockException &err) override; void onManager() override; + void attachServer(const TcpServer &server) override; + protected: // 通知其停止推流 bool close(MediaSource &sender,bool force) override; // 观看总人数 int totalReaderCount(MediaSource &sender) override; void onRtpPacket(const char *data,uint64_t len) override; + private: - uint32_t _ssrc = 0; RtpProcess::Ptr _process; Ticker _ticker; struct sockaddr addr; + string _stream_id; }; }//namespace mediakit diff --git a/tests/test_rtp.cpp b/tests/test_rtp.cpp index d5d68511..7d6d0b42 100644 --- a/tests/test_rtp.cpp +++ b/tests/test_rtp.cpp @@ -38,6 +38,7 @@ static bool loadFile(const char *path){ uint16_t len; char rtp[2 * 1024]; struct sockaddr addr = {0}; + string stream_id; while (true) { if (2 != fread(&len, 1, 2, fp)) { WarnL; @@ -55,7 +56,7 @@ static bool loadFile(const char *path){ } uint32_t timeStamp; - RtpSelector::Instance().inputRtp(nullptr,rtp,len, &addr,&timeStamp); + RtpSelector::Instance().inputRtp(nullptr, stream_id, rtp, len, &addr, &timeStamp); if(timeStamp_last){ auto diff = timeStamp - timeStamp_last; if(diff > 0 && diff < 500){ From 248b2d5cb98cc7c853472b172d853f802644fa3e Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 09:36:10 +0800 Subject: [PATCH 32/59] =?UTF-8?q?=E5=AE=8C=E5=96=84GB28181=E6=8E=A8?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtp/RtpProcess.h | 15 +++++++++++++++ src/Rtp/RtpSelector.cpp | 17 +++++++---------- src/Rtp/RtpSelector.h | 23 ++++++++++++++++++++++- src/Rtp/RtpServer.cpp | 36 ++++++++++++++++++++++++++++-------- src/Rtp/RtpServer.h | 1 + tests/test_rtp.cpp | 3 +-- 6 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/Rtp/RtpProcess.h b/src/Rtp/RtpProcess.h index 0c55e375..1f53451b 100644 --- a/src/Rtp/RtpProcess.h +++ b/src/Rtp/RtpProcess.h @@ -27,9 +27,24 @@ public: typedef std::shared_ptr Ptr; RtpProcess(const string &stream_id); ~RtpProcess(); + + /** + * 输入rtp + * @param sock 本地监听的socket + * @param data rtp数据指针 + * @param data_len rtp数据长度 + * @param addr 数据源地址 + * @param dts_out 解析出最新的dts + * @return 是否解析成功 + */ bool inputRtp(const Socket::Ptr &sock, const char *data,int data_len, const struct sockaddr *addr , uint32_t *dts_out = nullptr); + + /** + * 是否超时,用于超时移除对象 + */ bool alive(); + /// SockInfo override string get_local_ip() override; uint16_t get_local_port() override; string get_peer_ip() override; diff --git a/src/Rtp/RtpSelector.cpp b/src/Rtp/RtpSelector.cpp index 36d8f8bc..06979972 100644 --- a/src/Rtp/RtpSelector.cpp +++ b/src/Rtp/RtpSelector.cpp @@ -15,20 +15,17 @@ namespace mediakit{ INSTANCE_IMP(RtpSelector); -bool RtpSelector::inputRtp(const Socket::Ptr &sock, string &stream_id, const char *data, int data_len, +bool RtpSelector::inputRtp(const Socket::Ptr &sock, const char *data, int data_len, const struct sockaddr *addr,uint32_t *dts_out) { - if (stream_id.empty()) { - //未指定流id,那么使用ssrc为流id - uint32_t ssrc = 0; - if (!getSSRC(data, data_len, ssrc)) { - WarnL << "get ssrc from rtp failed:" << data_len; - return false; - } - stream_id = printSSRC(ssrc); + //使用ssrc为流id + uint32_t ssrc = 0; + if (!getSSRC(data, data_len, ssrc)) { + WarnL << "get ssrc from rtp failed:" << data_len; + return false; } //假定指定了流id,那么通过流id来区分是否为一路流(哪怕可能同时收到多路流) - auto process = getProcess(stream_id, true); + auto process = getProcess(printSSRC(ssrc), true); if (process) { return process->inputRtp(sock, data, data_len, addr, dts_out); } diff --git a/src/Rtp/RtpSelector.h b/src/Rtp/RtpSelector.h index adb6f1a5..83f8bd2e 100644 --- a/src/Rtp/RtpSelector.h +++ b/src/Rtp/RtpSelector.h @@ -49,10 +49,31 @@ public: static bool getSSRC(const char *data,int data_len, uint32_t &ssrc); static RtpSelector &Instance(); - bool inputRtp(const Socket::Ptr &sock, string &stream_id, const char *data, int data_len, + /** + * 输入多个rtp流,根据ssrc分流 + * @param sock 本地socket + * @param data 收到的数据 + * @param data_len 收到的数据长度 + * @param addr rtp流源地址 + * @param dts_out 解析出最新的dts + * @return 是否成功 + */ + bool inputRtp(const Socket::Ptr &sock, const char *data, int data_len, const struct sockaddr *addr, uint32_t *dts_out = nullptr); + /** + * 获取一个rtp处理器 + * @param stream_id 流id + * @param makeNew 不存在时是否新建 + * @return rtp处理器 + */ RtpProcess::Ptr getProcess(const string &stream_id, bool makeNew); + + /** + * 删除rtp处理器 + * @param stream_id 流id + * @param ptr rtp处理器指针 + */ void delProcess(const string &stream_id, const RtpProcess *ptr); private: diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp index 466b6a0c..fd006c50 100644 --- a/src/Rtp/RtpServer.cpp +++ b/src/Rtp/RtpServer.cpp @@ -17,25 +17,20 @@ RtpServer::RtpServer() { } RtpServer::~RtpServer() { - if(_udp_server){ - _udp_server->setOnRead(nullptr); + if(_on_clearup){ + _on_clearup(); } } void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_tcp, const char *local_ip) { _udp_server.reset(new Socket(nullptr, false)); - auto &ref = RtpSelector::Instance(); - auto sock = _udp_server; - _udp_server->setOnRead([&ref, sock, stream_id](const Buffer::Ptr &buf, struct sockaddr *addr, int) { - ref.inputRtp(sock, const_cast(stream_id), buf->data(), buf->size(), addr); - }); - //创建udp服务器 if (!_udp_server->bindUdpSock(local_port, local_ip)) { _udp_server = nullptr; string err = (StrPrinter << "bindUdpSock on " << local_ip << ":" << local_port << " failed:" << get_uv_errmsg(true)); throw std::runtime_error(err); } + //设置udp socket读缓存 SockUtil::setRecvBuf(_udp_server->rawFD(), 4 * 1024 * 1024); @@ -51,6 +46,31 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable throw; } } + + auto sock = _udp_server; + RtpProcess::Ptr process; + if (!stream_id.empty()) { + //指定了流id,那么一个端口一个流(不管是否包含多个ssrc的多个流,绑定rtp源后,会筛选掉ip端口不匹配的流) + process = RtpSelector::Instance().getProcess(stream_id, true); + _udp_server->setOnRead([sock, process](const Buffer::Ptr &buf, struct sockaddr *addr, int) { + process->inputRtp(sock, buf->data(), buf->size(), addr); + }); + } else { + //未指定流id,一个端口多个流,通过ssrc来分流 + auto &ref = RtpSelector::Instance(); + _udp_server->setOnRead([&ref, sock](const Buffer::Ptr &buf, struct sockaddr *addr, int) { + ref.inputRtp(sock, buf->data(), buf->size(), addr); + }); + } + + _on_clearup = [sock, process, stream_id]() { + //去除循环引用 + sock->setOnRead(nullptr); + if (process) { + //删除rtp处理器 + RtpSelector::Instance().delProcess(stream_id, process.get()); + } + }; } EventPoller::Ptr RtpServer::getPoller() { diff --git a/src/Rtp/RtpServer.h b/src/Rtp/RtpServer.h index 7c406903..2623ae2b 100644 --- a/src/Rtp/RtpServer.h +++ b/src/Rtp/RtpServer.h @@ -55,6 +55,7 @@ public: protected: Socket::Ptr _udp_server; TcpServer::Ptr _tcp_server; + function _on_clearup; }; }//namespace mediakit diff --git a/tests/test_rtp.cpp b/tests/test_rtp.cpp index 7d6d0b42..24d9ac83 100644 --- a/tests/test_rtp.cpp +++ b/tests/test_rtp.cpp @@ -38,7 +38,6 @@ static bool loadFile(const char *path){ uint16_t len; char rtp[2 * 1024]; struct sockaddr addr = {0}; - string stream_id; while (true) { if (2 != fread(&len, 1, 2, fp)) { WarnL; @@ -56,7 +55,7 @@ static bool loadFile(const char *path){ } uint32_t timeStamp; - RtpSelector::Instance().inputRtp(nullptr, stream_id, rtp, len, &addr, &timeStamp); + RtpSelector::Instance().inputRtp(nullptr, rtp, len, &addr, &timeStamp); if(timeStamp_last){ auto diff = timeStamp - timeStamp_last; if(diff > 0 && diff < 500){ From e58a63c528d21184a7b777c0f7e979888d3dd4a2 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 10:09:16 +0800 Subject: [PATCH 33/59] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtp/RtpServer.cpp | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp index fd006c50..365aceb2 100644 --- a/src/Rtp/RtpServer.cpp +++ b/src/Rtp/RtpServer.cpp @@ -23,54 +23,52 @@ RtpServer::~RtpServer() { } void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_tcp, const char *local_ip) { - _udp_server.reset(new Socket(nullptr, false)); //创建udp服务器 - if (!_udp_server->bindUdpSock(local_port, local_ip)) { - _udp_server = nullptr; - string err = (StrPrinter << "bindUdpSock on " << local_ip << ":" << local_port << " failed:" << get_uv_errmsg(true)); - throw std::runtime_error(err); + Socket::Ptr udp_server = std::make_shared(nullptr, false); + if (!udp_server->bindUdpSock(local_port, local_ip)) { + throw std::runtime_error(StrPrinter << "bindUdpSock on " << local_ip << ":" << local_port << " failed:" << get_uv_errmsg(true)); } - //设置udp socket读缓存 - SockUtil::setRecvBuf(_udp_server->rawFD(), 4 * 1024 * 1024); + SockUtil::setRecvBuf(udp_server->rawFD(), 4 * 1024 * 1024); + TcpServer::Ptr tcp_server; if (enable_tcp) { try { //创建tcp服务器 - _tcp_server = std::make_shared(_udp_server->getPoller()); - (*_tcp_server)[RtpSession::kStreamID] = stream_id; - _tcp_server->start(_udp_server->get_local_port(), local_ip); + tcp_server = std::make_shared(udp_server->getPoller()); + (*tcp_server)[RtpSession::kStreamID] = stream_id; + tcp_server->start(udp_server->get_local_port(), local_ip); } catch (...) { - _tcp_server = nullptr; - _udp_server = nullptr; throw; } } - auto sock = _udp_server; RtpProcess::Ptr process; if (!stream_id.empty()) { //指定了流id,那么一个端口一个流(不管是否包含多个ssrc的多个流,绑定rtp源后,会筛选掉ip端口不匹配的流) process = RtpSelector::Instance().getProcess(stream_id, true); - _udp_server->setOnRead([sock, process](const Buffer::Ptr &buf, struct sockaddr *addr, int) { - process->inputRtp(sock, buf->data(), buf->size(), addr); + udp_server->setOnRead([udp_server, process](const Buffer::Ptr &buf, struct sockaddr *addr, int) { + process->inputRtp(udp_server, buf->data(), buf->size(), addr); }); } else { //未指定流id,一个端口多个流,通过ssrc来分流 auto &ref = RtpSelector::Instance(); - _udp_server->setOnRead([&ref, sock](const Buffer::Ptr &buf, struct sockaddr *addr, int) { - ref.inputRtp(sock, buf->data(), buf->size(), addr); + udp_server->setOnRead([&ref, udp_server](const Buffer::Ptr &buf, struct sockaddr *addr, int) { + ref.inputRtp(udp_server, buf->data(), buf->size(), addr); }); } - _on_clearup = [sock, process, stream_id]() { + _on_clearup = [udp_server, process, stream_id]() { //去除循环引用 - sock->setOnRead(nullptr); + udp_server->setOnRead(nullptr); if (process) { //删除rtp处理器 RtpSelector::Instance().delProcess(stream_id, process.get()); } }; + + _tcp_server = tcp_server; + _udp_server = udp_server; } EventPoller::Ptr RtpServer::getPoller() { From b2ff53037b99189853612c612b1e0d80c7f00243 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 10:25:30 +0800 Subject: [PATCH 34/59] =?UTF-8?q?http=20api=E6=96=B0=E5=BB=BA=E7=9A=84rtp?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=8F=AF=E4=BB=A5=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E8=B6=85=E6=97=B6=E7=A7=BB=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 13 +++++++++++-- src/Rtp/RtpProcess.cpp | 10 ++++++++++ src/Rtp/RtpProcess.h | 11 +++++++++++ src/Rtp/RtpSelector.cpp | 2 ++ src/Rtp/RtpServer.cpp | 7 +++++++ src/Rtp/RtpServer.h | 6 ++++++ 6 files changed, 47 insertions(+), 2 deletions(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 1980ee02..bbfc803d 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -761,11 +761,20 @@ void installWebApi() { RtpServer::Ptr server = std::make_shared(); server->start(allArgs["port"], allArgs["stream_id"], allArgs["enable_tcp"].as()); - val["port"] = server->getPort(); + + auto port = server->getPort(); + server->setOnDetach([port]() { + //设置rtp超时移除事件 + lock_guard lck(s_rtpServerMapMtx); + s_rtpServerMap.erase(port); + }); //保存对象 lock_guard lck(s_rtpServerMapMtx); - s_rtpServerMap.emplace(server->getPort(), server); + s_rtpServerMap.emplace(port, server); + + //回复json + val["port"] = port; }); api_regist1("/index/api/closeRtpServer",[](API_ARGS1){ diff --git a/src/Rtp/RtpProcess.cpp b/src/Rtp/RtpProcess.cpp index b3f32d19..0693ddae 100644 --- a/src/Rtp/RtpProcess.cpp +++ b/src/Rtp/RtpProcess.cpp @@ -177,6 +177,16 @@ bool RtpProcess::alive() { return false; } +void RtpProcess::onDetach(){ + if(_on_detach){ + _on_detach(); + } +} + +void RtpProcess::setOnDetach(const function &cb) { + _on_detach = cb; +} + string RtpProcess::get_peer_ip() { if(_addr){ return SockUtil::inet_ntoa(((struct sockaddr_in *) _addr)->sin_addr); diff --git a/src/Rtp/RtpProcess.h b/src/Rtp/RtpProcess.h index 1f53451b..81dc7f2f 100644 --- a/src/Rtp/RtpProcess.h +++ b/src/Rtp/RtpProcess.h @@ -44,6 +44,16 @@ public: */ bool alive(); + /** + * 超时时被RtpSelector移除时触发 + */ + void onDetach(); + + /** + * 设置onDetach事件回调 + */ + void setOnDetach(const function &cb); + /// SockInfo override string get_local_ip() override; uint16_t get_local_port() override; @@ -79,6 +89,7 @@ private: MediaInfo _media_info; uint64_t _total_bytes = 0; Socket::Ptr _sock; + function _on_detach; }; }//namespace mediakit diff --git a/src/Rtp/RtpSelector.cpp b/src/Rtp/RtpSelector.cpp index 06979972..fb790048 100644 --- a/src/Rtp/RtpSelector.cpp +++ b/src/Rtp/RtpSelector.cpp @@ -91,7 +91,9 @@ void RtpSelector::onManager() { continue; } WarnL << "RtpProcess timeout:" << it->first; + auto process = it->second->getProcess(); it = _map_rtp_process.erase(it); + process->onDetach(); } } diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp index 365aceb2..f7a4c9eb 100644 --- a/src/Rtp/RtpServer.cpp +++ b/src/Rtp/RtpServer.cpp @@ -69,6 +69,13 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable _tcp_server = tcp_server; _udp_server = udp_server; + _rtp_process = process; +} + +void RtpServer::setOnDetach(const function &cb){ + if(_rtp_process){ + _rtp_process->setOnDetach(cb); + } } EventPoller::Ptr RtpServer::getPoller() { diff --git a/src/Rtp/RtpServer.h b/src/Rtp/RtpServer.h index 2623ae2b..bcc045bc 100644 --- a/src/Rtp/RtpServer.h +++ b/src/Rtp/RtpServer.h @@ -52,9 +52,15 @@ public: */ EventPoller::Ptr getPoller(); + /** + * 设置RtpProcess onDetach事件回调 + */ + void setOnDetach(const function &cb); + protected: Socket::Ptr _udp_server; TcpServer::Ptr _tcp_server; + RtpProcess::Ptr _rtp_process; function _on_clearup; }; From 7bce212701443de20643f910de17b781b82face7 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 12:42:05 +0800 Subject: [PATCH 35/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8Drtsp=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=8E=A8=E6=B5=81=E5=88=A4=E6=96=AD=E6=97=A0=E6=95=88=E7=9A=84?= =?UTF-8?q?bug:#394?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtsp/RtspSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index d60941b4..4b2cabe0 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -218,7 +218,7 @@ void RtspSession::handleReq_Options(const Parser &parser) { } void RtspSession::handleReq_ANNOUNCE(const Parser &parser) { - auto src = dynamic_pointer_cast(MediaSource::find(RTSP_SCHEMA, + auto src = dynamic_pointer_cast(MediaSource::find(RTSP_SCHEMA, _mediaInfo._vhost, _mediaInfo._app, _mediaInfo._streamid)); From b0e9f8c449488231fa8aecb7810e75c6f15a1952 Mon Sep 17 00:00:00 2001 From: wxf Date: Wed, 8 Jul 2020 16:27:26 +0800 Subject: [PATCH 36/59] =?UTF-8?q?=E5=AE=89=E8=A3=85=20C++=20SDK=20?= =?UTF-8?q?=E6=97=B6=E4=B9=9F=E5=AE=89=E8=A3=85=E7=AC=AC=E4=B8=89=E6=96=B9?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a6fe11b..10148135 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,7 @@ if(ENABLE_HLS) add_library(mpeg STATIC ${src_mpeg}) list(APPEND LINK_LIB_LIST mpeg) + list(APPEND CXX_API_TARGETS mpeg) if(WIN32) set_target_properties(mpeg PROPERTIES COMPILE_FLAGS ${VS_FALGS} ) @@ -140,6 +141,7 @@ if(ENABLE_MP4) add_library(mov STATIC ${src_mov}) add_library(flv STATIC ${src_flv}) list(APPEND LINK_LIB_LIST mov flv) + list(APPEND CXX_API_TARGETS mov flv) if(WIN32) set_target_properties(mov flv PROPERTIES COMPILE_FLAGS ${VS_FALGS} ) @@ -157,6 +159,7 @@ if(ENABLE_RTPPROXY AND ENABLE_HLS) add_library(rtp STATIC ${src_rtp}) add_definitions(-DENABLE_RTPPROXY) list(APPEND LINK_LIB_LIST rtp) + list(APPEND CXX_API_TARGETS rtp) endif() #收集源代码 @@ -178,6 +181,7 @@ endif () #添加库 add_library(zltoolkit STATIC ${ToolKit_src_list}) add_library(zlmediakit STATIC ${MediaKit_src_list}) +list(APPEND CXX_API_TARGETS zltoolkit zlmediakit) #安装目录 if (WIN32) @@ -192,7 +196,7 @@ if(ENABLE_CXX_API) # 保留目录结构 install(DIRECTORY ${ToolKit_Root}/ DESTINATION ${INSTALL_PATH_INCLUDE}/ZLToolKit REGEX "(.*[.](md|cpp)|win32)$" EXCLUDE) install(DIRECTORY ${MediaKit_Root}/ DESTINATION ${INSTALL_PATH_INCLUDE}/ZLMediaKit REGEX ".*[.](md|cpp)$" EXCLUDE) - install(TARGETS zltoolkit zlmediakit DESTINATION ${INSTALL_PATH_LIB}) + install(TARGETS ${CXX_API_TARGETS} DESTINATION ${INSTALL_PATH_LIB}) endif() if (WIN32) From 1c19394b3dd46b92cc8b6572238c465fe6197e95 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 21:39:30 +0800 Subject: [PATCH 37/59] =?UTF-8?q?=E9=98=B2=E6=AD=A2rtmp=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E7=94=9F=E6=88=90Track?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtmp/RtmpDemuxer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Rtmp/RtmpDemuxer.cpp b/src/Rtmp/RtmpDemuxer.cpp index ad4b84b7..6e38b0d7 100644 --- a/src/Rtmp/RtmpDemuxer.cpp +++ b/src/Rtmp/RtmpDemuxer.cpp @@ -106,6 +106,7 @@ void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec) { //设置rtmp解码器代理,生成的frame写入该Track _videoRtmpDecoder->addDelegate(_videoTrack); onAddTrack(_videoTrack); + _tryedGetVideoTrack = true; } else { //找不到相应的rtmp解码器,该track无效 _videoTrack.reset(); @@ -123,6 +124,7 @@ void RtmpDemuxer::makeAudioTrack(const AMFValue &audioCodec,int sample_rate, int //设置rtmp解码器代理,生成的frame写入该Track _audioRtmpDecoder->addDelegate(_audioTrack); onAddTrack(_audioTrack); + _tryedGetAudioTrack = true; } else { //找不到相应的rtmp解码器,该track无效 _audioTrack.reset(); From be65ec5f1da692c14fd78bd708aa210b07958671 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 22:19:05 +0800 Subject: [PATCH 38/59] =?UTF-8?q?=E6=8F=90=E4=BE=9Brtsp=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E7=A8=B3=E5=AE=9A=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtsp/RtspSession.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index 4b2cabe0..df43487e 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -189,14 +189,10 @@ void RtspSession::onRtpPacket(const char *data, uint64_t len) { uint8_t interleaved = data[1]; if(interleaved %2 == 0){ trackIdx = getTrackIndexByInterleaved(interleaved); - if (trackIdx != -1) { - handleOneRtp(trackIdx,_aTrackInfo[trackIdx],(unsigned char *)data + 4, len - 4); - } + handleOneRtp(trackIdx,_aTrackInfo[trackIdx],(unsigned char *)data + 4, len - 4); }else{ trackIdx = getTrackIndexByInterleaved(interleaved - 1); - if (trackIdx != -1) { - onRtcpPacket(trackIdx, _aTrackInfo[trackIdx], (unsigned char *) data + 4, len - 4); - } + onRtcpPacket(trackIdx, _aTrackInfo[trackIdx], (unsigned char *) data + 4, len - 4); } } @@ -624,10 +620,6 @@ void RtspSession::handleReq_Setup(const Parser &parser) { controlSuffix = controlSuffix.substr(1); } int trackIdx = getTrackIndexByControlSuffix(controlSuffix); - if (trackIdx == -1) { - //未找到相应track - throw SockException(Err_shutdown, StrPrinter << "can not find any track by control suffix:" << controlSuffix); - } SdpTrack::Ptr &trackRef = _aTrackInfo[trackIdx]; if (trackRef->_inited) { //已经初始化过该Track @@ -1077,7 +1069,7 @@ inline int RtspSession::getTrackIndexByTrackType(TrackType type) { if(_aTrackInfo.size() == 1){ return 0; } - return -1; + throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) type); } inline int RtspSession::getTrackIndexByControlSuffix(const string &controlSuffix) { for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { @@ -1088,7 +1080,7 @@ inline int RtspSession::getTrackIndexByControlSuffix(const string &controlSuffix if(_aTrackInfo.size() == 1){ return 0; } - return -1; + throw SockException(Err_shutdown, StrPrinter << "no such track with suffix:" << controlSuffix); } inline int RtspSession::getTrackIndexByInterleaved(int interleaved){ @@ -1100,7 +1092,7 @@ inline int RtspSession::getTrackIndexByInterleaved(int interleaved){ if(_aTrackInfo.size() == 1){ return 0; } - return -1; + throw SockException(Err_shutdown, StrPrinter << "no such track with interleaved:" << interleaved); } bool RtspSession::close(MediaSource &sender,bool force) { @@ -1155,9 +1147,6 @@ void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { #if RTSP_SERVER_SEND_RTCP int iTrackIndex = getTrackIndexByTrackType(pkt->type); - if(iTrackIndex == -1){ - return; - } RtcpCounter &counter = _aRtcpCnt[iTrackIndex]; counter.pktCnt += 1; counter.octCount += (pkt->length - pkt->offset); From d4908c3162242a3289b0c963f2f08327eabd1940 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 22:29:08 +0800 Subject: [PATCH 39/59] =?UTF-8?q?=E6=8F=90=E9=AB=98rtsp=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E5=81=A5=E5=A3=AE=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtsp/RtspPlayer.cpp | 15 ++++----------- src/Rtsp/RtspPusher.cpp | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index 297266f7..fdfc6a1c 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -464,14 +464,10 @@ void RtspPlayer::onRtpPacket(const char *data, uint64_t len) { uint8_t interleaved = data[1]; if(interleaved %2 == 0){ trackIdx = getTrackIndexByInterleaved(interleaved); - if (trackIdx != -1) { - handleOneRtp(trackIdx, _sdp_track[trackIdx], (unsigned char *)data + 4, len - 4); - } + handleOneRtp(trackIdx, _sdp_track[trackIdx], (unsigned char *)data + 4, len - 4); }else{ trackIdx = getTrackIndexByInterleaved(interleaved - 1); - if (trackIdx != -1) { - onRtcpPacket(trackIdx, _sdp_track[trackIdx], (unsigned char *) data + 4, len - 4); - } + onRtcpPacket(trackIdx, _sdp_track[trackIdx], (unsigned char *) data + 4, len - 4); } } @@ -713,9 +709,6 @@ void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &tra onRecvRTP(pkt, track); int iTrackIndex = getTrackIndexByInterleaved(pkt->interleaved); - if (iTrackIndex == -1) { - return; - } RtcpCounter &counter = _rtcp_counter[iTrackIndex]; counter.pktCnt = pkt->sequence; auto &ticker = _rtcp_send_ticker[iTrackIndex]; @@ -788,7 +781,7 @@ int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const { if (_sdp_track.size() == 1) { return 0; } - return -1; + throw SockException(Err_shutdown, StrPrinter << "no such track with interleaved:" << interleaved); } int RtspPlayer::getTrackIndexByTrackType(TrackType trackType) const { @@ -800,7 +793,7 @@ int RtspPlayer::getTrackIndexByTrackType(TrackType trackType) const { if (_sdp_track.size() == 1) { return 0; } - return -1; + throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) trackType); } } /* namespace mediakit */ diff --git a/src/Rtsp/RtspPusher.cpp b/src/Rtsp/RtspPusher.cpp index f259a0d6..16dd12b7 100644 --- a/src/Rtsp/RtspPusher.cpp +++ b/src/Rtsp/RtspPusher.cpp @@ -347,7 +347,7 @@ inline int RtspPusher::getTrackIndexByTrackType(TrackType type) { if(_aTrackInfo.size() == 1){ return 0; } - return -1; + throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) type); } void RtspPusher::sendRecord() { From d191347839e77815d3f8f51c6fcf3d1c8b2e4cf2 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 22:49:08 +0800 Subject: [PATCH 40/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtsp/RtspPlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index fdfc6a1c..4f7c02bb 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -708,7 +708,7 @@ void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &tra _rtp_recv_ticker.resetTime(); onRecvRTP(pkt, track); - int iTrackIndex = getTrackIndexByInterleaved(pkt->interleaved); + int iTrackIndex = getTrackIndexByTrackType(pkt->type); RtcpCounter &counter = _rtcp_counter[iTrackIndex]; counter.pktCnt = pkt->sequence; auto &ticker = _rtcp_send_ticker[iTrackIndex]; From a164b286084c70860a1e05c154e948f0c888bb22 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Wed, 8 Jul 2020 23:23:11 +0800 Subject: [PATCH 41/59] =?UTF-8?q?=E4=BC=98=E5=8C=96rtp=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtp/RtpProcess.cpp | 8 +------- src/Rtp/RtpProcess.h | 1 - src/Rtsp/RtpReceiver.cpp | 33 +++++++++++++++++---------------- src/Rtsp/RtpReceiver.h | 8 ++++++-- src/Rtsp/RtspPlayer.cpp | 5 +++-- src/Rtsp/RtspSession.cpp | 5 +++-- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/Rtp/RtpProcess.cpp b/src/Rtp/RtpProcess.cpp index 0693ddae..87812741 100644 --- a/src/Rtp/RtpProcess.cpp +++ b/src/Rtp/RtpProcess.cpp @@ -21,12 +21,6 @@ static string printAddress(const struct sockaddr *addr){ } RtpProcess::RtpProcess(const string &stream_id) { - _track = std::make_shared(); - _track->_interleaved = 0; - _track->_samplerate = 90000; - _track->_type = TrackVideo; - _track->_ssrc = 0; - _media_info._schema = RTP_APP_NAME; _media_info._vhost = DEFAULT_VHOST; _media_info._app = RTP_APP_NAME; @@ -104,7 +98,7 @@ bool RtpProcess::inputRtp(const Socket::Ptr &sock, const char *data, int data_le } _total_bytes += data_len; - bool ret = handleOneRtp(0,_track,(unsigned char *)data,data_len); + bool ret = handleOneRtp(0, TrackVideo, 90000, (unsigned char *) data, data_len); if(dts_out){ *dts_out = _dts; } diff --git a/src/Rtp/RtpProcess.h b/src/Rtp/RtpProcess.h index 81dc7f2f..d2d9c5ee 100644 --- a/src/Rtp/RtpProcess.h +++ b/src/Rtp/RtpProcess.h @@ -78,7 +78,6 @@ private: std::shared_ptr _save_file_rtp; std::shared_ptr _save_file_ps; std::shared_ptr _save_file_video; - SdpTrack::Ptr _track; struct sockaddr *_addr = nullptr; uint16_t _sequence = 0; MultiMediaSourceMuxer::Ptr _muxer; diff --git a/src/Rtsp/RtpReceiver.cpp b/src/Rtsp/RtpReceiver.cpp index e7703de7..0b10063c 100644 --- a/src/Rtsp/RtpReceiver.cpp +++ b/src/Rtsp/RtpReceiver.cpp @@ -27,7 +27,7 @@ namespace mediakit { RtpReceiver::RtpReceiver() {} RtpReceiver::~RtpReceiver() {} -bool RtpReceiver::handleOneRtp(int track_index,SdpTrack::Ptr &track, unsigned char *rtp_raw_ptr, unsigned int rtp_raw_len) { +bool RtpReceiver::handleOneRtp(int track_index, TrackType type, int samplerate, unsigned char *rtp_raw_ptr, unsigned int rtp_raw_len) { if(rtp_raw_len < 12){ WarnL << "rtp包太小:" << rtp_raw_len; return false; @@ -46,8 +46,8 @@ bool RtpReceiver::handleOneRtp(int track_index,SdpTrack::Ptr &track, unsigned ch auto rtp_ptr = _rtp_pool.obtain(); auto &rtp = *rtp_ptr; - rtp.type = track->_type; - rtp.interleaved = 2 * track->_type; + rtp.type = type; + rtp.interleaved = 2 * type; rtp.mark = rtp_raw_ptr[1] >> 7; rtp.PT = rtp_raw_ptr[1] & 0x7F; @@ -59,29 +59,29 @@ bool RtpReceiver::handleOneRtp(int track_index,SdpTrack::Ptr &track, unsigned ch memcpy(&rtp.timeStamp, rtp_raw_ptr + 4, 4); rtp.timeStamp = ntohl(rtp.timeStamp); - if(!track->_samplerate){ + if(!samplerate){ //无法把时间戳转换成毫秒 return false; } //时间戳转换成毫秒 - rtp.timeStamp = rtp.timeStamp * 1000LL / track->_samplerate; + rtp.timeStamp = rtp.timeStamp * 1000LL / samplerate; //ssrc,内存对齐 memcpy(&rtp.ssrc, rtp_raw_ptr + 8, 4); rtp.ssrc = ntohl(rtp.ssrc); - if (track->_ssrc != rtp.ssrc) { - if (track->_ssrc == 0) { + if (_ssrc[track_index] != rtp.ssrc) { + if (_ssrc[track_index] == 0) { //保存SSRC至track对象 - track->_ssrc = rtp.ssrc; + _ssrc[track_index] = rtp.ssrc; }else{ //ssrc错误 - WarnL << "ssrc错误:" << rtp.ssrc << " != " << track->_ssrc; + WarnL << "ssrc错误:" << rtp.ssrc << " != " << _ssrc[track_index]; if (_ssrc_err_count[track_index]++ > 10) { //ssrc切换后清除老数据 - WarnL << "ssrc更换:" << track->_ssrc << " -> " << rtp.ssrc; + WarnL << "ssrc更换:" << _ssrc[track_index] << " -> " << rtp.ssrc; _rtp_sort_cache_map[track_index].clear(); - track->_ssrc = rtp.ssrc; + _ssrc[track_index] = rtp.ssrc; } return false; } @@ -168,11 +168,12 @@ void RtpReceiver::sortRtp(const RtpPacket::Ptr &rtp,int track_index){ } void RtpReceiver::clear() { - CLEAR_ARR(_last_seq) - CLEAR_ARR(_ssrc_err_count) - CLEAR_ARR(_seq_ok_count) - CLEAR_ARR(_sort_started) - CLEAR_ARR(_seq_cycle_count) + CLEAR_ARR(_last_seq); + CLEAR_ARR(_ssrc); + CLEAR_ARR(_ssrc_err_count); + CLEAR_ARR(_seq_ok_count); + CLEAR_ARR(_sort_started); + CLEAR_ARR(_seq_cycle_count); _rtp_sort_cache_map[0].clear(); _rtp_sort_cache_map[1].clear(); diff --git a/src/Rtsp/RtpReceiver.h b/src/Rtsp/RtpReceiver.h index 1631184e..243fef20 100644 --- a/src/Rtsp/RtpReceiver.h +++ b/src/Rtsp/RtpReceiver.h @@ -32,12 +32,13 @@ protected: /** * 输入数据指针生成并排序rtp包 * @param track_index track下标索引 - * @param track sdp track相关信息 + * @param type track类型 + * @param samplerate rtp时间戳基准时钟,视频为90000,音频为采样率 * @param rtp_raw_ptr rtp数据指针 * @param rtp_raw_len rtp数据指针长度 * @return 解析成功返回true */ - bool handleOneRtp(int track_index,SdpTrack::Ptr &track, unsigned char *rtp_raw_ptr, unsigned int rtp_raw_len); + bool handleOneRtp(int track_index, TrackType type, int samplerate, unsigned char *rtp_raw_ptr, unsigned int rtp_raw_len); /** * rtp数据包排序后输出 @@ -49,9 +50,12 @@ protected: void setPoolSize(int size); int getJitterSize(int track_index); int getCycleCount(int track_index); + private: void sortRtp(const RtpPacket::Ptr &rtp , int track_index); + private: + uint32_t _ssrc[2] = { 0, 0 }; //ssrc不匹配计数 uint32_t _ssrc_err_count[2] = { 0, 0 }; //上次seq diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index 4f7c02bb..a2ce2b24 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -319,7 +319,8 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex) WarnL << "收到其他地址的rtp数据:" << SockUtil::inet_ntoa(((struct sockaddr_in *) addr)->sin_addr); return; } - strongSelf->handleOneRtp(uiTrackIndex, strongSelf->_sdp_track[uiTrackIndex], (unsigned char *) buf->data(), buf->size()); + strongSelf->handleOneRtp(uiTrackIndex, strongSelf->_sdp_track[uiTrackIndex]->_type, + strongSelf->_sdp_track[uiTrackIndex]->_samplerate, (unsigned char *) buf->data(), buf->size()); }); if(pRtcpSockRef) { @@ -464,7 +465,7 @@ void RtspPlayer::onRtpPacket(const char *data, uint64_t len) { uint8_t interleaved = data[1]; if(interleaved %2 == 0){ trackIdx = getTrackIndexByInterleaved(interleaved); - handleOneRtp(trackIdx, _sdp_track[trackIdx], (unsigned char *)data + 4, len - 4); + handleOneRtp(trackIdx, _sdp_track[trackIdx]->_type, _sdp_track[trackIdx]->_samplerate, (unsigned char *)data + 4, len - 4); }else{ trackIdx = getTrackIndexByInterleaved(interleaved - 1); onRtcpPacket(trackIdx, _sdp_track[trackIdx], (unsigned char *) data + 4, len - 4); diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index df43487e..8a160e75 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -189,7 +189,7 @@ void RtspSession::onRtpPacket(const char *data, uint64_t len) { uint8_t interleaved = data[1]; if(interleaved %2 == 0){ trackIdx = getTrackIndexByInterleaved(interleaved); - handleOneRtp(trackIdx,_aTrackInfo[trackIdx],(unsigned char *)data + 4, len - 4); + handleOneRtp(trackIdx, _aTrackInfo[trackIdx]->_type, _aTrackInfo[trackIdx]->_samplerate, (unsigned char *) data + 4, len - 4); }else{ trackIdx = getTrackIndexByInterleaved(interleaved - 1); onRtcpPacket(trackIdx, _aTrackInfo[trackIdx], (unsigned char *) data + 4, len - 4); @@ -922,7 +922,8 @@ inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBu if(intervaled % 2 == 0){ if(_pushSrc){ //这是rtsp推流上来的rtp包 - handleOneRtp(intervaled / 2,_aTrackInfo[intervaled / 2],( unsigned char *)pBuf->data(),pBuf->size()); + auto &ref = _aTrackInfo[intervaled / 2]; + handleOneRtp(intervaled / 2, ref->_type, ref->_samplerate, (unsigned char *) pBuf->data(), pBuf->size()); }else if(!_udpSockConnected.count(intervaled)){ //这是rtsp播放器的rtp打洞包 _udpSockConnected.emplace(intervaled); From 4b39fd487da7f1f69874f1aa1a3d8d5036cf6b8b Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 9 Jul 2020 10:38:57 +0800 Subject: [PATCH 42/59] =?UTF-8?q?=E5=8A=A8=E6=80=81=E5=88=9B=E5=BB=BArtp?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E9=87=87=E7=94=A8stream=5Fid=E4=B8=BA?= =?UTF-8?q?=E7=B4=A2=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index bbfc803d..1aef1402 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -257,7 +257,7 @@ static recursive_mutex s_ffmpegMapMtx; #if defined(ENABLE_RTPPROXY) //rtp服务器列表 -static unordered_map s_rtpServerMap; +static unordered_map s_rtpServerMap; static recursive_mutex s_rtpServerMapMtx; #endif @@ -759,38 +759,41 @@ void installWebApi() { CHECK_SECRET(); CHECK_ARGS("port", "enable_tcp", "stream_id"); + auto stream_id = allArgs["stream_id"]; RtpServer::Ptr server = std::make_shared(); - server->start(allArgs["port"], allArgs["stream_id"], allArgs["enable_tcp"].as()); + server->start(allArgs["port"], stream_id, allArgs["enable_tcp"].as()); - auto port = server->getPort(); - server->setOnDetach([port]() { + server->setOnDetach([stream_id]() { //设置rtp超时移除事件 lock_guard lck(s_rtpServerMapMtx); - s_rtpServerMap.erase(port); + s_rtpServerMap.erase(stream_id); }); - //保存对象 lock_guard lck(s_rtpServerMapMtx); - s_rtpServerMap.emplace(port, server); + //保存对象,强制覆盖 + s_rtpServerMap[stream_id] = server; //回复json - val["port"] = port; + val["port"] = server->getPort(); }); api_regist1("/index/api/closeRtpServer",[](API_ARGS1){ CHECK_SECRET(); - CHECK_ARGS("port"); + CHECK_ARGS("stream_id"); lock_guard lck(s_rtpServerMapMtx); - val["hit"] = (int)s_rtpServerMap.erase(allArgs["port"].as()); + val["hit"] = (int) s_rtpServerMap.erase(allArgs["stream_id"]); }); api_regist1("/index/api/listRtpServer",[](API_ARGS1){ CHECK_SECRET(); lock_guard lck(s_rtpServerMapMtx); - for(auto &pr : s_rtpServerMap){ - val["data"].append(pr.first); + for (auto &pr : s_rtpServerMap) { + Value obj; + obj["stream_id"] = pr.first; + obj["port"] = pr.second->getPort(); + val["data"].append(obj); } }); From 363673dd00a5784f3a60315435cea294c74298c7 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 9 Jul 2020 10:41:17 +0800 Subject: [PATCH 43/59] =?UTF-8?q?=E5=AE=8C=E5=96=84getRtpInfo=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 1aef1402..33ed0cbd 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -753,6 +753,8 @@ void installWebApi() { val["exist"] = true; val["peer_ip"] = process->get_peer_ip(); val["peer_port"] = process->get_peer_port(); + val["local_port"] = process->get_local_port(); + val["local_ip"] = process->get_local_ip(); }); api_regist1("/index/api/openRtpServer",[](API_ARGS1){ From d6d861c4015767a211855218f42f1825c1b6e661 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 9 Jul 2020 10:57:17 +0800 Subject: [PATCH 44/59] =?UTF-8?q?openRtpServer=E6=8E=A5=E5=8F=A3=E4=B8=8D?= =?UTF-8?q?=E5=85=81=E8=AE=B8=E6=B7=BB=E5=8A=A0=E9=87=8D=E5=A4=8D=E7=9A=84?= =?UTF-8?q?stream=5Fid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 33ed0cbd..7f2de674 100644 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -762,19 +762,23 @@ void installWebApi() { CHECK_ARGS("port", "enable_tcp", "stream_id"); auto stream_id = allArgs["stream_id"]; + + lock_guard lck(s_rtpServerMapMtx); + if(s_rtpServerMap.find(stream_id) != s_rtpServerMap.end()) { + //为了防止RtpProcess所有权限混乱的问题,不允许重复添加相同的stream_id + throw InvalidArgsException("该stream_id已存在"); + } + RtpServer::Ptr server = std::make_shared(); server->start(allArgs["port"], stream_id, allArgs["enable_tcp"].as()); - server->setOnDetach([stream_id]() { //设置rtp超时移除事件 lock_guard lck(s_rtpServerMapMtx); s_rtpServerMap.erase(stream_id); }); - lock_guard lck(s_rtpServerMapMtx); - //保存对象,强制覆盖 - s_rtpServerMap[stream_id] = server; - + //保存对象 + s_rtpServerMap.emplace(stream_id, server); //回复json val["port"] = server->getPort(); }); From bc5931dce9c8d53534da3d7cccd2b1dd8fc47833 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 9 Jul 2020 11:15:01 +0800 Subject: [PATCH 45/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8DG711=E7=94=9F=E6=88=90R?= =?UTF-8?q?TP=E7=B1=BB=E5=9E=8B=E6=97=A0=E6=95=88=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Extension/Factory.cpp | 4 ++-- src/Extension/G711Rtp.cpp | 18 ++++++------------ src/Extension/G711Rtp.h | 8 +++----- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/Extension/Factory.cpp b/src/Extension/Factory.cpp index 1e7a6284..92771f38 100644 --- a/src/Extension/Factory.cpp +++ b/src/Extension/Factory.cpp @@ -118,7 +118,7 @@ RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) { case CodecH265 : return std::make_shared(ssrc,mtu,sample_rate,pt,interleaved); case CodecAAC : return std::make_shared(ssrc,mtu,sample_rate,pt,interleaved); case CodecG711A : - case CodecG711U : return std::make_shared(ssrc, mtu, sample_rate, pt, interleaved); + case CodecG711U : return std::make_shared(codec_id, ssrc, mtu, sample_rate, pt, interleaved); default : WarnL << "暂不支持该CodecId:" << codec_id; return nullptr; } } @@ -129,7 +129,7 @@ RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) { case CodecH265 : return std::make_shared(); case CodecAAC : return std::make_shared(track->clone()); case CodecG711A : - case CodecG711U : return std::make_shared(track->clone()); + case CodecG711U : return std::make_shared(track->getCodecId()); default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr; } } diff --git a/src/Extension/G711Rtp.cpp b/src/Extension/G711Rtp.cpp index 8e7a5cf8..48238db5 100644 --- a/src/Extension/G711Rtp.cpp +++ b/src/Extension/G711Rtp.cpp @@ -12,8 +12,8 @@ namespace mediakit{ -G711RtpDecoder::G711RtpDecoder(const Track::Ptr &track){ - _codecid = track->getCodecId(); +G711RtpDecoder::G711RtpDecoder(CodecId codecid){ + _codecid = codecid; _frame = obtainFrame(); } @@ -59,16 +59,10 @@ void G711RtpDecoder::onGetG711(const G711Frame::Ptr &frame) { ///////////////////////////////////////////////////////////////////////////////////// -G711RtpEncoder::G711RtpEncoder(uint32_t ui32Ssrc, - uint32_t ui32MtuSize, - uint32_t ui32SampleRate, - uint8_t ui8PayloadType, - uint8_t ui8Interleaved) : - RtpInfo(ui32Ssrc, - ui32MtuSize, - ui32SampleRate, - ui8PayloadType, - ui8Interleaved) { +G711RtpEncoder::G711RtpEncoder(CodecId codecid, uint32_t ui32Ssrc, uint32_t ui32MtuSize, + uint32_t ui32SampleRate, uint8_t ui8PayloadType, uint8_t ui8Interleaved) : + G711RtpDecoder(codecid), + RtpInfo(ui32Ssrc, ui32MtuSize, ui32SampleRate, ui8PayloadType, ui8Interleaved) { } void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) { diff --git a/src/Extension/G711Rtp.h b/src/Extension/G711Rtp.h index f76f4a70..aca08e6d 100644 --- a/src/Extension/G711Rtp.h +++ b/src/Extension/G711Rtp.h @@ -21,7 +21,7 @@ class G711RtpDecoder : public RtpCodec , public ResourcePoolHelper { public: typedef std::shared_ptr Ptr; - G711RtpDecoder(const Track::Ptr &track); + G711RtpDecoder(CodecId codecid); ~G711RtpDecoder() {} /** @@ -35,9 +35,6 @@ public: return _codecid; } -protected: - G711RtpDecoder() {} - private: void onGetG711(const G711Frame::Ptr &frame); G711Frame::Ptr obtainFrame(); @@ -61,7 +58,8 @@ public: * @param ui8PayloadType pt类型 * @param ui8Interleaved rtsp interleaved 值 */ - G711RtpEncoder(uint32_t ui32Ssrc, + G711RtpEncoder(CodecId codecid, + uint32_t ui32Ssrc, uint32_t ui32MtuSize, uint32_t ui32SampleRate, uint8_t ui8PayloadType = 0, From b5880535712c5bb3eb5e5ca5e356a842873f6ce2 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Fri, 10 Jul 2020 10:42:23 +0800 Subject: [PATCH 46/59] =?UTF-8?q?=E6=95=B4=E7=90=86rtsp=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtsp/RtspSession.cpp | 528 +++++++++++++++++++-------------------- src/Rtsp/RtspSession.h | 165 ++++++------ 2 files changed, 335 insertions(+), 358 deletions(-) diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index 8a160e75..f62e66f4 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -56,29 +56,29 @@ static unordered_map > g_mapGetter; //对g_mapGetter上锁保护 static recursive_mutex g_mtxGetter; -RtspSession::RtspSession(const Socket::Ptr &pSock) : TcpSession(pSock) { +RtspSession::RtspSession(const Socket::Ptr &sock) : TcpSession(sock) { DebugP(this); GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond); - pSock->setSendTimeOutSecond(keep_alive_sec); + sock->setSendTimeOutSecond(keep_alive_sec); //起始接收buffer缓存设置为4K,节省内存 - pSock->setReadBuffer(std::make_shared(4 * 1024)); + sock->setReadBuffer(std::make_shared(4 * 1024)); } RtspSession::~RtspSession() { DebugP(this); } -void RtspSession::onError(const SockException& err) { - bool isPlayer = !_pushSrc; - uint64_t duration = _ticker.createdTime()/1000; +void RtspSession::onError(const SockException &err) { + bool isPlayer = !_push_src; + uint64_t duration = _alive_ticker.createdTime() / 1000; WarnP(this) << (isPlayer ? "RTSP播放器(" : "RTSP推流器(") - << _mediaInfo._vhost << "/" - << _mediaInfo._app << "/" - << _mediaInfo._streamid + << _media_info._vhost << "/" + << _media_info._app << "/" + << _media_info._streamid << ")断开:" << err.what() << ",耗时(s):" << duration; - if (_rtpType == Rtsp::RTP_MULTICAST) { + if (_rtp_type == Rtsp::RTP_MULTICAST) { //取消UDP端口监听 UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this); } @@ -91,8 +91,8 @@ void RtspSession::onError(const SockException& err) { //流量统计事件广播 GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold); - if(_ui64TotalBytes > iFlowThreshold * 1024){ - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _mediaInfo, _ui64TotalBytes, duration, isPlayer, static_cast(*this)); + if(_bytes_usage > iFlowThreshold * 1024){ + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, isPlayer, static_cast(*this)); } } @@ -101,30 +101,28 @@ void RtspSession::onManager() { GET_CONFIG(uint32_t,handshake_sec,Rtsp::kHandshakeSecond); GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond); - if (_ticker.createdTime() > handshake_sec * 1000) { - if (_strSession.size() == 0) { + if (_alive_ticker.createdTime() > handshake_sec * 1000) { + if (_sessionid.size() == 0) { shutdown(SockException(Err_timeout,"illegal connection")); return; } } - - if ((_rtpType == Rtsp::RTP_UDP || _pushSrc ) && _ticker.elapsedTime() > keep_alive_sec * 1000) { + if ((_rtp_type == Rtsp::RTP_UDP || _push_src ) && _alive_ticker.elapsedTime() > keep_alive_sec * 1000) { //如果是推流端或者rtp over udp类型的播放端,那么就做超时检测 shutdown(SockException(Err_timeout,"rtp over udp session timeouted")); return; } } -void RtspSession::onRecv(const Buffer::Ptr &pBuf) { - _ticker.resetTime(); - _ui64TotalBytes += pBuf->size(); - if (_onRecv) { +void RtspSession::onRecv(const Buffer::Ptr &buf) { + _alive_ticker.resetTime(); + _bytes_usage += buf->size(); + if (_on_recv) { //http poster的请求数据转发给http getter处理 - _onRecv(pBuf); + _on_recv(buf); } else { -// TraceP(this) << pBuf->size() << "\r\n" << pBuf->data(); - input(pBuf->data(),pBuf->size()); + input(buf->data(), buf->size()); } } @@ -132,15 +130,15 @@ void RtspSession::onRecv(const Buffer::Ptr &pBuf) { static inline bool end_of(const string &str, const string &substr){ auto pos = str.rfind(substr); return pos != string::npos && pos == str.size() - substr.size(); -}; +} void RtspSession::onWholeRtspPacket(Parser &parser) { - string strCmd = parser.Method(); //提取出请求命令字 - _iCseq = atoi(parser["CSeq"].data()); - if(_strContentBase.empty() && strCmd != "GET"){ - _strContentBase = parser.Url(); - _mediaInfo.parse(parser.FullUrl()); - _mediaInfo._schema = RTSP_SCHEMA; + string method = parser.Method(); //提取出请求命令字 + _cseq = atoi(parser["CSeq"].data()); + if(_content_base.empty() && method != "GET"){ + _content_base = parser.Url(); + _media_info.parse(parser.FullUrl()); + _media_info._schema = RTSP_SCHEMA; } typedef void (RtspSession::*rtsp_request_handler)(const Parser &parser); @@ -160,10 +158,10 @@ void RtspSession::onWholeRtspPacket(Parser &parser) { s_cmd_functions.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER); }, []() {}); - auto it = s_cmd_functions.find(strCmd); + auto it = s_cmd_functions.find(method); if (it == s_cmd_functions.end()) { sendRtspResponse("403 Forbidden"); - shutdown(SockException(Err_shutdown,StrPrinter << "403 Forbidden:" << strCmd)); + shutdown(SockException(Err_shutdown,StrPrinter << "403 Forbidden:" << method)); return; } @@ -181,24 +179,22 @@ void RtspSession::onWholeRtspPacket(Parser &parser) { } void RtspSession::onRtpPacket(const char *data, uint64_t len) { - if(!_pushSrc){ + if(!_push_src){ return; } - int trackIdx = -1; uint8_t interleaved = data[1]; if(interleaved %2 == 0){ - trackIdx = getTrackIndexByInterleaved(interleaved); - handleOneRtp(trackIdx, _aTrackInfo[trackIdx]->_type, _aTrackInfo[trackIdx]->_samplerate, (unsigned char *) data + 4, len - 4); + auto track_idx = getTrackIndexByInterleaved(interleaved); + handleOneRtp(track_idx, _sdp_track[track_idx]->_type, _sdp_track[track_idx]->_samplerate, (unsigned char *) data + 4, len - 4); }else{ - trackIdx = getTrackIndexByInterleaved(interleaved - 1); - onRtcpPacket(trackIdx, _aTrackInfo[trackIdx], (unsigned char *) data + 4, len - 4); + auto track_idx = getTrackIndexByInterleaved(interleaved - 1); + onRtcpPacket(track_idx, _sdp_track[track_idx], (unsigned char *) data + 4, len - 4); } } -void RtspSession::onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen){ +void RtspSession::onRtcpPacket(int track_idx, SdpTrack::Ptr &track, unsigned char *data, unsigned int len){} -} int64_t RtspSession::getContentLength(Parser &parser) { if(parser.Method() == "POST"){ //http post请求的content数据部分是base64编码后的rtsp请求信令包 @@ -207,7 +203,6 @@ int64_t RtspSession::getContentLength(Parser &parser) { return RtspSplitter::getContentLength(parser); } - void RtspSession::handleReq_Options(const Parser &parser) { //支持这些命令 sendRtspResponse("200 OK",{"Public" , "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, ANNOUNCE, RECORD, SET_PARAMETER, GET_PARAMETER"}); @@ -215,16 +210,16 @@ void RtspSession::handleReq_Options(const Parser &parser) { void RtspSession::handleReq_ANNOUNCE(const Parser &parser) { auto src = dynamic_pointer_cast(MediaSource::find(RTSP_SCHEMA, - _mediaInfo._vhost, - _mediaInfo._app, - _mediaInfo._streamid)); + _media_info._vhost, + _media_info._app, + _media_info._streamid)); if(src){ sendRtspResponse("406 Not Acceptable", {"Content-Type", "text/plain"}, "Already publishing."); string err = StrPrinter << "ANNOUNCE:" << "Already publishing:" - << _mediaInfo._vhost << " " - << _mediaInfo._app << " " - << _mediaInfo._streamid << endl; + << _media_info._vhost << " " + << _media_info._app << " " + << _media_info._streamid << endl; throw SockException(Err_shutdown,err); } @@ -232,30 +227,30 @@ void RtspSession::handleReq_ANNOUNCE(const Parser &parser) { if(end_of(full_url,".sdp")){ //去除.sdp后缀,防止EasyDarwin推流器强制添加.sdp后缀 full_url = full_url.substr(0,full_url.length() - 4); - _mediaInfo.parse(full_url); + _media_info.parse(full_url); } - if(_mediaInfo._app.empty() || _mediaInfo._streamid.empty()){ + if(_media_info._app.empty() || _media_info._streamid.empty()){ //推流rtsp url必须最少两级(rtsp://host/app/stream_id),不允许莫名其妙的推流url sendRtspResponse("403 Forbidden", {"Content-Type", "text/plain"}, "rtsp推流url非法,最少确保两级rtsp url"); throw SockException(Err_shutdown,StrPrinter << "rtsp推流url非法:" << full_url); } SdpParser sdpParser(parser.Content()); - _strSession = makeRandStr(12); - _aTrackInfo = sdpParser.getAvailableTrack(); + _sessionid = makeRandStr(12); + _sdp_track = sdpParser.getAvailableTrack(); - _pushSrc = std::make_shared(_mediaInfo._vhost,_mediaInfo._app,_mediaInfo._streamid); - _pushSrc->setListener(dynamic_pointer_cast(shared_from_this())); - _pushSrc->setSdp(sdpParser.toString()); + _push_src = std::make_shared(_media_info._vhost, _media_info._app, _media_info._streamid); + _push_src->setListener(dynamic_pointer_cast(shared_from_this())); + _push_src->setSdp(sdpParser.toString()); - sendRtspResponse("200 OK",{"Content-Base",_strContentBase + "/"}); + sendRtspResponse("200 OK",{"Content-Base", _content_base + "/"}); } void RtspSession::handleReq_RECORD(const Parser &parser){ - if (_aTrackInfo.empty() || parser["Session"] != _strSession) { + if (_sdp_track.empty() || parser["Session"] != _sessionid) { send_SessionNotFound(); - throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any availabe track when record" : "session not found when record"); + throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any availabe track when record" : "session not found when record"); } auto onRes = [this](const string &err,bool enableRtxp,bool enableHls,bool enableMP4){ bool authSuccess = err.empty(); @@ -266,21 +261,21 @@ void RtspSession::handleReq_RECORD(const Parser &parser){ } //设置转协议 - _pushSrc->setProtocolTranslation(enableRtxp,enableHls,enableMP4); + _push_src->setProtocolTranslation(enableRtxp, enableHls, enableMP4); _StrPrinter rtp_info; - for(auto &track : _aTrackInfo){ + for(auto &track : _sdp_track){ if (track->_inited == false) { //还有track没有setup shutdown(SockException(Err_shutdown,"track not setuped")); return; } - rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ","; + rtp_info << "url=" << _content_base << "/" << track->_control_surffix << ","; } rtp_info.pop_back(); sendRtspResponse("200 OK", {"RTP-Info",rtp_info}); - if(_rtpType == Rtsp::RTP_TCP){ + if(_rtp_type == Rtsp::RTP_TCP){ //如果是rtsp推流服务器,并且是TCP推流,那么加大TCP接收缓存,这样能提升接收性能 _sock->setReadBuffer(std::make_shared(256 * 1024)); setSocketFlags(); @@ -303,7 +298,7 @@ void RtspSession::handleReq_RECORD(const Parser &parser){ }; //rtsp推流需要鉴权 - auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish,_mediaInfo,invoker,static_cast(*this)); + auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish, _media_info, invoker, static_cast(*this)); if(!flag){ //该事件无人监听,默认不鉴权 GET_CONFIG(bool,toRtxp,General::kPublishToRtxp); @@ -341,7 +336,7 @@ void RtspSession::emitOnPlay(){ }; //广播通用播放url鉴权事件 - auto flag = _emit_on_play ? false : NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _mediaInfo, invoker, static_cast(*this)); + auto flag = _emit_on_play ? false : NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _media_info, invoker, static_cast(*this)); if (!flag) { //该事件无人监听,默认不鉴权 onRes(""); @@ -381,7 +376,7 @@ void RtspSession::handleReq_Describe(const Parser &parser) { if(_rtsp_realm.empty()){ //广播是否需要rtsp专属认证事件 - if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm, _mediaInfo, invoker, static_cast(*this))) { + if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm, _media_info, invoker, static_cast(*this))) { //无人监听此事件,说明无需认证 invoker(""); } @@ -389,10 +384,11 @@ void RtspSession::handleReq_Describe(const Parser &parser) { invoker(_rtsp_realm); } } + void RtspSession::onAuthSuccess() { TraceP(this); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - MediaSource::findAsync(_mediaInfo,weakSelf.lock(),[weakSelf](const MediaSource::Ptr &src){ + MediaSource::findAsync(_media_info, weakSelf.lock(), [weakSelf](const MediaSource::Ptr &src){ auto strongSelf = weakSelf.lock(); if(!strongSelf){ return; @@ -400,43 +396,44 @@ void RtspSession::onAuthSuccess() { auto rtsp_src = dynamic_pointer_cast(src); if (!rtsp_src) { //未找到相应的MediaSource - string err = StrPrinter << "no such stream:" << strongSelf->_mediaInfo._vhost << " " << strongSelf->_mediaInfo._app << " " << strongSelf->_mediaInfo._streamid; + string err = StrPrinter << "no such stream:" << strongSelf->_media_info._vhost << " " << strongSelf->_media_info._app << " " << strongSelf->_media_info._streamid; strongSelf->send_StreamNotFound(); strongSelf->shutdown(SockException(Err_shutdown,err)); return; } //找到了相应的rtsp流 - strongSelf->_aTrackInfo = SdpParser(rtsp_src->getSdp()).getAvailableTrack(); - if (strongSelf->_aTrackInfo.empty()) { + strongSelf->_sdp_track = SdpParser(rtsp_src->getSdp()).getAvailableTrack(); + if (strongSelf->_sdp_track.empty()) { //该流无效 DebugL << "无trackInfo,该流无效"; strongSelf->send_StreamNotFound(); strongSelf->shutdown(SockException(Err_shutdown,"can not find any available track in sdp")); return; } - strongSelf->_strSession = makeRandStr(12); - strongSelf->_pMediaSrc = rtsp_src; - for(auto &track : strongSelf->_aTrackInfo){ + strongSelf->_sessionid = makeRandStr(12); + strongSelf->_play_src = rtsp_src; + for(auto &track : strongSelf->_sdp_track){ track->_ssrc = rtsp_src->getSsrc(track->_type); track->_seq = rtsp_src->getSeqence(track->_type); track->_time_stamp = rtsp_src->getTimeStamp(track->_type); } strongSelf->sendRtspResponse("200 OK", - {"Content-Base",strongSelf->_strContentBase + "/", + {"Content-Base", strongSelf->_content_base + "/", "x-Accept-Retransmit","our-retransmit", "x-Accept-Dynamic-Rate","1" },rtsp_src->getSdp()); }); } + void RtspSession::onAuthFailed(const string &realm,const string &why,bool close) { GET_CONFIG(bool,authBasic,Rtsp::kAuthBasic); if (!authBasic) { //我们需要客户端优先以md5方式认证 - _strNonce = makeRandStr(32); + _auth_nonce = makeRandStr(32); sendRtspResponse("401 Unauthorized", {"WWW-Authenticate", - StrPrinter << "Digest realm=\"" << realm << "\",nonce=\"" << _strNonce << "\"" }); + StrPrinter << "Digest realm=\"" << realm << "\",nonce=\"" << _auth_nonce << "\"" }); }else { //当然我们也支持base64认证,但是我们不建议这样做 sendRtspResponse("401 Unauthorized", @@ -448,56 +445,56 @@ void RtspSession::onAuthFailed(const string &realm,const string &why,bool close) } } -void RtspSession::onAuthBasic(const string &realm,const string &strBase64){ +void RtspSession::onAuthBasic(const string &realm,const string &auth_base64){ //base64认证 char user_pwd_buf[512]; - av_base64_decode((uint8_t *)user_pwd_buf,strBase64.data(),strBase64.size()); - auto user_pwd_vec = split(user_pwd_buf,":"); - if(user_pwd_vec.size() < 2){ + av_base64_decode((uint8_t *) user_pwd_buf, auth_base64.data(), auth_base64.size()); + auto user_pwd_vec = split(user_pwd_buf, ":"); + if (user_pwd_vec.size() < 2) { //认证信息格式不合法,回复401 Unauthorized - onAuthFailed(realm,"can not find user and passwd when basic64 auth"); + onAuthFailed(realm, "can not find user and passwd when basic64 auth"); return; } auto user = user_pwd_vec[0]; auto pwd = user_pwd_vec[1]; weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - onAuth invoker = [pwd,realm,weakSelf](bool encrypted,const string &good_pwd){ + onAuth invoker = [pwd, realm, weakSelf](bool encrypted, const string &good_pwd) { auto strongSelf = weakSelf.lock(); - if(!strongSelf){ + if (!strongSelf) { //本对象已经销毁 return; } //切换到自己的线程执行 - strongSelf->async([weakSelf,good_pwd,pwd,realm](){ + strongSelf->async([weakSelf, good_pwd, pwd, realm]() { auto strongSelf = weakSelf.lock(); - if(!strongSelf){ + if (!strongSelf) { //本对象已经销毁 return; } //base64忽略encrypted参数,上层必须传入明文密码 - if(pwd == good_pwd){ + if (pwd == good_pwd) { //提供的密码且匹配正确 strongSelf->onAuthSuccess(); return; } //密码错误 - strongSelf->onAuthFailed(realm,StrPrinter << "password mismatch when base64 auth:" << pwd << " != " << good_pwd); + strongSelf->onAuthFailed(realm, StrPrinter << "password mismatch when base64 auth:" << pwd << " != " << good_pwd); }); }; //此时必须提供明文密码 - if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,_mediaInfo,realm,user, true,invoker,static_cast(*this))){ + if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth, _media_info, realm, user, true, invoker, static_cast(*this))) { //表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之 WarnP(this) << "请监听kBroadcastOnRtspAuth事件!"; //但是我们还是忽略认证以便完成播放 //我们输入的密码是明文 - invoker(false,pwd); + invoker(false, pwd); } } -void RtspSession::onAuthDigest(const string &realm,const string &strMd5){ - DebugP(this) << strMd5; - auto mapTmp = Parser::parseArgs(strMd5,",","="); +void RtspSession::onAuthDigest(const string &realm,const string &auth_md5){ + DebugP(this) << auth_md5; + auto mapTmp = Parser::parseArgs(auth_md5, ",", "="); decltype(mapTmp) map; for(auto &pr : mapTmp){ map[trim(string(pr.first)," \"")] = trim(pr.second," \""); @@ -509,8 +506,8 @@ void RtspSession::onAuthDigest(const string &realm,const string &strMd5){ } //check nonce auto nonce = map["nonce"]; - if(_strNonce != nonce){ - onAuthFailed(realm,StrPrinter << "nonce not mached:" << nonce << " != " << _strNonce); + if(_auth_nonce != nonce){ + onAuthFailed(realm,StrPrinter << "nonce not mached:" << nonce << " != " << _auth_nonce); return ; } //check username and uri @@ -570,7 +567,7 @@ void RtspSession::onAuthDigest(const string &realm,const string &strMd5){ }; //此时可以提供明文或md5加密的密码 - if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,_mediaInfo,realm,username, false,invoker,static_cast(*this))){ + if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth, _media_info, realm, username, false, invoker, static_cast(*this))){ //表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之 WarnP(this) << "请监听kBroadcastOnRtspAuth事件!"; //但是我们还是忽略认证以便完成播放 @@ -602,9 +599,11 @@ void RtspSession::onAuthUser(const string &realm,const string &authorization){ onAuthFailed(realm,StrPrinter << "unsupported auth type:" << authType); } } + inline void RtspSession::send_StreamNotFound() { sendRtspResponse("404 Stream Not Found",{"Connection","Close"}); } + inline void RtspSession::send_UnsupportedTransport() { sendRtspResponse("461 Unsupported Transport",{"Connection","Close"}); } @@ -614,36 +613,36 @@ inline void RtspSession::send_SessionNotFound() { } void RtspSession::handleReq_Setup(const Parser &parser) { -//处理setup命令,该函数可能进入多次 - auto controlSuffix = split(parser.FullUrl(),"/").back();// parser.FullUrl().substr(_strContentBase.size()); + //处理setup命令,该函数可能进入多次 + auto controlSuffix = split(parser.FullUrl(),"/").back(); if(controlSuffix.front() == '/'){ controlSuffix = controlSuffix.substr(1); } int trackIdx = getTrackIndexByControlSuffix(controlSuffix); - SdpTrack::Ptr &trackRef = _aTrackInfo[trackIdx]; + SdpTrack::Ptr &trackRef = _sdp_track[trackIdx]; if (trackRef->_inited) { //已经初始化过该Track throw SockException(Err_shutdown, "can not setup one track twice"); } trackRef->_inited = true; //现在初始化 - if(_rtpType == Rtsp::RTP_Invalid){ + if(_rtp_type == Rtsp::RTP_Invalid){ auto &strTransport = parser["Transport"]; if(strTransport.find("TCP") != string::npos){ - _rtpType = Rtsp::RTP_TCP; + _rtp_type = Rtsp::RTP_TCP; }else if(strTransport.find("multicast") != string::npos){ - _rtpType = Rtsp::RTP_MULTICAST; + _rtp_type = Rtsp::RTP_MULTICAST; }else{ - _rtpType = Rtsp::RTP_UDP; + _rtp_type = Rtsp::RTP_UDP; } } //允许接收rtp、rtcp包 - RtspSplitter::enableRecvRtp(_rtpType == Rtsp::RTP_TCP); + RtspSplitter::enableRecvRtp(_rtp_type == Rtsp::RTP_TCP); - switch (_rtpType) { + switch (_rtp_type) { case Rtsp::RTP_TCP: { - if(_pushSrc){ + if(_push_src){ //rtsp推流时,interleaved由推流者决定 auto key_values = Parser::parseArgs(parser["Transport"],";","="); int interleaved_rtp = -1 , interleaved_rtcp = -1; @@ -657,14 +656,16 @@ void RtspSession::handleReq_Setup(const Parser &parser) { trackRef->_interleaved = 2 * trackRef->_type; } sendRtspResponse("200 OK", - {"Transport",StrPrinter << "RTP/AVP/TCP;unicast;" - << "interleaved=" << (int)trackRef->_interleaved << "-" << (int)trackRef->_interleaved + 1 << ";" - << "ssrc=" << printSSRC(trackRef->_ssrc), - "x-Transport-Options" , "late-tolerance=1.400000", - "x-Dynamic-Rate" , "1" + {"Transport", StrPrinter << "RTP/AVP/TCP;unicast;" + << "interleaved=" << (int) trackRef->_interleaved << "-" + << (int) trackRef->_interleaved + 1 << ";" + << "ssrc=" << printSSRC(trackRef->_ssrc), + "x-Transport-Options", "late-tolerance=1.400000", + "x-Dynamic-Rate", "1" }); } break; + case Rtsp::RTP_UDP: { std::pair pr; try{ @@ -675,8 +676,8 @@ void RtspSession::handleReq_Setup(const Parser &parser) { throw SockException(Err_shutdown, ex.what()); } - _apRtpSock[trackIdx] = pr.first; - _apRtcpSock[trackIdx] = pr.second; + _rtp_socks[trackIdx] = pr.first; + _rtcp_socks[trackIdx] = pr.second; //设置客户端内网端口信息 string strClientPort = FindField(parser["Transport"].data(), "client_port=", NULL); @@ -705,14 +706,15 @@ void RtspSession::handleReq_Setup(const Parser &parser) { sendRtspResponse("200 OK", {"Transport", StrPrinter << "RTP/AVP/UDP;unicast;" << "client_port=" << strClientPort << ";" - << "server_port=" << pr.first->get_local_port() << "-" << pr.second->get_local_port() << ";" + << "server_port=" << pr.first->get_local_port() << "-" + << pr.second->get_local_port() << ";" << "ssrc=" << printSSRC(trackRef->_ssrc) }); } break; case Rtsp::RTP_MULTICAST: { if(!_multicaster){ - _multicaster = RtpMultiCaster::get(getPoller(),get_local_ip(),_mediaInfo._vhost, _mediaInfo._app, _mediaInfo._streamid); + _multicaster = RtpMultiCaster::get(getPoller(), get_local_ip(), _media_info._vhost, _media_info._app, _media_info._streamid); if (!_multicaster) { send_NotAcceptable(); throw SockException(Err_shutdown, "can not get a available udp multicast socket"); @@ -739,12 +741,12 @@ void RtspSession::handleReq_Setup(const Parser &parser) { GET_CONFIG(uint32_t,udpTTL,MultiCast::kUdpTTL); sendRtspResponse("200 OK", - {"Transport",StrPrinter << "RTP/AVP;multicast;" - << "destination=" << _multicaster->getIP() << ";" - << "source=" << get_local_ip() << ";" - << "port=" << iSrvPort << "-" << pSockRtcp->get_local_port() << ";" - << "ttl=" << udpTTL << ";" - << "ssrc=" << printSSRC(trackRef->_ssrc) + {"Transport", StrPrinter << "RTP/AVP;multicast;" + << "destination=" << _multicaster->getIP() << ";" + << "source=" << get_local_ip() << ";" + << "port=" << iSrvPort << "-" << pSockRtcp->get_local_port() << ";" + << "ttl=" << udpTTL << ";" + << "ssrc=" << printSSRC(trackRef->_ssrc) }); } break; @@ -754,19 +756,19 @@ void RtspSession::handleReq_Setup(const Parser &parser) { } void RtspSession::handleReq_Play(const Parser &parser) { - if (_aTrackInfo.empty() || parser["Session"] != _strSession) { + if (_sdp_track.empty() || parser["Session"] != _sessionid) { send_SessionNotFound(); - throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any available track when play" : "session not found when play"); + throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any available track when play" : "session not found when play"); } - auto pMediaSrc = _pMediaSrc.lock(); - if(!pMediaSrc){ + auto play_src = _play_src.lock(); + if(!play_src){ send_StreamNotFound(); shutdown(SockException(Err_shutdown,"rtsp stream released")); return; } - bool useBuf = true; - _enableSendRtp = false; + bool useGOP = true; + _enable_send_rtp = false; float iStartTime = 0; auto strRange = parser["Range"]; if (strRange.size()) { @@ -777,53 +779,53 @@ void RtspSession::handleReq_Play(const Parser &parser) { } iStartTime = 1000 * atof(strStart.data()); InfoP(this) << "rtsp seekTo(ms):" << iStartTime; - useBuf = !pMediaSrc->seekTo(iStartTime); - } else if (pMediaSrc->totalReaderCount() == 0) { + useGOP = !play_src->seekTo(iStartTime); + } else if (play_src->totalReaderCount() == 0) { //第一个消费者 - pMediaSrc->seekTo(0); + play_src->seekTo(0); } _StrPrinter rtp_info; - for (auto &track : _aTrackInfo) { + for (auto &track : _sdp_track) { if (track->_inited == false) { //还有track没有setup shutdown(SockException(Err_shutdown, "track not setuped")); return; } - track->_ssrc = pMediaSrc->getSsrc(track->_type); - track->_seq = pMediaSrc->getSeqence(track->_type); - track->_time_stamp = pMediaSrc->getTimeStamp(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=" << _strContentBase << "/" << track->_control_surffix << ";" + rtp_info << "url=" << _content_base << "/" << track->_control_surffix << ";" << "seq=" << track->_seq << ";" << "rtptime=" << (int) (track->_time_stamp * (track->_samplerate / 1000)) << ","; } rtp_info.pop_back(); sendRtspResponse("200 OK", - {"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useBuf? pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000), + {"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useGOP ? play_src->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000), "RTP-Info",rtp_info }); - _enableSendRtp = true; + _enable_send_rtp = true; setSocketFlags(); - if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) { + if (!_play_reader && _rtp_type != Rtsp::RTP_MULTICAST) { weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); - _pRtpReader = pMediaSrc->getRing()->attach(getPoller(), useBuf); - _pRtpReader->setDetachCB([weakSelf]() { + _play_reader = play_src->getRing()->attach(getPoller(), useGOP); + _play_reader->setDetachCB([weakSelf]() { auto strongSelf = weakSelf.lock(); if (!strongSelf) { return; } strongSelf->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached")); }); - _pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) { + _play_reader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) { auto strongSelf = weakSelf.lock(); if (!strongSelf) { return; } - if (strongSelf->_enableSendRtp) { + if (strongSelf->_enable_send_rtp) { strongSelf->sendRtpPacket(pack); } }); @@ -831,13 +833,13 @@ void RtspSession::handleReq_Play(const Parser &parser) { } void RtspSession::handleReq_Pause(const Parser &parser) { - if (parser["Session"] != _strSession) { + if (parser["Session"] != _sessionid) { send_SessionNotFound(); throw SockException(Err_shutdown,"session not found when pause"); } sendRtspResponse("200 OK"); - _enableSendRtp = false; + _enable_send_rtp = false; } void RtspSession::handleReq_Teardown(const Parser &parser) { @@ -873,7 +875,7 @@ void RtspSession::handleReq_Post(const Parser &parser) { g_mapGetter.erase(sessioncookie); //http poster收到请求后转发给http getter处理 - _onRecv = [this,httpGetterWeak](const Buffer::Ptr &pBuf){ + _on_recv = [this,httpGetterWeak](const Buffer::Ptr &buf){ auto httpGetterStrong = httpGetterWeak.lock(); if(!httpGetterStrong){ shutdown(SockException(Err_shutdown,"http getter released")); @@ -881,18 +883,18 @@ void RtspSession::handleReq_Post(const Parser &parser) { } //切换到http getter的线程 - httpGetterStrong->async([pBuf,httpGetterWeak](){ + httpGetterStrong->async([buf,httpGetterWeak](){ auto httpGetterStrong = httpGetterWeak.lock(); if(!httpGetterStrong){ return; } - httpGetterStrong->onRecv(std::make_shared(decodeBase64(string(pBuf->data(),pBuf->size())))); + httpGetterStrong->onRecv(std::make_shared(decodeBase64(string(buf->data(), buf->size())))); }); }; if(!parser.Content().empty()){ //http poster后面的粘包 - _onRecv(std::make_shared(parser.Content())); + _on_recv(std::make_shared(parser.Content())); } sendRtspResponse("200 OK", @@ -911,82 +913,82 @@ inline void RtspSession::send_NotAcceptable() { sendRtspResponse("406 Not Acceptable",{"Connection","Close"}); } - -void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) { - _pushSrc->onWrite(rtppt, false); +void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtp, int) { + _push_src->onWrite(rtp, false); } -inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr& addr) { - //这是rtcp心跳包,说明播放器还存活 - _ticker.resetTime(); - if(intervaled % 2 == 0){ - if(_pushSrc){ +inline void RtspSession::onRcvPeerUdpData(int interleaved, const Buffer::Ptr &buf, const struct sockaddr &addr) { + //这是rtcp心跳包,说明播放器还存活 + _alive_ticker.resetTime(); + + if (interleaved % 2 == 0) { + if (_push_src) { //这是rtsp推流上来的rtp包 - auto &ref = _aTrackInfo[intervaled / 2]; - handleOneRtp(intervaled / 2, ref->_type, ref->_samplerate, (unsigned char *) pBuf->data(), pBuf->size()); - }else if(!_udpSockConnected.count(intervaled)){ + auto &ref = _sdp_track[interleaved / 2]; + handleOneRtp(interleaved / 2, ref->_type, ref->_samplerate, (unsigned char *) buf->data(), buf->size()); + } else if (!_udp_connected_flags.count(interleaved)) { //这是rtsp播放器的rtp打洞包 - _udpSockConnected.emplace(intervaled); - _apRtpSock[intervaled / 2]->setSendPeerAddr(&addr); + _udp_connected_flags.emplace(interleaved); + _rtp_socks[interleaved / 2]->setSendPeerAddr(&addr); } - }else{ + } else { //rtcp包 - if(!_udpSockConnected.count(intervaled)){ - _udpSockConnected.emplace(intervaled); - _apRtcpSock[(intervaled - 1) / 2]->setSendPeerAddr(&addr); + if (!_udp_connected_flags.count(interleaved)) { + _udp_connected_flags.emplace(interleaved); + _rtcp_socks[(interleaved - 1) / 2]->setSendPeerAddr(&addr); } - onRtcpPacket((intervaled - 1) / 2, _aTrackInfo[(intervaled - 1) / 2], (unsigned char *) pBuf->data(),pBuf->size()); + onRtcpPacket((interleaved - 1) / 2, _sdp_track[(interleaved - 1) / 2], (unsigned char *) buf->data(), + buf->size()); } } - -inline void RtspSession::startListenPeerUdpData(int trackIdx) { +inline void RtspSession::startListenPeerUdpData(int track_idx) { weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); auto srcIP = inet_addr(get_peer_ip().data()); - auto onUdpData = [weakSelf,srcIP](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr,int intervaled){ - auto strongSelf=weakSelf.lock(); - if(!strongSelf) { + auto onUdpData = [weakSelf,srcIP](const Buffer::Ptr &buf, struct sockaddr *peer_addr, int interleaved){ + auto strongSelf = weakSelf.lock(); + if (!strongSelf) { return false; } - if (((struct sockaddr_in *) pPeerAddr)->sin_addr.s_addr != srcIP) { - WarnP(strongSelf.get()) << ((intervaled % 2 == 0) ? "收到其他地址的rtp数据:" : "收到其他地址的rtcp数据:") - << SockUtil::inet_ntoa(((struct sockaddr_in *) pPeerAddr)->sin_addr); + if (((struct sockaddr_in *) peer_addr)->sin_addr.s_addr != srcIP) { + WarnP(strongSelf.get()) << ((interleaved % 2 == 0) ? "收到其他地址的rtp数据:" : "收到其他地址的rtcp数据:") + << SockUtil::inet_ntoa(((struct sockaddr_in *) peer_addr)->sin_addr); return true; } - struct sockaddr addr=*pPeerAddr; - strongSelf->async([weakSelf,pBuf,addr,intervaled]() { - auto strongSelf=weakSelf.lock(); - if(!strongSelf) { + struct sockaddr addr = *peer_addr; + strongSelf->async([weakSelf, buf, addr, interleaved]() { + auto strongSelf = weakSelf.lock(); + if (!strongSelf) { return; } - strongSelf->onRcvPeerUdpData(intervaled,pBuf,addr); + strongSelf->onRcvPeerUdpData(interleaved, buf, addr); }); return true; }; - switch (_rtpType){ + switch (_rtp_type){ case Rtsp::RTP_MULTICAST:{ //组播使用的共享rtcp端口 - UDPServer::Instance().listenPeer(get_peer_ip().data(), this, [onUdpData]( - int intervaled, const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr) { - return onUdpData(pBuf,pPeerAddr,intervaled); + UDPServer::Instance().listenPeer(get_peer_ip().data(), this, + [onUdpData]( int interleaved, const Buffer::Ptr &buf, struct sockaddr *peer_addr) { + return onUdpData(buf, peer_addr, interleaved); }); } break; case Rtsp::RTP_UDP:{ - auto setEvent = [&](Socket::Ptr &sock,int intervaled){ + auto setEvent = [&](Socket::Ptr &sock,int interleaved){ if(!sock){ - WarnP(this) << "udp端口为空:" << intervaled; + WarnP(this) << "udp端口为空:" << interleaved; return; } - sock->setOnRead([onUdpData,intervaled](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr , int addr_len){ - onUdpData(pBuf,pPeerAddr,intervaled); + sock->setOnRead([onUdpData,interleaved](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr , int addr_len){ + onUdpData(pBuf, pPeerAddr, interleaved); }); }; - setEvent(_apRtpSock[trackIdx], 2*trackIdx ); - setEvent(_apRtcpSock[trackIdx], 2*trackIdx + 1 ); + setEvent(_rtp_socks[track_idx], 2 * track_idx ); + setEvent(_rtcp_socks[track_idx], 2 * track_idx + 1 ); } break; @@ -1003,14 +1005,11 @@ static string dateStr(){ return buf; } -bool RtspSession::sendRtspResponse(const string &res_code, - const StrCaseMap &header_const, - const string &sdp, - const char *protocol){ +bool RtspSession::sendRtspResponse(const string &res_code, const StrCaseMap &header_const, const string &sdp, const char *protocol){ auto header = header_const; - header.emplace("CSeq",StrPrinter << _iCseq); - if(!_strSession.empty()){ - header.emplace("Session",_strSession); + header.emplace("CSeq",StrPrinter << _cseq); + if(!_sessionid.empty()){ + header.emplace("Session", _sessionid); } header.emplace("Server",SERVER_NAME); @@ -1040,14 +1039,11 @@ int RtspSession::send(const Buffer::Ptr &pkt){ // if(!_enableSendRtp){ // DebugP(this) << pkt->data(); // } - _ui64TotalBytes += pkt->size(); + _bytes_usage += pkt->size(); return TcpSession::send(pkt); } -bool RtspSession::sendRtspResponse(const string &res_code, - const std::initializer_list &header, - const string &sdp, - const char *protocol) { +bool RtspSession::sendRtspResponse(const string &res_code, const std::initializer_list &header, const string &sdp, const char *protocol) { string key; StrCaseMap header_map; int i = 0; @@ -1062,43 +1058,44 @@ bool RtspSession::sendRtspResponse(const string &res_code, } inline int RtspSession::getTrackIndexByTrackType(TrackType type) { - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - if (type == _aTrackInfo[i]->_type) { + for (unsigned int i = 0; i < _sdp_track.size(); i++) { + if (type == _sdp_track[i]->_type) { return i; } } - if(_aTrackInfo.size() == 1){ + if(_sdp_track.size() == 1){ return 0; } throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) type); } + inline int RtspSession::getTrackIndexByControlSuffix(const string &controlSuffix) { - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - if (controlSuffix == _aTrackInfo[i]->_control_surffix) { + for (unsigned int i = 0; i < _sdp_track.size(); i++) { + if (controlSuffix == _sdp_track[i]->_control_surffix) { return i; } } - if(_aTrackInfo.size() == 1){ + if(_sdp_track.size() == 1){ return 0; } throw SockException(Err_shutdown, StrPrinter << "no such track with suffix:" << controlSuffix); } inline int RtspSession::getTrackIndexByInterleaved(int interleaved){ - for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { - if (_aTrackInfo[i]->_interleaved == interleaved) { + for (unsigned int i = 0; i < _sdp_track.size(); i++) { + if (_sdp_track[i]->_interleaved == interleaved) { return i; } } - if(_aTrackInfo.size() == 1){ + if(_sdp_track.size() == 1){ return 0; } throw SockException(Err_shutdown, StrPrinter << "no such track with interleaved:" << interleaved); } -bool RtspSession::close(MediaSource &sender,bool force) { +bool RtspSession::close(MediaSource &sender, bool force) { //此回调在其他线程触发 - if(!_pushSrc || (!force && _pushSrc->totalReaderCount())){ + if(!_push_src || (!force && _push_src->totalReaderCount())){ return false; } string err = StrPrinter << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; @@ -1107,17 +1104,34 @@ bool RtspSession::close(MediaSource &sender,bool force) { } int RtspSession::totalReaderCount(MediaSource &sender) { - return _pushSrc ? _pushSrc->totalReaderCount() : sender.readerCount(); + return _push_src ? _push_src->totalReaderCount() : sender.readerCount(); +} + +inline void RtspSession::onSendRtpPacket(const RtpPacket::Ptr &pkt){ +#if RTSP_SERVER_SEND_RTCP + int track_index = getTrackIndexByTrackType(pkt->type); + RtcpCounter &counter = _rtcp_counter[track_index]; + counter.pktCnt += 1; + counter.octCount += (pkt->size() - pkt->offset); + auto &ticker = _rtcp_send_tickers[track_index]; + if (ticker.elapsedTime() > 5 * 1000) { + //send rtcp every 5 second + ticker.resetTime(); + //直接保存网络字节序 + memcpy(&counter.timeStamp, pkt->data() + 8, 4); + sendSenderReport(_rtp_type == Rtsp::RTP_TCP, track_index); + } +#endif } void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { - //InfoP(this) <<(int)pkt.Interleaved; - switch (_rtpType) { + switch (_rtp_type) { case Rtsp::RTP_TCP: { int i = 0; int size = pkt->size(); setSendFlushFlag(false); pkt->for_each([&](const RtpPacket::Ptr &rtp) { + onSendRtpPacket(rtp); if (++i == size) { setSendFlushFlag(true); } @@ -1129,15 +1143,15 @@ void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { int i = 0; int size = pkt->size(); pkt->for_each([&](const RtpPacket::Ptr &rtp) { - int iTrackIndex = getTrackIndexByTrackType(rtp->type); - auto &pSock = _apRtpSock[iTrackIndex]; + onSendRtpPacket(rtp); + int track_index = getTrackIndexByTrackType(rtp->type); + auto &pSock = _rtp_socks[track_index]; if (!pSock) { shutdown(SockException(Err_shutdown, "udp sock not opened yet")); return; } - BufferRtp::Ptr buffer(new BufferRtp(rtp, 4)); - _ui64TotalBytes += buffer->size(); + _bytes_usage += buffer->size(); pSock->send(buffer, nullptr, 0, ++i == size); }); } @@ -1145,42 +1159,27 @@ void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { default: break; } - -#if RTSP_SERVER_SEND_RTCP - int iTrackIndex = getTrackIndexByTrackType(pkt->type); - RtcpCounter &counter = _aRtcpCnt[iTrackIndex]; - counter.pktCnt += 1; - counter.octCount += (pkt->length - pkt->offset); - auto &ticker = _aRtcpTicker[iTrackIndex]; - if (ticker.elapsedTime() > 5 * 1000) { - //send rtcp every 5 second - ticker.resetTime(); - //直接保存网络字节序 - memcpy(&counter.timeStamp, pkt->payload + 8 , 4); - sendSenderReport(_rtpType == Rtsp::RTP_TCP,iTrackIndex); - } -#endif } -void RtspSession::sendSenderReport(bool overTcp,int iTrackIndex) { +void RtspSession::sendSenderReport(bool over_tcp, int track_index) { static const char s_cname[] = "ZLMediaKitRtsp"; - uint8_t aui8Rtcp[4 + 28 + 10 + sizeof(s_cname) + 1] = {0}; - uint8_t *pui8Rtcp_SR = aui8Rtcp + 4, *pui8Rtcp_SDES = pui8Rtcp_SR + 28; - auto &track = _aTrackInfo[iTrackIndex]; - auto &counter = _aRtcpCnt[iTrackIndex]; + uint8_t rtcp_buf[4 + 28 + 10 + sizeof(s_cname) + 1] = {0}; + uint8_t *rtcp_sr = rtcp_buf + 4, *rtcp_sdes = rtcp_sr + 28; + auto &track = _sdp_track[track_index]; + auto &counter = _rtcp_counter[track_index]; - aui8Rtcp[0] = '$'; - aui8Rtcp[1] = track->_interleaved + 1; - aui8Rtcp[2] = (sizeof(aui8Rtcp) - 4) >> 8; - aui8Rtcp[3] = (sizeof(aui8Rtcp) - 4) & 0xFF; + rtcp_buf[0] = '$'; + rtcp_buf[1] = track->_interleaved + 1; + rtcp_buf[2] = (sizeof(rtcp_buf) - 4) >> 8; + rtcp_buf[3] = (sizeof(rtcp_buf) - 4) & 0xFF; - pui8Rtcp_SR[0] = 0x80; - pui8Rtcp_SR[1] = 0xC8; - pui8Rtcp_SR[2] = 0x00; - pui8Rtcp_SR[3] = 0x06; + rtcp_sr[0] = 0x80; + rtcp_sr[1] = 0xC8; + rtcp_sr[2] = 0x00; + rtcp_sr[3] = 0x06; - uint32_t ssrc=htonl(track->_ssrc); - memcpy(&pui8Rtcp_SR[4], &ssrc, 4); + uint32_t ssrc = htonl(track->_ssrc); + memcpy(&rtcp_sr[4], &ssrc, 4); uint64_t msw; uint64_t lsw; @@ -1190,35 +1189,35 @@ void RtspSession::sendSenderReport(bool overTcp,int iTrackIndex) { lsw = (uint32_t) ((double) tv.tv_usec * (double) (((uint64_t) 1) << 32) * 1.0e-6); msw = htonl(msw); - memcpy(&pui8Rtcp_SR[8], &msw, 4); + memcpy(&rtcp_sr[8], &msw, 4); lsw = htonl(lsw); - memcpy(&pui8Rtcp_SR[12], &lsw, 4); + memcpy(&rtcp_sr[12], &lsw, 4); //直接使用网络字节序 - memcpy(&pui8Rtcp_SR[16], &counter.timeStamp, 4); + memcpy(&rtcp_sr[16], &counter.timeStamp, 4); uint32_t pktCnt = htonl(counter.pktCnt); - memcpy(&pui8Rtcp_SR[20], &pktCnt, 4); + memcpy(&rtcp_sr[20], &pktCnt, 4); uint32_t octCount = htonl(counter.octCount); - memcpy(&pui8Rtcp_SR[24], &octCount, 4); + memcpy(&rtcp_sr[24], &octCount, 4); - pui8Rtcp_SDES[0] = 0x81; - pui8Rtcp_SDES[1] = 0xCA; - pui8Rtcp_SDES[2] = 0x00; - pui8Rtcp_SDES[3] = 0x06; + rtcp_sdes[0] = 0x81; + rtcp_sdes[1] = 0xCA; + rtcp_sdes[2] = 0x00; + rtcp_sdes[3] = 0x06; - memcpy(&pui8Rtcp_SDES[4], &ssrc, 4); + memcpy(&rtcp_sdes[4], &ssrc, 4); - pui8Rtcp_SDES[8] = 0x01; - pui8Rtcp_SDES[9] = 0x0f; - memcpy(&pui8Rtcp_SDES[10], s_cname, sizeof(s_cname)); - pui8Rtcp_SDES[10 + sizeof(s_cname)] = 0x00; + rtcp_sdes[8] = 0x01; + rtcp_sdes[9] = 0x0f; + memcpy(&rtcp_sdes[10], s_cname, sizeof(s_cname)); + rtcp_sdes[10 + sizeof(s_cname)] = 0x00; - if(overTcp){ - send(obtainBuffer((char *) aui8Rtcp, sizeof(aui8Rtcp))); - }else { - _apRtcpSock[iTrackIndex]->send((char *) aui8Rtcp + 4, sizeof(aui8Rtcp) - 4); + if (over_tcp) { + send(obtainBuffer((char *) rtcp_buf, sizeof(rtcp_buf))); + } else { + _rtcp_socks[track_index]->send((char *) rtcp_buf + 4, sizeof(rtcp_buf) - 4); } } @@ -1234,4 +1233,3 @@ void RtspSession::setSocketFlags(){ } /* namespace mediakit */ - diff --git a/src/Rtsp/RtspSession.h b/src/Rtsp/RtspSession.h index eeba0d85..2436efb6 100644 --- a/src/Rtsp/RtspSession.h +++ b/src/Rtsp/RtspSession.h @@ -59,51 +59,31 @@ public: //在请求明文密码时如果提供md5密码者则会导致认证失败 typedef std::function onAuth; - RtspSession(const Socket::Ptr &pSock); + RtspSession(const Socket::Ptr &sock); virtual ~RtspSession(); ////TcpSession override//// - void onRecv(const Buffer::Ptr &pBuf) override; + void onRecv(const Buffer::Ptr &buf) override; void onError(const SockException &err) override; void onManager() override; + protected: - //RtspSplitter override - /** - * 收到完整的rtsp包回调,包括sdp等content数据 - * @param parser rtsp包 - */ + /////RtspSplitter override///// + //收到完整的rtsp包回调,包括sdp等content数据 void onWholeRtspPacket(Parser &parser) override; - - /** - * 收到rtp包回调 - * @param data - * @param len - */ - void onRtpPacket(const char *data,uint64_t len) override; - - /** - * 从rtsp头中获取Content长度 - * @param parser - * @return - */ + //收到rtp包回调 + void onRtpPacket(const char *data, uint64_t len) override; + //从rtsp头中获取Content长度 int64_t getContentLength(Parser &parser) override; - - //RtpReceiver override - void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override; - //MediaSourceEvent override - bool close(MediaSource &sender,bool force) override ; + ////RtpReceiver override//// + void onRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) override; + ////MediaSourceEvent override//// + bool close(MediaSource &sender, bool force) override ; int totalReaderCount(MediaSource &sender) override; - - //TcpSession override + /////TcpSession override//// int send(const Buffer::Ptr &pkt) override; + //收到RTCP包回调 + virtual void onRtcpPacket(int track_idx, SdpTrack::Ptr &track, unsigned char *data, unsigned int len); - /** - * 收到RTCP包回调 - * @param iTrackidx - * @param track - * @param pucData - * @param uiLen - */ - virtual void onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen); private: //处理options方法,获取服务器能力 void handleReq_Options(const Parser &parser); @@ -127,101 +107,100 @@ private: void handleReq_Post(const Parser &parser); //处理SET_PARAMETER、GET_PARAMETER方法,一般用于心跳 void handleReq_SET_PARAMETER(const Parser &parser); - //rtsp资源未找到 - void inline send_StreamNotFound(); + void send_StreamNotFound(); //不支持的传输模式 - void inline send_UnsupportedTransport(); + void send_UnsupportedTransport(); //会话id错误 - void inline send_SessionNotFound(); + void send_SessionNotFound(); //一般rtsp服务器打开端口失败时触发 - void inline send_NotAcceptable(); - + void send_NotAcceptable(); //获取track下标 - inline int getTrackIndexByTrackType(TrackType type); - inline int getTrackIndexByControlSuffix(const string &controlSuffix); - inline int getTrackIndexByInterleaved(int interleaved); - + int getTrackIndexByTrackType(TrackType type); + int getTrackIndexByControlSuffix(const string &control_suffix); + int getTrackIndexByInterleaved(int interleaved); //一般用于接收udp打洞包,也用于rtsp推流 - inline void onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr &addr); + void onRcvPeerUdpData(int interleaved, const Buffer::Ptr &buf, const struct sockaddr &addr); //配合onRcvPeerUdpData使用 - inline void startListenPeerUdpData(int iTrackIdx); - + void startListenPeerUdpData(int track_idx); ////rtsp专有认证相关//// //认证成功 void onAuthSuccess(); //认证失败 - void onAuthFailed(const string &realm,const string &why,bool close = true); + void onAuthFailed(const string &realm, const string &why, bool close = true); //开始走rtsp专有认证流程 - void onAuthUser(const string &realm,const string &authorization); + void onAuthUser(const string &realm, const string &authorization); //校验base64方式的认证加密 - void onAuthBasic(const string &realm,const string &strBase64); + void onAuthBasic(const string &realm, const string &auth_base64); //校验md5方式的认证加密 - void onAuthDigest(const string &realm,const string &strMd5); + void onAuthDigest(const string &realm, const string &auth_md5); //触发url鉴权事件 void emitOnPlay(); - //发送rtp给客户端 void sendRtpPacket(const RtspMediaSource::RingDataType &pkt); + //触发rtcp发送 + void onSendRtpPacket(const RtpPacket::Ptr &rtp); //回复客户端 - bool sendRtspResponse(const string &res_code,const std::initializer_list &header, const string &sdp = "" , const char *protocol = "RTSP/1.0"); - bool sendRtspResponse(const string &res_code,const StrCaseMap &header = StrCaseMap(), const string &sdp = "",const char *protocol = "RTSP/1.0"); + bool sendRtspResponse(const string &res_code, const std::initializer_list &header, const string &sdp = "", const char *protocol = "RTSP/1.0"); + bool sendRtspResponse(const string &res_code, const StrCaseMap &header = StrCaseMap(), const string &sdp = "", const char *protocol = "RTSP/1.0"); //服务器发送rtcp - void sendSenderReport(bool overTcp,int iTrackIndex); + void sendSenderReport(bool over_tcp, int track_idx); //设置socket标志 void setSocketFlags(); + private: - //用于判断客户端是否超时 - Ticker _ticker; - //收到的seq,回复时一致 - int _iCseq = 0; - //ContentBase - string _strContentBase; - //Session号 - string _strSession; - //记录是否需要rtsp专属鉴权,防止重复触发事件 - string _rtsp_realm; //是否已经触发on_play事件 bool _emit_on_play = false; - //url解析后保存的相关信息 - MediaInfo _mediaInfo; - //rtsp播放器绑定的直播源 - std::weak_ptr _pMediaSrc; - //直播源读取器 - RtspMediaSource::RingType::RingReader::Ptr _pRtpReader; + //是否开始发送rtp + bool _enable_send_rtp; //推流或拉流客户端采用的rtp传输方式 - Rtsp::eRtpType _rtpType = Rtsp::RTP_Invalid; + Rtsp::eRtpType _rtp_type = Rtsp::RTP_Invalid; + //收到的seq,回复时一致 + int _cseq = 0; + //消耗的总流量 + uint64_t _bytes_usage = 0; + //ContentBase + string _content_base; + //Session号 + string _sessionid; + //记录是否需要rtsp专属鉴权,防止重复触发事件 + string _rtsp_realm; + //登录认证 + string _auth_nonce; + //用于判断客户端是否超时 + Ticker _alive_ticker; + + //url解析后保存的相关信息 + MediaInfo _media_info; + //rtsp推流相关绑定的源 + RtspMediaSourceImp::Ptr _push_src; + //rtsp播放器绑定的直播源 + std::weak_ptr _play_src; + //直播源读取器 + RtspMediaSource::RingType::RingReader::Ptr _play_reader; //sdp里面有效的track,包含音频或视频 - vector _aTrackInfo; + vector _sdp_track; + + //rtcp统计,trackid idx 为数组下标 + RtcpCounter _rtcp_counter[2]; + //rtcp发送时间,trackid idx 为数组下标 + Ticker _rtcp_send_tickers[2]; + ////////RTP over udp//////// //RTP端口,trackid idx 为数组下标 - Socket::Ptr _apRtpSock[2]; + Socket::Ptr _rtp_socks[2]; //RTCP端口,trackid idx 为数组下标 - Socket::Ptr _apRtcpSock[2]; + Socket::Ptr _rtcp_socks[2]; //标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号 - unordered_set _udpSockConnected; + unordered_set _udp_connected_flags; ////////RTP over udp_multicast//////// //共享的rtp组播对象 RtpMultiCaster::Ptr _multicaster; - - //登录认证 - string _strNonce; - //消耗的总流量 - uint64_t _ui64TotalBytes = 0; - - //RTSP over HTTP + ////////RTSP over HTTP //////// //quicktime 请求rtsp会产生两次tcp连接, //一次发送 get 一次发送post,需要通过x-sessioncookie关联起来 string _http_x_sessioncookie; - function _onRecv; - //是否开始发送rtp - bool _enableSendRtp; - //rtsp推流相关 - RtspMediaSourceImp::Ptr _pushSrc; - //rtcp统计,trackid idx 为数组下标 - RtcpCounter _aRtcpCnt[2]; - //rtcp发送时间,trackid idx 为数组下标 - Ticker _aRtcpTicker[2]; + function _on_recv; }; /** From c66e5dcdb1cbf52f577f6e15b6d16b9f54d16f5b Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sat, 11 Jul 2020 21:56:39 +0800 Subject: [PATCH 47/59] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E5=BA=93=EF=BC=8C=E4=BF=AE=E5=A4=8Dps=20rtp=E8=A7=A3?= =?UTF-8?q?=E5=8C=85=E7=9B=B8=E5=85=B3=E9=97=AE=E9=A2=98:#388?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdpart/media-server | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdpart/media-server b/3rdpart/media-server index 7f7906b0..43facc34 160000 --- a/3rdpart/media-server +++ b/3rdpart/media-server @@ -1 +1 @@ -Subproject commit 7f7906b05d84c5efeceecb8d6f540a71c8153431 +Subproject commit 43facc343afc2b5b70bbbc3c177f20dfa936f2bf From 58fb88eac09a82a13f3eb8d138cd3eeedddd8b3c Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sat, 11 Jul 2020 23:17:36 +0800 Subject: [PATCH 48/59] =?UTF-8?q?=E6=B7=BB=E5=8A=A0postman=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- postman/127.0.0.1.postman_environment.json | 24 + postman/ZLMediaKit.postman_collection.json | 1093 ++++++++++++++++++++ postman/readme.md | 1 + 3 files changed, 1118 insertions(+) create mode 100644 postman/127.0.0.1.postman_environment.json create mode 100644 postman/ZLMediaKit.postman_collection.json create mode 100644 postman/readme.md diff --git a/postman/127.0.0.1.postman_environment.json b/postman/127.0.0.1.postman_environment.json new file mode 100644 index 00000000..06037cd2 --- /dev/null +++ b/postman/127.0.0.1.postman_environment.json @@ -0,0 +1,24 @@ +{ + "id": "95afe791-f716-426e-99c4-a797e112ab2c", + "name": "127.0.0.1", + "values": [ + { + "key": "ZLMediaKit_URL", + "value": "127.0.0.1", + "enabled": true + }, + { + "key": "ZLMediaKit_secret", + "value": "035c73f7-bb6b-4889-a715-d9eb2d1925cc", + "enabled": true + }, + { + "key": "defaultVhost", + "value": "__defaultVhost__", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2020-07-11T15:16:04.479Z", + "_postman_exported_using": "Postman/7.27.1" +} \ No newline at end of file diff --git a/postman/ZLMediaKit.postman_collection.json b/postman/ZLMediaKit.postman_collection.json new file mode 100644 index 00000000..498e9386 --- /dev/null +++ b/postman/ZLMediaKit.postman_collection.json @@ -0,0 +1,1093 @@ +{ + "info": { + "_postman_id": "ff20487b-d269-40c3-b811-44bc643a3b74", + "name": "ZLMediaKit", + "description": "媒体服务器", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "获取服务器api列表(getApiList)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getApiList?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getApiList" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + } + ] + } + }, + "response": [] + }, + { + "name": "获取网络线程负载(getThreadsLoad)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getThreadsLoad?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getThreadsLoad" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + } + ] + } + }, + "response": [] + }, + { + "name": "获取后台线程负载(getWorkThreadsLoad)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getWorkThreadsLoad?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getWorkThreadsLoad" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + } + ] + } + }, + "response": [] + }, + { + "name": "获取服务器配置(getServerConfig)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getServerConfig?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getServerConfig" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + } + ] + } + }, + "response": [] + }, + { + "name": "设置服务器配置(setServerConfig)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/setServerConfig?secret={{ZLMediaKit_secret}}&api.apiDebug=0", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "setServerConfig" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "api.apiDebug", + "value": "0", + "description": "配置键与配置项值" + } + ] + } + }, + "response": [] + }, + { + "name": "重启服务器(restartServer)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/restartServer?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "restartServer" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + } + ] + } + }, + "response": [] + }, + { + "name": "获取流列表(getMediaList)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getMediaList?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getMediaList" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "schema", + "value": "rtmp", + "description": "筛选协议,例如 rtsp或rtmp", + "disabled": true + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "筛选虚拟主机,例如__defaultVhost__", + "disabled": true + }, + { + "key": "app", + "value": null, + "description": "筛选应用名,例如 live", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "关断单个流(close_stream)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/close_stream?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=live&stream=test", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "close_stream" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "schema", + "value": "rtsp", + "description": "协议,例如 rtsp或rtmp" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "live", + "description": "应用名,例如 live" + }, + { + "key": "stream", + "value": "test", + "description": "流id,例如 test" + }, + { + "key": "force", + "value": "1", + "description": "是否强制关闭(有人在观看是否还关闭)", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "批量关断流(close_streams)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/close_streams?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=live&stream=test", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "close_streams" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "schema", + "value": "rtsp", + "description": "协议,例如 rtsp或rtmp" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "live", + "description": "应用名,例如 live" + }, + { + "key": "stream", + "value": "test", + "description": "流id,例如 test" + }, + { + "key": "force", + "value": "1", + "description": "是否强制关闭(有人在观看是否还关闭)", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "获取TcpSession列表(getAllSession)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getAllSession?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getAllSession" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "local_port", + "value": "", + "description": "筛选本机端口,例如筛选rtsp链接:554", + "disabled": true + }, + { + "key": "peer_ip", + "value": null, + "description": "筛选客户端ip", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "断开tcp连接(kick_session)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/kick_session?secret={{ZLMediaKit_secret}}&id=123456", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "kick_session" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "id", + "value": "123456", + "description": "客户端唯一id,可以通过getAllSession接口获取" + } + ] + } + }, + "response": [] + }, + { + "name": "批量断开tcp连接(kick_sessions)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/kick_sessions?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "kick_sessions" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "local_port", + "value": "", + "description": "筛选本机端口,例如筛选rtsp链接:554", + "disabled": true + }, + { + "key": "peer_ip", + "value": null, + "description": "筛选客户端ip", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "添加rtsp/rtmp/hls拉流代理(addStreamProxy)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/addStreamProxy?secret={{ZLMediaKit_secret}}&vhost={{defaultVhost}}&app=live&stream=test&url=rtmp://live.hkstv.hk.lxdns.com/live/hks2&enable_rtsp=1&enable_rtmp=1", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "addStreamProxy" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "添加的流的虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "live", + "description": "添加的流的应用名,例如live" + }, + { + "key": "stream", + "value": "test", + "description": "添加的流的id名,例如test" + }, + { + "key": "url", + "value": "rtmp://live.hkstv.hk.lxdns.com/live/hks2", + "description": "拉流地址,例如rtmp://live.hkstv.hk.lxdns.com/live/hks2" + }, + { + "key": "enable_rtsp", + "value": "1", + "description": "是否转rtsp" + }, + { + "key": "enable_rtmp", + "value": "1", + "description": "是否转rtmp" + }, + { + "key": "enable_hls", + "value": null, + "description": "是否转hls", + "disabled": true + }, + { + "key": "enable_mp4", + "value": null, + "description": "是否mp4录制", + "disabled": true + }, + { + "key": "rtp_type", + "value": null, + "description": "rtsp拉流时,拉流方式,0:tcp,1:udp,2:组播", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "关闭拉流代理(delStreamProxy)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/delStreamProxy?secret={{ZLMediaKit_secret}}&key=__defaultVhost__/live/1", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "delStreamProxy" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "key", + "value": "__defaultVhost__/live/1", + "description": "addStreamProxy接口返回的key" + } + ] + } + }, + "response": [] + }, + { + "name": "添加FFmpeg拉流代理(addFFmpegSource)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/addFFmpegSource?secret={{ZLMediaKit_secret}}&src_url=http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8&dst_url=rtmp://10.8.9.115:8554/live/hks2&timeout_ms=10000", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "addFFmpegSource" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "src_url", + "value": "http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8", + "description": "FFmpeg拉流地址,支持任意协议或格式(只要FFmpeg支持即可)" + }, + { + "key": "dst_url", + "value": "rtmp://10.8.9.115:8554/live/hks2", + "description": "FFmpeg rtmp推流地址,一般都是推给自己,例如rtmp://127.0.0.1/live/stream_form_ffmpeg" + }, + { + "key": "timeout_ms", + "value": "10000", + "description": "FFmpeg推流成功超时时间,单位毫秒" + } + ] + } + }, + "response": [] + }, + { + "name": "关闭FFmpeg拉流代理(delFFmpegSource)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/delFFmpegSource?secret={{ZLMediaKit_secret}}&key=5f748d2ef9712e4b2f6f970c1d44d93a", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "delFFmpegSource" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "key", + "value": "5f748d2ef9712e4b2f6f970c1d44d93a" + } + ] + } + }, + "response": [] + }, + { + "name": "流是否在线(isMediaOnline)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/isMediaOnline?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=proxy&stream=1", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "isMediaOnline" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "schema", + "value": "rtsp", + "description": "协议,例如 rtsp或rtmp" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "proxy", + "description": "应用名,例如 live" + }, + { + "key": "stream", + "value": "1", + "description": "流id,例如 test" + } + ] + } + }, + "response": [] + }, + { + "name": "获取流信息(getMediaInfo)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getMediaInfo?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=live&stream=mym9", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getMediaInfo" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "schema", + "value": "rtsp", + "description": "协议,例如 rtsp或rtmp" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "live", + "description": "应用名,例如 live" + }, + { + "key": "stream", + "value": "mym9", + "description": "流id,例如 test" + } + ] + } + }, + "response": [] + }, + { + "name": "获取流信息(getMp4RecordFile)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getMp4RecordFile?secret={{ZLMediaKit_secret}}&vhost={{defaultVhost}}&app=proxy&stream=2&period=2020-05-26", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getMp4RecordFile" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "proxy", + "description": "应用名,例如 live" + }, + { + "key": "stream", + "value": "2", + "description": "流id,例如 test" + }, + { + "key": "period", + "value": "2020-05-26", + "description": "流的录像日期,格式为2020-02-01,如果不是完整的日期,那么是搜索录像文件夹列表,否则搜索对应日期下的mp4文件列表" + } + ] + } + }, + "response": [] + }, + { + "name": "开始录制(startRecord)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/startRecord?secret={{ZLMediaKit_secret}}&type=1&vhost={{defaultVhost}}&app=live&stream=obs&customized_path", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "startRecord" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "type", + "value": "1", + "description": "0为hls,1为mp4" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "live", + "description": "应用名,例如 live" + }, + { + "key": "stream", + "value": "obs", + "description": "流id,例如 obs" + }, + { + "key": "customized_path", + "value": null, + "description": "录像保存目录" + } + ] + } + }, + "response": [] + }, + { + "name": "停止录制(stopRecord)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/stopRecord?secret={{ZLMediaKit_secret}}&type=1&vhost={{defaultVhost}}&app=live&stream=obs", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "stopRecord" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "type", + "value": "1", + "description": "0为hls,1为mp4" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "live", + "description": "应用名,例如 live" + }, + { + "key": "stream", + "value": "obs", + "description": "流id,例如 obs" + } + ] + } + }, + "response": [] + }, + { + "name": "是否正在录制(isRecording)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/isRecording?secret={{ZLMediaKit_secret}}&type=1&vhost={{defaultVhost}}&app=live&stream=obs", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "isRecording" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "type", + "value": "1", + "description": "0为hls,1为mp4" + }, + { + "key": "vhost", + "value": "{{defaultVhost}}", + "description": "虚拟主机,例如__defaultVhost__" + }, + { + "key": "app", + "value": "live", + "description": "应用名,例如 live" + }, + { + "key": "stream", + "value": "obs", + "description": "流id,例如 obs" + } + ] + } + }, + "response": [] + }, + { + "name": "获取截图(getSnap)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getSnap?secret={{ZLMediaKit_secret}}&url=rtsp://www.mym9.com/101065?from=2019-06-28/01:12:13&timeout_sec=10&expire_sec=1", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getSnap" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "url", + "value": "rtsp://www.mym9.com/101065?from=2019-06-28/01:12:13", + "description": "需要截图的url,可以是本机的,也可以是远程主机的" + }, + { + "key": "timeout_sec", + "value": "10", + "description": "截图失败超时时间,防止FFmpeg一直等待截图" + }, + { + "key": "expire_sec", + "value": "1", + "description": "截图的过期时间,该时间内产生的截图都会作为缓存返回" + } + ] + } + }, + "response": [] + }, + { + "name": "获取rtp推流信息(getRtpInfo)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/getRtpInfo?secret={{ZLMediaKit_secret}}&stream_id=test", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "getRtpInfo" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "stream_id", + "value": "test", + "description": "流id" + } + ] + } + }, + "response": [] + }, + { + "name": "创建RTP服务器(openRtpServer)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/openRtpServer?secret={{ZLMediaKit_secret}}&port=0&enable_tcp=1&stream_id=test", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "openRtpServer" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "port", + "value": "0", + "description": "绑定的端口,0时为随机端口" + }, + { + "key": "enable_tcp", + "value": "1", + "description": "创建 udp端口时是否同时监听tcp端口" + }, + { + "key": "stream_id", + "value": "test", + "description": "该端口绑定的流id\n" + } + ] + } + }, + "response": [] + }, + { + "name": "关闭RTP服务器(closeRtpServer)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/closeRtpServer?secret={{ZLMediaKit_secret}}&stream_id=test", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "closeRtpServer" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + }, + { + "key": "stream_id", + "value": "test", + "description": "该端口绑定的流id" + } + ] + } + }, + "response": [] + }, + { + "name": "获取RTP服务器列表(listRtpServer)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/listRtpServer?secret={{ZLMediaKit_secret}}", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "listRtpServer" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数" + } + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "90757ea3-58c0-4f84-8000-513ed7088bbc", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "0ddf2b8e-9932-409d-a055-1ab3b7765600", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "id": "0e272976-965b-4f25-8b9e-5916c59234d7", + "key": "ZLMediaKit_URL", + "value": "zlmediakit.com:8880" + }, + { + "id": "321374c3-3357-4405-915e-9cb524d95fbc", + "key": "ZLMediaKit_secret", + "value": "035c73f7-bb6b-4889-a715-d9eb2d1925cc" + }, + { + "id": "468ce1f6-ec79-44d2-819e-5cb9f42cd396", + "key": "defaultVhost", + "value": "__defaultVhost__" + } + ], + "protocolProfileBehavior": {} +} \ No newline at end of file diff --git a/postman/readme.md b/postman/readme.md new file mode 100644 index 00000000..26a5dee4 --- /dev/null +++ b/postman/readme.md @@ -0,0 +1 @@ +把这两个json文件导入postman就可以愉快的测试ZLMediaKit的restful接口了 \ No newline at end of file From 0bb593f8174430d14857d10e6abc0ea9e1c7f64a Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 14 Jul 2020 09:50:06 +0800 Subject: [PATCH 49/59] =?UTF-8?q?rtp=E6=8E=A8=E6=B5=81=E6=97=A0=E4=BA=BA?= =?UTF-8?q?=E8=A7=82=E7=9C=8B=E6=97=B6=EF=BC=8C=E8=87=AA=E5=8A=A8=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E7=AB=AF=E5=8F=A3=EF=BC=9A#410?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtp/RtpSelector.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Rtp/RtpSelector.cpp b/src/Rtp/RtpSelector.cpp index fb790048..8f74e8ce 100644 --- a/src/Rtp/RtpSelector.cpp +++ b/src/Rtp/RtpSelector.cpp @@ -80,7 +80,9 @@ void RtpSelector::delProcess(const string &stream_id,const RtpProcess *ptr) { if (it->second->getProcess().get() != ptr) { return; } + auto process = it->second->getProcess(); _map_rtp_process.erase(it); + process->onDetach(); } void RtpSelector::onManager() { From 971a4d765d74716d4c3d91d75c5586ce03e6e752 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Mon, 13 Jul 2020 14:38:45 +0800 Subject: [PATCH 50/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=97=B6=E9=97=B4=E6=88=B3=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E5=99=A8=E4=B8=8D=E7=B2=BE=E5=87=86=E7=9A=84?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdpart/ZLToolKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index ed47015f..20920e0e 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit ed47015f92cc79dfe3344b3666aafb54f1bbc2f4 +Subproject commit 20920e0e4aec25027b16553f8d864926cd7d0476 From c507e8a772ed7d13a54cbb9d2eede2db914b1042 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Tue, 14 Jul 2020 15:03:47 +0800 Subject: [PATCH 51/59] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=AF=B9=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E6=97=B6=E9=97=B4=E6=88=B3=E8=B7=B3=E5=8F=98=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdpart/ZLToolKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 20920e0e..60aab3b9 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 20920e0e4aec25027b16553f8d864926cd7d0476 +Subproject commit 60aab3b9f6230312c882b9d3d360ed27c94ebd9f From f420509c5c489246f75125af0d4c8585da0e205e Mon Sep 17 00:00:00 2001 From: lyg1949 Date: Wed, 15 Jul 2020 14:17:18 +0800 Subject: [PATCH 52/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=82=B9=E6=92=ADrtmp?= =?UTF-8?q?=E6=97=B6=E5=A4=9A=E5=87=BA=E4=B8=80=E4=B8=AA=E5=90=8E=E7=BC=80?= =?UTF-8?q?=E5=90=8D=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vlc,mpv等播放rtmp时的url规则与代码中注释的不同,导致出现2个后缀名 --- src/Rtmp/RtmpSession.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index d52b0943..777f3a13 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -380,7 +380,12 @@ string RtmpSession::getStreamId(const string &str){ //vlc和ffplay在播放 rtmp://127.0.0.1/record/0.mp4时, //传过来的url会是rtmp://127.0.0.1/record/mp4:0, //我们在这里还原成0.mp4 - stream_id = stream_id.substr(pos + 1) + "." + stream_id.substr(0,pos); + //实际使用时发现vlc,mpv等会传过来rtmp://127.0.0.1/record/mp4:0.mp4,这里做个判断 + auto ext = stream_id.substr(0,pos); + stream_id = stream_id.substr(pos + 1); + if(stream_id.find(ext) == string::npos){ + stream_id = stream_id + "." + ext; + } } if(params.empty()){ From bdb28c53de0f01666b688d1c24e76dd847b28003 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 16 Jul 2020 10:40:30 +0800 Subject: [PATCH 53/59] =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=E5=89=8D?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E5=85=B3=E9=97=ADmp4=E6=96=87=E4=BB=B6:#416?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Record/MP4.cpp | 1 + src/Record/MP4Muxer.h | 8 +++++++- src/Record/MP4Recorder.cpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Record/MP4.cpp b/src/Record/MP4.cpp index a0152ef1..0dd1756a 100644 --- a/src/Record/MP4.cpp +++ b/src/Record/MP4.cpp @@ -93,6 +93,7 @@ void MP4File::openFile(const char *file,const char *mode) { //创建智能指针 _file.reset(fp,[file_buf](FILE *fp) { + fflush(fp); fclose(fp); }); } diff --git a/src/Record/MP4Muxer.h b/src/Record/MP4Muxer.h index eef8def9..f2e3fbd2 100644 --- a/src/Record/MP4Muxer.h +++ b/src/Record/MP4Muxer.h @@ -25,6 +25,8 @@ namespace mediakit{ class MP4Muxer : public MediaSinkInterface, public MP4File{ public: + typedef std::shared_ptr Ptr; + MP4Muxer(const char *file); ~MP4Muxer() override; @@ -42,9 +44,13 @@ public: */ void resetTracks() override ; + /** + * 手动关闭文件(对象析构时会自动关闭) + */ + void closeMP4(); + private: void openMP4(); - void closeMP4(); void stampSync(); private: diff --git a/src/Record/MP4Recorder.cpp b/src/Record/MP4Recorder.cpp index bf0966a9..1f247354 100644 --- a/src/Record/MP4Recorder.cpp +++ b/src/Record/MP4Recorder.cpp @@ -75,7 +75,7 @@ void MP4Recorder::asyncClose() { //获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间 const_cast(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime; //关闭mp4非常耗时,所以要放在后台线程执行 - const_cast(muxer).reset(); + muxer->closeMP4(); //临时文件名改成正式文件名,防止mp4未完成时被访问 rename(strFileTmp.data(),strFile.data()); //获取文件大小 From 85f28ce1f0234cc82f14d36e9ed7667ca4226d1d Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 16 Jul 2020 15:46:34 +0800 Subject: [PATCH 54/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dseq=E6=BA=A2=E5=87=BA?= =?UTF-8?q?=E6=97=B6=E7=9A=84=E6=97=A5=E5=BF=97=E8=AF=AF=E6=8A=A5:#418?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtp/RtpProcess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rtp/RtpProcess.cpp b/src/Rtp/RtpProcess.cpp index 87812741..3b9a689d 100644 --- a/src/Rtp/RtpProcess.cpp +++ b/src/Rtp/RtpProcess.cpp @@ -111,7 +111,7 @@ static inline bool checkTS(const uint8_t *packet, int bytes){ } void RtpProcess::onRtpSorted(const RtpPacket::Ptr &rtp, int) { - if(rtp->sequence != _sequence + 1 && _sequence != 0){ + if(rtp->sequence != _sequence + (uint16_t)1 && _sequence != 0){ WarnP(this) << "rtp丢包:" << rtp->sequence << " != " << _sequence << "+1" << ",公网环境下请使用tcp方式推流"; } _sequence = rtp->sequence; From f84b3d90b4de4d2c02e4ce4bb948d0f7d94447b0 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 16 Jul 2020 16:00:31 +0800 Subject: [PATCH 55/59] =?UTF-8?q?=E6=B5=81=E6=9C=AA=E6=89=BE=E5=88=B0?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E4=B8=AD=EF=BC=8C=E5=8F=AF=E4=BB=A5=E7=AB=8B?= =?UTF-8?q?=E5=8D=B3=E8=BF=94=E5=9B=9E=E6=92=AD=E6=94=BE=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?:=20#417?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3rdpart/ZLToolKit | 2 +- src/Common/MediaSource.cpp | 53 +++++++++++++++++++++----------------- src/Common/config.h | 2 +- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 60aab3b9..17e82574 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 60aab3b9f6230312c882b9d3d360ed27c94ebd9f +Subproject commit 17e82574991134f798ae32f82d48e2d6c6b97b06 diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp index e7bc6b14..b6a454a3 100644 --- a/src/Common/MediaSource.cpp +++ b/src/Common/MediaSource.cpp @@ -178,39 +178,44 @@ static void eraseIfEmpty(MAP &map, IT0 it0, IT1 it1, IT2 it2) { } } } -}; +} void MediaSource::findAsync_l(const MediaInfo &info, const std::shared_ptr &session, bool retry, const function &cb){ auto src = MediaSource::find_l(info._schema, info._vhost, info._app, info._streamid, true); - if(src || !retry){ + if (src || !retry) { cb(src); return; } void *listener_tag = session.get(); weak_ptr weakSession = session; - //广播未找到流,此时可以立即去拉流,这样还来得及 - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastNotFoundStream,info, static_cast(*session)); - //最多等待一定时间,如果这个时间内,流未注册上,那么返回未找到流 - GET_CONFIG(int,maxWaitMS,General::kMaxStreamWaitTimeMS); - - //若干秒后执行等待媒体注册超时回调 - auto onRegistTimeout = session->getPoller()->doDelayTask(maxWaitMS,[cb,listener_tag](){ - //取消监听该事件 - NoticeCenter::Instance().delListener(listener_tag,Broadcast::kBroadcastMediaChanged); + GET_CONFIG(int, maxWaitMS, General::kMaxStreamWaitTimeMS); + auto onTimeout = session->getPoller()->doDelayTask(maxWaitMS, [cb, listener_tag]() { + //最多等待一定时间,如果这个时间内,流未注册上,那么返回未找到流 + NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged); cb(nullptr); return 0; }); - auto onRegist = [listener_tag,weakSession,info,cb,onRegistTimeout](BroadcastMediaChangedArgs) { + auto cancelAll = [onTimeout, listener_tag]() { + //取消延时任务,防止多次回调 + onTimeout->cancel(); + //取消媒体注册事件监听 + NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged); + }; + + function closePlayer = [cb, cancelAll]() { + cancelAll(); + //告诉播放器,流不存在,这样会立即断开播放器 + cb(nullptr); + }; + + auto onRegist = [weakSession, info, cb, cancelAll](BroadcastMediaChangedArgs) { auto strongSession = weakSession.lock(); - if(!strongSession) { + if (!strongSession) { //自己已经销毁 - //取消延时任务,防止多次回调 - onRegistTimeout->cancel(); - //取消事件监听 - NoticeCenter::Instance().delListener(listener_tag,Broadcast::kBroadcastMediaChanged); + cancelAll(); return; } @@ -223,24 +228,24 @@ void MediaSource::findAsync_l(const MediaInfo &info, const std::shared_ptrcancel(); - //取消事件监听 - NoticeCenter::Instance().delListener(listener_tag,Broadcast::kBroadcastMediaChanged); + cancelAll(); //播发器请求的流终于注册上了,切换到自己的线程再回复 - strongSession->async([weakSession,info,cb](){ + strongSession->async([weakSession, info, cb]() { auto strongSession = weakSession.lock(); - if(!strongSession) { + if (!strongSession) { return; } DebugL << "收到媒体注册事件,回复播放器:" << info._schema << "/" << info._vhost << "/" << info._app << "/" << info._streamid; //再找一遍媒体源,一般能找到 - findAsync_l(info,strongSession,false,cb); + findAsync_l(info, strongSession, false, cb); }, false); }; + //监听媒体注册事件 NoticeCenter::Instance().addListener(listener_tag, Broadcast::kBroadcastMediaChanged, onRegist); + //广播未找到流,此时可以立即去拉流,这样还来得及 + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastNotFoundStream, info, static_cast(*session), closePlayer); } void MediaSource::findAsync(const MediaInfo &info, const std::shared_ptr &session,const function &cb){ diff --git a/src/Common/config.h b/src/Common/config.h index 5d210ce5..6832aec1 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -111,7 +111,7 @@ extern const string kBroadcastFlowReport; //未找到流后会广播该事件,请在监听该事件后去拉流或其他方式产生流,这样就能按需拉流了 extern const string kBroadcastNotFoundStream; -#define BroadcastNotFoundStreamArgs const MediaInfo &args,SockInfo &sender +#define BroadcastNotFoundStreamArgs const MediaInfo &args,SockInfo &sender, const function &closePlayer //某个流无人消费时触发,目的为了实现无人观看时主动断开拉流等业务逻辑 extern const string kBroadcastStreamNoneReader; From c612f291db57a9ada1d1fee9eb6b15e1f81705c1 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 16 Jul 2020 16:03:22 +0800 Subject: [PATCH 56/59] =?UTF-8?q?=E5=85=B3=E9=97=ADhook=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=B5=81=E4=B8=8D=E5=AD=98=E5=9C=A8=E5=B0=B1=E7=AB=8B=E5=8D=B3?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=92=AD=E6=94=BE=E5=A4=B1=E8=B4=A5:#417?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebHook.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/server/WebHook.cpp b/server/WebHook.cpp index 471db2ba..244b07a7 100644 --- a/server/WebHook.cpp +++ b/server/WebHook.cpp @@ -336,6 +336,7 @@ void installWebHook(){ //监听播放失败(未找到特定的流)事件 NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastNotFoundStream,[](BroadcastNotFoundStreamArgs){ if(!hook_enable || hook_stream_not_found.empty()){ + closePlayer(); return; } auto body = make_json(args); From c31b0cc26b83c54f80f5b1ee6577e4274ba53881 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 16 Jul 2020 16:26:13 +0800 Subject: [PATCH 57/59] =?UTF-8?q?H264Track=E4=B8=8D=E8=BF=87=E6=BB=A4SEI:?= =?UTF-8?q?=20#411?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Extension/H264.h | 5 ----- src/Extension/H264Rtmp.cpp | 7 +++---- src/Record/MP4Muxer.cpp | 8 +++++++- src/Record/TsMuxer.cpp | 8 +++++++- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Extension/H264.h b/src/Extension/H264.h index 1d890af0..a7fca526 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -228,11 +228,6 @@ private: } break; - case H264Frame::NAL_SEI:{ - //忽略SEI - break; - } - default: VideoTrack::inputFrame(frame); break; diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index 53ecef62..798de496 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -166,6 +166,9 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { auto pcData = frame->data() + frame->prefixSize(); auto iLen = frame->size() - frame->prefixSize(); auto type = H264_TYPE(((uint8_t*)pcData)[0]); + if(type == H264Frame::NAL_SEI){ + return; + } if (!_gotSpsPps) { //尝试从frame中获取sps pps @@ -187,10 +190,6 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { } } - if(type == H264Frame::NAL_SEI){ - return; - } - if(_lastPacket && _lastPacket->timeStamp != frame->dts()) { RtmpCodec::inputRtmp(_lastPacket, _lastPacket->isVideoKeyFrame()); _lastPacket = nullptr; diff --git a/src/Record/MP4Muxer.cpp b/src/Record/MP4Muxer.cpp index c62c3dbb..af350f67 100644 --- a/src/Record/MP4Muxer.cpp +++ b/src/Record/MP4Muxer.cpp @@ -11,6 +11,7 @@ #ifdef ENABLE_MP4 #include "MP4Muxer.h" #include "Util/File.h" +#include "Extension/H264.h" namespace mediakit{ MP4Muxer::MP4Muxer(const char *file) { @@ -65,7 +66,12 @@ void MP4Muxer::inputFrame(const Frame::Ptr &frame) { int64_t dts_out, pts_out; switch (frame->getCodecId()) { - case CodecH264: + case CodecH264: { + int type = H264_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); + if(type == H264Frame::NAL_SEI){ + break; + } + } case CodecH265: { //这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理, if (!_frameCached.empty() && _frameCached.back()->dts() != frame->dts()) { diff --git a/src/Record/TsMuxer.cpp b/src/Record/TsMuxer.cpp index 560e2ef6..40bee618 100644 --- a/src/Record/TsMuxer.cpp +++ b/src/Record/TsMuxer.cpp @@ -12,6 +12,7 @@ #if defined(ENABLE_HLS) #include "mpeg-ts-proto.h" #include "mpeg-ts.h" +#include "Extension/H264.h" namespace mediakit { @@ -89,8 +90,13 @@ void TsMuxer::inputFrame(const Frame::Ptr &frame) { int64_t dts_out, pts_out; _is_idr_fast_packet = !_have_video; switch (frame->getCodecId()){ - case CodecH265: case CodecH264: { + int type = H264_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); + if(type == H264Frame::NAL_SEI){ + break; + } + } + case CodecH265: { //这里的代码逻辑是让SPS、PPS、IDR这些时间戳相同的帧打包到一起当做一个帧处理, if (!_frameCached.empty() && _frameCached.back()->dts() != frame->dts()) { Frame::Ptr back = _frameCached.back(); From 7254c39fc202b2cde643f50407552cd33a26c340 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Thu, 16 Jul 2020 16:36:26 +0800 Subject: [PATCH 58/59] =?UTF-8?q?rtsp=E6=8E=A8=E6=B5=81=E9=87=87=E7=94=A8?= =?UTF-8?q?=E7=9B=B8=E5=AF=B9=E6=97=B6=E9=97=B4=E6=88=B3,=E9=98=B2?= =?UTF-8?q?=E6=AD=A2=E9=9F=B3=E8=A7=86=E9=A2=91=E4=B8=8D=E5=90=8C=E6=AD=A5?= =?UTF-8?q?:#392?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtsp/RtspSession.cpp | 11 ++++++++--- src/Rtsp/RtspSession.h | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index f62e66f4..c0b49472 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -913,7 +913,13 @@ inline void RtspSession::send_NotAcceptable() { sendRtspResponse("406 Not Acceptable",{"Connection","Close"}); } -void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtp, int) { +void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) { + if (_start_stamp[track_idx] == -1) { + //记录起始时间戳 + _start_stamp[track_idx] = rtp->timeStamp; + } + //时间戳增量 + rtp->timeStamp -= _start_stamp[track_idx]; _push_src->onWrite(rtp, false); } @@ -937,8 +943,7 @@ inline void RtspSession::onRcvPeerUdpData(int interleaved, const Buffer::Ptr &bu _udp_connected_flags.emplace(interleaved); _rtcp_socks[(interleaved - 1) / 2]->setSendPeerAddr(&addr); } - onRtcpPacket((interleaved - 1) / 2, _sdp_track[(interleaved - 1) / 2], (unsigned char *) buf->data(), - buf->size()); + onRtcpPacket((interleaved - 1) / 2, _sdp_track[(interleaved - 1) / 2], (unsigned char *) buf->data(), buf->size()); } } diff --git a/src/Rtsp/RtspSession.h b/src/Rtsp/RtspSession.h index 2436efb6..47e9d5da 100644 --- a/src/Rtsp/RtspSession.h +++ b/src/Rtsp/RtspSession.h @@ -157,6 +157,8 @@ private: Rtsp::eRtpType _rtp_type = Rtsp::RTP_Invalid; //收到的seq,回复时一致 int _cseq = 0; + //rtsp推流起始时间戳,目的是为了同步 + int64_t _start_stamp[2] = {-1, -1}; //消耗的总流量 uint64_t _bytes_usage = 0; //ContentBase From 04840742cf93db8414108552a08d48de053e3cc7 Mon Sep 17 00:00:00 2001 From: Zhou Weimin Date: Sun, 19 Jul 2020 07:21:18 +0000 Subject: [PATCH 59/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8Drtsp=E6=8B=89=E6=B5=81r?= =?UTF-8?q?tp=20FU-A=E6=9C=80=E5=90=8E=E4=B8=80=E4=B8=AA=E5=88=86=E7=89=87?= =?UTF-8?q?size=E4=B8=BA0=E7=9A=84=E9=97=AE=E9=A2=98;#424?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Extension/H264Rtp.cpp | 4 ++-- src/Extension/H265Rtp.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Extension/H264Rtp.cpp b/src/Extension/H264Rtp.cpp index 481c57a7..76958147 100644 --- a/src/Extension/H264Rtp.cpp +++ b/src/Extension/H264Rtp.cpp @@ -234,7 +234,7 @@ void H264RtpEncoder::inputFrame(const Frame::Ptr &frame) { bool mark = false; int nOffset = 1; while (!mark) { - if (iLen < nOffset + iSize) { + if (iLen <= nOffset + iSize) { //已经拆分结束 iSize = iLen - nOffset; mark = true; @@ -274,4 +274,4 @@ void H264RtpEncoder::makeH264Rtp(int nal_type,const void* data, unsigned int len RtpCodec::inputRtp(makeRtp(getTrackType(),data,len,mark,uiStamp),first_packet && nal_type == H264Frame::NAL_IDR); } -}//namespace mediakit \ No newline at end of file +}//namespace mediakit diff --git a/src/Extension/H265Rtp.cpp b/src/Extension/H265Rtp.cpp index d1f52bba..6af6c6ee 100644 --- a/src/Extension/H265Rtp.cpp +++ b/src/Extension/H265Rtp.cpp @@ -166,7 +166,7 @@ void H265RtpEncoder::inputFrame(const Frame::Ptr &frame) { bool mark = false; int nOffset = 2; while (!mark) { - if (iLen < nOffset + maxSize) { //是否拆分结束 + if (iLen <= nOffset + maxSize) { //是否拆分结束 maxSize = iLen - nOffset; mark = true; //FU end @@ -208,4 +208,4 @@ void H265RtpEncoder::makeH265Rtp(int nal_type,const void* data, unsigned int len RtpCodec::inputRtp(makeRtp(getTrackType(),data,len,mark,uiStamp),first_packet && H265Frame::isKeyFrame(nal_type)); } -}//namespace mediakit \ No newline at end of file +}//namespace mediakit