Merge branch 'ZLMediaKit:master' into master

This commit is contained in:
Dw9 2023-01-06 22:36:36 +08:00 committed by GitHub
commit 7b5391e339
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 120 additions and 93 deletions

@ -1 +1 @@
Subproject commit 357ef885afa5112c8cb873eab21d94d26744c0ab
Subproject commit 51e08ea0cc366ed772e5690f874cebbbeebe591e

View File

@ -64,4 +64,5 @@ WuPeng <wp@zafu.edu.cn>
[custompal](https://github.com/custompal)
[PioLing](https://github.com/PioLing)
[KevinZang](https://github.com/ZSC714725)
[gongluck](https://github.com/gongluck)
[gongluck](https://github.com/gongluck)
[a-ucontrol](https://github.com/a-ucontrol)

View File

@ -50,6 +50,7 @@ option(ENABLE_SERVER "Enable Server" ON)
option(ENABLE_SERVER_LIB "Enable server as android static library" OFF)
option(ENABLE_SRT "Enable SRT" ON)
option(ENABLE_TESTS "Enable Tests" ON)
option(ENABLE_SCTP "Enable SCTP" ON)
option(ENABLE_WEBRTC "Enable WebRTC" ON)
option(ENABLE_X264 "Enable x264" OFF)
option(ENABLE_WEPOLL "Enable wepoll" ON)

View File

@ -80,7 +80,7 @@
- fMP4
- 支持http[s]-fmp4直播
- 支持ws[s]-fmp4直播
- 支持H264/H265/AAC/G711/OPUS编码
- 支持H264/H265/AAC/G711/OPUS/MJPEG编码
- HTTP[S]与WebSocket
- 服务器支持`目录索引生成`,`文件下载`,`表单提交请求`
@ -290,6 +290,7 @@ bash build_docker_images.sh
[PioLing](https://github.com/PioLing)
[KevinZang](https://github.com/ZSC714725)
[gongluck](https://github.com/gongluck)
[a-ucontrol](https://github.com/a-ucontrol)
## 使用案例

View File

@ -293,15 +293,8 @@ h264_pt=98
h265_pt=99
#rtp ps 负载的pt
ps_pt=96
#rtp ts 负载的pt
ts_pt=33
#rtp opus 负载的pt
opus_pt=100
#rtp g711u 负载的pt
g711u_pt=0
#rtp g711a 负载的pt
g711a_pt=8
[rtc]
#rtc播放推流、播放超时时间

View File

@ -317,10 +317,7 @@ const string kPortRange = RTP_PROXY_FIELD "port_range";
const string kH264PT = RTP_PROXY_FIELD "h264_pt";
const string kH265PT = RTP_PROXY_FIELD "h265_pt";
const string kPSPT = RTP_PROXY_FIELD "ps_pt";
const string kTSPT = RTP_PROXY_FIELD "ts_pt";
const string kOpusPT = RTP_PROXY_FIELD "opus_pt";
const string kG711UPT = RTP_PROXY_FIELD "g711u_pt";
const string kG711APT = RTP_PROXY_FIELD "g711a_pt";
static onceToken token([]() {
mINI::Instance()[kDumpDir] = "";
@ -329,10 +326,7 @@ static onceToken token([]() {
mINI::Instance()[kH264PT] = 98;
mINI::Instance()[kH265PT] = 99;
mINI::Instance()[kPSPT] = 96;
mINI::Instance()[kTSPT] = 33;
mINI::Instance()[kOpusPT] = 100;
mINI::Instance()[kG711UPT] = 0;
mINI::Instance()[kG711APT] = 8;
});
} // namespace RtpProxy

View File

@ -350,14 +350,8 @@ extern const std::string kH264PT;
extern const std::string kH265PT;
// rtp server ps 的pt
extern const std::string kPSPT;
// rtp server ts 的pt
extern const std::string kTSPT;
// rtp server opus 的pt
extern const std::string kOpusPT;
// rtp server g711u 的pt
extern const std::string kG711UPT;
// rtp server g711a 的pt
extern const std::string kG711APT;
} // namespace RtpProxy
/**

View File

@ -8,7 +8,7 @@ namespace mediakit {
bool JPEGTrack::inputFrame(const Frame::Ptr &frame) {
if (!ready()) {
if ((_height & _width) > 0) {
if (_height > 0 && _width > 0) {
if (_tmp == 0) _tmp = frame->dts();
else _fps = 1000.0 / (frame->dts() - _tmp);
} else getVideoResolution((uint8_t*)frame->data(), frame->size());

View File

@ -15,6 +15,7 @@
#include "Extension/G711.h"
#include "Extension/H264.h"
#include "Extension/H265.h"
#include "Extension/JPEG.h"
#include "Common/config.h"
using namespace std;
@ -145,6 +146,7 @@ static uint8_t getObject(CodecId codecId) {
case CodecAAC : return MOV_OBJECT_AAC;
case CodecH264 : return MOV_OBJECT_H264;
case CodecH265 : return MOV_OBJECT_HEVC;
case CodecJPEG : return MOV_OBJECT_JPEG;
default : return 0;
}
}
@ -302,6 +304,28 @@ bool MP4MuxerInterface::addTrack(const Track::Ptr &track) {
break;
}
case CodecJPEG: {
auto jpeg_track = dynamic_pointer_cast<JPEGTrack>(track);
if (!jpeg_track) {
WarnL << "不是JPEG Track";
return false;
}
auto track_id = mp4_writer_add_video(_mov_writter.get(),
mp4_object,
jpeg_track->getVideoWidth(),
jpeg_track->getVideoHeight(),
nullptr,
0);
if (track_id < 0) {
WarnL << "添加JPEG Track失败:" << track_id;
return false;
}
_codec_to_trackid[track->getCodecId()].track_id = track_id;
_have_video = true;
break;
}
default: WarnL << "MP4录制不支持该编码格式:" << track->getCodecName(); return false;
}

View File

@ -13,14 +13,15 @@
#include "Extension/CommonRtp.h"
#include "Extension/Factory.h"
#include "Extension/G711.h"
#include "Extension/H264Rtp.h"
#include "Extension/H264.h"
#include "Extension/H265.h"
#include "Extension/Opus.h"
#include "Extension/JPEG.h"
#include "Http/HttpTSPlayer.h"
#include "Util/File.h"
#include "Common/config.h"
#include "Rtsp/RtpCodec.h"
#include "Rtsp/RtpReceiver.h"
#include "Rtsp/Rtsp.h"
using namespace std;
using namespace toolkit;
@ -76,10 +77,7 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) {
GET_CONFIG(uint32_t, h264_pt, RtpProxy::kH264PT);
GET_CONFIG(uint32_t, h265_pt, RtpProxy::kH265PT);
GET_CONFIG(uint32_t, ps_pt, RtpProxy::kPSPT);
GET_CONFIG(uint32_t, ts_pt, RtpProxy::kTSPT);
GET_CONFIG(uint32_t, opus_pt, RtpProxy::kOpusPT);
GET_CONFIG(uint32_t, g711u_pt, RtpProxy::kG711UPT);
GET_CONFIG(uint32_t, g711a_pt, RtpProxy::kG711APT);
RtpHeader *header = (RtpHeader *)data;
auto pt = header->pt;
@ -89,53 +87,62 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) {
// 防止pt类型太多导致内存溢出
throw std::invalid_argument("rtp pt类型不得超过2种!");
}
if (pt == opus_pt) {
// opus负载
ref = std::make_shared<RtpReceiverImp>(48000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<OpusTrack>();
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
} else if (pt == h265_pt) {
// H265负载
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<H265Track>();
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
} else if (pt == h264_pt) {
// H264负载
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<H264Track>();
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
} else if (pt == g711u_pt || pt == g711a_pt) {
// CodecG711U
// CodecG711A
ref = std::make_shared<RtpReceiverImp>(8000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<G711Track>(pt == g711u_pt ? CodecG711U : CodecG711A, 8000, 1, 16);
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
} else {
if (pt != ts_pt && pt != ps_pt) {
WarnL << "rtp payload type未识别(" << (int)pt << "),已按ts或ps负载处理";
switch (pt) {
case Rtsp::PT_PCMA:
case Rtsp::PT_PCMU: {
// CodecG711U or CodecG711A
ref = std::make_shared<RtpReceiverImp>(8000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<G711Track>(pt == Rtsp::PT_PCMU ? CodecG711U : CodecG711A, 8000, 1, 16);
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
break;
}
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
// ts或ps负载
_rtp_decoder[pt] = std::make_shared<CommonRtpDecoder>(CodecInvalid, 32 * 1024);
// 设置dump目录
GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir);
if (!dump_dir.empty()) {
auto save_path = File::absolutePath(_media_info._streamid + ".mp2", dump_dir);
_save_file_ps.reset(File::create_file(save_path.data(), "wb"), [](FILE *fp) {
if (fp) {
fclose(fp);
case Rtsp::PT_JPEG: {
// mjpeg
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<JPEGTrack>();
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
break;
}
default: {
if (pt == opus_pt) {
// opus负载
ref = std::make_shared<RtpReceiverImp>(48000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<OpusTrack>();
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
} else if (pt == h265_pt) {
// H265负载
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<H265Track>();
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
} else if (pt == h264_pt) {
// H264负载
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = std::make_shared<H264Track>();
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByTrack(track);
} else {
if (pt != Rtsp::PT_MP2T && pt != ps_pt) {
WarnL << "rtp payload type未识别(" << (int)pt << "),已按ts或ps负载处理";
}
});
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
// ts或ps负载
_rtp_decoder[pt] = std::make_shared<CommonRtpDecoder>(CodecInvalid, 32 * 1024);
// 设置dump目录
GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir);
if (!dump_dir.empty()) {
auto save_path = File::absolutePath(_media_info._streamid + ".mpeg", dump_dir);
_save_file_ps.reset(File::create_file(save_path.data(), "wb"), [](FILE *fp) {
if (fp) {
fclose(fp);
}
});
}
}
break;
}
}
// 设置frame回调

View File

@ -99,13 +99,13 @@ RtpMultiCaster::~RtpMultiCaster() {
DebugL;
}
RtpMultiCaster::RtpMultiCaster(SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream) {
RtpMultiCaster::RtpMultiCaster(SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream, uint32_t multicast_ip, uint16_t video_port, uint16_t audio_port) {
auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA, vhost, app, stream));
if (!src) {
auto err = StrPrinter << "未找到媒体源:" << vhost << " " << app << " " << stream << endl;
throw std::runtime_error(err);
}
_multicast_ip = MultiCastAddressMaker::Instance().obtain();
_multicast_ip = (multicast_ip) ? make_shared<uint32_t>(multicast_ip) : MultiCastAddressMaker::Instance().obtain();
if (!_multicast_ip) {
throw std::runtime_error("获取组播地址失败");
}
@ -113,7 +113,7 @@ RtpMultiCaster::RtpMultiCaster(SocketHelper &helper, const string &local_ip, con
for (auto i = 0; i < 2; ++i) {
//创建udp socket, 数组下标为TrackType
_udp_sock[i] = helper.createSocket();
if (!_udp_sock[i]->bindUdpSock(0, local_ip.data())) {
if (!_udp_sock[i]->bindUdpSock((i == TrackVideo) ? video_port : audio_port, local_ip.data())) {
auto err = StrPrinter << "绑定UDP端口失败:" << local_ip << endl;
throw std::runtime_error(err);
}
@ -171,11 +171,11 @@ string RtpMultiCaster::getMultiCasterIP() {
return SockUtil::inet_ntoa(addr);
}
RtpMultiCaster::Ptr RtpMultiCaster::get(SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream) {
static auto on_create = [](SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream){
RtpMultiCaster::Ptr RtpMultiCaster::get(SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream, uint32_t multicast_ip, uint16_t video_port, uint16_t audio_port) {
static auto on_create = [](SocketHelper &helper, const string &local_ip, const string &vhost, const string &app, const string &stream, uint32_t multicast_ip, uint16_t video_port, uint16_t audio_port){
try {
auto poller = helper.getPoller();
auto ret = RtpMultiCaster::Ptr(new RtpMultiCaster(helper, local_ip, vhost, app, stream), [poller](RtpMultiCaster *ptr) {
auto ret = RtpMultiCaster::Ptr(new RtpMultiCaster(helper, local_ip, vhost, app, stream, multicast_ip, video_port, audio_port), [poller](RtpMultiCaster *ptr) {
poller->async([ptr]() {
delete ptr;
});
@ -194,12 +194,12 @@ RtpMultiCaster::Ptr RtpMultiCaster::get(SocketHelper &helper, const string &loca
lock_guard<recursive_mutex> lck(g_mtx);
auto it = g_multi_caster_map.find(strKey);
if (it == g_multi_caster_map.end()) {
return on_create(helper, local_ip, vhost, app, stream);
return on_create(helper, local_ip, vhost, app, stream, multicast_ip, video_port, audio_port);
}
auto ret = it->second.lock();
if (!ret) {
g_multi_caster_map.erase(it);
return on_create(helper, local_ip, vhost, app, stream);
return on_create(helper, local_ip, vhost, app, stream, multicast_ip, video_port, audio_port);
}
return ret;
}

View File

@ -46,14 +46,14 @@ public:
~RtpMultiCaster();
static Ptr get(toolkit::SocketHelper &helper, const std::string &local_ip, const std::string &vhost, const std::string &app, const std::string &stream);
static Ptr get(toolkit::SocketHelper &helper, const std::string &local_ip, const std::string &vhost, const std::string &app, const std::string &stream, uint32_t multicast_ip = 0, uint16_t video_port = 0, uint16_t audio_port = 0);
void setDetachCB(void *listener,const onDetach &cb);
std::string getMultiCasterIP();
uint16_t getMultiCasterPort(TrackType trackType);
private:
RtpMultiCaster(toolkit::SocketHelper &helper, const std::string &local_ip, const std::string &vhost, const std::string &app, const std::string &stream);
RtpMultiCaster(toolkit::SocketHelper &helper, const std::string &local_ip, const std::string &vhost, const std::string &app, const std::string &stream, uint32_t multicast_ip, uint16_t video_port, uint16_t audio_port);
private:
std::recursive_mutex _mtx;

View File

@ -307,7 +307,7 @@ void RtspSession::handleReq_ANNOUNCE(const Parser &parser) {
void RtspSession::handleReq_RECORD(const Parser &parser){
if (_sdp_track.empty() || parser["Session"] != _sessionid) {
send_SessionNotFound();
throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any availabe track when record" : "session not found when record");
throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any available track when record" : "session not found when record");
}
_StrPrinter rtp_info;
@ -721,7 +721,7 @@ void RtspSession::handleReq_Setup(const Parser &parser) {
break;
case Rtsp::RTP_MULTICAST: {
if(!_multicaster){
_multicaster = RtpMultiCaster::get(*this, get_local_ip(), _media_info._vhost, _media_info._app, _media_info._streamid);
_multicaster = RtpMultiCaster::get(*this, get_local_ip(), _media_info._vhost, _media_info._app, _media_info._streamid, _multicast_ip, _multicast_video_port, _multicast_audio_port);
if (!_multicaster) {
send_NotAcceptable();
throw SockException(Err_shutdown, "can not get a available udp multicast socket");

View File

@ -72,6 +72,24 @@ protected:
//收到RTCP包回调
virtual void onRtcpPacket(int track_idx, SdpTrack::Ptr &track, const char *data, size_t len);
//回复客户端
virtual bool sendRtspResponse(const std::string &res_code, const StrCaseMap &header = StrCaseMap(), const std::string &sdp = "", const char *protocol = "RTSP/1.0");
protected:
//url解析后保存的相关信息
MediaInfo _media_info;
////////RTP over udp_multicast////////
//共享的rtp组播对象
RtpMultiCaster::Ptr _multicaster;
//Session号
std::string _sessionid;
uint32_t _multicast_ip = 0;
uint16_t _multicast_video_port = 0;
uint16_t _multicast_audio_port = 0;
private:
//处理options方法,获取服务器能力
void handleReq_Options(const Parser &parser);
@ -130,7 +148,6 @@ private:
void updateRtcpContext(const RtpPacket::Ptr &rtp);
//回复客户端
bool sendRtspResponse(const std::string &res_code, const std::initializer_list<std::string> &header, const std::string &sdp = "", const char *protocol = "RTSP/1.0");
bool sendRtspResponse(const std::string &res_code, const StrCaseMap &header = StrCaseMap(), const std::string &sdp = "", const char *protocol = "RTSP/1.0");
//设置socket标志
void setSocketFlags();
@ -149,8 +166,6 @@ private:
uint64_t _bytes_usage = 0;
//ContentBase
std::string _content_base;
//Session号
std::string _sessionid;
//记录是否需要rtsp专属鉴权防止重复触发事件
std::string _rtsp_realm;
//登录认证
@ -158,8 +173,6 @@ private:
//用于判断客户端是否超时
toolkit::Ticker _alive_ticker;
//url解析后保存的相关信息
MediaInfo _media_info;
//rtsp推流相关绑定的源
RtspMediaSourceImp::Ptr _push_src;
//推流器所有权
@ -180,9 +193,6 @@ private:
toolkit::Socket::Ptr _rtcp_socks[2];
//标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号
std::unordered_set<int> _udp_connected_flags;
////////RTP over udp_multicast////////
//共享的rtp组播对象
RtpMultiCaster::Ptr _multicaster;
////////RTSP over HTTP ////////
//quicktime 请求rtsp会产生两次tcp连接
//一次发送 get 一次发送post需要通过x-sessioncookie关联起来

View File

@ -38,6 +38,7 @@ set(LINK_LIBRARIES ${SRTP_LIBRARIES})
set(COMPILE_DEFINITIONS)
set(INCLUDE_DIRECTORIES)
if(ENABLE_SCTP)
find_package(SCTP QUIET)
if(SCTP_FOUND)
message(STATUS "found library: ${SCTP_INCLUDE_DIRS} ${SCTP_LIBRARIES}")
@ -48,6 +49,7 @@ if(SCTP_FOUND)
list(APPEND LINK_LIBRARIES ${SCTP_LIBRARIES})
message(STATUS "WebRTC datachannel 功能已打开")
endif()
endif()
file(GLOB WEBRTC_SRC_LIST
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp