Compare commits

..

10 Commits

Author SHA1 Message Date
xia-chu
df9f3bd8a9 更新StreamUI
Some checks failed
Android / build (push) Has been cancelled
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
Linux / build (push) Has been cancelled
macOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2025-12-03 15:21:19 +08:00
xia-chu
96c62cdac0 添加submodule 2025-12-03 15:08:08 +08:00
xia-chu
881238fcf3 只拷贝frontend前端页面到www/StreamUI 2025-12-03 15:02:48 +08:00
xia-chu
85524f102b 修复gil线程安全bug 2025-12-03 14:51:51 +08:00
xia-chu
a28b0fc0a4 支持HTTP PUT 2025-12-03 14:49:21 +08:00
xia-chu
b0cf40d281 支持回调http请求到fastapi 2025-12-03 14:44:15 +08:00
xia-chu
b118c5e936 完成配置文件相关python接口 2025-12-02 20:48:10 +08:00
xia-chu
171b354e64 on_flow_report回调到python层 2025-12-02 20:33:21 +08:00
xia-chu
e3b3630f34 on_play鉴权回调到python层 2025-12-02 20:21:41 +08:00
xia-chu
9b37d69bfd 添加python插件 2025-12-02 16:21:40 +08:00
48 changed files with 264 additions and 730 deletions

@ -1 +1 @@
Subproject commit 7302286cf4be39d416b023fec3fd4ca9c54af762
Subproject commit 493d14e1682cc0c79e72b3893dd98f865d45b8e9

View File

@ -44,7 +44,6 @@ option(ENABLE_FFMPEG "Enable FFmpeg" OFF)
option(ENABLE_HLS "Enable HLS" ON)
option(ENABLE_JEMALLOC_STATIC "Enable static linking to the jemalloc library" OFF)
option(ENABLE_JEMALLOC_DUMP "Enable jemalloc to dump malloc statistics" OFF)
option(ENABLE_TCMALLOC "Enable linking to the tcmalloc library" OFF)
option(ENABLE_MEM_DEBUG "Enable Memory Debug" OFF)
option(ENABLE_MP4 "Enable MP4" ON)
option(ENABLE_MSVC_MT "Enable MSVC Mt/Mtd lib" ON)
@ -258,8 +257,8 @@ endif()
# Multiple modules depend on ffmpeg related libraries, unified search
if(ENABLE_FFMPEG)
find_package(PkgConfig QUIET)
# ffmpeg/libavutil
# find ffmpeg/libavutil installed
# ffmpeg/libutil
# find ffmpeg/libutil installed
if(PKG_CONFIG_FOUND)
pkg_check_modules(AVUTIL QUIET IMPORTED_TARGET libavutil)
if(AVUTIL_FOUND)
@ -298,19 +297,8 @@ if(ENABLE_FFMPEG)
endif()
endif()
# ffmpeg/libavfilter
# find ffmpeg/libavfilter installed
if(PKG_CONFIG_FOUND)
pkg_check_modules(AVFILTER QUIET IMPORTED_TARGET libavfilter)
if(AVFILTER_FOUND)
update_cached_list(MK_LINK_LIBRARIES PkgConfig::AVFILTER)
message(STATUS "found library: ${AVFILTER_LIBRARIES}")
endif()
endif()
# ffmpeg/libavutil
# find ffmpeg/libavutil installed
# ffmpeg/libutil
# find ffmpeg/libutil installed
if(NOT AVUTIL_FOUND)
find_package(AVUTIL QUIET)
if(AVUTIL_FOUND)
@ -353,16 +341,7 @@ if(ENABLE_FFMPEG)
endif()
endif()
if(NOT AVFILTER_FOUND)
find_package(AVFILTER QUIET)
if(AVFILTER_FOUND)
include_directories(SYSTEM ${AVFILTER_INCLUDE_DIR})
update_cached_list(MK_LINK_LIBRARIES ${AVFILTER_LIBRARIES})
message(STATUS "found library: ${AVFILTER_LIBRARIES}")
endif()
endif()
if(AVUTIL_FOUND AND AVCODEC_FOUND AND SWSCALE_FOUND AND SWRESAMPLE_FOUND AND AVFILTER_FOUND)
if(AVUTIL_FOUND AND AVCODEC_FOUND AND SWSCALE_FOUND AND SWRESAMPLE_FOUND)
update_cached_list(MK_COMPILE_DEFINITIONS ENABLE_FFMPEG)
update_cached_list(MK_LINK_LIBRARIES ${CMAKE_DL_LIBS})
else()
@ -423,19 +402,6 @@ if(JEMALLOC_FOUND)
endif ()
endif()
# tcmalloc
# find tcmalloc installed
if(ENABLE_TCMALLOC)
find_package(TCMALLOC QUIET)
if(TCMALLOC_FOUND)
message(STATUS "Link with tcmalloc library: ${TCMALLOC_LIBRARIES}")
update_cached_list(MK_LINK_LIBRARIES ${TCMALLOC_LIBRARIES})
else()
set(ENABLE_TCMALLOC OFF)
message(WARNING "tcmalloc 相关功能未找到")
endif()
endif()
# openssl
# find openssl installed
find_package(OpenSSL QUIET)
@ -614,9 +580,6 @@ if (ENABLE_PYTHON)
)
endif ()
if (ENABLE_FFMPEG)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/DejaVuSans.ttf" DESTINATION ${EXECUTABLE_OUTPUT_PATH})
endif ()
# VideoStack
# Copy the default background image used by VideoStack when there is no video stream
if (ENABLE_VIDEOSTACK AND ENABLE_FFMPEG AND ENABLE_X264)

Binary file not shown.

View File

@ -327,7 +327,6 @@ API_EXPORT uint16_t API_CALL mk_ice_server_start(uint16_t port){
iceServer_udp = std::make_shared<UdpServer>();
iceServer_udp->start<IceSession>(port);
iceServer_tcp->start<IceSession>(port);
return 0;
} catch (std::exception &ex) {
iceServer_udp = nullptr;
iceServer_tcp = nullptr;

View File

@ -1,16 +0,0 @@
find_path(AVFILTER_INCLUDE_DIR
NAMES libavfilter/avfilter.h
HINTS ${FFMPEG_PATH_ROOT}
PATH_SUFFIXES include)
find_library(AVFILTER_LIBRARY
NAMES avfilter
HINTS ${FFMPEG_PATH_ROOT}
PATH_SUFFIXES bin lib)
set(AVFILTER_LIBRARIES ${AVFILTER_LIBRARY})
set(AVFILTER_INCLUDE_DIRS ${AVFILTER_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(AVFILTER DEFAULT_MSG AVFILTER_LIBRARY AVFILTER_INCLUDE_DIR)

View File

@ -1,16 +0,0 @@
find_path(Tcmalloc_INCLUDE_DIR
NAMES google/tcmalloc.h
)
find_library(Tcmalloc_LIBRARY
NAMES tcmalloc_minimal tcmalloc
)
set(TCMALLOC_LIBRARIES ${Tcmalloc_LIBRARY})
set(TCMALLOC_INCLUDE_DIRS ${Tcmalloc_INCLUDE_DIR})
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(TCMALLOC
DEFAULT_MSG
TCMALLOC_LIBRARIES TCMALLOC_INCLUDE_DIRS
)

View File

@ -412,14 +412,10 @@ nackMaxMS=3000
nackMaxCount=15
#nack重传频率rtt的倍数
nackIntervalRatio=1.0
#视频nack包中rtp个数减小此值可以让nack包响应更灵敏
#nack包中rtp个数减小此值可以让nack包响应更灵敏
nackRtpSize=8
#音频nack包中rtp个数减小此值可以让nack包响应更灵敏
nackAudioRtpSize=4
#是否尝试过滤 b帧
bfilter=0
# 是否优先采用webrtc over tcp模式
preferred_tcp=0
[srt]
#srt播放推流、播放超时时间,单位秒

View File

@ -57,7 +57,7 @@ public:
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
protected:
aom_av1_t _context {};
aom_av1_t _context = {0};
};
} // namespace mediakit

View File

@ -20,7 +20,7 @@ using namespace toolkit;
namespace mediakit {
Buffer::Ptr G711Track::getExtraData() const {
struct wave_format_t wav {};
struct wave_format_t wav = {0};
wav.wFormatTag = getCodecId() == CodecG711A ? WAVE_FORMAT_ALAW : WAVE_FORMAT_MULAW;
wav.nChannels = getAudioChannel();
wav.nSamplesPerSec = getAudioSampleRate();

View File

@ -28,7 +28,7 @@ void OpusTrack::setExtraData(const uint8_t *data, size_t size) {
}
Buffer::Ptr OpusTrack::getExtraData() const {
struct opus_head_t opus {};
struct opus_head_t opus = { 0 };
opus.version = 1;
opus.channels = getAudioChannel();
opus.input_sample_rate = getAudioSampleRate();

View File

@ -41,7 +41,7 @@ public:
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
private:
webm_vpx_t _vpx {};
webm_vpx_t _vpx = {0};
};
} // namespace mediakit

View File

@ -334,7 +334,7 @@ bool VP8RtpEncoder::inputFrame(const Frame::Ptr &frame) {
bool key = frame->keyFrame();
bool mark = false;
for (size_t pos = 0; pos < len; pos += pdu_size) {
if (static_cast<int>(len - pos) <= pdu_size) {
if (len - pos <= pdu_size) {
pdu_size = len - pos;
mark = true;
}

View File

@ -56,6 +56,9 @@ public:
using Ptr = std::shared_ptr<VP8RtpEncoder>;
bool inputFrame(const Frame::Ptr &frame) override;
private:
uint16_t _pic_id = 0;
};
}//namespace mediakit

View File

@ -41,7 +41,7 @@ public:
toolkit::Buffer::Ptr getExtraData() const override;
void setExtraData(const uint8_t *data, size_t size) override;
private:
webm_vpx_t _vpx {};
webm_vpx_t _vpx = {0};
};
} // namespace mediakit

View File

@ -297,7 +297,7 @@ bool VP9RtpEncoder::inputFrame(const Frame::Ptr &frame) {
int pdu_size = getRtpInfo().getMaxSize() - nheader;
bool mark = false;
for (int pos = 0; pos < len; pos += pdu_size) {
for (size_t pos = 0; pos < len; pos += pdu_size) {
if (len - pos <= pdu_size) {
pdu_size = len - pos;
header[0] |= kEBit;

View File

@ -50,10 +50,6 @@ target_compile_definitions(MediaServer
target_compile_options(MediaServer
PRIVATE ${COMPILE_OPTIONS_DEFAULT})
if(MINGW)
update_cached_list(MK_LINK_LIBRARIES dbghelp)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
target_link_libraries(MediaServer -Wl,--start-group ${MK_LINK_LIBRARIES} -Wl,--end-group)
else()

View File

@ -115,6 +115,8 @@ static void responseApi(int code, const string &msg, const HttpSession::HttpResp
responseApi(res, invoker);
}
static ApiArgsType getAllArgs(const Parser &parser);
static HttpApi toApi(const function<void(API_ARGS_MAP_ASYNC)> &cb) {
return [cb](const Parser &parser, const HttpSession::HttpResponseInvoker &invoker, SockInfo &sender) {
GET_CONFIG(string, charSet, Http::kCharSet);
@ -213,7 +215,7 @@ void api_regist(const string &api_path, const function<void(API_ARGS_STRING_ASYN
// 获取HTTP请求中url参数、content参数 [AUTO-TRANSLATED:d161a1e1]
// Get URL parameters and content parameters from the HTTP request
ApiArgsType getAllArgs(const Parser &parser) {
static ApiArgsType getAllArgs(const Parser &parser) {
ApiArgsType allArgs;
if (parser["Content-Type"].find("application/x-www-form-urlencoded") == 0) {
auto contentArgs = parser.parseArgs(parser.content());
@ -1077,7 +1079,6 @@ void installWebApi() {
}
fillSockInfo(jsession, session.get());
jsession["id"] = id;
jsession["type"] = session->getSock()->sockType() == SockNum::Sock_TCP ? "tcp" : "udp";
jsession["typeid"] = toolkit::demangle(typeid(*session).name());
val["data"].append(jsession);
});

View File

@ -238,7 +238,6 @@ uint16_t openRtpServer(uint16_t local_port, const mediakit::MediaTuple &tuple, i
#endif
Json::Value makeMediaSourceJson(mediakit::MediaSource &media);
ApiArgsType getAllArgs(const mediakit::Parser &parser);
void getStatisticJson(const std::function<void(Json::Value &val)> &cb);
void addStreamProxy(const mediakit::MediaTuple &tuple, const std::string &url, int retry_count,
const mediakit::ProtocolOption &option, int rtp_type, float timeout_sec, const toolkit::mINI &args,

View File

@ -18,7 +18,6 @@
#include "Http/HttpRequester.h"
#include "Network/Session.h"
#include "Rtsp/RtspSession.h"
#include "Player/PlayerProxy.h"
#include "WebHook.h"
#include "WebApi.h"
@ -501,6 +500,10 @@ void installWebHook() {
// 监听rtsp、rtmp源注册或注销事件 [AUTO-TRANSLATED:6396afa8]
// Listen to rtsp, rtmp source registration or deregistration events
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastMediaChanged, [](BroadcastMediaChangedArgs) {
GET_CONFIG(string, hook_stream_changed, Hook::kOnStreamChanged);
if (!hook_enable || hook_stream_changed.empty()) {
return;
}
GET_CONFIG_FUNC(std::set<std::string>, stream_changed_set, Hook::kStreamChangedSchemas, [](const std::string &str) {
std::set<std::string> ret;
auto vec = split(str, "/");
@ -517,15 +520,6 @@ void installWebHook() {
// This protocol registration deregistration event is ignored
return;
}
#if defined(ENABLE_PYTHON)
if (PythonInvoker::Instance().on_media_changed(bRegist, sender)) {
return;
}
#endif
GET_CONFIG(string, hook_stream_changed, Hook::kOnStreamChanged);
if (!hook_enable || hook_stream_changed.empty()) {
return;
}
ArgsType body;
if (bRegist) {
@ -805,14 +799,6 @@ void installWebHook() {
do_http_hook(rtp_server_timeout, body);
});
NoticeCenter::Instance().addListener(&web_hook_tag, Broadcast::kBroadcastPlayerProxyFailed, [](BroadcastPlayerProxyFailedArgs) {
#if defined(ENABLE_PYTHON)
if (PythonInvoker::Instance().on_player_proxy_failed(sender, ex)) {
return;
}
#endif
});
// 汇报服务器重新启动 [AUTO-TRANSLATED:bd7d83df]
// Report server restart
reportServerStarted();

View File

@ -273,16 +273,6 @@ int start_main(int argc,char *argv[]) {
}
#endif //! defined(_WIN32)
// 设置poller线程数和cpu亲和性,该函数必须在使用ZLToolKit网络相关对象之前调用才能生效 [AUTO-TRANSLATED:7f03a1e5]
// Set the number of poller threads and CPU affinity. This function must be called before using ZLToolKit network related objects to take effect.
// 如果需要调用getSnap和addFFmpegSource接口可以关闭cpu亲和性 [AUTO-TRANSLATED:7629f7bc]
// If you need to call the getSnap and addFFmpegSource interfaces, you can turn off CPU affinity
EventPollerPool::setPoolSize(threads);
WorkThreadPool::setPoolSize(threads);
EventPollerPool::enableCpuAffinity(affinity);
WorkThreadPool::enableCpuAffinity(affinity);
// 开启崩溃捕获等 [AUTO-TRANSLATED:9c7c759c]
// Enable crash capture, etc.
System::systemSetup();
@ -339,6 +329,15 @@ int start_main(int argc,char *argv[]) {
uint16_t httpsPort = mINI::Instance()[Http::kSSLPort];
uint16_t rtpPort = mINI::Instance()[RtpProxy::kPort];
// 设置poller线程数和cpu亲和性,该函数必须在使用ZLToolKit网络相关对象之前调用才能生效 [AUTO-TRANSLATED:7f03a1e5]
// Set the number of poller threads and CPU affinity. This function must be called before using ZLToolKit network related objects to take effect.
// 如果需要调用getSnap和addFFmpegSource接口可以关闭cpu亲和性 [AUTO-TRANSLATED:7629f7bc]
// If you need to call the getSnap and addFFmpegSource interfaces, you can turn off CPU affinity
EventPollerPool::setPoolSize(threads);
WorkThreadPool::setPoolSize(threads);
EventPollerPool::enableCpuAffinity(affinity);
// 简单的telnet服务器可用于服务器调试但是不能使用23端口否则telnet上了莫名其妙的现象 [AUTO-TRANSLATED:f9324c6e]
// Simple telnet server, can be used for server debugging, but cannot use port 23, otherwise telnet will have inexplicable phenomena
// 测试方法:telnet 127.0.0.1 9000 [AUTO-TRANSLATED:de0ac883]
@ -509,11 +508,9 @@ int start_main(int argc,char *argv[]) {
#endif
#if defined(ENABLE_PYTHON)
// 初始化python解释器
auto &ref = PythonInvoker::Instance();
auto py_plugin = mINI::Instance()[Python::kPlugin];
if (!py_plugin.empty()) {
ref.load(py_plugin);
PythonInvoker::Instance().load(py_plugin);
}
#endif
sem.wait();
@ -522,10 +519,6 @@ int start_main(int argc,char *argv[]) {
unInstallWebHook();
onProcessExited();
#if defined(ENABLE_PYTHON)
PythonInvoker::release();
#endif
// 休眠1秒再退出防止资源释放顺序错误 [AUTO-TRANSLATED:1b11a74f]
// sleep for 1 second before exiting, to prevent resource release order errors
InfoL << "程序退出中,请等待...";

View File

@ -7,10 +7,7 @@
#include <iostream>
#include <string>
#include <type_traits>
#include "WebApi.h"
#include "WebHook.h"
#include "Util/util.h"
#include "Util/File.h"
#include "Common/Parser.h"
#include "Http/HttpSession.h"
@ -73,11 +70,6 @@ py::dict to_python(const SockInfo &info) {
return jsonToPython(json);
}
template <typename T>
std::shared_ptr<T> to_python2(const T &t) {
return std::shared_ptr<T>(const_cast<T *>(&t), py::nodelete());
}
template <typename T>
T &to_native(const py::capsule &cap) {
static auto name_str = toolkit::demangle(typeid(T).name());
@ -118,22 +110,6 @@ void handle_http_request(const py::object &check_route, const py::object &submit
}
consumed = true;
// http api被python拦截了再api统一鉴权
try {
auto args = getAllArgs(parser);
auto allArgs = ArgsMap(parser, args);
GET_CONFIG(std::string, api_secret, API::kSecret);
CHECK_SECRET(); // 检测secret
} catch (std::exception &ex) {
Json::Value val;
val["code"] = API::Exception;
val["msg"] = ex.what();
HttpSession::KeyValue headerOut;
headerOut["Content-Type"] = "application/json";
invoker(200, headerOut, val.toStyledString());
return;
}
StrCaseMap resp_headers;
std::string resp_body;
int status = 500;
@ -176,18 +152,11 @@ PYBIND11_EMBEDDED_MODULE(mk_loader, m) {
}
return "";
});
m.def("get_full_path", [](const std::string &path, const std::string &current_path) -> std::string {
py::gil_scoped_release release;
return File::absolutePath(path, current_path);
});
m.def("set_config", [](const std::string &key, const std::string &value) -> bool {
py::gil_scoped_release release;
mINI::Instance()[key]= value;
return true;
});
m.def("update_config", []() {
NOTICE_EMIT(BroadcastReloadConfigArgs, Broadcast::kBroadcastReloadConfig);
mINI::Instance().dumpFile(g_ini_file);
@ -202,7 +171,6 @@ PYBIND11_EMBEDDED_MODULE(mk_loader, m) {
auto &invoker = to_native<Broadcast::PublishAuthInvoker>(cap);
invoker(err, option);
});
m.def("auth_invoker_do", [](const py::capsule &cap, const std::string &err) {
// 执行c++代码时释放gil锁
py::gil_scoped_release release;
@ -218,46 +186,6 @@ PYBIND11_EMBEDDED_MODULE(mk_loader, m) {
});
});
py::enum_<TrackType>(m, "TrackType")
.value("Invalid", TrackInvalid)
.value("Video", TrackVideo)
.value("Audio", TrackAudio)
.value("Title", TrackTitle)
.value("Application", TrackApplication)
.export_values();
py::class_<MediaSource, MediaSource::Ptr>(m, "MediaSource")
.def("getSchema", &MediaSource::getSchema)
.def("getUrl", &MediaSource::getUrl)
.def("getMediaTuple", &MediaSource::getMediaTuple)
.def("getTimeStamp", &MediaSource::getTimeStamp)
.def("setTimeStamp", &MediaSource::setTimeStamp)
.def("getBytesSpeed", &MediaSource::getBytesSpeed)
.def("getTotalBytes", &MediaSource::getTotalBytes)
.def("getCreateStamp", &MediaSource::getCreateStamp)
.def("getAliveSecond", &MediaSource::getAliveSecond)
.def("readerCount", &MediaSource::readerCount)
.def("totalReaderCount", &MediaSource::totalReaderCount)
.def("getOriginType", &MediaSource::getOriginType)
.def("getOriginUrl", &MediaSource::getOriginUrl)
.def("getOriginSock", &MediaSource::getOriginSock)
.def("seekTo", &MediaSource::seekTo)
.def("pause", &MediaSource::pause)
.def("speed", &MediaSource::speed)
.def("close", &MediaSource::close)
.def("setupRecord", &MediaSource::setupRecord)
.def("isRecording", &MediaSource::isRecording)
.def("stopSendRtp", &MediaSource::stopSendRtp)
.def("getLossRate", &MediaSource::getLossRate);
py::class_<MediaTuple, std::shared_ptr<MediaTuple>>(m, "MediaTuple")
.def_readwrite("vhost", &MediaTuple::vhost)
.def_readwrite("app", &MediaTuple::app)
.def_readwrite("stream", &MediaTuple::stream)
.def_readwrite("params", &MediaTuple::params)
.def("shortUrl", &MediaTuple::shortUrl);
py::class_<SockException, std::shared_ptr<SockException>>(m, "SockException").def("what", &SockException::what).def("code", &SockException::getErrCode);
}
namespace mediakit {
@ -287,18 +215,9 @@ bool set_python_path() {
return true;
}
static std::shared_ptr<PythonInvoker> g_instance;
PythonInvoker &PythonInvoker::Instance() {
static toolkit::onceToken s_token([]() {
g_instance.reset(new PythonInvoker);
});
return *g_instance;
}
void PythonInvoker::release() {
g_instance = nullptr;
static std::shared_ptr<PythonInvoker> instance(new PythonInvoker);
return *instance;
}
PythonInvoker::PythonInvoker() {
@ -325,34 +244,32 @@ PythonInvoker::~PythonInvoker() {
}
_on_exit = py::object();
_on_publish = py::object();
_on_play = py::object();
_on_flow_report = py::object();
_on_reload_config = py::object();
_on_media_changed = py::object();
_on_player_proxy_failed = py::object();
_module = py::module();
}
delete _rel;
delete _interpreter;
}
#define GET_FUNC(instance, name) \
if (hasattr(instance, #name)) { \
_##name = instance.attr(#name); \
}
void PythonInvoker::load(const std::string &module_name) {
try {
py::gil_scoped_acquire gil; // 加锁
_module = py::module::import(module_name.c_str());
GET_FUNC(_module, on_exit);
GET_FUNC(_module, on_publish);
GET_FUNC(_module, on_play);
GET_FUNC(_module, on_flow_report);
GET_FUNC(_module, on_reload_config);
GET_FUNC(_module, on_media_changed);
GET_FUNC(_module, on_player_proxy_failed);
if (hasattr(_module, "on_exit")) {
_on_exit = _module.attr("on_exit");
}
if (hasattr(_module, "on_publish")) {
_on_publish = _module.attr("on_publish");
}
if (hasattr(_module, "on_play")) {
_on_play = _module.attr("on_play");
}
if (hasattr(_module, "on_flow_report")) {
_on_flow_report = _module.attr("on_flow_report");
}
if (hasattr(_module, "on_reload_config")) {
_on_reload_config = _module.attr("on_reload_config");
}
if (hasattr(_module, "on_start")) {
py::object on_start = _module.attr("on_start");
if (on_start) {
@ -388,22 +305,6 @@ bool PythonInvoker::on_flow_report(BroadcastFlowReportArgs) const {
return _on_flow_report(to_python(args), totalBytes, totalDuration, isPlayer, to_python(sender)).cast<bool>();
}
bool PythonInvoker::on_media_changed(BroadcastMediaChangedArgs) const {
py::gil_scoped_acquire gil; // 确保在 Python 调用期间持有 GIL
if (!_on_media_changed) {
return false;
}
return _on_media_changed(bRegist, to_python2(sender)).cast<bool>();
}
bool PythonInvoker::on_player_proxy_failed(BroadcastPlayerProxyFailedArgs) const {
py::gil_scoped_acquire gil; // 确保在 Python 调用期间持有 GIL
if (!_on_player_proxy_failed) {
return false;
}
return _on_player_proxy_failed(sender.getUrl(), to_python2(sender.getMediaTuple()), to_python2(ex)).cast<bool>();
}
} // namespace mediakit
#endif

View File

@ -11,7 +11,6 @@
#include "Util/logger.h"
#include "Common/config.h"
#include "Common/MediaSource.h"
#include "Player/PlayerProxy.h"
namespace py = pybind11;
@ -22,14 +21,11 @@ public:
~PythonInvoker();
static PythonInvoker& Instance();
static void release();
void load(const std::string &module_name);
bool on_publish(BroadcastMediaPublishArgs) const;
bool on_play(BroadcastMediaPlayedArgs) const;
bool on_flow_report(BroadcastFlowReportArgs) const;
bool on_media_changed(BroadcastMediaChangedArgs) const;
bool on_player_proxy_failed(BroadcastPlayerProxyFailedArgs) const;
private:
PythonInvoker();
@ -50,10 +46,6 @@ private:
py::object _on_flow_report;
// 配置文件热更新回调
py::object _on_reload_config;
// 媒体注册注销
py::object _on_media_changed;
// 拉流代理失败
py::object _on_player_proxy_failed;
};
} // namespace mediakit

View File

@ -231,6 +231,10 @@ FFmpegFrame::FFmpegFrame(std::shared_ptr<AVFrame> frame) {
}
FFmpegFrame::~FFmpegFrame() {
if (_data) {
delete[] _data;
_data = nullptr;
}
}
AVFrame *FFmpegFrame::get() const {
@ -238,9 +242,9 @@ AVFrame *FFmpegFrame::get() const {
}
void FFmpegFrame::fillPicture(AVPixelFormat target_format, int target_width, int target_height) {
auto buffer_size = av_image_get_buffer_size(target_format, target_width, target_height, 32);
_data = std::unique_ptr<char[]>(new char[buffer_size]);
av_image_fill_arrays(_frame->data, _frame->linesize, (uint8_t *)_data.get(), target_format, target_width, target_height, 32);
assert(_data == nullptr);
_data = new char[av_image_get_buffer_size(target_format, target_width, target_height, 32)];
av_image_fill_arrays(_frame->data, _frame->linesize, (uint8_t *) _data, target_format, target_width, target_height, 32);
}
int FFmpegFrame::getChannels() const {
@ -252,14 +256,6 @@ int FFmpegFrame::getChannels() const {
#endif
}
// 资源池复用前调用
void FFmpegFrame::reset() {
_data.reset();
if (_frame) {
av_frame_unref(_frame.get()); // 清理AVFrame数据引用
}
}
///////////////////////////////////////////////////////////////////////////
template<bool decoder = true>
@ -738,7 +734,6 @@ FFmpegFrame::Ptr FFmpegSws::inputFrame(const FFmpegFrame::Ptr &frame, int &ret,
}
if (_ctx) {
auto out = _sws_frame_pool.obtain2();
out->reset(); // 清理旧数据和帧引用
if (!out->get()->data[0]) {
if (data) {
av_image_fill_arrays(out->get()->data, out->get()->linesize, data, _target_format, target_width, target_height, 32);
@ -761,16 +756,45 @@ FFmpegFrame::Ptr FFmpegSws::inputFrame(const FFmpegFrame::Ptr &frame, int &ret,
return nullptr;
}
std::tuple<bool, std::string> FFmpegUtils::saveFrame(const FFmpegFrame::Ptr &frame, const char *filename, AVPixelFormat fmt, int w, int h, const char *font_path) {
std::shared_ptr<AVFilterGraph> _filter_graph;
AVFilterContext *buffersrc_ctx = nullptr;
AVFilterContext *buffersink_ctx = nullptr;
const AVFilter *buffersrc = nullptr;
const AVFilter *buffersink = nullptr;
// kServerName
const string mark = "ZLMediaKit";
char drawtext_args1[512];
std::tuple<bool, std::string> FFmpegUtils::saveFrame(const FFmpegFrame::Ptr &frame, const char *filename, AVPixelFormat fmt) {
_StrPrinter ss;
const AVCodec *jpeg_codec = avcodec_find_encoder(fmt == AV_PIX_FMT_YUVJ420P ? AV_CODEC_ID_MJPEG : AV_CODEC_ID_PNG);
std::unique_ptr<AVCodecContext, void (*)(AVCodecContext *)> jpeg_codec_ctx(
jpeg_codec ? avcodec_alloc_context3(jpeg_codec) : nullptr, [](AVCodecContext *ctx) { avcodec_free_context(&ctx); });
if (!jpeg_codec_ctx) {
ss << "Could not allocate JPEG/PNG codec context";
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
jpeg_codec_ctx->width = frame->get()->width;
jpeg_codec_ctx->height = frame->get()->height;
jpeg_codec_ctx->pix_fmt = fmt;
jpeg_codec_ctx->time_base = { 1, 1 };
auto ret = avcodec_open2(jpeg_codec_ctx.get(), jpeg_codec, NULL);
if (ret < 0) {
ss << "Could not open JPEG/PNG codec, " << ffmpeg_err(ret);
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
FFmpegSws sws(fmt, 0, 0);
auto new_frame = sws.inputFrame(frame);
if (!new_frame) {
ss << "Could not scale the frame: " << ffmpeg_err(ret);
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
auto pkt = alloc_av_packet();
ret = avcodec_send_frame(jpeg_codec_ctx.get(), new_frame->get());
if (ret < 0) {
ss << "Error sending a frame for encoding, " << ffmpeg_err(ret);
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
std::unique_ptr<FILE, void (*)(FILE *)> tmp_save_file_jpg(File::create_file(filename, "wb"), [](FILE *fp) {
if (fp) {
@ -784,104 +808,10 @@ std::tuple<bool, std::string> FFmpegUtils::saveFrame(const FFmpegFrame::Ptr &fra
return make_tuple<bool, std::string>(false, ss.data());
}
std::string fontfile("");
if (font_path && File::fileExist(font_path)) {
fontfile = font_path;
} else {
// Fallback to common default
fontfile = exeDir() + "/DejaVuSans.ttf";
}
snprintf(drawtext_args1, sizeof(drawtext_args1), "text='%s':fontfile='%s':fontcolor=white@0.1:fontsize=h/50:x=w*0.02:y=h-th-h*0.02", mark.data(), fontfile.c_str());
const AVCodec *jpeg_codec = avcodec_find_encoder(fmt == AV_PIX_FMT_YUVJ420P ? AV_CODEC_ID_MJPEG : AV_CODEC_ID_PNG);
std::unique_ptr<AVCodecContext, void (*)(AVCodecContext *)> jpeg_codec_ctx(
jpeg_codec ? avcodec_alloc_context3(jpeg_codec) : nullptr, [](AVCodecContext *ctx) { avcodec_free_context(&ctx); });
if (!jpeg_codec_ctx) {
ss << "Could not allocate JPEG/PNG codec context";
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
jpeg_codec_ctx->width = (w > 0 && w < 8192) ? w : frame->get()->width;
jpeg_codec_ctx->height = (h > 0 && h < 4320) ? h : frame->get()->height;
jpeg_codec_ctx->pix_fmt = fmt;
jpeg_codec_ctx->time_base = { 1, 1 };
auto ret = avcodec_open2(jpeg_codec_ctx.get(), jpeg_codec, NULL);
if (ret < 0) {
ss << "Could not open JPEG/PNG codec, " << ffmpeg_err(ret);
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
FFmpegSws sws(fmt, jpeg_codec_ctx->width, jpeg_codec_ctx->height);
auto new_frame = sws.inputFrame(frame);
if (!new_frame) {
ss << "Could not scale the frame";
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
_filter_graph.reset(avfilter_graph_alloc(), [](AVFilterGraph *ctx) { avfilter_graph_free(&ctx); });
if (!_filter_graph) {
ss << "avfilter_graph_alloc failed";
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
char args[512];
snprintf(
args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", jpeg_codec_ctx->width, jpeg_codec_ctx->height,
jpeg_codec_ctx->pix_fmt, jpeg_codec_ctx->time_base.num, jpeg_codec_ctx->time_base.den, jpeg_codec_ctx->sample_aspect_ratio.num,
jpeg_codec_ctx->sample_aspect_ratio.den);
buffersrc = avfilter_get_by_name("buffer");
if ((ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, _filter_graph.get())) < 0) {
ss << "avfilter_graph_create_filter buffersrc failed: " << ret << " " << ffmpeg_err(ret);
DebugL << ss;
return make_tuple<bool, std::string>(false, ss.data());
}
buffersink = avfilter_get_by_name("buffersink");
if ((ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, _filter_graph.get())) < 0) {
ss << "avfilter_graph_create_filter buffersink failed: " << ret << " " << ffmpeg_err(ret);
return make_tuple<bool, std::string>(false, ss.data());
}
AVFilterContext *drawtext_ctx1 = nullptr;
const AVFilter *drawtext_filter = avfilter_get_by_name("drawtext");
if ((ret = avfilter_graph_create_filter(&drawtext_ctx1, drawtext_filter, "drawtext", drawtext_args1, NULL, _filter_graph.get())) < 0) {
ss << "avfilter_graph_create_filter drawtext_filter failed: " << ret << " " << ffmpeg_err(ret);
return make_tuple<bool, std::string>(false, ss.data());
}
if ((ret = avfilter_link(buffersrc_ctx, 0, drawtext_ctx1, 0) < 0 || avfilter_link(drawtext_ctx1, 0, buffersink_ctx, 0))< 0) {
ss << "avfilter_link: " << ret << " " << ffmpeg_err(ret);
return make_tuple<bool, std::string>(false, ss.data());
}
if ((ret = avfilter_graph_config(_filter_graph.get(), NULL)) < 0) {
ss << "avfilter_graph_config failed: " << ret << " " << ffmpeg_err(ret);
return make_tuple<bool, std::string>(false, ss.data());
}
if ((ret = av_buffersrc_add_frame_flags(buffersrc_ctx, new_frame->get(), 0)) < 0) {
ss << "av_buffersink_get_frame failed: " << ret << " " << ffmpeg_err(ret);
return make_tuple<bool, std::string>(false, ss.data());
}
auto pkt = alloc_av_packet();
while (av_buffersink_get_frame(buffersink_ctx, new_frame->get()) >= 0) {
if (avcodec_send_frame(jpeg_codec_ctx.get(), new_frame->get()) == 0) {
while (avcodec_receive_packet(jpeg_codec_ctx.get(), pkt.get()) == 0) {
fwrite(pkt.get()->data, pkt.get()->size, 1, tmp_save_file_jpg.get());
}
}
while (avcodec_receive_packet(jpeg_codec_ctx.get(), pkt.get()) == 0) {
fwrite(pkt.get()->data, pkt.get()->size, 1, tmp_save_file_jpg.get());
}
DebugL << "Screenshot successful: " << filename;
return make_tuple<bool, std::string>(true, "");
}

View File

@ -27,9 +27,6 @@ extern "C" {
#include "libavutil/audio_fifo.h"
#include "libavutil/imgutils.h"
#include "libavutil/frame.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#ifdef __cplusplus
}
#endif
@ -48,10 +45,9 @@ public:
AVFrame *get() const;
void fillPicture(AVPixelFormat target_format, int target_width, int target_height);
int getChannels() const;
void reset();
private:
std::unique_ptr<char[]> _data;
char *_data = nullptr;
std::shared_ptr<AVFrame> _frame;
};
@ -174,11 +170,9 @@ public:
* @param frame
* @param filename
* @param fmt jpg:AV_PIX_FMT_YUVJ420PPNG:AV_PIX_FMT_RGB24
* @param w h ()
* @param font_path (), default DejaVuSans.ttf
* @return
*/
static std::tuple<bool, std::string> saveFrame(const FFmpegFrame::Ptr &frame, const char *filename, AVPixelFormat fmt = AV_PIX_FMT_YUVJ420P, int w = 0, int h = 0, const char *font_path = nullptr);
static std::tuple<bool, std::string> saveFrame(const FFmpegFrame::Ptr &frame, const char *filename, AVPixelFormat fmt = AV_PIX_FMT_YUVJ420P);
};
}//namespace mediakit

View File

@ -176,9 +176,7 @@ void MediaSink::checkTrackIfReady() {
}
void MediaSink::addTrackCompleted() {
if (!_track_map.empty()) {
setMaxTrackCount(_track_map.size());
}
setMaxTrackCount(_track_map.size());
}
void MediaSink::setMaxTrackCount(size_t i) {

View File

@ -287,36 +287,6 @@ public:
// Maximum number of tracks
size_t max_track = 2;
#define OPT_VALUE(XX) \
XX(modify_stamp) \
XX(enable_audio) \
XX(add_mute_audio) \
XX(auto_close) \
XX(continue_push_ms) \
XX(paced_sender_ms) \
\
XX(enable_hls) \
XX(enable_hls_fmp4) \
XX(enable_mp4) \
XX(enable_rtsp) \
XX(enable_rtmp) \
XX(enable_ts) \
XX(enable_fmp4) \
\
XX(hls_demand) \
XX(rtsp_demand) \
XX(rtmp_demand) \
XX(ts_demand) \
XX(fmp4_demand) \
\
XX(mp4_max_second) \
XX(mp4_as_player) \
XX(mp4_save_path) \
\
XX(hls_save_path) \
XX(stream_replace) \
XX(max_track)
template <typename MAP>
ProtocolOption(const MAP &allArgs) : ProtocolOption() {
load(allArgs);
@ -324,18 +294,35 @@ public:
template <typename MAP>
void load(const MAP &allArgs) {
#define GET(key) getArgsValue(allArgs, #key, key);
OPT_VALUE(GET)
#undef GET
}
#define GET_OPT_VALUE(key) getArgsValue(allArgs, #key, key)
GET_OPT_VALUE(modify_stamp);
GET_OPT_VALUE(enable_audio);
GET_OPT_VALUE(add_mute_audio);
GET_OPT_VALUE(auto_close);
GET_OPT_VALUE(continue_push_ms);
GET_OPT_VALUE(paced_sender_ms);
template <typename MAP>
MAP as() {
MAP ret;
#define SET(key) ret[#key] = key;
OPT_VALUE(SET)
#undef SET
return ret;
GET_OPT_VALUE(enable_hls);
GET_OPT_VALUE(enable_hls_fmp4);
GET_OPT_VALUE(enable_mp4);
GET_OPT_VALUE(enable_rtsp);
GET_OPT_VALUE(enable_rtmp);
GET_OPT_VALUE(enable_ts);
GET_OPT_VALUE(enable_fmp4);
GET_OPT_VALUE(hls_demand);
GET_OPT_VALUE(rtsp_demand);
GET_OPT_VALUE(rtmp_demand);
GET_OPT_VALUE(ts_demand);
GET_OPT_VALUE(fmp4_demand);
GET_OPT_VALUE(mp4_max_second);
GET_OPT_VALUE(mp4_as_player);
GET_OPT_VALUE(mp4_save_path);
GET_OPT_VALUE(hls_save_path);
GET_OPT_VALUE(stream_replace);
GET_OPT_VALUE(max_track);
}
};

View File

@ -401,20 +401,15 @@ bool MultiMediaSourceMuxer::setupRecord(Recorder::type type, bool start, const s
}
}
std::string MultiMediaSourceMuxer::startRecord(const std::string &file_path, int back_time_ms, int forward_time_ms) {
std::string MultiMediaSourceMuxer::startRecord(const std::string &file_path, uint32_t back_time_ms, uint32_t forward_time_ms) {
#if !defined(ENABLE_MP4)
throw std::invalid_argument("mp4相关功能未打开请开启ENABLE_MP4宏后编译再测试");
#else
if (!_ring) {
throw std::runtime_error("frame gop cache disabled, start record event video failed");
}
std::string path;
if (!start_with(file_path, "/")) {
path = Recorder::getRecordPath(Recorder::type_mp4, _tuple, _option.mp4_save_path);
path += file_path;
} else {
path = file_path;
}
auto path = Recorder::getRecordPath(Recorder::type_mp4, _tuple, _option.mp4_save_path);
path += file_path;
TraceL << "mp4 save path: " << path;
auto muxer = std::make_shared<MP4Muxer>();
@ -424,124 +419,68 @@ std::string MultiMediaSourceMuxer::startRecord(const std::string &file_path, int
}
muxer->addTrackCompleted();
bool have_history = false;
if (back_time_ms > 0) {
// 回溯录制
std::list<Frame::Ptr> history;
_ring->flushGop([&](const Frame::Ptr &frame) { history.emplace_back(frame); });
std::list<Frame::Ptr> history;
_ring->flushGop([&](const Frame::Ptr &frame) { history.emplace_back(frame); });
if (!history.empty()) {
auto now_dts = history.back()->dts();
decltype(history)::iterator pos = history.end();
for (auto it = history.rbegin(); it != history.rend(); ++it) {
auto &frame = *it;
if (frame->getTrackType() != TrackVideo || (!frame->configFrame() && !frame->keyFrame())) {
continue;
}
// 如果视频关键帧到末尾的时长超过一定的时间,那前面的数据应该全部删除
if (frame->dts() + back_time_ms < now_dts) {
pos = it.base();
--pos;
break;
}
}
if (pos != history.end()) {
// 移除前面过多的数据
TraceL << "clear history video: " << history.front()->dts() << " -> " << (*pos)->dts();
history.erase(history.begin(), pos);
}
if (!history.empty()) {
auto now_dts = history.back()->dts();
auto &front = history.front();
InfoL << "start record: " << path
<< ", start_dts: " << front->dts() << ", key_frame: " << front->keyFrame() << ", config_frame: " << front->configFrame()
<< ", now_dts: " << now_dts;
}
decltype(history)::iterator pos = history.end();
for (auto it = history.rbegin(); it != history.rend(); ++it) {
auto &frame = *it;
if (frame->getTrackType() != TrackVideo || (!frame->configFrame() && !frame->keyFrame())) {
continue;
}
// 如果视频关键帧到末尾的时长超过一定的时间,那前面的数据应该全部删除
if (frame->dts() + back_time_ms < now_dts) {
pos = it.base();
--pos;
break;
}
}
if (pos != history.end()) {
// 移除历史视频前面过多的数据
DebugL << "clear history front video: " << history.front()->dts() << " -> " << (*pos)->dts();
history.erase(history.begin(), pos);
}
if (forward_time_ms < 0) {
// 如果后向录制时长为负,说明回溯录制要截取一段尾部
pos = history.end();
for (auto it = history.rbegin(); it != history.rend(); ++it) {
auto &frame = *it;
if (frame->getTrackType() != TrackVideo) {
continue;
}
if (frame->dts() < now_dts + forward_time_ms) {
pos = it.base();
++pos;
break;
}
}
if (pos != history.end()) {
// 移除历史视频后面过多的数据
DebugL << "clear history tail video: " << (*pos)->dts() << " -> " << now_dts;
history.erase(pos, history.end());
}
}
if (!history.empty()) {
auto &front = history.front();
InfoL << "start record: " << path
<< ", start_dts: " << front->dts() << ", key_frame: " << front->keyFrame() << ", config_frame: " << front->configFrame()
<< ", now_dts: " << now_dts;
have_history = true;
}
for (auto &frame : history) {
muxer->inputFrame(frame);
}
for (auto &frame : history) {
muxer->inputFrame(frame);
}
}
if (forward_time_ms > 0) {
if (!have_history) {
InfoL << "start record: " << path << ", back_time_ms: " << back_time_ms << ", forward_time_ms: " << forward_time_ms;
auto reader = _ring->attach(MultiMediaSourceMuxer::getOwnerPoller(MediaSource::NullMediaSource()), false);
uint64_t now_dts = 0;
int selected_index = -1;
Ticker ticker;
bool is_live_stream = _dur_sec < 0.01;
reader->setReadCB([muxer, now_dts, selected_index, forward_time_ms, reader, path, ticker, is_live_stream](const Frame::Ptr &frame) mutable {
// 循环引用自身
if (!now_dts) {
now_dts = frame->dts();
selected_index = frame->getIndex();
}
weak_ptr<MultiMediaSourceMuxer> weak_self = shared_from_this();
auto lam = [weak_self, muxer, forward_time_ms, have_history, path]() {
auto strong_self = weak_self.lock();
if (!strong_self) {
return;
}
uint64_t now_dts = 0;
int selected_index = -1;
Ticker ticker;
bool is_live_stream = strong_self->_dur_sec < 0.01;
auto reader = strong_self->_ring->attach(strong_self->MultiMediaSourceMuxer::getOwnerPoller(MediaSource::NullMediaSource()), !have_history, 1);
reader->setReadCB([muxer, now_dts, selected_index, forward_time_ms, reader, path, ticker, is_live_stream](const Frame::Ptr &frame) mutable {
if (!reader) {
// 已经关闭录制
return;
}
// 循环引用自身
if (!now_dts) {
now_dts = frame->dts();
selected_index = frame->getIndex();
}
// 新增兜底机制如果直播录制任务时长超过预期时间3秒不管数据时间戳是否增长是否达到预期都强制停止录制
if ((frame->getIndex() == selected_index && now_dts + forward_time_ms < frame->dts())
|| (is_live_stream && ticker.createdTime() > forward_time_ms + 3000ULL)) {
InfoL << "stop record: " << path << ", end dts: " << frame->dts();
WorkThreadPool::Instance().getPoller()->async([muxer]() { muxer->closeMP4(); });
reader = nullptr;
return;
}
muxer->inputFrame(frame);
});
std::weak_ptr<RingType::RingReader> weak_reader = reader;
reader->setDetachCB([weak_reader]() {
if (auto strong_reader = weak_reader.lock()) {
// 防止循环引用
strong_reader->setReadCB(nullptr);
}
});
};
if (back_time_ms >= 0) {
// 立即前向录制
lam();
} else {
// 延时启动录制
MultiMediaSourceMuxer::getOwnerPoller(MediaSource::NullMediaSource())->doDelayTask(-back_time_ms, [lam]() {
lam();
return 0;
});
// 新增兜底机制如果直播录制任务时长超过预期时间3秒不管数据时间戳是否增长是否达到预期都强制停止录制
if ((frame->getIndex() == selected_index && now_dts + forward_time_ms < frame->dts()) || (is_live_stream && ticker.createdTime() > forward_time_ms + 3000)) {
InfoL << "stop record: " << path << ", end dts: " << frame->dts();
WorkThreadPool::Instance().getPoller()->async([muxer]() { muxer->closeMP4(); });
reader = nullptr;
return;
}
}
muxer->inputFrame(frame);
});
std::weak_ptr<RingType::RingReader> weak_reader = reader;
reader->setDetachCB([weak_reader]() {
if (auto strong_reader = weak_reader.lock()) {
// 防止循环引用
strong_reader->setReadCB(nullptr);
}
});
return path;
#endif

View File

@ -129,7 +129,7 @@ public:
* @param forward_time_ms
* @return
*/
std::string startRecord(const std::string &file_path, int back_time_ms, int forward_time_ms);
std::string startRecord(const std::string &file_path, uint32_t back_time_ms, uint32_t forward_time_ms);
/**
*

View File

@ -81,7 +81,6 @@ const string kBroadcastRtcSctpClosed = "kBroadcastRtcSctpClosed";
const string kBroadcastRtcSctpSend = "kBroadcastRtcSctpSend";
const string kBroadcastRtcSctpReceived = "kBroadcastRtcSctpReceived";
const string kBroadcastPlayerCountChanged = "kBroadcastPlayerCountChanged";
const string kBroadcastPlayerProxyFailed = "kBroadcastPlayerProxyFailed";
} // namespace Broadcast

View File

@ -161,9 +161,6 @@ extern const std::string kBroadcastRtcSctpReceived;
extern const std::string kBroadcastPlayerCountChanged;
#define BroadcastPlayerCountChangedArgs const MediaTuple& args, const int& count
extern const std::string kBroadcastPlayerProxyFailed;
#define BroadcastPlayerProxyFailedArgs const PlayerProxy& sender, const toolkit::SockException &ex
#define ReloadConfigTag ((void *)(0xFF))
#define RELOAD_KEY(arg, key) \
do { \

View File

@ -110,9 +110,7 @@ void PlayerProxy::play(const string &strUrlTmp) {
if (!strongSelf) {
return;
}
if (err) {
NOTICE_EMIT(BroadcastPlayerProxyFailedArgs, Broadcast::kBroadcastPlayerProxyFailed, *strongSelf, err);
}
if (strongSelf->_on_play) {
strongSelf->_on_play(err);
strongSelf->_on_play = nullptr;
@ -148,9 +146,6 @@ void PlayerProxy::play(const string &strUrlTmp) {
if (!strongSelf) {
return;
}
if (err) {
NOTICE_EMIT(BroadcastPlayerProxyFailedArgs, Broadcast::kBroadcastPlayerProxyFailed, *strongSelf, err);
}
// 注销直接拉流代理产生的流:#532 [AUTO-TRANSLATED:c6343a3b]
// Unregister the stream generated by the direct stream proxy: #532

View File

@ -18,7 +18,8 @@
namespace mediakit {
struct StreamInfo {
struct StreamInfo
{
TrackType codec_type;
std::string codec_name;
int bitrate;
@ -29,7 +30,8 @@ struct StreamInfo {
int video_height;
float video_fps;
StreamInfo() {
StreamInfo()
{
codec_type = TrackInvalid;
codec_name = "none";
bitrate = -1;
@ -42,12 +44,14 @@ struct StreamInfo {
}
};
struct TranslationInfo {
struct TranslationInfo
{
std::vector<StreamInfo> stream_info;
int byte_speed;
uint64_t start_time_stamp;
TranslationInfo() {
TranslationInfo()
{
byte_speed = -1;
start_time_stamp = 0;
}

View File

@ -115,13 +115,7 @@ void PusherProxy::rePublish(const string &dst_url, int failed_cnt) {
return false;
}
WarnL << "推流重试[" << failed_cnt << "]:" << dst_url;
try {
strong_self->MediaPusher::publish(dst_url);
} catch (std::exception &e) {
WarnL << e.what();
// 回调推流失败,一般是媒体注销了
strong_self->_on_close(SockException(Err_other, e.what()));
}
strong_self->MediaPusher::publish(dst_url);
return false;
},
getPoller());

View File

@ -19,11 +19,7 @@ using namespace toolkit;
namespace mediakit {
MP4Muxer::~MP4Muxer() {
try {
closeMP4();
} catch (std::exception &e) {
WarnL << e.what();
}
closeMP4();
}
void MP4Muxer::openMP4(const string &file) {

View File

@ -56,33 +56,30 @@ AudioMeta::AudioMeta(const AudioTrack::Ptr &audio) {
}
uint8_t getCodecFlags(CodecId cid) {
switch (cid) {
#define XX(a, b, c) \
case a: return static_cast<uint8_t>(b);
RTMP_CODEC_MAP(XX)
switch(cid) {
#define XX(a, b, c) case a: return static_cast<uint8_t>(b);
RTMP_CODEC_MAP(XX)
#undef XX
default: return 0;
}
return 0;
}
uint32_t getCodecFourCC(CodecId cid) {
switch (cid) {
#define XX(a, b, c) \
case a: return static_cast<uint32_t>(c);
RTMP_CODEC_MAP(XX)
switch(cid) {
#define XX(a, b, c) case a: return static_cast<uint32_t>(c);
RTMP_CODEC_MAP(XX)
#undef XX
default: return 0;
}
return 0;
}
CodecId getFourccCodec(uint32_t id) {
switch (id) {
#define XX(a, b, c) \
case (uint32_t)c: return a;
RTMP_CODEC_MAP(XX)
switch(id) {
#define XX(a, b, c) case (uint32_t)c: return a;
RTMP_CODEC_MAP(XX)
#undef XX
default: return CodecInvalid;
}
return CodecInvalid;
}
uint8_t getAudioRtmpFlags(const Track::Ptr &track) {
@ -198,10 +195,12 @@ bool RtmpPacket::isConfigFrame() const {
switch (type_id) {
case MSG_AUDIO: {
switch ((RtmpAudioCodec)getRtmpCodecId()) {
case RtmpAudioCodec::aac: return (RtmpAACPacketType)buffer[1] == RtmpAACPacketType::aac_config_header;
case RtmpAudioCodec::ex_header: return (RtmpPacketType)(buffer[0] & 0x0f) == RtmpPacketType::PacketTypeSequenceStart;
default: return false;
case RtmpAudioCodec::aac:
return (RtmpAACPacketType)buffer[1] == RtmpAACPacketType::aac_config_header;
case RtmpAudioCodec::ex_header:
return (RtmpPacketType)(buffer[0] & 0x0f) == RtmpPacketType::PacketTypeSequenceStart;
}
return false;
}
case MSG_VIDEO: {
if (!isVideoKeyFrame()) {

View File

@ -26,35 +26,11 @@ using namespace toolkit;
#define S2_FMS_KEY_SIZE 68
#define C1_OFFSET_SIZE 4
#ifdef ENABLE_OPENSSL
#include "Util/SSLBox.h"
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
static uint8_t FMSKey[] = {
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20,
0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c,
0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69,
0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Media Server 001
0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8,
0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57,
0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
}; // 68
static uint8_t FPKey[] = {
0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20,
0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x46, 0x6C,
0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79,
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Player 001
0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8,
0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E, 0x7E, 0x57,
0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB,
0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
}; // 62
static string openssl_HMACsha256(const void *key, size_t key_len, const void *data, size_t data_len){
std::shared_ptr<char> out(new char[32], [](char *ptr) { delete[] ptr; });
unsigned int out_len;
@ -353,16 +329,8 @@ const char* RtmpProtocol::handle_S0S1S2(const char *data, size_t len, const func
}
// 发送 C2 [AUTO-TRANSLATED:e51c339e]
// Send C2
uint8_t *pS1 = (uint8_t*)data + 1;
RtmpHandshake c2(0);
memcpy(&c2, pS1, sizeof(c2));
#ifdef ENABLE_OPENSSL
if(pS1[4] >=3){ // 复杂握手计算c2
handle_S1_complex((char*)pS1, c2);
}
#endif
onSendRawData(obtainBuffer(&c2, C1_HANDSHARK_SIZE));
const char *pcC2 = data + 1;
onSendRawData(obtainBuffer(pcC2, C1_HANDSHARK_SIZE));
// 握手结束 [AUTO-TRANSLATED:9df763ff]
// Handshake finished
_next_step_func = [this](const char *data, size_t len) {
@ -440,7 +408,7 @@ void RtmpProtocol::handle_C1_complex(const char *data){
check_C1_Digest(digest, c1_joined);
send_complex_S0S1S2(0, digest);
// InfoL << "schema0";
// InfoL << "schema0";
} catch (std::exception &) {
// 貌似flash从来都不用schema1 [AUTO-TRANSLATED:2c6d140f]
// It seems that flash never uses schema1
@ -458,70 +426,40 @@ void RtmpProtocol::handle_C1_complex(const char *data){
check_C1_Digest(digest, c1_joined);
send_complex_S0S1S2(1, digest);
// InfoL << "schema1";
// InfoL << "schema1";
} catch (std::exception &) {
//WarnL << "try rtmp complex schema1 failed:" << ex.what();
// WarnL << "try rtmp complex schema1 failed:" << ex.what();
handle_C1_simple(data);
}
}
}
void RtmpProtocol::check_S1_Digest(const std::string &digest,const std::string &data){
auto sha256 = openssl_HMACsha256(FMSKey, S1_FMS_KEY_SIZE, data.data(), data.size());
if (sha256 != digest) {
throw std::runtime_error("digest mismatched");
} else {
InfoL << "check rtmp complex handshark success!";
}
}
#if !defined(u_int8_t)
#define u_int8_t unsigned char
#endif // !defined(u_int8_t)
void RtmpProtocol::handle_S1_complex(const char *data,RtmpHandshake &c2){
static u_int8_t FMSKey[] = {
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20,
0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c,
0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69,
0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Media Server 001
0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8,
0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57,
0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
}; // 68
const char *s1_start = data;
const char *schema_start = s1_start + 8;
char *digest_start;
std::string digest;
try {
/* c1s1 schema0
time: 4bytes
version: 4bytes
key: 764bytes
digest: 764bytes
*/
digest = get_C1_digest((uint8_t *) schema_start + C1_SCHEMA_SIZE, &digest_start);
string s1_joined(s1_start, C1_HANDSHARK_SIZE);
s1_joined.erase(digest_start - s1_start, C1_DIGEST_SIZE);
check_S1_Digest(digest, s1_joined);
//InfoL << "schema0";
} catch (std::exception &ex) {
// 貌似flash从来都不用schema1 [AUTO-TRANSLATED:2c6d140f]
// It seems that flash never uses schema1
//WarnL << "try rtmp complex schema0 failed:" << ex.what();
try {
/* c1s1 schema1
time: 4bytes
version: 4bytes
digest: 764bytes
key: 764bytes
*/
digest = get_C1_digest((uint8_t *) schema_start, &digest_start);
string s1_joined(s1_start, C1_HANDSHARK_SIZE);
s1_joined.erase(digest_start - s1_start, C1_DIGEST_SIZE);
check_S1_Digest(digest, s1_joined);
//send_complex_S0S1S2(1, digest);
//InfoL << "schema1";
} catch (std::exception &ex) {
WarnL << "try rtmp complex schema1 failed:" << ex.what();
return;
}
}
//InfoL << "send complex C2";
auto c2_key = openssl_HMACsha256(FPKey, sizeof(FPKey), digest.data(), digest.size());
std::string c2_str((char*)(&c2), sizeof(c2)- C1_DIGEST_SIZE);
auto c2_digest = openssl_HMACsha256(c2_key.data(), c2_key.size(), c2_str.data(), c2_str.size());
memcpy(c2.random + RANDOM_LEN - C1_DIGEST_SIZE, c2_digest.data(), C1_DIGEST_SIZE);
}
static u_int8_t FPKey[] = {
0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20,
0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x46, 0x6C,
0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79,
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Player 001
0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8,
0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E, 0x7E, 0x57,
0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB,
0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
}; // 62
void RtmpProtocol::check_C1_Digest(const string &digest,const string &data){
auto sha256 = openssl_HMACsha256(FPKey, C1_FPKEY_SIZE, data.data(), data.size());

View File

@ -63,16 +63,14 @@ protected:
void sendRtmp(uint8_t type, uint32_t stream_index, const std::string &buffer, uint32_t stamp, int chunk_id);
void sendRtmp(uint8_t type, uint32_t stream_index, const toolkit::Buffer::Ptr &buffer, uint32_t stamp, int chunk_id);
toolkit::BufferRaw::Ptr obtainBuffer(const void *data = nullptr, size_t len = 0);
private:
void handle_C1_simple(const char *data);
#ifdef ENABLE_OPENSSL
void handle_S1_complex(const char *data, RtmpHandshake &c2);
void handle_C1_complex(const char *data);
std::string get_C1_digest(const uint8_t *ptr,char **digestPos);
std::string get_C1_key(const uint8_t *ptr);
void check_C1_Digest(const std::string &digest,const std::string &data);
void check_S1_Digest(const std::string &digest,const std::string &data);
void send_complex_S0S1S2(int schemeType,const std::string &digest);
#endif //ENABLE_OPENSSL

View File

@ -446,11 +446,7 @@ void RtspPlayer::sendOptions() {
}
void RtspPlayer::sendKeepAlive() {
if (_play_check_timer)
{
WarnL << "receive RTP packet before handleResPAUSE";
}
_on_keepalive_reponse = [](const Parser &parser) {};
_on_response = [](const Parser &parser) {};
if (_supported_cmd.find("GET_PARAMETER") != _supported_cmd.end()) {
// 支持GET_PARAMETER用此命令保活 [AUTO-TRANSLATED:b45cd737]
// Support GET_PARAMETER, use this command to keep alive
@ -536,10 +532,6 @@ void RtspPlayer::onWholeRtspPacket(Parser &parser) {
try {
decltype(_on_response) func;
_on_response.swap(func);
if (!func)
{
_on_keepalive_reponse.swap(func);
}
if (func) {
func(parser);
}

View File

@ -162,7 +162,6 @@ private:
float _speed = 0.0f;
std::vector<SdpTrack::Ptr> _sdp_track;
std::function<void(const Parser&)> _on_response;
std::function<void(const Parser&)> _on_keepalive_reponse;
protected:
// RTP端口,trackid idx 为数组下标 [AUTO-TRANSLATED:77c186bb]
// RTP port, trackid idx is the array subscript

View File

@ -64,6 +64,7 @@ public:
private:
MultiMediaSourceMuxer::Ptr _muxer;
uint64_t timeStamp = 0;
uint64_t timeStamp_last = 0;
};

View File

@ -83,10 +83,6 @@ struct sniff_tcp {
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#if defined(TH_FLAGS)
#undef TH_FLAGS
#endif
#define TH_FLAGS (TH_FINTH_SYNTH_RSTTH_ACKTH_URGTH_ECETH_CWR)
u_short th_win; /* TCP滑动窗口 */
u_short th_sum; /* 头部校验和 */
@ -158,7 +154,7 @@ static bool loadFile(const char *path, const EventPoller::Ptr &poller) {
return false;
}
auto total_size = std::make_shared<size_t>(0);
struct pcap_pkthdr header {};
struct pcap_pkthdr header = {0};
while (true) {
const u_char *pkt_buff = pcap_next(handle.get(), &header);
if (!pkt_buff) {

View File

@ -1175,7 +1175,7 @@ void IceAgent::connectivityCheck(const Pair::Ptr &pair, CandidateTuple& candidat
}
void IceAgent::tryTriggerredCheck(const Pair::Ptr& pair) {
// DebugL;
DebugL;
//FIXME 暂不实现,因为当前实现基本收到candidate就会发起check
}

View File

@ -46,7 +46,6 @@ const string kNackIntervalRatio = RTC_FIELD "nackIntervalRatio";
// nack包中rtp个数减小此值可以让nack包响应更灵敏 [AUTO-TRANSLATED:12393868]
// Number of rtp in nack packet, reducing this value can make nack packet response more sensitive
const string kNackRtpSize = RTC_FIELD "nackRtpSize";
const string kNackAudioRtpSize = RTC_FIELD "nackAudioRtpSize";
static onceToken token([]() {
mINI::Instance()[kMaxRtpCacheMS] = 5 * 1000;
@ -56,7 +55,6 @@ static onceToken token([]() {
mINI::Instance()[kNackMaxCount] = 15;
mINI::Instance()[kNackIntervalRatio] = 1.0f;
mINI::Instance()[kNackRtpSize] = 8;
mINI::Instance()[kNackAudioRtpSize] = 4;
});
} // namespace Rtc
@ -157,8 +155,7 @@ int64_t NackList::getNtpStamp(uint16_t seq) {
////////////////////////////////////////////////////////////////////////////////////////////////
NackContext::NackContext(TrackType type) {
_type = type;
NackContext::NackContext() {
setOnNack(nullptr);
}
@ -220,9 +217,7 @@ void NackContext::makeNack(uint16_t max_seq, bool flush) {
// 最多生成5个nack包防止seq大幅跳跃导致一直循环 [AUTO-TRANSLATED:9cc5da25]
// Generate at most 5 nack packets to prevent seq from jumping significantly and causing continuous loops
auto max_nack = 5u;
GET_CONFIG(uint32_t, nack_video_rtpsize, Rtc::kNackRtpSize);
GET_CONFIG(uint32_t, nack_audio_rtpsize, Rtc::kNackAudioRtpSize);
auto nack_rtpsize = _type == TrackVideo ? nack_video_rtpsize : nack_audio_rtpsize;
GET_CONFIG(uint32_t, nack_rtpsize, Rtc::kNackRtpSize);
// kNackRtpSize must between 0 and 16
nack_rtpsize = std::min<uint32_t>(nack_rtpsize, FCI_NACK::kBitSize);
while (_nack_seq != max_seq && max_nack--) {

View File

@ -55,7 +55,7 @@ public:
using Ptr = std::shared_ptr<NackContext>;
using onNack = std::function<void(const FCI_NACK &nack)>;
NackContext(TrackType type = TrackVideo);
NackContext();
void received(uint16_t seq, bool is_rtx = false);
void setOnNack(onNack cb);
@ -71,7 +71,6 @@ private:
private:
bool _started = false;
int _rtt = 50;
TrackType _type;
onNack _cb;
std::set<uint16_t> _seq;
// 最新nack包中的rtp seq值 [AUTO-TRANSLATED:6984d95a]

View File

@ -204,16 +204,11 @@ SrtpSession::SrtpSession(Type type, CryptoSuite cryptoSuite, uint8_t *key, size_
policy.key = key;
// Required for sending RTP retransmission without RTX.
policy.allow_repeat_tx = 1;
#if 0
if (type == Type::OUTBOUND) {
policy.window_size = 0x8000 - 1;
} else {
policy.window_size = 1024;
}
#else
// TODO 关闭防重放攻击
policy.window_size = 0x8000 - 1;
#endif
policy.next = nullptr;
// Set the SRTP session.

View File

@ -69,11 +69,10 @@ void WebRtcSession::onRecv_l(const char *data, size_t len) {
auto sock = Socket::createSocket(transport->getPoller(), false);
// 1、克隆socket(fd不变)切换poller线程到WebRtcTransport所在线程 [AUTO-TRANSLATED:f930bfab]
// 1. Clone socket (fd remains unchanged), switch poller thread to the thread where WebRtcTransport is located
auto on_complete = sock->cloneSocket(*(getSock()));
sock->cloneSocket(*(getSock()));
auto server = _server;
std::string str(data, len);
// on_complete在创建WebRtcSession后才析构(才开始网络事件监听)
sock->getPoller()->async([sock, server, str, on_complete](){
sock->getPoller()->async([sock, server, str](){
auto strong_server = server.lock();
if (strong_server) {
auto session = static_pointer_cast<WebRtcSession>(strong_server->createSession(sock));

View File

@ -82,7 +82,6 @@ const string kMinBitrate = RTC_FIELD "min_bitrate";
// 数据通道设置 [AUTO-TRANSLATED:2dc48bc3]
// Data channel setting
const string kDataChannelEcho = RTC_FIELD "datachannel_echo";
const string kPreferredTcp = RTC_FIELD "preferred_tcp";
static onceToken token([]() {
mINI::Instance()[kTimeOutSec] = 15;
@ -106,7 +105,6 @@ static onceToken token([]() {
mINI::Instance()[kIceTransportPolicy] = 0; // 默认值:不限制(kAll)
mINI::Instance()[kIceUfrag] = "ZLMediaKit";
mINI::Instance()[kIcePwd] = "ZLMediaKit";
mINI::Instance()[kPreferredTcp] = 0;
});
} // namespace Rtc
@ -1104,7 +1102,7 @@ void WebRtcTransportImp::setIceCandidate(vector<SdpAttrCandidate> cands) {
class RtpChannel : public RtpTrackImp, public std::enable_shared_from_this<RtpChannel> {
public:
RtpChannel(TrackType type, EventPoller::Ptr poller, RtpTrackImp::OnSorted cb, function<void(const FCI_NACK &nack)> on_nack) : _nack_ctx(type){
RtpChannel(EventPoller::Ptr poller, RtpTrackImp::OnSorted cb, function<void(const FCI_NACK &nack)> on_nack) {
_poller = std::move(poller);
_on_nack = std::move(on_nack);
setOnSorted(std::move(cb));
@ -1316,7 +1314,7 @@ void WebRtcTransportImp::createRtpChannel(const string &rid, uint32_t ssrc, Medi
// rid --> RtpReceiverImp
auto &ref = track.rtp_channel[rid];
weak_ptr<WebRtcTransportImp> weak_self = static_pointer_cast<WebRtcTransportImp>(shared_from_this());
ref = std::make_shared<RtpChannel>(track.media->type,
ref = std::make_shared<RtpChannel>(
getPoller(), [&track, this, rid](RtpPacket::Ptr rtp) mutable { onSortedRtp(track, rid, std::move(rtp)); },
[&track, weak_self, ssrc](const FCI_NACK &nack) mutable {
// nack发送可能由定时器异步触发 [AUTO-TRANSLATED:186d6723]
@ -1633,7 +1631,6 @@ WebRtcPluginManager &WebRtcPluginManager::Instance() {
}
void WebRtcPluginManager::registerPlugin(const string &type, Plugin cb) {
InfoL << "Load webrtc plugin:" << type;
lock_guard<mutex> lck(_mtx_creator);
_map_creator[type] = std::move(cb);
}
@ -1670,7 +1667,6 @@ void echo_plugin(SocketHelper& sender, const WebRtcArgs &args, const onCreateWeb
cb(*WebRtcEchoTest::create(EventPollerPool::Instance().getPoller()));
}
template<typename Type>
void push_plugin(SocketHelper& sender, const WebRtcArgs &args, const onCreateWebRtc &cb) {
MediaInfo info(args["url"]);
Broadcast::PublishAuthInvoker invoker = [cb, info](const string &err, const ProtocolOption &option) mutable {
@ -1715,7 +1711,7 @@ void push_plugin(SocketHelper& sender, const WebRtcArgs &args, const onCreateWeb
push_src_ownership = push_src->getOwnership();
push_src->setProtocolOption(option);
}
auto rtc = Type::create(EventPollerPool::Instance().getPoller(), push_src, push_src_ownership, info, option,
auto rtc = WebRtcPusher::create(EventPollerPool::Instance().getPoller(), push_src, push_src_ownership, info, option,
WebRtcTransport::Role::PEER, WebRtcTransport::SignalingProtocols::WHEP_WHIP);
push_src->setListener(rtc);
cb(*rtc);
@ -1786,12 +1782,9 @@ static void setWebRtcArgs(const WebRtcArgs &args, WebRtcInterface &rtc) {
}
}
auto preferred_tcp = args["preferred_tcp"];
if (!preferred_tcp.empty()) {
bool preferred_tcp = args["preferred_tcp"];
{
rtc.setPreferredTcp(preferred_tcp);
} else {
GET_CONFIG(bool, s_preferred_tcp, Rtc::kPreferredTcp);
rtc.setPreferredTcp(s_preferred_tcp);
}
{
@ -1839,7 +1832,7 @@ static onceToken s_rtc_auto_register([]() {
// Enable echo plugin only in debug mode
WebRtcPluginManager::Instance().registerPlugin("echo", echo_plugin);
#endif
WebRtcPluginManager::Instance().registerPlugin("push", push_plugin<WebRtcPusher>);
WebRtcPluginManager::Instance().registerPlugin("push", push_plugin);
WebRtcPluginManager::Instance().registerPlugin("play", play_plugin<WebRtcPlayer>);
WebRtcPluginManager::Instance().registerPlugin("talk", play_plugin<WebRtcTalk>);

View File

@ -286,7 +286,7 @@ public:
struct WrappedMediaTrack {
MediaTrack::Ptr track;
explicit WrappedMediaTrack(MediaTrack::Ptr ptr): track(std::move(ptr)) {}
explicit WrappedMediaTrack(MediaTrack::Ptr ptr): track(ptr) {}
virtual ~WrappedMediaTrack() {}
virtual void inputRtp(const char *buf, size_t len, uint64_t stamp_ms, RtpHeader *rtp) = 0;
};