From 61625f458fee8984daab63d2fb393b42bd7ad8f7 Mon Sep 17 00:00:00 2001 From: xgj Date: Fri, 1 Apr 2022 18:28:09 +0800 Subject: [PATCH 1/3] for webapi startsendrtp can send raw rtp --- server/WebApi.cpp | 7 +- src/Common/MediaSource.cpp | 10 +-- src/Common/MediaSource.h | 6 +- src/Common/MultiMediaSourceMuxer.cpp | 4 +- src/Common/MultiMediaSourceMuxer.h | 2 +- src/Rtp/RawEncoder.cpp | 102 +++++++++++++++++++++++++++ src/Rtp/RawEncoder.h | 59 ++++++++++++++++ src/Rtp/RtpCache.cpp | 6 ++ src/Rtp/RtpCache.h | 11 +++ src/Rtp/RtpSender.cpp | 12 ++-- src/Rtp/RtpSender.h | 4 +- 11 files changed, 205 insertions(+), 18 deletions(-) create mode 100644 src/Rtp/RawEncoder.cpp create mode 100644 src/Rtp/RawEncoder.h diff --git a/server/WebApi.cpp b/server/WebApi.cpp index b44309e6..ebe24d03 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -1104,7 +1104,10 @@ void installWebApi() { if (!src) { throw ApiRetException("该媒体流不存在", API::OtherFailed); } - + uint8_t pt = allArgs["pt"].empty() ? 96 : allArgs["pt"].as(); + bool use_ps = allArgs["use_ps"].empty() ? true : allArgs["use_ps"].as(); + bool only_audio = allArgs["only_audio"].empty() ? true : allArgs["only_audio"].as(); + //src_port为空时,则随机本地端口 src->startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException &ex) mutable{ if (ex) { @@ -1113,7 +1116,7 @@ void installWebApi() { } val["local_port"] = local_port; invoker(200, headerOut, val.toStyledString()); - }); + },pt,use_ps,only_audio); }); api_regist("/index/api/stopSendRtp",[](API_ARGS_MAP){ diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp index 3de3291f..8245fae1 100644 --- a/src/Common/MediaSource.cpp +++ b/src/Common/MediaSource.cpp @@ -237,13 +237,13 @@ bool MediaSource::isRecording(Recorder::type type){ return listener->isRecording(*this, type); } -void MediaSource::startSendRtp(const string &dst_url, uint16_t dst_port, const string &ssrc, bool is_udp, uint16_t src_port, const function &cb){ +void MediaSource::startSendRtp(const string &dst_url, uint16_t dst_port, const string &ssrc, bool is_udp, uint16_t src_port, const function &cb,uint8_t pt, bool use_ps,bool only_audio){ auto listener = _listener.lock(); if (!listener) { cb(0, SockException(Err_other, "尚未设置事件监听器")); return; } - return listener->startSendRtp(*this, dst_url, dst_port, ssrc, is_udp, src_port, cb); + return listener->startSendRtp(*this, dst_url, dst_port, ssrc, is_udp, src_port, cb, use_ps, only_audio); } bool MediaSource::stopSendRtp(const string &ssrc) { @@ -720,12 +720,12 @@ vector MediaSourceEventInterceptor::getMediaTracks(MediaSource &send return listener->getMediaTracks(sender, trackReady); } -void MediaSourceEventInterceptor::startSendRtp(MediaSource &sender, const string &dst_url, uint16_t dst_port, const string &ssrc, bool is_udp, uint16_t src_port, const function &cb){ +void MediaSourceEventInterceptor::startSendRtp(MediaSource &sender, const string &dst_url, uint16_t dst_port, const string &ssrc, bool is_udp, uint16_t src_port, const function &cb, uint8_t pt, bool use_ps,bool only_audio ){ auto listener = _listener.lock(); if (listener) { - listener->startSendRtp(sender, dst_url, dst_port, ssrc, is_udp, src_port, cb); + listener->startSendRtp(sender, dst_url, dst_port, ssrc, is_udp, src_port, cb, pt, use_ps, only_audio); } else { - MediaSourceEvent::startSendRtp(sender, dst_url, dst_port, ssrc, is_udp, src_port, cb); + MediaSourceEvent::startSendRtp(sender, dst_url, dst_port, ssrc, is_udp, src_port, cb, pt, use_ps, only_audio); } } diff --git a/src/Common/MediaSource.h b/src/Common/MediaSource.h index 7a5b2ebb..94d1c11a 100644 --- a/src/Common/MediaSource.h +++ b/src/Common/MediaSource.h @@ -86,7 +86,7 @@ public: // 获取所有track相关信息 virtual std::vector getMediaTracks(MediaSource &sender, bool trackReady = true) const { return std::vector(); }; // 开始发送ps-rtp - virtual void startSendRtp(MediaSource &sender, const std::string &dst_url, uint16_t dst_port, const std::string &ssrc, bool is_udp, uint16_t src_port, const std::function &cb) { cb(0, toolkit::SockException(toolkit::Err_other, "not implemented"));}; + virtual void startSendRtp(MediaSource &sender, const std::string &dst_url, uint16_t dst_port, const std::string &ssrc, bool is_udp, uint16_t src_port, const std::function &cb, uint8_t pt=96, bool use_ps = true,bool only_audio = true) { cb(0, toolkit::SockException(toolkit::Err_other, "not implemented"));}; // 停止发送ps-rtp virtual bool stopSendRtp(MediaSource &sender, const std::string &ssrc) {return false; } @@ -117,7 +117,7 @@ public: bool setupRecord(MediaSource &sender, Recorder::type type, bool start, const std::string &custom_path, size_t max_second) override; bool isRecording(MediaSource &sender, Recorder::type type) override; std::vector getMediaTracks(MediaSource &sender, bool trackReady = true) const override; - void startSendRtp(MediaSource &sender, const std::string &dst_url, uint16_t dst_port, const std::string &ssrc, bool is_udp, uint16_t src_port, const std::function &cb) override; + void startSendRtp(MediaSource &sender, const std::string &dst_url, uint16_t dst_port, const std::string &ssrc, bool is_udp, uint16_t src_port, const std::function &cb, uint8_t pt=96, bool use_ps = true,bool only_audio = true) override; bool stopSendRtp(MediaSource &sender, const std::string &ssrc) override; private: @@ -269,7 +269,7 @@ public: // 获取录制状态 bool isRecording(Recorder::type type); // 开始发送ps-rtp - void startSendRtp(const std::string &dst_url, uint16_t dst_port, const std::string &ssrc, bool is_udp, uint16_t src_port, const std::function &cb); + void startSendRtp(const std::string &dst_url, uint16_t dst_port, const std::string &ssrc, bool is_udp, uint16_t src_port, const std::function &cb , uint8_t pt = 96, bool use_ps = true,bool only_audio = true); // 停止发送ps-rtp bool stopSendRtp(const std::string &ssrc); diff --git a/src/Common/MultiMediaSourceMuxer.cpp b/src/Common/MultiMediaSourceMuxer.cpp index 33902a78..028a765d 100644 --- a/src/Common/MultiMediaSourceMuxer.cpp +++ b/src/Common/MultiMediaSourceMuxer.cpp @@ -213,9 +213,9 @@ bool MultiMediaSourceMuxer::isRecording(MediaSource &sender, Recorder::type type } } -void MultiMediaSourceMuxer::startSendRtp(MediaSource &, const string &dst_url, uint16_t dst_port, const string &ssrc, bool is_udp, uint16_t src_port, const function &cb){ +void MultiMediaSourceMuxer::startSendRtp(MediaSource &, const string &dst_url, uint16_t dst_port, const string &ssrc, bool is_udp, uint16_t src_port, const function &cb ,uint8_t pt, bool use_ps,bool only_audio){ #if defined(ENABLE_RTPPROXY) - RtpSender::Ptr rtp_sender = std::make_shared(atoi(ssrc.data())); + RtpSender::Ptr rtp_sender = std::make_shared(atoi(ssrc.data()),pt,use_ps,only_audio); weak_ptr weak_self = shared_from_this(); rtp_sender->startSend(dst_url, dst_port, is_udp, src_port, [weak_self, rtp_sender, cb, ssrc](uint16_t local_port, const SockException &ex) { cb(local_port, ex); diff --git a/src/Common/MultiMediaSourceMuxer.h b/src/Common/MultiMediaSourceMuxer.h index 8e640730..48588953 100644 --- a/src/Common/MultiMediaSourceMuxer.h +++ b/src/Common/MultiMediaSourceMuxer.h @@ -134,7 +134,7 @@ public: * @param is_udp 是否为udp * @param cb 启动成功或失败回调 */ - void startSendRtp(MediaSource &sender, const std::string &dst_url, uint16_t dst_port, const std::string &ssrc, bool is_udp, uint16_t src_port, const std::function &cb) override; + void startSendRtp(MediaSource &sender, const std::string &dst_url, uint16_t dst_port, const std::string &ssrc, bool is_udp, uint16_t src_port, const std::function &cb ,uint8_t pt = 96, bool use_ps = true,bool only_audio = true) override; /** * 停止ps-rtp发送 diff --git a/src/Rtp/RawEncoder.cpp b/src/Rtp/RawEncoder.cpp new file mode 100644 index 00000000..9f560c83 --- /dev/null +++ b/src/Rtp/RawEncoder.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xia-chu/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 "RawEncoder.h" +#include "Extension/H264Rtp.h" +#include "Extension/AACRtp.h" +#include "Extension/H265Rtp.h" +#include "Extension/CommonRtp.h" +#include "Extension/G711Rtp.h" +#include "Rtsp/RtspMuxer.h" + +using namespace toolkit; + +namespace mediakit{ + +RawEncoderImp::RawEncoderImp(uint32_t ssrc, uint8_t payload_type,bool sendAudio):_ssrc(ssrc),_payload_type(payload_type),_sendAudio(sendAudio) { + +} + +RawEncoderImp::~RawEncoderImp() { + InfoL << this << " " << printSSRC(_ssrc); +} + +bool RawEncoderImp::addTrack(const Track::Ptr &track){ + if(_sendAudio && track->getTrackType() == TrackType::TrackAudio && !_rtp_encoder){// audio + _rtp_encoder = createRtpEncoder(track); + _rtp_encoder->setRtpRing(std::make_shared()); + _rtp_encoder->getRtpRing()->setDelegate(std::make_shared([this](RtpPacket::Ptr rtp, bool is_key){ + onRTP(std::move(rtp)); + })); + return true; + } + + if(!_sendAudio && track->getTrackType()==TrackType::TrackVideo && !_rtp_encoder){ + _rtp_encoder = createRtpEncoder(track); + _rtp_encoder->setRtpRing(std::make_shared()); + _rtp_encoder->getRtpRing()->setDelegate(std::make_shared([this](RtpPacket::Ptr rtp, bool is_key){ + onRTP(std::move(rtp)); + })); + return true; + } + return true; +} + + +void RawEncoderImp::resetTracks(){ + return; +} + + +bool RawEncoderImp::inputFrame(const Frame::Ptr &frame){ + if(frame->getTrackType() == TrackType::TrackAudio && _sendAudio && _rtp_encoder){ + _rtp_encoder->inputFrame(frame); + } + + if(frame->getTrackType() == TrackType::TrackVideo && !_sendAudio && _rtp_encoder){ + _rtp_encoder->inputFrame(frame); + } + return true; +} + +RtpCodec::Ptr RawEncoderImp::createRtpEncoder(const Track::Ptr &track){ + GET_CONFIG(uint32_t,audio_mtu,Rtp::kAudioMtuSize); + GET_CONFIG(uint32_t,video_mtu,Rtp::kVideoMtuSize); + auto codec_id = track->getCodecId(); + uint32_t sample_rate = 90000; + int channels = 1; + auto mtu = (track->getTrackType() == TrackVideo ? video_mtu : audio_mtu); + if(track->getTrackType() == TrackType::TrackAudio){ + AudioTrack::Ptr audioTrack = std::dynamic_pointer_cast(track); + sample_rate = audioTrack->getAudioSampleRate(); + channels = audioTrack->getAudioChannel(); + } + switch (codec_id){ + case CodecH264 : return std::make_shared(_ssrc, mtu, sample_rate, _payload_type, 0); + case CodecH265 : return std::make_shared(_ssrc, mtu, sample_rate, _payload_type, 0); + case CodecAAC : return std::make_shared(_ssrc, mtu, sample_rate, _payload_type, 0); + case CodecL16 : + case CodecOpus : return std::make_shared(codec_id, _ssrc, mtu, sample_rate, _payload_type, 0); + case CodecG711A : + case CodecG711U : { + if (_payload_type == Rtsp::PT_PCMA || _payload_type == Rtsp::PT_PCMU) { + return std::make_shared(codec_id, _ssrc, mtu, sample_rate, _payload_type, 0, channels); + } + return std::make_shared(codec_id, _ssrc, mtu, sample_rate, _payload_type, 0); + } + default : WarnL << "暂不支持该CodecId:" << codec_id; return nullptr; + } +} + +}//namespace mediakit + +#endif//defined(ENABLE_RTPPROXY) diff --git a/src/Rtp/RawEncoder.h b/src/Rtp/RawEncoder.h new file mode 100644 index 00000000..82dbb1f0 --- /dev/null +++ b/src/Rtp/RawEncoder.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. + * + * This file is part of ZLMediaKit(https://github.com/xia-chu/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_RAWENCODER_H +#define ZLMEDIAKIT_RAWENCODER_H + +#if defined(ENABLE_RTPPROXY) + + +#include "Common/MediaSink.h" +#include "Common/Stamp.h" +#include "Extension/CommonRtp.h" + +namespace mediakit{ + +class RawEncoderImp : public MediaSinkInterface{ +public: + RawEncoderImp(uint32_t ssrc, uint8_t payload_type = 96, bool sendAudio = true); + ~RawEncoderImp() override; + + /** + * 添加音视频轨道 + */ + bool addTrack(const Track::Ptr &track) override; + + + /** + * 重置音视频轨道 + */ + void resetTracks() override; + + /** + * 输入帧数据 + */ + bool inputFrame(const Frame::Ptr &frame) override; + +protected: + //rtp打包后回调 + virtual void onRTP(toolkit::Buffer::Ptr rtp) = 0; +private: + RtpCodec::Ptr createRtpEncoder(const Track::Ptr &track); + + uint32_t _ssrc; + uint8_t _payload_type; + bool _sendAudio; + RtpCodec::Ptr _rtp_encoder; +}; + +}//namespace mediakit + +#endif //ENABLE_RTPPROXY +#endif //ZLMEDIAKIT_RAWENCODER_H diff --git a/src/Rtp/RtpCache.cpp b/src/Rtp/RtpCache.cpp index d65cc049..08ecba22 100644 --- a/src/Rtp/RtpCache.cpp +++ b/src/Rtp/RtpCache.cpp @@ -34,6 +34,12 @@ void RtpCachePS::onRTP(Buffer::Ptr buffer) { input(stamp, std::move(buffer)); } +void RtpCacheRaw::onRTP(Buffer::Ptr buffer) { + auto rtp = std::static_pointer_cast(buffer); + auto stamp = rtp->getStampMS(); + input(stamp, std::move(buffer)); +} + }//namespace mediakit #endif//#if defined(ENABLE_RTPPROXY) \ No newline at end of file diff --git a/src/Rtp/RtpCache.h b/src/Rtp/RtpCache.h index 474fbbc0..fa9da2ae 100644 --- a/src/Rtp/RtpCache.h +++ b/src/Rtp/RtpCache.h @@ -14,6 +14,7 @@ #if defined(ENABLE_RTPPROXY) #include "PSEncoder.h" +#include "RawEncoder.h" #include "Extension/CommonRtp.h" namespace mediakit{ @@ -47,6 +48,16 @@ protected: void onRTP(toolkit::Buffer::Ptr rtp) override; }; + +class RtpCacheRaw : public RtpCache, public RawEncoderImp{ +public: + RtpCacheRaw(onFlushed cb, uint32_t ssrc, uint8_t payload_type = 96,bool sendAudio = true) : RtpCache(std::move(cb)), RawEncoderImp(ssrc, payload_type,sendAudio) {}; + ~RtpCacheRaw() override = default; + +protected: + void onRTP(toolkit::Buffer::Ptr rtp) override; +}; + }//namespace mediakit #endif//ENABLE_RTPPROXY #endif //ZLMEDIAKIT_RTPCACHE_H diff --git a/src/Rtp/RtpSender.cpp b/src/Rtp/RtpSender.cpp index d808f33b..5d93275f 100644 --- a/src/Rtp/RtpSender.cpp +++ b/src/Rtp/RtpSender.cpp @@ -19,11 +19,15 @@ using namespace toolkit; namespace mediakit{ -RtpSender::RtpSender(uint32_t ssrc, uint8_t payload_type) { +RtpSender::RtpSender(uint32_t ssrc, uint8_t payload_type,bool use_ps, bool only_audio) { _poller = EventPollerPool::Instance().getPoller(); - _interface = std::make_shared([this](std::shared_ptr > list) { - onFlushRtpList(std::move(list)); - }, ssrc, payload_type); + if (use_ps) { + _interface = std::make_shared( + [this](std::shared_ptr> list) { onFlushRtpList(std::move(list)); }, ssrc, payload_type); + }else{ + _interface = std::make_shared( + [this](std::shared_ptr> list) { onFlushRtpList(std::move(list)); }, ssrc, payload_type,only_audio); + } } RtpSender::~RtpSender() {} diff --git a/src/Rtp/RtpSender.h b/src/Rtp/RtpSender.h index b2391ab8..3eee7d69 100644 --- a/src/Rtp/RtpSender.h +++ b/src/Rtp/RtpSender.h @@ -27,8 +27,10 @@ public: * 构造函数,创建GB28181 RTP发送客户端 * @param ssrc rtp的ssrc * @param payload_type 国标中ps-rtp的pt一般为96 + * @param use_ps 是否打包为PS然后发送 + * @param only_audio use_ps 为false 时有效,指定发送音频还是视频 */ - RtpSender(uint32_t ssrc, uint8_t payload_type = 96); + RtpSender(uint32_t ssrc, uint8_t payload_type = 96,bool use_ps = true,bool only_audio = true); /** * 开始发送ps-rtp包 From 9d532cf16b020a6bbc5b35e2671ac0fd80f379d5 Mon Sep 17 00:00:00 2001 From: xgj Date: Fri, 1 Apr 2022 19:12:37 +0800 Subject: [PATCH 2/3] fix startsendrtp pt error --- server/WebApi.cpp | 2 +- src/Common/MediaSource.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index ebe24d03..63d8816e 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -1107,7 +1107,7 @@ void installWebApi() { uint8_t pt = allArgs["pt"].empty() ? 96 : allArgs["pt"].as(); bool use_ps = allArgs["use_ps"].empty() ? true : allArgs["use_ps"].as(); bool only_audio = allArgs["only_audio"].empty() ? true : allArgs["only_audio"].as(); - + TraceL << "pt "<startSendRtp(allArgs["dst_url"], allArgs["dst_port"], allArgs["ssrc"], allArgs["is_udp"], allArgs["src_port"], [val, headerOut, invoker](uint16_t local_port, const SockException &ex) mutable{ if (ex) { diff --git a/src/Common/MediaSource.cpp b/src/Common/MediaSource.cpp index 8245fae1..8c50f3b0 100644 --- a/src/Common/MediaSource.cpp +++ b/src/Common/MediaSource.cpp @@ -243,7 +243,7 @@ void MediaSource::startSendRtp(const string &dst_url, uint16_t dst_port, const s cb(0, SockException(Err_other, "尚未设置事件监听器")); return; } - return listener->startSendRtp(*this, dst_url, dst_port, ssrc, is_udp, src_port, cb, use_ps, only_audio); + return listener->startSendRtp(*this, dst_url, dst_port, ssrc, is_udp, src_port, cb, pt, use_ps, only_audio); } bool MediaSource::stopSendRtp(const string &ssrc) { From 29ceddd23df645a9af851b9f4df349259b4c19f5 Mon Sep 17 00:00:00 2001 From: xgj Date: Fri, 1 Apr 2022 19:15:35 +0800 Subject: [PATCH 3/3] fix startsendrtp pt error --- server/WebApi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/WebApi.cpp b/server/WebApi.cpp index 63d8816e..4bf7a9fb 100755 --- a/server/WebApi.cpp +++ b/server/WebApi.cpp @@ -1104,7 +1104,7 @@ void installWebApi() { if (!src) { throw ApiRetException("该媒体流不存在", API::OtherFailed); } - uint8_t pt = allArgs["pt"].empty() ? 96 : allArgs["pt"].as(); + uint8_t pt = allArgs["pt"].empty() ? 96 : allArgs["pt"].as(); bool use_ps = allArgs["use_ps"].empty() ? true : allArgs["use_ps"].as(); bool only_audio = allArgs["only_audio"].empty() ? true : allArgs["only_audio"].as(); TraceL << "pt "<