From eedf262059d8f00ab8f3f077ab201f55e28ff7e0 Mon Sep 17 00:00:00 2001 From: imp_rayjay <32894715+rayjay214@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:26:53 +0800 Subject: [PATCH 01/31] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81mjpeg?= =?UTF-8?q?=E8=B4=9F=E8=BD=BD=E7=9A=84mp4=E6=96=87=E4=BB=B6=E7=82=B9?= =?UTF-8?q?=E6=92=AD=20(#2898)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Record/MP4Demuxer.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Record/MP4Demuxer.cpp b/src/Record/MP4Demuxer.cpp index 02c66976..87936137 100644 --- a/src/Record/MP4Demuxer.cpp +++ b/src/Record/MP4Demuxer.cpp @@ -16,8 +16,10 @@ #include "Extension/AAC.h" #include "Extension/G711.h" #include "Extension/Opus.h" -using namespace toolkit; +#include "Extension/JPEG.h" + using namespace std; +using namespace toolkit; namespace mediakit { @@ -105,8 +107,9 @@ void MP4Demuxer::onVideoTrack(uint32_t track, uint8_t object, int width, int hei video->inputFrame(std::make_shared((char *)config, size, 0, 0,4)); } } - } break; + } + case MOV_OBJECT_HEVC: { auto video = std::make_shared(); _track_to_codec.emplace(track,video); @@ -120,11 +123,16 @@ void MP4Demuxer::onVideoTrack(uint32_t track, uint8_t object, int width, int hei video->inputFrame(std::make_shared((char *) config, size, 0, 0,4)); } } + break; } + + case MOV_OBJECT_JPEG: { + auto video = std::make_shared(); + _track_to_codec.emplace(track,video); break; - default: - WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object); - break; + } + + default: WarnL << "不支持该编码类型的MP4,已忽略:" << getObjectName(object); break; } } @@ -243,6 +251,11 @@ Frame::Ptr MP4Demuxer::makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int6 break; } + case CodecJPEG: { + ret = std::make_shared(buf, (uint64_t)dts, 0, DATA_OFFSET); + break; + } + case CodecAAC: { AACTrack::Ptr track = dynamic_pointer_cast(it->second); assert(track); @@ -283,4 +296,4 @@ uint64_t MP4Demuxer::getDurationMS() const { } }//namespace mediakit -#endif// ENABLE_MP4 \ No newline at end of file +#endif// ENABLE_MP4 From b8cb8957e4e4f91a62acc831ae37cced3656a389 Mon Sep 17 00:00:00 2001 From: Armstrong Date: Fri, 13 Oct 2023 15:26:31 +0800 Subject: [PATCH 02/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8DWebApi=E9=80=80?= =?UTF-8?q?=E5=87=BA=E6=B8=85=E7=90=86=E6=97=B6=E9=87=8D=E5=A4=8D=E6=9E=90?= =?UTF-8?q?=E6=9E=84=E9=97=AE=E9=A2=98=20(#2900)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. s_???Map.clear()会触发key/value的析构,先执行析构再移除map成员。析构执行完之前map成员仍然有可见性。 2. s_???Map的成员析构时,根据当前状态,可能触发回调,如播放终止回调。 3. 在状态变更的回调函数中,通过s_???Map.erase(key)的方式解注册,此时也会触发一次析构。 两次析构导致double free:a) map.erase, b) map.clear Signed-off-by: ArmstrongCN --- server/WebApi.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index e8081756..7c8e35c0 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -1911,24 +1911,28 @@ void installWebApi() { void unInstallWebApi(){ { lock_guard lck(s_proxyMapMtx); - s_proxyMap.clear(); + auto proxyMap(std::move(s_proxyMap)); + proxyMap.clear(); } { lock_guard lck(s_ffmpegMapMtx); - s_ffmpegMap.clear(); + auto ffmpegMap(std::move(s_ffmpegMap)); + ffmpegMap.clear(); } { lock_guard lck(s_proxyPusherMapMtx); - s_proxyPusherMap.clear(); + auto proxyPusherMap(std::move(s_proxyPusherMap)); + proxyPusherMap.clear(); } { #if defined(ENABLE_RTPPROXY) RtpSelector::Instance().clear(); lock_guard lck(s_rtpServerMapMtx); - s_rtpServerMap.clear(); + auto rtpServerMap(std::move(s_rtpServerMap)); + rtpServerMap.clear(); #endif } NoticeCenter::Instance().delListener(&web_api_tag); From 7ee2d66eaa37a8131f6f8264f7b184bccc32f4f8 Mon Sep 17 00:00:00 2001 From: ljx0305 Date: Thu, 19 Oct 2023 17:55:30 +0800 Subject: [PATCH 03/31] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E9=A3=8E=E6=A0=BC=20(#2910)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit openRtpServer时,如果开启tcp模式,从tcp端口池获取 --- .github/workflows/c-cpp.yml | 34 ++++++++++++++++++++++++++++++++++ server/WebHook.cpp | 4 ++-- src/Common/config.cpp | 2 +- src/Common/config.h | 2 +- src/Http/HttpSession.cpp | 12 ++++++------ src/Http/HttpSession.h | 2 +- src/Rtp/RtpServer.cpp | 4 ++-- 7 files changed, 47 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/c-cpp.yml diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml new file mode 100644 index 00000000..4418c935 --- /dev/null +++ b/.github/workflows/c-cpp.yml @@ -0,0 +1,34 @@ +name: Linux + +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v1 + + - name: 下载submodule源码 + run: mv -f .gitmodules_github .gitmodules && git submodule sync && git submodule update --init + + - name: apt-get安装依赖库(非必选) + run: sudo apt-get update && sudo apt-get install -y cmake libssl-dev libsdl-dev libavcodec-dev libavutil-dev libswscale-dev libresample-dev libusrsctp-dev + + - name: 下载 SRTP + uses: actions/checkout@v2 + with: + repository: cisco/libsrtp + fetch-depth: 1 + ref: v2.3.0 + path: 3rdpart/libsrtp + + - name: 编译 SRTP + run: cd 3rdpart/libsrtp && ./configure --enable-openssl && make -j4 && sudo make install + + - name: 编译 + run: mkdir -p linux_build && cd linux_build && cmake .. -DENABLE_WEBRTC=true -DENABLE_FFMPEG=true && make -j $(nproc) + + - name: 运行MediaServer + run: pwd && cd release/linux/Debug && sudo ./MediaServer -d & diff --git a/server/WebHook.cpp b/server/WebHook.cpp index d05c4f60..43329927 100755 --- a/server/WebHook.cpp +++ b/server/WebHook.cpp @@ -674,7 +674,7 @@ void installWebHook() { }); }); - NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::KBroadcastRtpServerTimeout, [](BroadcastRtpServerTimeoutArgs) { + NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastRtpServerTimeout, [](BroadcastRtpServerTimeoutArgs) { GET_CONFIG(string, rtp_server_timeout, Hook::kOnRtpServerTimeout); if (!hook_enable || rtp_server_timeout.empty()) { return; @@ -703,4 +703,4 @@ void unInstallWebHook() { void onProcessExited() { reportServerExited(); -} \ No newline at end of file +} diff --git a/src/Common/config.cpp b/src/Common/config.cpp index 6e75e27d..603c434c 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -57,7 +57,7 @@ const string kBroadcastNotFoundStream = "kBroadcastNotFoundStream"; const string kBroadcastStreamNoneReader = "kBroadcastStreamNoneReader"; const string kBroadcastHttpBeforeAccess = "kBroadcastHttpBeforeAccess"; const string kBroadcastSendRtpStopped = "kBroadcastSendRtpStopped"; -const string KBroadcastRtpServerTimeout = "KBroadcastRtpServerTimeout"; +const string kBroadcastRtpServerTimeout = "kBroadcastRtpServerTimeout"; } // namespace Broadcast diff --git a/src/Common/config.h b/src/Common/config.h index 341f1d6c..25f36271 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -106,7 +106,7 @@ extern const std::string kBroadcastReloadConfig; #define BroadcastReloadConfigArgs void // rtp server 超时 -extern const std::string KBroadcastRtpServerTimeout; +extern const std::string kBroadcastRtpServerTimeout; #define BroadcastRtpServerTimeoutArgs uint16_t &local_port, const string &stream_id,int &tcp_mode, bool &re_use_port, uint32_t &ssrc #define ReloadConfigTag ((void *)(0xFF)) diff --git a/src/Http/HttpSession.cpp b/src/Http/HttpSession.cpp index 69407928..c6d390d1 100644 --- a/src/Http/HttpSession.cpp +++ b/src/Http/HttpSession.cpp @@ -166,11 +166,11 @@ void HttpSession::onError(const SockException &err) { if (_is_live_stream) { // flv/ts播放器 uint64_t duration = _ticker.createdTime() / 1000; - WarnP(this) << "FLV/TS/FMP4播放器(" << _mediaInfo.shortUrl() << ")断开:" << err << ",耗时(s):" << duration; + WarnP(this) << "FLV/TS/FMP4播放器(" << _media_info.shortUrl() << ")断开:" << err << ",耗时(s):" << duration; GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold); if (_total_bytes_usage >= iFlowThreshold * 1024) { - NOTICE_EMIT(BroadcastFlowReportArgs, Broadcast::kBroadcastFlowReport, _mediaInfo, _total_bytes_usage, duration, true, *this); + NOTICE_EMIT(BroadcastFlowReportArgs, Broadcast::kBroadcastFlowReport, _media_info, _total_bytes_usage, duration, true, *this); } return; } @@ -263,9 +263,9 @@ bool HttpSession::checkLiveStream(const string &schema, const string &url_suffix } // 解析带上协议+参数完整的url - _mediaInfo.parse(schema + "://" + _parser["Host"] + url); + _media_info.parse(schema + "://" + _parser["Host"] + url); - if (_mediaInfo.app.empty() || _mediaInfo.stream.empty()) { + if (_media_info.app.empty() || _media_info.stream.empty()) { // url不合法 return false; } @@ -288,7 +288,7 @@ bool HttpSession::checkLiveStream(const string &schema, const string &url_suffix } // 异步查找直播流 - MediaSource::findAsync(strong_self->_mediaInfo, strong_self, [weak_self, close_flag, cb](const MediaSource::Ptr &src) { + MediaSource::findAsync(strong_self->_media_info, strong_self, [weak_self, close_flag, cb](const MediaSource::Ptr &src) { auto strong_self = weak_self.lock(); if (!strong_self) { // 本对象已经销毁 @@ -311,7 +311,7 @@ bool HttpSession::checkLiveStream(const string &schema, const string &url_suffix } }; - auto flag = NOTICE_EMIT(BroadcastMediaPlayedArgs, Broadcast::kBroadcastMediaPlayed, _mediaInfo, invoker, *this); + auto flag = NOTICE_EMIT(BroadcastMediaPlayedArgs, Broadcast::kBroadcastMediaPlayed, _media_info, invoker, *this); if (!flag) { // 该事件无人监听,默认不鉴权 onRes(""); diff --git a/src/Http/HttpSession.h b/src/Http/HttpSession.h index 513f8b63..98b43d71 100644 --- a/src/Http/HttpSession.h +++ b/src/Http/HttpSession.h @@ -124,7 +124,7 @@ private: void setSocketFlags(); protected: - MediaInfo _mediaInfo; + MediaInfo _media_info; private: bool _is_live_stream = false; diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp index 78aee8e1..e40eeda7 100644 --- a/src/Rtp/RtpServer.cpp +++ b/src/Rtp/RtpServer.cpp @@ -102,7 +102,7 @@ public: process->setOnDetach(std::move(strong_self->_on_detach)); } if (!process) { // process 未创建,触发rtp server 超时事件 - NOTICE_EMIT(BroadcastRtpServerTimeoutArgs, Broadcast::KBroadcastRtpServerTimeout, strong_self->_local_port, strong_self->_stream_id, + NOTICE_EMIT(BroadcastRtpServerTimeoutArgs, Broadcast::kBroadcastRtpServerTimeout, strong_self->_local_port, strong_self->_stream_id, (int)strong_self->_tcp_mode, strong_self->_re_use_port, strong_self->_ssrc); } } @@ -161,7 +161,7 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, TcpMode tcp_ if (local_port == 0) { //随机端口,rtp端口采用偶数 auto pair = std::make_pair(rtp_socket, rtcp_socket); - makeSockPair(pair, local_ip, re_use_port); + makeSockPair(pair, local_ip, re_use_port, TcpMode::NONE == tcp_mode); local_port = rtp_socket->get_local_port(); } else if (!rtp_socket->bindUdpSock(local_port, local_ip, re_use_port)) { //用户指定端口 From d9ea82c800d6852a9dbfba4b7c9d40acf2ad8903 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Mon, 23 Oct 2023 20:39:10 +0800 Subject: [PATCH 04/31] =?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 b11582c3..273592b6 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit b11582c38e8dbbb8d93ca9ce33c9a0b0cd58f59a +Subproject commit 273592b6ba39babe6407021ffc089bfe7328e447 From 08d86c498ecb7cdcad9b540b9d4ac136376083a6 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Mon, 23 Oct 2023 20:41:38 +0800 Subject: [PATCH 05/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8Djemalloc=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/JemallocUtil.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Common/JemallocUtil.cpp b/src/Common/JemallocUtil.cpp index fa2de64a..d8b8414e 100644 --- a/src/Common/JemallocUtil.cpp +++ b/src/Common/JemallocUtil.cpp @@ -12,6 +12,7 @@ #include "JemallocUtil.h" #include "Util/logger.h" #ifdef USE_JEMALLOC +#include #include #include #endif From ebde21a314fc397e279e29c0a891f94ef545fcc5 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Mon, 23 Oct 2023 20:45:58 +0800 Subject: [PATCH 06/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8DopenRtpServer=E5=BC=80?= =?UTF-8?q?=E5=90=AFtcp=E6=A8=A1=E5=BC=8F=E5=90=8E=E6=89=93=E5=BC=80?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E5=A4=B1=E8=B4=A5=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两次监听同个tcp端口将导致打开tcp模式失败 --- src/Rtp/RtpServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp index e40eeda7..1c6a8c1b 100644 --- a/src/Rtp/RtpServer.cpp +++ b/src/Rtp/RtpServer.cpp @@ -161,7 +161,7 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, TcpMode tcp_ if (local_port == 0) { //随机端口,rtp端口采用偶数 auto pair = std::make_pair(rtp_socket, rtcp_socket); - makeSockPair(pair, local_ip, re_use_port, TcpMode::NONE == tcp_mode); + makeSockPair(pair, local_ip, re_use_port); local_port = rtp_socket->get_local_port(); } else if (!rtp_socket->bindUdpSock(local_port, local_ip, re_use_port)) { //用户指定端口 From a871fc1882a4db57ef3d9a0c7f963f255cdd6794 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Mon, 23 Oct 2023 20:58:12 +0800 Subject: [PATCH 07/31] =?UTF-8?q?websocket=E6=9C=8D=E5=8A=A1=E5=99=A8?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=9C=A8=E5=88=9B=E5=BB=BA=E5=99=A8=E4=B8=AD?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E6=B6=88=E6=81=AF=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过该修改可以更灵活的指定同端口下不同websocket服务的消息类型 --- src/Http/WebSocketSession.h | 9 +++++---- tests/test_wsServer.cpp | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Http/WebSocketSession.h b/src/Http/WebSocketSession.h index 96021c4d..8978330c 100644 --- a/src/Http/WebSocketSession.h +++ b/src/Http/WebSocketSession.h @@ -69,7 +69,7 @@ template class SessionCreator { public: //返回的Session必须派生于SendInterceptor,可以返回null - toolkit::Session::Ptr operator()(const mediakit::Parser &header, const mediakit::HttpSession &parent, const toolkit::Socket::Ptr &pSock){ + toolkit::Session::Ptr operator()(const mediakit::Parser &header, const mediakit::HttpSession &parent, const toolkit::Socket::Ptr &pSock, mediakit::WebSocketHeader::Type &data_type){ return std::make_shared >(header,parent,pSock); } }; @@ -128,7 +128,8 @@ protected: */ bool onWebSocketConnect(const mediakit::Parser &header) override{ //创建websocket session类 - _session = _creator(header, *this, HttpSessionType::getSock()); + auto data_type = DataType; + _session = _creator(header, *this, HttpSessionType::getSock(), data_type); if (!_session) { // 此url不允许创建websocket连接 return false; @@ -140,13 +141,13 @@ protected: //此处截取数据并进行websocket协议打包 std::weak_ptr weakSelf = std::static_pointer_cast(HttpSessionType::shared_from_this()); - std::dynamic_pointer_cast(_session)->setOnBeforeSendCB([weakSelf](const toolkit::Buffer::Ptr &buf) { + std::dynamic_pointer_cast(_session)->setOnBeforeSendCB([weakSelf, data_type](const toolkit::Buffer::Ptr &buf) { auto strongSelf = weakSelf.lock(); if (strongSelf) { mediakit::WebSocketHeader header; header._fin = true; header._reserved = 0; - header._opcode = DataType; + header._opcode = data_type; header._mask_flag = false; strongSelf->HttpSessionType::encode(header, buf); } diff --git a/tests/test_wsServer.cpp b/tests/test_wsServer.cpp index bd46787a..f839d352 100644 --- a/tests/test_wsServer.cpp +++ b/tests/test_wsServer.cpp @@ -81,9 +81,11 @@ public: */ struct EchoSessionCreator { //返回的Session必须派生于SendInterceptor,可以返回null(拒绝连接) - Session::Ptr operator()(const Parser &header, const HttpSession &parent, const Socket::Ptr &pSock) { + Session::Ptr operator()(const Parser &header, const HttpSession &parent, const Socket::Ptr &pSock, mediakit::WebSocketHeader::Type &type) { // return nullptr; if (header.url() == "/") { + // 可以指定传输方式 + // type = mediakit::WebSocketHeader::BINARY; return std::make_shared >(header, parent, pSock); } return std::make_shared >(header, parent, pSock); From 0a19627d86984c5f208b67da547ffbd7ef9dc618 Mon Sep 17 00:00:00 2001 From: leibnewton <787627654@qq.com> Date: Wed, 25 Oct 2023 15:14:08 +0800 Subject: [PATCH 08/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8DstartSendRtp=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E5=90=8Eudp=E5=A5=97=E6=8E=A5=E5=AD=97=E8=A2=AB?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E7=9A=84=E9=97=AE=E9=A2=98=20(#2468=20#2924)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对端端口未打开,udp得到connection refused的错误而关闭。 --- src/Rtp/RtpSender.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Rtp/RtpSender.cpp b/src/Rtp/RtpSender.cpp index a102d5e2..172c9f2e 100644 --- a/src/Rtp/RtpSender.cpp +++ b/src/Rtp/RtpSender.cpp @@ -140,7 +140,7 @@ void RtpSender::startSend(const MediaSourceEvent::SendRtpArgs &args, const funct cb(0, SockException(Err_other, ex.what())); return; } - strong_self->_socket_rtp->bindPeerAddr((struct sockaddr *)&addr); + strong_self->_socket_rtp->bindPeerAddr((struct sockaddr *)&addr, 0, true); strong_self->onConnect(); cb(strong_self->_socket_rtp->get_local_port(), SockException()); }); @@ -182,7 +182,7 @@ void RtpSender::createRtcpSocket() { case AF_INET6: ((sockaddr_in6 *)&addr)->sin6_port = htons(ntohs(((sockaddr_in6 *)&addr)->sin6_port) + 1); break; default: assert(0); break; } - _socket_rtcp->bindPeerAddr((struct sockaddr *)&addr); + _socket_rtcp->bindPeerAddr((struct sockaddr *)&addr, 0, true); _rtcp_context = std::make_shared(); weak_ptr weak_self = shared_from_this(); @@ -349,4 +349,4 @@ void RtpSender::setOnClose(std::function } }//namespace mediakit -#endif// defined(ENABLE_RTPPROXY) \ No newline at end of file +#endif// defined(ENABLE_RTPPROXY) From ae662fa0836290b534d6fa29ce5202f8f95feb22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=8F=E6=A5=9A?= <771730766@qq.com> Date: Wed, 25 Oct 2023 17:50:29 +0800 Subject: [PATCH 09/31] =?UTF-8?q?=20webrtc=20dtls=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E9=87=87=E7=94=A8https=E8=AF=81=E4=B9=A6=EF=BC=8C=E5=A6=82?= =?UTF-8?q?=E6=9E=9Chttps=E8=AF=81=E4=B9=A6=E4=B8=8D=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E5=88=99=E9=9A=8F=E6=9C=BA=E7=94=9F=E6=88=90=20=20(#2928)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 之前默认随机创建dtls证书,导致每次启动证书都不一致,而Firefox要求同主机的dtls证书必须一致,所以导致每次服务重启,Firefox可能拒绝dtls握手。 并且在集群模式下,如果Firefox接入多个不同集群实例的webrtc服务,也可能导致webrtc dtls握手失败。 --- 3rdpart/ZLToolKit | 2 +- webrtc/DtlsTransport.cpp | 71 ++++++++------------------------------ webrtc/DtlsTransport.hpp | 2 +- webrtc/WebRtcTransport.cpp | 2 +- 4 files changed, 18 insertions(+), 59 deletions(-) diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 273592b6..3fd2b856 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 273592b6ba39babe6407021ffc089bfe7328e447 +Subproject commit 3fd2b856b6856dd679a32c673431561c0affdd0c diff --git a/webrtc/DtlsTransport.cpp b/webrtc/DtlsTransport.cpp index 66183f8e..5ae4f4b0 100644 --- a/webrtc/DtlsTransport.cpp +++ b/webrtc/DtlsTransport.cpp @@ -29,6 +29,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include // std::sprintf(), std::fopen() #include // std::memcpy(), std::strcmp() #include "Util/util.h" +#include "Util/SSLBox.h" +#include "Util/SSLUtil.h" using namespace std; @@ -129,16 +131,10 @@ namespace RTC MS_TRACE(); // Generate a X509 certificate and private key (unless PEM files are provided). - if (true /* - Settings::configuration.dtlsCertificateFile.empty() || - Settings::configuration.dtlsPrivateKeyFile.empty()*/) - { + auto ssl = toolkit::SSL_Initor::Instance().getSSLCtx("", true); + if (!ssl || !ReadCertificateAndPrivateKeyFromContext(ssl.get())) { GenerateCertificateAndPrivateKey(); } - else - { - ReadCertificateAndPrivateKeyFromFiles(); - } // Create a global SSL_CTX. CreateSslCtx(); @@ -297,59 +293,22 @@ namespace RTC MS_THROW_ERROR("DTLS certificate and private key generation failed"); } - void DtlsTransport::DtlsEnvironment::ReadCertificateAndPrivateKeyFromFiles() + bool DtlsTransport::DtlsEnvironment::ReadCertificateAndPrivateKeyFromContext(SSL_CTX *ctx) { -#if 0 MS_TRACE(); - - FILE* file{ nullptr }; - - file = fopen(Settings::configuration.dtlsCertificateFile.c_str(), "r"); - - if (!file) - { - MS_ERROR("error reading DTLS certificate file: %s", std::strerror(errno)); - - goto error; + certificate = SSL_CTX_get0_certificate(ctx); + if (!certificate) { + return false; } + X509_up_ref(certificate); - certificate = PEM_read_X509(file, nullptr, nullptr, nullptr); - - if (!certificate) - { - LOG_OPENSSL_ERROR("PEM_read_X509() failed"); - - goto error; + privateKey = SSL_CTX_get0_privatekey(ctx); + if (!privateKey) { + return false; } - - fclose(file); - - file = fopen(Settings::configuration.dtlsPrivateKeyFile.c_str(), "r"); - - if (!file) - { - MS_ERROR("error reading DTLS private key file: %s", std::strerror(errno)); - - goto error; - } - - privateKey = PEM_read_PrivateKey(file, nullptr, nullptr, nullptr); - - if (!privateKey) - { - LOG_OPENSSL_ERROR("PEM_read_PrivateKey() failed"); - - goto error; - } - - fclose(file); - - return; - - error: - - MS_THROW_ERROR("error reading DTLS certificate and private key PEM files"); -#endif + EVP_PKEY_up_ref(privateKey); + InfoL << "Load webrtc dtls certificate: " << toolkit::SSLUtil::getServerName(certificate); + return true; } void DtlsTransport::DtlsEnvironment::CreateSslCtx() diff --git a/webrtc/DtlsTransport.hpp b/webrtc/DtlsTransport.hpp index bf57d01d..53a1981d 100644 --- a/webrtc/DtlsTransport.hpp +++ b/webrtc/DtlsTransport.hpp @@ -88,7 +88,7 @@ namespace RTC private: DtlsEnvironment(); void GenerateCertificateAndPrivateKey(); - void ReadCertificateAndPrivateKeyFromFiles(); + bool ReadCertificateAndPrivateKeyFromContext(SSL_CTX *ctx); void CreateSslCtx(); void GenerateFingerprints(); diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 4ec13e6f..9ac6251f 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -251,7 +251,7 @@ void WebRtcTransport::sendSockData(const char *buf, size_t len, RTC::TransportTu } Session::Ptr WebRtcTransport::getSession() const { - auto tuple = _ice_server->GetSelectedTuple(true); + auto tuple = _ice_server ? _ice_server->GetSelectedTuple(true) : nullptr; return tuple ? static_pointer_cast(tuple->shared_from_this()) : nullptr; } From 4b568b33a1a624c0c314a45399582d539d488259 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Wed, 25 Oct 2023 20:33:52 +0800 Subject: [PATCH 10/31] =?UTF-8?q?=E6=96=B0=E5=A2=9Eweb=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=BD=91=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 5 ++++- .gitmodules_github | 3 +++ README.md | 1 + README_en.md | 1 + www/webassist | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) create mode 160000 www/webassist diff --git a/.gitmodules b/.gitmodules index 7ef0bc71..5f9e1fb9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,4 +6,7 @@ url = https://gitee.com/ireader/media-server [submodule "3rdpart/jsoncpp"] path = 3rdpart/jsoncpp - url = https://gitee.com/mirrors/jsoncpp.git \ No newline at end of file + url = https://gitee.com/mirrors/jsoncpp.git +[submodule "www/webassist"] + path = www/webassist + url = https://github.com/1002victor/zlm_webassist diff --git a/.gitmodules_github b/.gitmodules_github index ddd310e6..87b576ee 100644 --- a/.gitmodules_github +++ b/.gitmodules_github @@ -7,3 +7,6 @@ [submodule "3rdpart/jsoncpp"] path = 3rdpart/jsoncpp url = https://github.com/open-source-parsers/jsoncpp.git +[submodule "www/webassist"] + path = www/webassist + url = https://github.com/1002victor/zlm_webassist \ No newline at end of file diff --git a/README.md b/README.md index 97fb5751..cbefd9b3 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ bash build_docker_images.sh - [BXC_gb28181Player](https://github.com/any12345com/BXC_gb28181Player) C++开发的支持国标GB28181协议的视频流播放器 - WEB管理网站 + - [zlm_webassist](https://github.com/1002victor/zlm_webassist) 本项目配套的前后端分离web管理项目 - [AKStreamNVR](https://github.com/langmansh/AKStreamNVR) 前后端分离web项目,支持webrtc播放 - SDK diff --git a/README_en.md b/README_en.md index 5eee72d1..07d215b1 100644 --- a/README_en.md +++ b/README_en.md @@ -342,6 +342,7 @@ bash build_docker_images.sh ## Collaborative Projects - Visual management website + - [A backend management website for this project](https://github.com/1002victor/zlm_webassist) - [The latest web project with front-end and back-end separation, supporting webrtc playback](https://github.com/langmansh/AKStreamNVR) - [Management web site based on ZLMediaKit master branch](https://gitee.com/kkkkk5G/MediaServerUI) - [Management web site based on ZLMediaKit branch](https://github.com/chenxiaolei/ZLMediaKit_NVR_UI) diff --git a/www/webassist b/www/webassist new file mode 160000 index 00000000..0d1e8c90 --- /dev/null +++ b/www/webassist @@ -0,0 +1 @@ +Subproject commit 0d1e8c902feab2c16723bfa05df89f43b0acaefc From 1a4b8406bb8f7a619a785bc023141cef2a463c82 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Wed, 25 Oct 2023 20:41:39 +0800 Subject: [PATCH 11/31] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BD=9C=E8=80=85?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AUTHORS | 5 ++++- README.md | 4 ++++ README_en.md | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 57928af2..c26bfefb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -84,4 +84,7 @@ WuPeng [Luosh](https://github.com/Luosh) [linxiaoyan87](https://github.com/linxiaoyan) [waken](https://github.com/mc373906408) -[Deepslient](https://github.com/Deepslient) \ No newline at end of file +[Deepslient](https://github.com/Deepslient) +[imp_rayjay](https://github.com/rayjay214) +[ArmstrongCN](https://github.com/ArmstrongCN) +[leibnewton](https://github.com/leibnewton) \ No newline at end of file diff --git a/README.md b/README.md index cbefd9b3..a32a5d9f 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,10 @@ bash build_docker_images.sh [linxiaoyan87](https://github.com/linxiaoyan) [waken](https://github.com/mc373906408) [Deepslient](https://github.com/Deepslient) +[imp_rayjay](https://github.com/rayjay214) +[ArmstrongCN](https://github.com/ArmstrongCN) +[leibnewton](https://github.com/leibnewton) +[1002victor](https://github.com/1002victor) 同时感谢JetBrains对开源项目的支持,本项目使用CLion开发与调试: diff --git a/README_en.md b/README_en.md index 07d215b1..0c8c6437 100644 --- a/README_en.md +++ b/README_en.md @@ -494,6 +494,10 @@ Thanks to all those who have supported this project in various ways, including b [linxiaoyan87](https://github.com/linxiaoyan) [waken](https://github.com/mc373906408) [Deepslient](https://github.com/Deepslient) +[imp_rayjay](https://github.com/rayjay214) +[ArmstrongCN](https://github.com/ArmstrongCN) +[leibnewton](https://github.com/leibnewton) +[1002victor](https://github.com/1002victor) Also thank to JetBrains for their support for open source project, we developed and debugged zlmediakit with CLion: From c876e539243ada420dfd29862d620e21ccffcfeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=8F=E6=A5=9A?= <771730766@qq.com> Date: Fri, 27 Oct 2023 21:39:36 +0800 Subject: [PATCH 12/31] =?UTF-8?q?=E4=BC=98=E5=8C=96ffmpeg=20url=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E8=A7=84=E5=88=99=EF=BC=8C=E6=8F=90=E9=AB=98rtmp?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=85=BC=E5=AE=B9=E6=80=A7=20(#2936?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根据ffmpeg测试,类似rtmp://ip/a/b/c/d/e/f这样的url,app应该为a/b,stream_id应该为c/d/e/f, tcl_url应该为rtmp://ip/a/b, teams的rtmps服务需要按这种方式才能推成功 --------- Co-authored-by: yangkun --- src/Rtmp/RtmpPlayer.cpp | 21 +++++++++++---------- src/Rtmp/RtmpPusher.cpp | 16 +++++++++++----- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Rtmp/RtmpPlayer.cpp b/src/Rtmp/RtmpPlayer.cpp index 42914cda..13c0131b 100644 --- a/src/Rtmp/RtmpPlayer.cpp +++ b/src/Rtmp/RtmpPlayer.cpp @@ -52,17 +52,18 @@ void RtmpPlayer::teardown() { void RtmpPlayer::play(const string &url) { teardown(); - string host_url = findSubString(url.data(), "://", "/"); - { - auto pos = url.find_last_of('/'); - if (pos != string::npos) { - _stream_id = url.substr(pos + 1); - } + auto schema = findSubString(url.data(), nullptr, "://"); + auto host_url = findSubString(url.data(), "://", "/"); + _app = findSubString(url.data(), (host_url + "/").data(), "/"); + _stream_id = findSubString(url.data(), (host_url + "/" + _app + "/").data(), NULL); + auto app_second = findSubString(_stream_id.data(), nullptr, "/"); + if (!app_second.empty() && app_second.find('?') == std::string::npos) { + // _stream_id存在多级;不包含'?', 说明分割符'/'不是url参数的一部分 + _app += "/" + app_second; + _stream_id.erase(0, app_second.size() + 1); } - _app = findSubString(url.data(), (host_url + "/").data(), ("/" + _stream_id).data()); - _tc_url = string("rtmp://") + host_url + "/" + _app; - - if (!_app.size() || !_stream_id.size()) { + _tc_url = schema + "://" + host_url + "/" + _app; + if (_app.empty() || _stream_id.empty()) { onPlayResult_l(SockException(Err_other, "rtmp url非法"), false); return; } diff --git a/src/Rtmp/RtmpPusher.cpp b/src/Rtmp/RtmpPusher.cpp index f401cf34..c48f3820 100644 --- a/src/Rtmp/RtmpPusher.cpp +++ b/src/Rtmp/RtmpPusher.cpp @@ -63,14 +63,20 @@ void RtmpPusher::onPublishResult_l(const SockException &ex, bool handshake_done) } } -void RtmpPusher::publish(const string &url) { +void RtmpPusher::publish(const string &url) { teardown(); - string host_url = findSubString(url.data(), "://", "/"); + auto schema = findSubString(url.data(), nullptr, "://"); + auto host_url = findSubString(url.data(), "://", "/"); _app = findSubString(url.data(), (host_url + "/").data(), "/"); _stream_id = findSubString(url.data(), (host_url + "/" + _app + "/").data(), NULL); - _tc_url = string("rtmp://") + host_url + "/" + _app; - - if (!_app.size() || !_stream_id.size()) { + auto app_second = findSubString(_stream_id.data(), nullptr, "/"); + if (!app_second.empty() && app_second.find('?') == std::string::npos) { + // _stream_id存在多级;不包含'?', 说明分割符'/'不是url参数的一部分 + _app += "/" + app_second; + _stream_id.erase(0, app_second.size() + 1); + } + _tc_url = schema + "://" + host_url + "/" + _app; + if (_app.empty() || _stream_id.empty()) { onPublishResult_l(SockException(Err_other, "rtmp url非法"), false); return; } From 6d06649a5be30c752249c90093836b0ebe2849a0 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Fri, 27 Oct 2023 21:45:03 +0800 Subject: [PATCH 13/31] =?UTF-8?q?=E6=9B=B4=E6=96=B0webassist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 2 +- www/webassist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 5f9e1fb9..c6211ba1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,4 +9,4 @@ url = https://gitee.com/mirrors/jsoncpp.git [submodule "www/webassist"] path = www/webassist - url = https://github.com/1002victor/zlm_webassist + url = https://gitee.com/victor1002/zlm_webassist diff --git a/www/webassist b/www/webassist index 0d1e8c90..e2ed4e0c 160000 --- a/www/webassist +++ b/www/webassist @@ -1 +1 @@ -Subproject commit 0d1e8c902feab2c16723bfa05df89f43b0acaefc +Subproject commit e2ed4e0c6d8ca9d9f0e8a1660ea141d9cde9fdff From 0f94b488239c3f389af5f20a926c2193f30b0f89 Mon Sep 17 00:00:00 2001 From: xiongguangjie Date: Fri, 27 Oct 2023 22:49:42 +0800 Subject: [PATCH 14/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8Durl=E5=8F=8D=E8=BD=AC?= =?UTF-8?q?=E4=B9=89=E5=A4=B1=E8=B4=A5=E6=97=B6=E5=AD=97=E7=AC=A6=E4=B9=B1?= =?UTF-8?q?=E7=A0=81=E7=9B=B8=E5=85=B3bug=20(#2932=20#2935)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/strCoding.cpp | 64 ++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/src/Common/strCoding.cpp b/src/Common/strCoding.cpp index 144bf1f2..4f6c4e53 100644 --- a/src/Common/strCoding.cpp +++ b/src/Common/strCoding.cpp @@ -36,20 +36,21 @@ void UnicodeToUTF8(char *pOut, const wchar_t *pText) { return; } -char CharToInt(char ch) { - if (ch >= '0' && ch <= '9')return (char) (ch - '0'); - if (ch >= 'a' && ch <= 'f')return (char) (ch - 'a' + 10); - if (ch >= 'A' && ch <= 'F')return (char) (ch - 'A' + 10); +char HexCharToBin(char ch) { + if (ch >= '0' && ch <= '9') return (char)(ch - '0'); + if (ch >= 'a' && ch <= 'f') return (char)(ch - 'a' + 10); + if (ch >= 'A' && ch <= 'F') return (char)(ch - 'A' + 10); return -1; } -char StrToBin(const char *str) { - char tempWord[2]; - char chn; - tempWord[0] = CharToInt(str[0]); //make the B to 11 -- 00001011 - tempWord[1] = CharToInt(str[1]); //make the 0 to 0 -- 00000000 - chn = (tempWord[0] << 4) | tempWord[1]; //to change the BO to 10110000 - return chn; +char HexStrToBin(const char *str) { + auto high = HexCharToBin(str[0]); + auto low = HexCharToBin(str[1]); + if (high == -1 || low == -1) { + // 无法把16进制字符串转换为二进制 + return -1; + } + return (high << 4) | low; } string strCoding::UrlEncode(const string &str) { @@ -70,26 +71,51 @@ string strCoding::UrlEncode(const string &str) { string strCoding::UrlDecode(const string &str) { string output; - char tmp[2]; size_t i = 0, len = str.length(); while (i < len) { if (str[i] == '%') { - if (i > len - 3) { - //防止内存溢出 + if (i + 3 > len) { + // %后面必须还有两个字节才会反转义 + output.append(str, i, len - i); break; } - tmp[0] = str[i + 1]; - tmp[1] = str[i + 2]; - output += StrToBin(tmp); - i = i + 3; + char ch = HexStrToBin(&(str[i + 1])); + if (ch == -1) { + // %后面两个字节不是16进制字符串,转义失败;直接拼接3个原始字符 + output.append(str, i, 3); + } else { + output += ch; + } + i += 3; } else { output += str[i]; - i++; + ++i; } } return output; } +#if 0 +#include "Util/onceToken.h" +static toolkit::onceToken token([]() { + auto str0 = strCoding::UrlDecode( + "rtsp%3A%2F%2Fadmin%3AJm13317934%25jm%40111.47.84.69%3A554%2FStreaming%2FChannels%2F101%3Ftransportmode%3Dunicast%26amp%3Bprofile%3DProfile_1"); + auto str1 = strCoding::UrlDecode("%j1"); // 测试%后面两个字节不是16进制字符串 + auto str2 = strCoding::UrlDecode("%a"); // 测试%后面字节数不够 + auto str3 = strCoding::UrlDecode("%"); // 测试只有% + auto str4 = strCoding::UrlDecode("%%%"); // 测试多个% + auto str5 = strCoding::UrlDecode("%%%%40"); // 测试多个非法%后恢复正常解析 + auto str6 = strCoding::UrlDecode("Jm13317934%jm"); // 测试多个非法%后恢复正常解析 + cout << str0 << endl; + cout << str1 << endl; + cout << str2 << endl; + cout << str3 << endl; + cout << str4 << endl; + cout << str5 << endl; + cout << str6 << endl; +}); +#endif + ///////////////////////////////windows专用/////////////////////////////////// #if defined(_WIN32) void UnicodeToGB2312(char* pOut, wchar_t uData) From c1b82961cf3e135eb1cab39184e47e4a408ed1f5 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Sat, 28 Oct 2023 10:22:43 +0800 Subject: [PATCH 15/31] =?UTF-8?q?deleteRecordDirectory=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=96=B0=E5=A2=9Ename=E5=8F=82=E6=95=B0=EF=BC=8C=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E6=8C=87=E5=AE=9A=E5=88=A0=E9=99=A4=E7=89=B9=E5=AE=9A?= =?UTF-8?q?=E5=BD=95=E5=83=8F=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 7c8e35c0..784782b9 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -1491,11 +1491,15 @@ void installWebApi() { // http://127.0.0.1/index/api/deleteRecordDirectroy?vhost=__defaultVhost__&app=live&stream=ss&period=2020-01-01 api_regist("/index/api/deleteRecordDirectory", [](API_ARGS_MAP) { CHECK_SECRET(); - CHECK_ARGS("vhost", "app", "stream"); + CHECK_ARGS("vhost", "app", "stream", "period"); auto tuple = MediaTuple{allArgs["vhost"], allArgs["app"], allArgs["stream"]}; auto record_path = Recorder::getRecordPath(Recorder::type_mp4, tuple, allArgs["customized_path"]); auto period = allArgs["period"]; record_path = record_path + period + "/"; + auto name = allArgs["name"]; + if (!name.empty()) { + record_path += name; + } int result = File::delete_file(record_path.data()); if (result) { // 不等于0时代表失败 From d8d7fe9144fb3e17e19748859fac9a5bcecd15bb Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Sat, 28 Oct 2023 11:09:31 +0800 Subject: [PATCH 16/31] =?UTF-8?q?=E9=80=9A=E8=BF=87getMediaList=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=8F=AF=E8=BF=94=E5=9B=9ETrack=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=88=B3=E5=A2=9E=E9=87=8F=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 1 + src/Extension/Frame.h | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 784782b9..5c63c943 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -370,6 +370,7 @@ Value makeMediaSourceJson(MediaSource &media){ obj["loss"] = loss; } obj["frames"] = track->getFrames(); + obj["duration"] = track->getDuration(); switch(codec_type){ case TrackAudio : { auto audio_track = dynamic_pointer_cast(track); diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index 3609ff41..a1b2b6dc 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -16,6 +16,7 @@ #include #include "Util/List.h" #include "Util/TimeTicker.h" +#include "Common/Stamp.h" #include "Network/Buffer.h" namespace mediakit { @@ -361,11 +362,18 @@ public: return _gop_interval_ms; } + int64_t getDuration() const { + std::lock_guard lck(_mtx); + return _stamp.getRelativeStamp(); + } + private: void doStatistics(const Frame::Ptr &frame) { if (!frame->configFrame() && !frame->dropAble()) { // 忽略配置帧与可丢弃的帧 ++_frames; + int64_t out; + _stamp.revise(frame->dts(), frame->pts(), out, out); if (frame->keyFrame() && frame->getTrackType() == TrackVideo) { // 遇视频关键帧时统计 ++_video_key_frames; @@ -384,6 +392,7 @@ private: uint64_t _last_frames = 0; uint64_t _frames = 0; uint64_t _video_key_frames = 0; + Stamp _stamp; mutable std::recursive_mutex _mtx; std::map _delegates; }; From 83b432b980bb48de0b8a2eb8fef7757d510b4ef5 Mon Sep 17 00:00:00 2001 From: xiongziliang Date: Thu, 2 Nov 2023 12:51:08 +0800 Subject: [PATCH 17/31] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=85=B3=E9=97=ADonly?= =?UTF-8?q?=5Faudio=E6=A8=A1=E5=BC=8F=EF=BC=8C=E4=BF=AE=E5=A4=8Dmk=5Fmedia?= =?UTF-8?q?=5Fstart=5Fsend=E6=8E=A5=E5=8F=A3=E5=8F=91=E9=80=81=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E5=A4=B1=E8=B4=A5=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Common/MediaSource.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h index bcf75a09..ffced627 100644 --- a/src/Common/MediaSource.h +++ b/src/Common/MediaSource.h @@ -99,7 +99,7 @@ public: // rtp采用ps还是es方式 bool use_ps = true; //发送es流时指定是否只发送纯音频流 - bool only_audio = true; + bool only_audio = false; //tcp被动方式 bool passive = false; // rtp payload type From 9f28384cd998f6ed6faf53b6d8ee3c9780c34bc5 Mon Sep 17 00:00:00 2001 From: xiongziliang Date: Thu, 2 Nov 2023 12:54:08 +0800 Subject: [PATCH 18/31] =?UTF-8?q?=E6=9B=B4=E6=96=B0=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 --- 3rdpart/ZLToolKit | 2 +- 3rdpart/jsoncpp | 2 +- 3rdpart/media-server | 2 +- www/webassist | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 3fd2b856..0b907a86 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 3fd2b856b6856dd679a32c673431561c0affdd0c +Subproject commit 0b907a864891cac59de925693e9a666e8a9869e1 diff --git a/3rdpart/jsoncpp b/3rdpart/jsoncpp index 8190e061..69098a18 160000 --- a/3rdpart/jsoncpp +++ b/3rdpart/jsoncpp @@ -1 +1 @@ -Subproject commit 8190e061bc2d95da37479a638aa2c9e483e58ec6 +Subproject commit 69098a18b9af0c47549d9a271c054d13ca92b006 diff --git a/3rdpart/media-server b/3rdpart/media-server index cdbb3d6b..3dc623a8 160000 --- a/3rdpart/media-server +++ b/3rdpart/media-server @@ -1 +1 @@ -Subproject commit cdbb3d6b9ea254f454c6e466c5962af5ace01199 +Subproject commit 3dc623a899eee3810587fb267dbff770b626a55b diff --git a/www/webassist b/www/webassist index e2ed4e0c..135fae3a 160000 --- a/www/webassist +++ b/www/webassist @@ -1 +1 @@ -Subproject commit e2ed4e0c6d8ca9d9f0e8a1660ea141d9cde9fdff +Subproject commit 135fae3a99c94ed297b8ad3d17d74bbf13ec93aa From 2206b031a9a708186ff42813bee6c227013df081 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sat, 4 Nov 2023 22:24:55 +0800 Subject: [PATCH 19/31] =?UTF-8?q?=E9=98=B2=E6=AD=A2=E6=9E=90=E6=9E=84?= =?UTF-8?q?=E6=97=B6=E6=8A=9B=E5=BC=82=E5=B8=B8=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Record/MP4Recorder.cpp | 8 ++++++-- src/TS/TSMediaSourceMuxer.h | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Record/MP4Recorder.cpp b/src/Record/MP4Recorder.cpp index 5373b8a1..59a0d590 100644 --- a/src/Record/MP4Recorder.cpp +++ b/src/Record/MP4Recorder.cpp @@ -34,8 +34,12 @@ MP4Recorder::MP4Recorder(const string &path, const string &vhost, const string & } MP4Recorder::~MP4Recorder() { - flush(); - closeFile(); + try { + flush(); + closeFile(); + } catch (std::exception &ex) { + WarnL << ex.what(); + } } void MP4Recorder::createFile() { diff --git a/src/TS/TSMediaSourceMuxer.h b/src/TS/TSMediaSourceMuxer.h index 389ea901..cdf08fbb 100644 --- a/src/TS/TSMediaSourceMuxer.h +++ b/src/TS/TSMediaSourceMuxer.h @@ -26,7 +26,13 @@ public: _media_src = std::make_shared(tuple); } - ~TSMediaSourceMuxer() override { MpegMuxer::flush(); }; + ~TSMediaSourceMuxer() override { + try { + MpegMuxer::flush(); + } catch (std::exception &ex) { + WarnL << ex.what(); + } + }; void setListener(const std::weak_ptr &listener){ setDelegate(listener); From b257c670eb18efcbac64e14cf4f9c9da78c3e9d0 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sat, 4 Nov 2023 22:35:19 +0800 Subject: [PATCH 20/31] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8C=81=E7=BB=AD?= =?UTF-8?q?=E9=9B=86=E6=88=90=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/c-cpp.yml | 34 ---------------------------------- .github/workflows/docker.yml | 4 +--- 2 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 .github/workflows/c-cpp.yml diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml deleted file mode 100644 index 4418c935..00000000 --- a/.github/workflows/c-cpp.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Linux - -on: [push, pull_request] - -jobs: - build: - - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v1 - - - name: 下载submodule源码 - run: mv -f .gitmodules_github .gitmodules && git submodule sync && git submodule update --init - - - name: apt-get安装依赖库(非必选) - run: sudo apt-get update && sudo apt-get install -y cmake libssl-dev libsdl-dev libavcodec-dev libavutil-dev libswscale-dev libresample-dev libusrsctp-dev - - - name: 下载 SRTP - uses: actions/checkout@v2 - with: - repository: cisco/libsrtp - fetch-depth: 1 - ref: v2.3.0 - path: 3rdpart/libsrtp - - - name: 编译 SRTP - run: cd 3rdpart/libsrtp && ./configure --enable-openssl && make -j4 && sudo make install - - - name: 编译 - run: mkdir -p linux_build && cd linux_build && cmake .. -DENABLE_WEBRTC=true -DENABLE_FFMPEG=true && make -j $(nproc) - - - name: 运行MediaServer - run: pwd && cd release/linux/Debug && sudo ./MediaServer -d & diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c18493ac..81c002c9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -40,9 +40,7 @@ jobs: # https://github.com/sigstore/cosign-installer - name: Install cosign if: github.event_name != 'pull_request' - uses: sigstore/cosign-installer@d6a3abf1bdea83574e28d40543793018b6035605 - with: - cosign-release: 'v1.7.1' + uses: sigstore/cosign-installer@d572c9c13673d2e0a26fabf90b5748f36886883f - name: Set up QEMU uses: docker/setup-qemu-action@v2 From bf6fccd954d377de517d549a5e9ae03dbc1efc69 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sun, 5 Nov 2023 13:04:41 +0800 Subject: [PATCH 21/31] =?UTF-8?q?=E6=9B=B4=E6=96=B0ZLToolkit=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20#2946?= 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 0b907a86..a4771b35 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 0b907a864891cac59de925693e9a666e8a9869e1 +Subproject commit a4771b353d9ebe1bc162364237a31f4184a7c435 From 2628690673e169172c71e89a084db3deacb5154c Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sun, 5 Nov 2023 13:26:42 +0800 Subject: [PATCH 22/31] =?UTF-8?q?=E5=9B=BD=E6=A0=87udp=E5=A4=9A=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E6=A8=A1=E5=BC=8F=E6=94=AF=E6=8C=81=E6=94=B6=E5=88=B0?= =?UTF-8?q?sr=20rtcp=E5=90=8E=E5=9B=9E=E5=A4=8Drr=20rtcp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 确保国标停止rtp推流后也可以仅靠rtcp保活 --- src/Rtp/RtpServer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp index 1c6a8c1b..34871562 100644 --- a/src/Rtp/RtpServer.cpp +++ b/src/Rtp/RtpServer.cpp @@ -89,6 +89,8 @@ public: for (auto &rtcp : rtcps) { strong_self->_process->onRtcp(rtcp); } + // 收到sr rtcp后驱动返回rr rtcp + strong_self->sendRtcp(strong_self->_ssrc, (struct sockaddr *)(strong_self->_rtcp_addr.get())); }); GET_CONFIG(uint64_t, timeoutSec, RtpProxy::kTimeoutSec); From c95ccbd54411d056ada83983cba6ec9c8d853249 Mon Sep 17 00:00:00 2001 From: xiongziliang <771730766@qq.com> Date: Sun, 5 Nov 2023 20:15:58 +0800 Subject: [PATCH 23/31] =?UTF-8?q?=E6=9B=B4=E6=96=B0webassist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- www/webassist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/webassist b/www/webassist index 135fae3a..b02d2a4c 160000 --- a/www/webassist +++ b/www/webassist @@ -1 +1 @@ -Subproject commit 135fae3a99c94ed297b8ad3d17d74bbf13ec93aa +Subproject commit b02d2a4c1abf95db45e50bb77d789defa0fcc4b7 From 433ecb1c5cea66deb900d5f7cbd392c38a728338 Mon Sep 17 00:00:00 2001 From: yujitai Date: Tue, 7 Nov 2023 19:34:40 +0800 Subject: [PATCH 24/31] =?UTF-8?q?RTC:=20=E4=BF=AE=E5=A4=8Dgop=E6=B2=A1?= =?UTF-8?q?=E6=9C=89sps/pps=E5=AF=BC=E8=87=B4=E7=9A=84=E7=A7=92=E5=BC=80?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98=20(#2959)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rtc场景下,如果directProxy设置为1,sdp没有传递sps/pps,因此gop的开始需要是rtp sps/pps配置帧而不是idr关键帧,这样才能保证秒开。 --- src/Extension/H264Rtp.cpp | 12 +++++++----- src/Extension/H264Rtp.h | 1 + src/Extension/H265Rtp.cpp | 10 ++++++---- src/Extension/H265Rtp.h | 1 + 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Extension/H264Rtp.cpp b/src/Extension/H264Rtp.cpp index 28c775c6..442205a6 100644 --- a/src/Extension/H264Rtp.cpp +++ b/src/Extension/H264Rtp.cpp @@ -44,13 +44,15 @@ H264Frame::Ptr H264RtpDecoder::obtainFrame() { bool H264RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) { auto seq = rtp->getSeq(); - auto ret = decodeRtp(rtp); - if (!_gop_dropped && seq != (uint16_t) (_last_seq + 1) && _last_seq) { + auto last_is_gop = _is_gop; + _is_gop = decodeRtp(rtp); + if (!_gop_dropped && seq != (uint16_t)(_last_seq + 1) && _last_seq) { _gop_dropped = true; WarnL << "start drop h264 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString(); } _last_seq = seq; - return ret; + // 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始 + return _is_gop && !last_is_gop; } /* @@ -74,7 +76,7 @@ bool H264RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, _frame->_buffer.assign("\x00\x00\x00\x01", 4); _frame->_buffer.append((char *) ptr, size); _frame->_pts = stamp; - auto key = _frame->keyFrame(); + auto key = _frame->keyFrame() || _frame->configFrame(); outputFrame(rtp, _frame); return key; } @@ -127,7 +129,7 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz if (!fu->end_bit) { //非末尾包 - return fu->start_bit ? _frame->keyFrame() : false; + return fu->start_bit ? (_frame->keyFrame() || _frame->configFrame()) : false; } //确保下一次fu必须收到第一个包 diff --git a/src/Extension/H264Rtp.h b/src/Extension/H264Rtp.h index 31200cb8..98d49cda 100644 --- a/src/Extension/H264Rtp.h +++ b/src/Extension/H264Rtp.h @@ -51,6 +51,7 @@ private: void outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame); private: + bool _is_gop = false; bool _gop_dropped = false; bool _fu_dropped = true; uint16_t _last_seq = 0; diff --git a/src/Extension/H265Rtp.cpp b/src/Extension/H265Rtp.cpp index 23bbb109..22866ff4 100644 --- a/src/Extension/H265Rtp.cpp +++ b/src/Extension/H265Rtp.cpp @@ -163,7 +163,7 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz if (!e_bit) { //非末尾包 - return s_bit ? _frame->keyFrame() : false; + return s_bit ? (_frame->keyFrame() || _frame->configFrame()) : false; } //确保下一次fu必须收到第一个包 @@ -175,13 +175,15 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz bool H265RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) { auto seq = rtp->getSeq(); - auto ret = decodeRtp(rtp); + auto last_is_gop = _is_gop; + _is_gop = decodeRtp(rtp); if (!_gop_dropped && seq != (uint16_t) (_last_seq + 1) && _last_seq) { _gop_dropped = true; WarnL << "start drop h265 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString(); } _last_seq = seq; - return ret; + // 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始 + return _is_gop && !last_is_gop; } bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) { @@ -220,7 +222,7 @@ bool H265RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, _frame->_buffer.assign("\x00\x00\x00\x01", 4); _frame->_buffer.append((char *) ptr, size); _frame->_pts = stamp; - auto key = _frame->keyFrame(); + auto key = _frame->keyFrame() || _frame->configFrame(); outputFrame(rtp, _frame); return key; } diff --git a/src/Extension/H265Rtp.h b/src/Extension/H265Rtp.h index cd9702f4..569d8091 100644 --- a/src/Extension/H265Rtp.h +++ b/src/Extension/H265Rtp.h @@ -51,6 +51,7 @@ private: void outputFrame(const RtpPacket::Ptr &rtp, const H265Frame::Ptr &frame); private: + bool _is_gop = false; bool _using_donl_field = false; bool _gop_dropped = false; bool _fu_dropped = true; From aa5343effaadb307f93650c563795f1f9f8d5403 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Tue, 7 Nov 2023 23:15:16 +0800 Subject: [PATCH 25/31] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dhttp=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E8=AE=BE=E7=BD=AEtcp=E8=BF=9E=E6=8E=A5=E8=B6=85?= =?UTF-8?q?=E6=97=B6=E6=97=B6=E9=97=B4=E5=8D=95=E4=BD=8D=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 须毫秒转换为秒 --- src/Http/HttpClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/HttpClient.cpp b/src/Http/HttpClient.cpp index 328872e6..dd1546db 100644 --- a/src/Http/HttpClient.cpp +++ b/src/Http/HttpClient.cpp @@ -80,7 +80,7 @@ void HttpClient::sendRequest(const string &url) { } if (!alive() || host_changed) { - startConnect(host, port, _wait_header_ms); + startConnect(host, port, _wait_header_ms / 1000.0f); } else { SockException ex; onConnect_l(ex); From 77b3c4312e93c937fbed6d2761727f52b5481889 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Tue, 7 Nov 2023 23:15:55 +0800 Subject: [PATCH 26/31] =?UTF-8?q?=E6=9B=B4=E6=96=B0zltoolkit=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=93=E5=BC=80=E6=96=87=E4=BB=B6=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0=E7=AC=A6=E5=A4=AA=E5=A4=9A=E6=97=B6=EF=BC=8Ctcp?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E6=97=A0=E5=93=8D=E5=BA=94=E7=9A=84?= =?UTF-8?q?bug=20(#2946)?= 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 a4771b35..12c2ec7b 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit a4771b353d9ebe1bc162364237a31f4184a7c435 +Subproject commit 12c2ec7b07dce1b6a0543d9979f5c5231f69e828 From 1609fe67d735f4e520ae2d0de7b5862a771bba52 Mon Sep 17 00:00:00 2001 From: fruit Juice <2317232721@qq.com> Date: Tue, 7 Nov 2023 23:36:41 +0800 Subject: [PATCH 27/31] =?UTF-8?q?Track=E6=96=B0=E5=A2=9Eupdate=E6=96=B9?= =?UTF-8?q?=E6=B3=95=EF=BC=8C=E6=94=AF=E6=8C=81=E6=9B=B4=E6=96=B0=E5=AE=BD?= =?UTF-8?q?=E9=AB=98=E9=87=87=E6=A0=B7=E7=8E=87=E7=AD=89=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=20(#2960)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当变分辨率时候,实时更新MP4封装层的参数信息,避免出现封装层与编码(SPS)层视频宽高不一样,造成解码参数错误花屏;同时也支持更新音频采样率等信息。 --------- Co-authored-by: xia-chu <771730766@qq.com> --- src/Common/MultiMediaSourceMuxer.cpp | 1 + src/Extension/AAC.cpp | 98 +++++++++++++++------------- src/Extension/AAC.h | 1 + src/Extension/H264.cpp | 4 ++ src/Extension/H264.h | 1 + src/Extension/H265.cpp | 4 ++ src/Extension/H265.h | 1 + src/Extension/Track.h | 5 ++ src/Player/PlayerProxy.cpp | 1 + src/Record/MP4Muxer.cpp | 1 + src/Rtmp/Rtmp.cpp | 2 + 11 files changed, 75 insertions(+), 44 deletions(-) diff --git a/src/Common/MultiMediaSourceMuxer.cpp b/src/Common/MultiMediaSourceMuxer.cpp index bbb9b357..e3151093 100644 --- a/src/Common/MultiMediaSourceMuxer.cpp +++ b/src/Common/MultiMediaSourceMuxer.cpp @@ -45,6 +45,7 @@ static string getTrackInfoStr(const TrackSource *track_src){ _StrPrinter codec_info; auto tracks = track_src->getTracks(true); for (auto &track : tracks) { + track->update(); auto codec_type = track->getTrackType(); codec_info << track->getCodecName(); switch (codec_type) { diff --git a/src/Extension/AAC.cpp b/src/Extension/AAC.cpp index 1047a8b3..27f18359 100644 --- a/src/Extension/AAC.cpp +++ b/src/Extension/AAC.cpp @@ -21,53 +21,56 @@ namespace mediakit{ #ifndef ENABLE_MP4 unsigned const samplingFrequencyTable[16] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0 }; -class AdtsHeader{ +class AdtsHeader { public: - unsigned int syncword = 0; //12 bslbf 同步字The bit string ‘1111 1111 1111’,说明一个ADTS帧的开始 - unsigned int id; //1 bslbf MPEG 标示符, 设置为1 - unsigned int layer; //2 uimsbf Indicates which layer is used. Set to ‘00’ - unsigned int protection_absent; //1 bslbf 表示是否误码校验 - unsigned int profile; //2 uimsbf 表示使用哪个级别的AAC,如01 Low Complexity(LC)--- AACLC - unsigned int sf_index; //4 uimsbf 表示使用的采样率下标 - unsigned int private_bit; //1 bslbf - unsigned int channel_configuration; //3 uimsbf 表示声道数 - unsigned int original; //1 bslbf - unsigned int home; //1 bslbf - //下面的为改变的参数即每一帧都不同 - unsigned int copyright_identification_bit; //1 bslbf - unsigned int copyright_identification_start; //1 bslbf + unsigned int syncword = 0; // 12 bslbf 同步字The bit string ‘1111 1111 1111’,说明一个ADTS帧的开始 + unsigned int id; // 1 bslbf MPEG 标示符, 设置为1 + unsigned int layer; // 2 uimsbf Indicates which layer is used. Set to ‘00’ + unsigned int protection_absent; // 1 bslbf 表示是否误码校验 + unsigned int profile; // 2 uimsbf 表示使用哪个级别的AAC,如01 Low Complexity(LC)--- AACLC + unsigned int sf_index; // 4 uimsbf 表示使用的采样率下标 + unsigned int private_bit; // 1 bslbf + unsigned int channel_configuration; // 3 uimsbf 表示声道数 + unsigned int original; // 1 bslbf + unsigned int home; // 1 bslbf + // 下面的为改变的参数即每一帧都不同 + unsigned int copyright_identification_bit; // 1 bslbf + unsigned int copyright_identification_start; // 1 bslbf unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block - unsigned int adts_buffer_fullness; //11 bslbf 0x7FF 说明是码率可变的码流 - //no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧. - //所以说number_of_raw_data_blocks_in_frame == 0 - //表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据) - unsigned int no_raw_data_blocks_in_frame; //2 uimsfb + unsigned int adts_buffer_fullness; // 11 bslbf 0x7FF 说明是码率可变的码流 + // no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧. + // 所以说number_of_raw_data_blocks_in_frame == 0 + // 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据) + unsigned int no_raw_data_blocks_in_frame; // 2 uimsfb }; static void dumpAdtsHeader(const AdtsHeader &hed, uint8_t *out) { - out[0] = (hed.syncword >> 4 & 0xFF); //8bit - out[1] = (hed.syncword << 4 & 0xF0); //4 bit - out[1] |= (hed.id << 3 & 0x08); //1 bit - out[1] |= (hed.layer << 1 & 0x06); //2bit - out[1] |= (hed.protection_absent & 0x01); //1 bit + out[0] = (hed.syncword >> 4 & 0xFF); // 8bit + out[1] = (hed.syncword << 4 & 0xF0); // 4 bit + out[1] |= (hed.id << 3 & 0x08); // 1 bit + out[1] |= (hed.layer << 1 & 0x06); // 2bit + out[1] |= (hed.protection_absent & 0x01); // 1 bit out[2] = (hed.profile << 6 & 0xC0); // 2 bit - out[2] |= (hed.sf_index << 2 & 0x3C); //4bit - out[2] |= (hed.private_bit << 1 & 0x02); //1 bit - out[2] |= (hed.channel_configuration >> 2 & 0x03); //1 bit - out[3] = (hed.channel_configuration << 6 & 0xC0); // 2 bit - out[3] |= (hed.original << 5 & 0x20); //1 bit - out[3] |= (hed.home << 4 & 0x10); //1 bit - out[3] |= (hed.copyright_identification_bit << 3 & 0x08); //1 bit - out[3] |= (hed.copyright_identification_start << 2 & 0x04); //1 bit - out[3] |= (hed.aac_frame_length >> 11 & 0x03); //2 bit - out[4] = (hed.aac_frame_length >> 3 & 0xFF); //8 bit - out[5] = (hed.aac_frame_length << 5 & 0xE0); //3 bit - out[5] |= (hed.adts_buffer_fullness >> 6 & 0x1F); //5 bit - out[6] = (hed.adts_buffer_fullness << 2 & 0xFC); //6 bit - out[6] |= (hed.no_raw_data_blocks_in_frame & 0x03); //2 bit + out[2] |= (hed.sf_index << 2 & 0x3C); // 4bit + out[2] |= (hed.private_bit << 1 & 0x02); // 1 bit + out[2] |= (hed.channel_configuration >> 2 & 0x03); // 1 bit + out[3] = (hed.channel_configuration << 6 & 0xC0); // 2 bit + out[3] |= (hed.original << 5 & 0x20); // 1 bit + out[3] |= (hed.home << 4 & 0x10); // 1 bit + out[3] |= (hed.copyright_identification_bit << 3 & 0x08); // 1 bit + out[3] |= (hed.copyright_identification_start << 2 & 0x04); // 1 bit + out[3] |= (hed.aac_frame_length >> 11 & 0x03); // 2 bit + out[4] = (hed.aac_frame_length >> 3 & 0xFF); // 8 bit + out[5] = (hed.aac_frame_length << 5 & 0xE0); // 3 bit + out[5] |= (hed.adts_buffer_fullness >> 6 & 0x1F); // 5 bit + out[6] = (hed.adts_buffer_fullness << 2 & 0xFC); // 6 bit + out[6] |= (hed.no_raw_data_blocks_in_frame & 0x03); // 2 bit } -static void parseAacConfig(const string &config, AdtsHeader &adts) { +static bool parseAacConfig(const string &config, AdtsHeader &adts) { + if (config.size() < 2) { + return false; + } uint8_t cfg1 = config[0]; uint8_t cfg2 = config[1]; @@ -94,6 +97,7 @@ static void parseAacConfig(const string &config, AdtsHeader &adts) { adts.aac_frame_length = 7; adts.adts_buffer_fullness = 2047; adts.no_raw_data_blocks_in_frame = 0; + return true; } #endif// ENABLE_MP4 @@ -168,10 +172,12 @@ int dumpAacConfig(const string &config, size_t length, uint8_t *out, size_t out_ #endif } -bool parseAacConfig(const string &config, int &samplerate, int &channels){ +bool parseAacConfig(const string &config, int &samplerate, int &channels) { #ifndef ENABLE_MP4 AdtsHeader header; - parseAacConfig(config, header); + if (!parseAacConfig(config, header)) { + return false; + } samplerate = samplingFrequencyTable[header.sf_index]; channels = header.channel_configuration; return true; @@ -326,11 +332,14 @@ bool AACTrack::inputFrame_l(const Frame::Ptr &frame) { return false; } +bool AACTrack::update() { + return parseAacConfig(_cfg, _sampleRate, _channel); +} + void AACTrack::onReady() { - if (_cfg.size() < 2) { - return; + if (!parseAacConfig(_cfg, _sampleRate, _channel)) { + _cfg.clear(); } - parseAacConfig(_cfg, _sampleRate, _channel); } Track::Ptr AACTrack::clone() { @@ -342,6 +351,7 @@ Sdp::Ptr AACTrack::getSdp() { WarnL << getCodecName() << " Track未准备好"; return nullptr; } + update(); return std::make_shared(getConfig(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024); } diff --git a/src/Extension/AAC.h b/src/Extension/AAC.h index b95fc6f2..32cf934b 100644 --- a/src/Extension/AAC.h +++ b/src/Extension/AAC.h @@ -52,6 +52,7 @@ public: int getAudioSampleRate() const override; int getAudioSampleBit() const override; bool inputFrame(const Frame::Ptr &frame) override; + bool update() override; private: void onReady(); diff --git a/src/Extension/H264.cpp b/src/Extension/H264.cpp index eeccd600..eda6b188 100644 --- a/src/Extension/H264.cpp +++ b/src/Extension/H264.cpp @@ -168,6 +168,10 @@ bool H264Track::inputFrame(const Frame::Ptr &frame) { return ret; } +bool H264Track::update() { + return getAVCInfo(_sps, _width, _height, _fps); +} + void H264Track::onReady() { if (!getAVCInfo(_sps, _width, _height, _fps)) { _sps.clear(); diff --git a/src/Extension/H264.h b/src/Extension/H264.h index 30a8f747..0afe593d 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -128,6 +128,7 @@ public: int getVideoWidth() const override; float getVideoFps() const override; bool inputFrame(const Frame::Ptr &frame) override; + bool update() override; private: void onReady(); diff --git a/src/Extension/H265.cpp b/src/Extension/H265.cpp index 9985a9cb..926ab2a4 100644 --- a/src/Extension/H265.cpp +++ b/src/Extension/H265.cpp @@ -144,6 +144,10 @@ bool H265Track::inputFrame_l(const Frame::Ptr &frame) { return ret; } +bool H265Track::update() { + return getHEVCInfo(_vps, _sps, _width, _height, _fps); +} + void H265Track::onReady() { if (!getHEVCInfo(_vps, _sps, _width, _height, _fps)) { _vps.clear(); diff --git a/src/Extension/H265.h b/src/Extension/H265.h index 521663f4..912f1f46 100644 --- a/src/Extension/H265.h +++ b/src/Extension/H265.h @@ -150,6 +150,7 @@ public: int getVideoHeight() const override; float getVideoFps() const override; bool inputFrame(const Frame::Ptr &frame) override; + bool update() override; private: void onReady(); diff --git a/src/Extension/Track.h b/src/Extension/Track.h index e7aa2b7c..3a1b8519 100644 --- a/src/Extension/Track.h +++ b/src/Extension/Track.h @@ -39,6 +39,11 @@ public: */ virtual Track::Ptr clone() = 0; + /** + * 更新track信息,比如触发sps/pps解析 + */ + virtual bool update() { return false; } + /** * 生成sdp * @return sdp对象 diff --git a/src/Player/PlayerProxy.cpp b/src/Player/PlayerProxy.cpp index 2a319ff8..73e46b71 100644 --- a/src/Player/PlayerProxy.cpp +++ b/src/Player/PlayerProxy.cpp @@ -70,6 +70,7 @@ void PlayerProxy::setTranslationInfo() _transtalion_info.stream_info.clear(); auto tracks = _muxer->getTracks(); for (auto &track : tracks) { + track->update(); _transtalion_info.stream_info.emplace_back(); auto &back = _transtalion_info.stream_info.back(); back.bitrate = track->getBitRate(); diff --git a/src/Record/MP4Muxer.cpp b/src/Record/MP4Muxer.cpp index c79cc132..5458a31d 100644 --- a/src/Record/MP4Muxer.cpp +++ b/src/Record/MP4Muxer.cpp @@ -198,6 +198,7 @@ bool MP4MuxerInterface::addTrack(const Track::Ptr &track) { return false; } + track->update(); switch (track->getCodecId()) { case CodecG711A: case CodecG711U: diff --git a/src/Rtmp/Rtmp.cpp b/src/Rtmp/Rtmp.cpp index 140afeed..33c46f11 100644 --- a/src/Rtmp/Rtmp.cpp +++ b/src/Rtmp/Rtmp.cpp @@ -57,6 +57,7 @@ AudioMeta::AudioMeta(const AudioTrack::Ptr &audio) { } uint8_t getAudioRtmpFlags(const Track::Ptr &track) { + track->update(); switch (track->getTrackType()) { case TrackAudio: { auto audioTrack = std::dynamic_pointer_cast(track); @@ -115,6 +116,7 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track) { void Metadata::addTrack(AMFValue &metadata, const Track::Ptr &track) { Metadata::Ptr new_metadata; + track->update(); switch (track->getTrackType()) { case TrackVideo: { new_metadata = std::make_shared(std::dynamic_pointer_cast(track)); From f8285a3f6c89e3fc01c03d73702c4cd7c58206ec Mon Sep 17 00:00:00 2001 From: Dw9 Date: Tue, 7 Nov 2023 23:38:58 +0800 Subject: [PATCH 28/31] =?UTF-8?q?startSendRtp=E6=8E=A5=E5=8F=A3=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=94=AF=E6=8C=81=E5=90=8Cssrc=E5=90=91=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=E6=9C=8D=E5=8A=A1=E5=99=A8=E6=8E=A8=E6=B5=81=20(#2951?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增ssrc_multi_send参数,支持同ssrc向多个服务器推流,兼容当前startSendRtp/stopSendRtp接口 --- postman/ZLMediaKit.postman_collection.json | 8 +++++++- server/WebApi.cpp | 1 + src/Common/MediaSource.h | 2 ++ src/Common/MultiMediaSourceMuxer.cpp | 9 +++++++-- src/Common/MultiMediaSourceMuxer.h | 2 +- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/postman/ZLMediaKit.postman_collection.json b/postman/ZLMediaKit.postman_collection.json index fdda9d2a..d8a49900 100644 --- a/postman/ZLMediaKit.postman_collection.json +++ b/postman/ZLMediaKit.postman_collection.json @@ -1710,10 +1710,16 @@ "value": "obs", "description": "流id,例如 obs" }, + { + "key": "ssrc_multi_send", + "value": "0", + "description": "是否支持同ssrc推流到多个上级服务器,该参数非必选参数 默认false", + "disabled": true + }, { "key": "ssrc", "value": "1", - "description": "rtp推流的ssrc,ssrc不同时,可以推流到多个上级服务器" + "description": "rtp推流的ssrc" }, { "key": "dst_url", diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 5c63c943..1ddc0c0f 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -1245,6 +1245,7 @@ void installWebApi() { args.passive = false; args.dst_url = allArgs["dst_url"]; args.dst_port = allArgs["dst_port"]; + args.ssrc_multi_send = allArgs["ssrc_multi_send"].empty() ? false : allArgs["ssrc_multi_send"].as(); args.ssrc = allArgs["ssrc"]; args.is_udp = allArgs["is_udp"]; args.src_port = allArgs["src_port"]; diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h index ffced627..73306385 100644 --- a/src/Common/MediaSource.h +++ b/src/Common/MediaSource.h @@ -104,6 +104,8 @@ public: bool passive = false; // rtp payload type uint8_t pt = 96; + //是否支持同ssrc多服务器发送 + bool ssrc_multi_send = false; // 指定rtp ssrc std::string ssrc; // 指定本地发送端口 diff --git a/src/Common/MultiMediaSourceMuxer.cpp b/src/Common/MultiMediaSourceMuxer.cpp index e3151093..99898b95 100644 --- a/src/Common/MultiMediaSourceMuxer.cpp +++ b/src/Common/MultiMediaSourceMuxer.cpp @@ -291,12 +291,14 @@ void MultiMediaSourceMuxer::startSendRtp(MediaSource &sender, const MediaSourceE auto ring = _ring; auto ssrc = args.ssrc; + auto ssrc_multi_send = args.ssrc_multi_send; auto tracks = getTracks(false); auto poller = getOwnerPoller(sender); auto rtp_sender = std::make_shared(poller); + weak_ptr weak_self = shared_from_this(); - rtp_sender->startSend(args, [ssrc, weak_self, rtp_sender, cb, tracks, ring, poller](uint16_t local_port, const SockException &ex) mutable { + rtp_sender->startSend(args, [ssrc,ssrc_multi_send, weak_self, rtp_sender, cb, tracks, ring, poller](uint16_t local_port, const SockException &ex) mutable { cb(local_port, ex); auto strong_self = weak_self.lock(); if (!strong_self || ex) { @@ -325,7 +327,10 @@ void MultiMediaSourceMuxer::startSendRtp(MediaSource &sender, const MediaSourceE // 可能归属线程发生变更 strong_self->getOwnerPoller(MediaSource::NullMediaSource())->async([=]() { - strong_self->_rtp_sender[ssrc] = std::move(reader); + if(!ssrc_multi_send) { + strong_self->_rtp_sender.erase(ssrc); + } + strong_self->_rtp_sender.emplace(ssrc,reader); }); }); #else diff --git a/src/Common/MultiMediaSourceMuxer.h b/src/Common/MultiMediaSourceMuxer.h index 4db34d42..45ab7623 100644 --- a/src/Common/MultiMediaSourceMuxer.h +++ b/src/Common/MultiMediaSourceMuxer.h @@ -168,7 +168,7 @@ private: toolkit::Ticker _last_check; Stamp _stamp[2]; std::weak_ptr _track_listener; - std::unordered_map _rtp_sender; + std::unordered_multimap _rtp_sender; FMP4MediaSourceMuxer::Ptr _fmp4; RtmpMediaSourceMuxer::Ptr _rtmp; RtspMediaSourceMuxer::Ptr _rtsp; From 6888f20d74b35558c0c3efd7cf26cb20014c6668 Mon Sep 17 00:00:00 2001 From: waken <33921191+mc373906408@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:26:13 +0800 Subject: [PATCH 29/31] =?UTF-8?q?=E6=96=B0=E5=A2=9EopenRtpServerMultiplex?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=94=AF=E6=8C=81=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=A4=9A=E8=B7=AF=E5=A4=8D=E7=94=A8RTP=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E7=AB=AF=E5=8F=A3=20(#2954)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #2953 --- postman/ZLMediaKit.postman_collection.json | 56 ++++++++++++++++++++-- server/WebApi.cpp | 22 ++++++++- server/WebApi.h | 2 +- src/Rtp/RtpServer.cpp | 5 +- src/Rtp/RtpServer.h | 3 +- 5 files changed, 78 insertions(+), 10 deletions(-) diff --git a/postman/ZLMediaKit.postman_collection.json b/postman/ZLMediaKit.postman_collection.json index d8a49900..784bb60c 100644 --- a/postman/ZLMediaKit.postman_collection.json +++ b/postman/ZLMediaKit.postman_collection.json @@ -1,9 +1,10 @@ { "info": { - "_postman_id": "39e8a1df-cc8e-4e3f-bf5e-197c86e7bf0f", + "_postman_id": "509e5f6b-728c-4d5f-b3e8-521d76b2cc7a", "name": "ZLMediaKit", "description": "媒体服务器", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "29185956" }, "item": [ { @@ -918,7 +919,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{ZLMediaKit_URL}}/index/api/broadcastMessage?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=live&stream=test&msg=Hello zlmediakit123", + "raw": "{{ZLMediaKit_URL}}/index/api/broadcastMessage?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=live&stream=test&msg=Hello ZLMediakit", "host": [ "{{ZLMediaKit_URL}}" ], @@ -1247,7 +1248,7 @@ }, { "key": "stamp", - "value": 1000, + "value": "1000", "description": "要设置的录像播放位置" } ] @@ -1478,6 +1479,53 @@ }, "response": [] }, + { + "name": "创建多路复用RTP服务器(openRtpServerMultiplex)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{ZLMediaKit_URL}}/index/api/openRtpServer?secret={{ZLMediaKit_secret}}&port=0&tcp_mode=1&stream_id=test", + "host": [ + "{{ZLMediaKit_URL}}" + ], + "path": [ + "index", + "api", + "openRtpServer" + ], + "query": [ + { + "key": "secret", + "value": "{{ZLMediaKit_secret}}", + "description": "api操作密钥(配置文件配置)" + }, + { + "key": "port", + "value": "0", + "description": "绑定的端口,0时为随机端口" + }, + { + "key": "tcp_mode", + "value": "1", + "description": "tcp模式,0时为不启用tcp监听,1时为启用tcp监听" + }, + { + "key": "stream_id", + "value": "test", + "description": "该端口绑定的流id\n" + }, + { + "key": "only_audio", + "value": "0", + "description": "是否为单音频track,用于语音对讲", + "disabled": true + } + ] + } + }, + "response": [] + }, { "name": "连接RTP服务器(connectRtpServer)", "request": { diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 1ddc0c0f..7833b933 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -404,7 +404,7 @@ Value makeMediaSourceJson(MediaSource &media){ } #if defined(ENABLE_RTPPROXY) -uint16_t openRtpServer(uint16_t local_port, const string &stream_id, int tcp_mode, const string &local_ip, bool re_use_port, uint32_t ssrc, bool only_audio) { +uint16_t openRtpServer(uint16_t local_port, const string &stream_id, int tcp_mode, const string &local_ip, bool re_use_port, uint32_t ssrc, bool only_audio, bool multiplex) { lock_guard lck(s_rtpServerMapMtx); if (s_rtpServerMap.find(stream_id) != s_rtpServerMap.end()) { //为了防止RtpProcess所有权限混乱的问题,不允许重复添加相同的stream_id @@ -412,7 +412,7 @@ uint16_t openRtpServer(uint16_t local_port, const string &stream_id, int tcp_mod } RtpServer::Ptr server = std::make_shared(); - server->start(local_port, stream_id, (RtpServer::TcpMode)tcp_mode, local_ip.c_str(), re_use_port, ssrc, only_audio); + server->start(local_port, stream_id, (RtpServer::TcpMode)tcp_mode, local_ip.c_str(), re_use_port, ssrc, only_audio, multiplex); server->setOnDetach([stream_id]() { //设置rtp超时移除事件 lock_guard lck(s_rtpServerMapMtx); @@ -1182,6 +1182,24 @@ void installWebApi() { //回复json val["port"] = port; }); + api_regist("/media/api/openRtpServerMultiplex", [](API_ARGS_MAP) { + CHECK_SECRET(); + CHECK_ARGS("port", "stream_id"); + auto stream_id = allArgs["stream_id"]; + auto tcp_mode = allArgs["tcp_mode"].as(); + if (allArgs["enable_tcp"].as() && !tcp_mode) { + // 兼容老版本请求,新版本去除enable_tcp参数并新增tcp_mode参数 + tcp_mode = 1; + } + + auto port = openRtpServer( + allArgs["port"], stream_id, tcp_mode, "::", true, 0, allArgs["only_audio"].as(),true); + if (port == 0) { + throw InvalidArgsException("该stream_id已存在"); + } + // 回复json + val["port"] = port; + }); api_regist("/index/api/connectRtpServer", [](API_ARGS_MAP_ASYNC) { CHECK_SECRET(); diff --git a/server/WebApi.h b/server/WebApi.h index 460d0132..f7ec0cb3 100755 --- a/server/WebApi.h +++ b/server/WebApi.h @@ -239,7 +239,7 @@ void installWebApi(); void unInstallWebApi(); #if defined(ENABLE_RTPPROXY) -uint16_t openRtpServer(uint16_t local_port, const std::string &stream_id, int tcp_mode, const std::string &local_ip, bool re_use_port, uint32_t ssrc, bool only_audio); +uint16_t openRtpServer(uint16_t local_port, const std::string &stream_id, int tcp_mode, const std::string &local_ip, bool re_use_port, uint32_t ssrc, bool only_audio, bool multiplex=false); void connectRtpServer(const std::string &stream_id, const std::string &dst_url, uint16_t dst_port, const std::function &cb); bool closeRtpServer(const std::string &stream_id); #endif diff --git a/src/Rtp/RtpServer.cpp b/src/Rtp/RtpServer.cpp index 34871562..1f71a4a8 100644 --- a/src/Rtp/RtpServer.cpp +++ b/src/Rtp/RtpServer.cpp @@ -156,7 +156,7 @@ private: EventPoller::DelayTask::Ptr _delay_task; }; -void RtpServer::start(uint16_t local_port, const string &stream_id, TcpMode tcp_mode, const char *local_ip, bool re_use_port, uint32_t ssrc, bool only_audio) { +void RtpServer::start(uint16_t local_port, const string &stream_id, TcpMode tcp_mode, const char *local_ip, bool re_use_port, uint32_t ssrc, bool only_audio, bool multiplex) { //创建udp服务器 Socket::Ptr rtp_socket = Socket::createSocket(nullptr, true); Socket::Ptr rtcp_socket = Socket::createSocket(nullptr, true); @@ -195,7 +195,8 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, TcpMode tcp_ //创建udp服务器 UdpServer::Ptr udp_server; RtcpHelper::Ptr helper; - if (!stream_id.empty()) { + //增加了多路复用判断,如果多路复用为true,就走else逻辑,同时保留了原来stream_id为空走else逻辑 + if (!stream_id.empty() && !multiplex) { //指定了流id,那么一个端口一个流(不管是否包含多个ssrc的多个流,绑定rtp源后,会筛选掉ip端口不匹配的流) helper = std::make_shared(std::move(rtcp_socket), stream_id); helper->startRtcp(); diff --git a/src/Rtp/RtpServer.h b/src/Rtp/RtpServer.h index 4efce859..71aa88e7 100644 --- a/src/Rtp/RtpServer.h +++ b/src/Rtp/RtpServer.h @@ -42,9 +42,10 @@ public: * @param local_ip 绑定的本地网卡ip * @param re_use_port 是否设置socket为re_use属性 * @param ssrc 指定的ssrc + * @param multiplex 多路复用 */ void start(uint16_t local_port, const std::string &stream_id = "", TcpMode tcp_mode = PASSIVE, - const char *local_ip = "::", bool re_use_port = true, uint32_t ssrc = 0, bool only_audio = false); + const char *local_ip = "::", bool re_use_port = true, uint32_t ssrc = 0, bool only_audio = false, bool multiplex = false); /** * 连接到tcp服务(tcp主动模式) From 7f25138b46d0aef8809742a33586fe0828e592b7 Mon Sep 17 00:00:00 2001 From: waken <33921191+mc373906408@users.noreply.github.com> Date: Thu, 9 Nov 2023 20:36:51 +0800 Subject: [PATCH 30/31] =?UTF-8?q?openRtpServerMultiplex=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E7=BB=9F=E4=B8=80url=E8=B7=AF=E5=BE=84=20(#2963)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/WebApi.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 7833b933..63b4d5e3 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -1182,7 +1182,8 @@ void installWebApi() { //回复json val["port"] = port; }); - api_regist("/media/api/openRtpServerMultiplex", [](API_ARGS_MAP) { + + api_regist("/index/api/openRtpServerMultiplex", [](API_ARGS_MAP) { CHECK_SECRET(); CHECK_ARGS("port", "stream_id"); auto stream_id = allArgs["stream_id"]; From 055fe2cb92dc0c1357dde8aeba6eaf7995c444aa Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Fri, 10 Nov 2023 13:15:00 +0800 Subject: [PATCH 31/31] =?UTF-8?q?=E6=9B=B4=E6=96=B0zltoolkit=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8Dfd=E6=BA=A2=E5=87=BA=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E7=B4=8A=E4=B9=B1bug=20(#2946)?= 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 12c2ec7b..97871cfa 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 12c2ec7b07dce1b6a0543d9979f5c5231f69e828 +Subproject commit 97871cfa78fcd2fae164243a8c653e323385772d