2019-12-05 19:20:12 +08:00
|
|
|
|
/*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
2019-12-06 11:54:10 +08:00
|
|
|
|
*
|
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
|
|
|
|
*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* 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.
|
2019-12-06 11:54:10 +08:00
|
|
|
|
*/
|
2019-12-05 19:20:12 +08:00
|
|
|
|
|
2019-12-06 11:54:10 +08:00
|
|
|
|
#if defined(ENABLE_RTPPROXY)
|
2020-10-24 23:33:13 +08:00
|
|
|
|
#include "GB28181Process.h"
|
2019-12-05 19:20:12 +08:00
|
|
|
|
#include "RtpProcess.h"
|
2020-10-24 23:33:13 +08:00
|
|
|
|
#include "RtpSplitter.h"
|
2019-12-05 19:20:12 +08:00
|
|
|
|
#include "Util/File.h"
|
2020-05-17 18:00:23 +08:00
|
|
|
|
#include "Http/HttpTSPlayer.h"
|
2020-10-24 23:33:13 +08:00
|
|
|
|
|
2020-04-23 16:14:24 +08:00
|
|
|
|
#define RTP_APP_NAME "rtp"
|
2019-12-05 19:20:12 +08:00
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
namespace mediakit {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
static string printAddress(const struct sockaddr *addr) {
|
2020-04-23 16:14:24 +08:00
|
|
|
|
return StrPrinter << SockUtil::inet_ntoa(((struct sockaddr_in *) addr)->sin_addr) << ":" << ntohs(((struct sockaddr_in *) addr)->sin_port);
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-07 10:01:12 +08:00
|
|
|
|
RtpProcess::RtpProcess(const string &stream_id) {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
_media_info._schema = RTP_APP_NAME;
|
|
|
|
|
_media_info._vhost = DEFAULT_VHOST;
|
|
|
|
|
_media_info._app = RTP_APP_NAME;
|
2020-07-07 10:01:12 +08:00
|
|
|
|
_media_info._streamid = stream_id;
|
2020-12-25 16:05:38 +08:00
|
|
|
|
_stop_rtp_check.store(false);
|
2019-12-05 19:20:12 +08:00
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir);
|
2019-12-05 19:20:12 +08:00
|
|
|
|
{
|
2020-04-24 12:39:22 +08:00
|
|
|
|
FILE *fp = !dump_dir.empty() ? File::create_file(File::absolutePath(_media_info._streamid + ".rtp", dump_dir).data(), "wb") : nullptr;
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (fp) {
|
|
|
|
|
_save_file_rtp.reset(fp, [](FILE *fp) {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
fclose(fp);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2020-04-24 12:39:22 +08:00
|
|
|
|
FILE *fp = !dump_dir.empty() ? File::create_file(File::absolutePath(_media_info._streamid + ".video", dump_dir).data(), "wb") : nullptr;
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (fp) {
|
|
|
|
|
_save_file_video.reset(fp, [](FILE *fp) {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
fclose(fp);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtpProcess::~RtpProcess() {
|
2020-10-24 23:33:13 +08:00
|
|
|
|
uint64_t duration = (_last_frame_time.createdTime() - _last_frame_time.elapsedTime()) / 1000;
|
2020-04-23 23:18:24 +08:00
|
|
|
|
WarnP(this) << "RTP推流器("
|
|
|
|
|
<< _media_info._vhost << "/"
|
|
|
|
|
<< _media_info._app << "/"
|
|
|
|
|
<< _media_info._streamid
|
|
|
|
|
<< ")断开,耗时(s):" << duration;
|
|
|
|
|
|
|
|
|
|
//流量统计事件广播
|
|
|
|
|
GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
|
2020-04-24 12:39:22 +08:00
|
|
|
|
if (_total_bytes > iFlowThreshold * 1024) {
|
|
|
|
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _total_bytes, duration, false, static_cast<SockInfo &>(*this));
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
2020-06-28 15:21:41 +08:00
|
|
|
|
|
|
|
|
|
if (_addr) {
|
|
|
|
|
delete _addr;
|
|
|
|
|
_addr = nullptr;
|
|
|
|
|
}
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
bool RtpProcess::inputRtp(bool is_udp, const Socket::Ptr &sock, const char *data, int len, const struct sockaddr *addr, uint32_t *dts_out) {
|
|
|
|
|
GET_CONFIG(bool, check_source, RtpProxy::kCheckSource);
|
2019-12-05 19:20:12 +08:00
|
|
|
|
//检查源是否合法
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (!_addr) {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
_addr = new struct sockaddr;
|
2020-04-23 23:33:58 +08:00
|
|
|
|
_sock = sock;
|
2020-10-24 23:33:13 +08:00
|
|
|
|
memcpy(_addr, addr, sizeof(struct sockaddr));
|
2020-04-23 23:18:24 +08:00
|
|
|
|
DebugP(this) << "bind to address:" << printAddress(_addr);
|
|
|
|
|
//推流鉴权
|
|
|
|
|
emitOnPublish();
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (!_muxer) {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
//无权限推流
|
|
|
|
|
return false;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (check_source && memcmp(_addr, addr, sizeof(struct sockaddr)) != 0) {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
DebugP(this) << "address dismatch:" << printAddress(addr) << " != " << printAddress(_addr);
|
2019-12-05 19:20:12 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
_total_bytes += len;
|
|
|
|
|
if (_save_file_rtp) {
|
|
|
|
|
uint16_t size = len;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
size = htons(size);
|
|
|
|
|
fwrite((uint8_t *) &size, 2, 1, _save_file_rtp.get());
|
2020-10-24 23:33:13 +08:00
|
|
|
|
fwrite((uint8_t *) data, len, 1, _save_file_rtp.get());
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (!_process) {
|
|
|
|
|
_process = std::make_shared<GB28181Process>(_media_info, this);
|
2020-03-06 13:00:06 +08:00
|
|
|
|
}
|
2020-11-14 23:11:28 +08:00
|
|
|
|
|
|
|
|
|
GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir);
|
|
|
|
|
if (!_muxer->isEnabled() && !dts_out && dump_dir.empty()) {
|
|
|
|
|
//无人访问、且不取时间戳、不导出调试文件时,我们可以直接丢弃数据
|
|
|
|
|
_last_frame_time.resetTime();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
bool ret = _process ? _process->inputRtp(is_udp, data, len) : false;
|
|
|
|
|
if (dts_out) {
|
|
|
|
|
*dts_out = _dts;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
2020-10-24 23:33:13 +08:00
|
|
|
|
return ret;
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
void RtpProcess::inputFrame(const Frame::Ptr &frame) {
|
|
|
|
|
_last_frame_time.resetTime();
|
2020-05-17 18:00:23 +08:00
|
|
|
|
_dts = frame->dts();
|
|
|
|
|
if (_save_file_video && frame->getTrackType() == TrackVideo) {
|
|
|
|
|
fwrite((uint8_t *) frame->data(), frame->size(), 1, _save_file_video.get());
|
2020-02-25 19:00:22 +08:00
|
|
|
|
}
|
2020-05-17 18:00:23 +08:00
|
|
|
|
_muxer->inputFrame(frame);
|
2020-02-25 19:00:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
void RtpProcess::addTrack(const Track::Ptr &track) {
|
2020-05-17 18:00:23 +08:00
|
|
|
|
_muxer->addTrack(track);
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-29 09:38:04 +08:00
|
|
|
|
void RtpProcess::addTrackCompleted() {
|
|
|
|
|
_muxer->addTrackCompleted();
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-05 19:20:12 +08:00
|
|
|
|
bool RtpProcess::alive() {
|
2020-12-27 21:21:31 +08:00
|
|
|
|
if (_stop_rtp_check.load()) {
|
2020-12-25 16:05:38 +08:00
|
|
|
|
return true;
|
2020-12-27 21:21:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
GET_CONFIG(int, timeoutSec, RtpProxy::kTimeoutSec)
|
|
|
|
|
if (_last_frame_time.elapsedTime() / 1000 < timeoutSec) {
|
2019-12-05 19:20:12 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-25 16:05:38 +08:00
|
|
|
|
void RtpProcess::setStopCheckRtp(bool is_check){
|
|
|
|
|
_stop_rtp_check = is_check;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
void RtpProcess::onDetach() {
|
|
|
|
|
if (_on_detach) {
|
2020-07-08 10:25:30 +08:00
|
|
|
|
_on_detach();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RtpProcess::setOnDetach(const function<void()> &cb) {
|
|
|
|
|
_on_detach = cb;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-24 12:39:22 +08:00
|
|
|
|
string RtpProcess::get_peer_ip() {
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (_addr) {
|
2020-04-24 12:39:22 +08:00
|
|
|
|
return SockUtil::inet_ntoa(((struct sockaddr_in *) _addr)->sin_addr);
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
2020-04-24 12:39:22 +08:00
|
|
|
|
return "0.0.0.0";
|
2019-12-05 19:20:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t RtpProcess::get_peer_port() {
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (!_addr) {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2019-12-05 19:20:12 +08:00
|
|
|
|
return ntohs(((struct sockaddr_in *) _addr)->sin_port);
|
|
|
|
|
}
|
2019-12-06 11:54:10 +08:00
|
|
|
|
|
2020-04-24 12:39:22 +08:00
|
|
|
|
string RtpProcess::get_local_ip() {
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (_sock) {
|
2020-04-24 12:39:22 +08:00
|
|
|
|
return _sock->get_local_ip();
|
2020-04-23 23:30:24 +08:00
|
|
|
|
}
|
2020-04-24 12:39:22 +08:00
|
|
|
|
return "0.0.0.0";
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t RtpProcess::get_local_port() {
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (_sock) {
|
|
|
|
|
return _sock->get_local_port();
|
2020-04-23 23:30:24 +08:00
|
|
|
|
}
|
2020-04-23 23:18:24 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
string RtpProcess::getIdentifier() const {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
return _media_info._streamid;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
int RtpProcess::totalReaderCount() {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
return _muxer ? _muxer->totalReaderCount() : 0;
|
2020-02-28 16:25:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:33:13 +08:00
|
|
|
|
void RtpProcess::setListener(const std::weak_ptr<MediaSourceEvent> &listener) {
|
2020-10-24 23:34:22 +08:00
|
|
|
|
setDelegate(listener);
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RtpProcess::emitOnPublish() {
|
|
|
|
|
weak_ptr<RtpProcess> weak_self = shared_from_this();
|
2020-09-12 19:09:56 +08:00
|
|
|
|
Broadcast::PublishAuthInvoker invoker = [weak_self](const string &err, bool enableHls, bool enableMP4) {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
auto strongSelf = weak_self.lock();
|
|
|
|
|
if (!strongSelf) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (err.empty()) {
|
|
|
|
|
strongSelf->_muxer = std::make_shared<MultiMediaSourceMuxer>(strongSelf->_media_info._vhost,
|
|
|
|
|
strongSelf->_media_info._app,
|
|
|
|
|
strongSelf->_media_info._streamid, 0,
|
2020-09-12 19:09:56 +08:00
|
|
|
|
true, true, enableHls, enableMP4);
|
2020-10-24 23:34:22 +08:00
|
|
|
|
strongSelf->_muxer->setMediaListener(strongSelf);
|
2020-04-23 23:18:24 +08:00
|
|
|
|
InfoP(strongSelf) << "允许RTP推流";
|
|
|
|
|
} else {
|
|
|
|
|
WarnP(strongSelf) << "禁止RTP推流:" << err;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//触发推流鉴权事件
|
|
|
|
|
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish, _media_info, invoker, static_cast<SockInfo &>(*this));
|
2020-10-24 23:33:13 +08:00
|
|
|
|
if (!flag) {
|
2020-04-23 23:18:24 +08:00
|
|
|
|
//该事件无人监听,默认不鉴权
|
|
|
|
|
GET_CONFIG(bool, toHls, General::kPublishToHls);
|
|
|
|
|
GET_CONFIG(bool, toMP4, General::kPublishToMP4);
|
2020-09-12 19:09:56 +08:00
|
|
|
|
invoker("", toHls, toMP4);
|
2020-04-23 23:18:24 +08:00
|
|
|
|
}
|
2020-02-28 16:25:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-24 23:34:22 +08:00
|
|
|
|
MediaOriginType RtpProcess::getOriginType(MediaSource &sender) const{
|
|
|
|
|
return MediaOriginType::rtp_push;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string RtpProcess::getOriginUrl(MediaSource &sender) const {
|
|
|
|
|
return _media_info._full_url;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<SockInfo> RtpProcess::getOriginSock(MediaSource &sender) const{
|
|
|
|
|
return const_cast<RtpProcess *>(this)->shared_from_this();
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-06 11:54:10 +08:00
|
|
|
|
}//namespace mediakit
|
|
|
|
|
#endif//defined(ENABLE_RTPPROXY)
|