Compare commits

...

7 Commits

Author SHA1 Message Date
alex
9087734511
Merge 90bd28249e into 8ccb4e95b3 2024-11-05 19:07:41 +08:00
mtdxc
8ccb4e95b3
update webassist (#3996)
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
更新webassist界面:
1. 增加获取播放器列表
2. 增加推流代理管理
3. 增加拉流代理管理
4. 增加ffmpeg源管理
5. 精简化medialist显示
2024-11-01 14:07:55 +08:00
mtdxc
901c381300
新增获取推流推流代理列表和ffmpeg源列表接口 (#3992) 2024-11-01 10:47:18 +08:00
wuxingzhong
6729257eab
修复时间戳回退导致超大mp4切片问题 (#3991)
Some checks are pending
Android / build (push) Waiting to run
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Docker / build (push) Waiting to run
Linux / build (push) Waiting to run
macOS / build (push) Waiting to run
Windows / build (push) Waiting to run
当出现dts回退时,应该取frame->dts(), 即MIN, 非MAX
2024-10-31 20:11:34 +08:00
alex
90bd28249e Translate comments in src/Common/MediaSink.cpp 2024-09-21 09:44:57 +08:00
alex
c3106d514a Translate comments in src/Common/MediaSink.cpp 2024-09-21 09:26:48 +08:00
alex
f03d414e82 Translate comments in src/Common/MediaSink.cpp 2024-09-21 09:26:17 +08:00
14 changed files with 182 additions and 18 deletions

View File

@ -700,6 +700,58 @@
}, },
"response": [] "response": []
}, },
{
"name": "获取拉流代理列表(listStreamProxy)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/listStreamProxy?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"listStreamProxy"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置)"
}
]
}
},
"response": []
},
{
"name": "获取推流代理列表(listStreamPusherProxy)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/listStreamPusherProxy?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"listStreamPusherProxy"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置)"
}
]
}
},
"response": []
},
{ {
"name": "添加rtsp/rtmp推流(addStreamPusherProxy)", "name": "添加rtsp/rtmp推流(addStreamPusherProxy)",
"request": { "request": {
@ -800,6 +852,32 @@
}, },
"response": [] "response": []
}, },
{
"name": "获取FFmpeg拉流代理列表(listFFmpegSource)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/listFFmpegSource?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"listFFmpegSource"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置)"
}
]
}
},
"response": []
},
{ {
"name": "添加FFmpeg拉流代理(addFFmpegSource)", "name": "添加FFmpeg拉流代理(addFFmpegSource)",
"request": { "request": {

View File

@ -103,6 +103,7 @@ void FFmpegSource::play(const string &ffmpeg_cmd_key, const string &src_url, con
snprintf(cmd, sizeof(cmd), ffmpeg_cmd.data(), File::absolutePath("", ffmpeg_bin).data(), src_url.data(), dst_url.data()); snprintf(cmd, sizeof(cmd), ffmpeg_cmd.data(), File::absolutePath("", ffmpeg_bin).data(), src_url.data(), dst_url.data());
auto log_file = ffmpeg_log.empty() ? "" : File::absolutePath("", ffmpeg_log); auto log_file = ffmpeg_log.empty() ? "" : File::absolutePath("", ffmpeg_log);
_process.run(cmd, log_file); _process.run(cmd, log_file);
_cmd = cmd;
InfoL << cmd; InfoL << cmd;
if (is_local_ip(_media_info.host)) { if (is_local_ip(_media_info.host)) {

View File

@ -77,6 +77,12 @@ public:
*/ */
void play(const std::string &ffmpeg_cmd_key, const std::string &src_url, const std::string &dst_url, int timeout_ms, const onPlay &cb); void play(const std::string &ffmpeg_cmd_key, const std::string &src_url, const std::string &dst_url, int timeout_ms, const onPlay &cb);
const std::string& getSrcUrl() const { return _src_url; }
const std::string& getDstUrl() const { return _dst_url; }
const std::string& getCmd() const { return _cmd; }
const std::string& getCmdKey() const { return _ffmpeg_cmd_key; }
const mediakit::MediaInfo& getMediaInfo() const { return _media_info; }
/** /**
* *
* @param enable_hls hls直播或录制 * @param enable_hls hls直播或录制
@ -115,6 +121,7 @@ private:
std::string _src_url; std::string _src_url;
std::string _dst_url; std::string _dst_url;
std::string _ffmpeg_cmd_key; std::string _ffmpeg_cmd_key;
std::string _cmd;
std::function<void()> _onClose; std::function<void()> _onClose;
toolkit::Ticker _replay_ticker; toolkit::Ticker _replay_ticker;
}; };

View File

@ -346,6 +346,15 @@ public:
return it->second; return it->second;
} }
void for_each(const std::function<void(const std::string&, const Pointer&)>& cb) {
std::lock_guard<std::recursive_mutex> lck(_mtx);
auto it = _map.begin();
while (it != _map.end()) {
cb(it->first, it->second);
it++;
}
}
template<class ..._Args> template<class ..._Args>
Pointer make(const std::string &key, _Args&& ...__args) { Pointer make(const std::string &key, _Args&& ...__args) {
// assert(!find(key)); // assert(!find(key));
@ -409,6 +418,29 @@ void dumpMediaTuple(const MediaTuple &tuple, Json::Value& item) {
item["params"] = tuple.params; item["params"] = tuple.params;
} }
Value ToJson(const PusherProxy::Ptr& p) {
Value item;
item["url"] = p->getUrl();
item["status"] = p->getStatus();
item["liveSecs"] = p->getLiveSecs();
item["rePublishCount"] = p->getRePublishCount();
if (auto src = p->getSrc()) {
dumpMediaTuple(src->getMediaTuple(), item["src"]);
}
return item;
}
Value ToJson(const PlayerProxy::Ptr& p) {
Value item;
item["url"] = p->getUrl();
item["status"] = p->getStatus();
item["liveSecs"] = p->getLiveSecs();
item["rePullCount"] = p->getRePullCount();
item["totalReaderCount"] = p->totalReaderCount();
dumpMediaTuple(p->getMediaTuple(), item["src"]);
return item;
}
Value makeMediaSourceJson(MediaSource &media){ Value makeMediaSourceJson(MediaSource &media){
Value item; Value item;
item["schema"] = media.getSchema(); item["schema"] = media.getSchema();
@ -1173,7 +1205,22 @@ void installWebApi() {
CHECK_ARGS("key"); CHECK_ARGS("key");
val["data"]["flag"] = s_pusher_proxy.erase(allArgs["key"]) == 1; val["data"]["flag"] = s_pusher_proxy.erase(allArgs["key"]) == 1;
}); });
api_regist("/index/api/listStreamPusherProxy", [](API_ARGS_MAP) {
CHECK_SECRET();
s_pusher_proxy.for_each([&val](const std::string& key, const PusherProxy::Ptr& p) {
Json::Value item = ToJson(p);
item["key"] = key;
val["data"].append(item);
});
});
api_regist("/index/api/listStreamProxy", [](API_ARGS_MAP) {
CHECK_SECRET();
s_player_proxy.for_each([&val](const std::string& key, const PlayerProxy::Ptr& p) {
Json::Value item = ToJson(p);
item["key"] = key;
val["data"].append(item);
});
});
// 动态添加rtsp/rtmp拉流代理 [AUTO-TRANSLATED:2616537c] // 动态添加rtsp/rtmp拉流代理 [AUTO-TRANSLATED:2616537c]
// Dynamically add rtsp/rtmp pull stream proxy // Dynamically add rtsp/rtmp pull stream proxy
// 测试url http://127.0.0.1/index/api/addStreamProxy?vhost=__defaultVhost__&app=proxy&enable_rtsp=1&enable_rtmp=1&stream=0&url=rtmp://127.0.0.1/live/obs [AUTO-TRANSLATED:71ddce15] // 测试url http://127.0.0.1/index/api/addStreamProxy?vhost=__defaultVhost__&app=proxy&enable_rtsp=1&enable_rtmp=1&stream=0&url=rtmp://127.0.0.1/live/obs [AUTO-TRANSLATED:71ddce15]
@ -1286,7 +1333,18 @@ void installWebApi() {
CHECK_ARGS("key"); CHECK_ARGS("key");
val["data"]["flag"] = s_ffmpeg_src.erase(allArgs["key"]) == 1; val["data"]["flag"] = s_ffmpeg_src.erase(allArgs["key"]) == 1;
}); });
api_regist("/index/api/listFFmpegSource", [](API_ARGS_MAP) {
CHECK_SECRET();
s_ffmpeg_src.for_each([&val](const std::string& key, const FFmpegSource::Ptr& src) {
Json::Value item;
item["src_url"] = src->getSrcUrl();
item["dst_url"] = src->getDstUrl();
item["cmd"] = src->getCmd();
item["ffmpeg_cmd_key"] = src->getCmdKey();
item["key"] = key;
val["data"].append(item);
});
});
// 新增http api下载可执行程序文件接口 [AUTO-TRANSLATED:d6e44e84] // 新增http api下载可执行程序文件接口 [AUTO-TRANSLATED:d6e44e84]
// Add a new http api to download executable files // Add a new http api to download executable files
// 测试url http://127.0.0.1/index/api/downloadBin [AUTO-TRANSLATED:9525e834] // 测试url http://127.0.0.1/index/api/downloadBin [AUTO-TRANSLATED:9525e834]
@ -1477,7 +1535,11 @@ void installWebApi() {
obj["vhost"] = vec[0]; obj["vhost"] = vec[0];
obj["app"] = vec[1]; obj["app"] = vec[1];
obj["stream_id"] = vec[2]; obj["stream_id"] = vec[2];
obj["port"] = pr.second->getPort(); auto& rtps = pr.second;
obj["port"] = rtps->getPort();
obj["ssrc"] = rtps->getSSRC();
obj["tcp_mode"] = rtps->getTcpMode();
obj["only_track"] = rtps->getOnlyTrack();
val["data"].append(obj); val["data"].append(obj);
} }
}); });
@ -1741,9 +1803,7 @@ void installWebApi() {
throw ApiRetException("can not find pusher", API::NotFound); throw ApiRetException("can not find pusher", API::NotFound);
} }
val["data"]["status"] = pusher->getStatus(); val["data"] = ToJson(pusher);
val["data"]["liveSecs"] = pusher->getLiveSecs();
val["data"]["rePublishCount"] = pusher->getRePublishCount();
invoker(200, headerOut, val.toStyledString()); invoker(200, headerOut, val.toStyledString());
}); });
@ -1755,9 +1815,7 @@ void installWebApi() {
throw ApiRetException("can not find the proxy", API::NotFound); throw ApiRetException("can not find the proxy", API::NotFound);
} }
val["data"]["status"] = proxy->getStatus(); val["data"] = ToJson(proxy);
val["data"]["liveSecs"] = proxy->getLiveSecs();
val["data"]["rePullCount"] = proxy->getRePullCount();
invoker(200, headerOut, val.toStyledString()); invoker(200, headerOut, val.toStyledString());
}); });

View File

@ -114,12 +114,14 @@ void MediaSink::checkTrackIfReady() {
} }
} }
// 等待音频超时时间 // 等待音频超时时间 [AUTO-TRANSLATED:5ec16b26]
// Wait for audio timeout time
GET_CONFIG(uint32_t, kWaitAudioTrackDataMS, General::kWaitAudioTrackDataMS); GET_CONFIG(uint32_t, kWaitAudioTrackDataMS, General::kWaitAudioTrackDataMS);
if (_max_track_size > 1) { if (_max_track_size > 1) {
for (auto it = _track_map.begin(); it != _track_map.end();) { for (auto it = _track_map.begin(); it != _track_map.end();) {
if (it->second.first->getTrackType() == TrackAudio && _ticker.elapsedTime() > kWaitAudioTrackDataMS && !it->second.second) { if (it->second.first->getTrackType() == TrackAudio && _ticker.elapsedTime() > kWaitAudioTrackDataMS && !it->second.second) {
// 音频超时且完全没收到音频数据,忽略音频 // 音频超时且完全没收到音频数据,忽略音频 [AUTO-TRANSLATED:0d0fbb13]
// Audio timeout and did not receive any audio data, ignore audio
auto index = it->second.first->getIndex(); auto index = it->second.first->getIndex();
WarnL << "Audio track index " << index << " codec " << it->second.first->getCodecName() << " receive no data for long " WarnL << "Audio track index " << index << " codec " << it->second.first->getCodecName() << " receive no data for long "
<< _ticker.elapsedTime() << "ms. Ignore it!"; << _ticker.elapsedTime() << "ms. Ignore it!";

View File

@ -139,6 +139,10 @@ public:
// Using this only makes sense after a successful connection to the server // Using this only makes sense after a successful connection to the server
TranslationInfo getTranslationInfo(); TranslationInfo getTranslationInfo();
const std::string& getUrl() const { return _pull_url; }
const MediaTuple& getMediaTuple() const { return _tuple; }
const ProtocolOption& getOption() const { return _option; }
private: private:
// MediaSourceEvent override // MediaSourceEvent override
bool close(MediaSource &sender) override; bool close(MediaSource &sender) override;

View File

@ -46,6 +46,7 @@ void MediaPusher::publish(const string &url) {
_delegate->setOnPublished(_on_publish); _delegate->setOnPublished(_on_publish);
_delegate->mINI::operator=(*this); _delegate->mINI::operator=(*this);
_delegate->publish(url); _delegate->publish(url);
_url = url;
} }
EventPoller::Ptr MediaPusher::getPoller(){ EventPoller::Ptr MediaPusher::getPoller(){

View File

@ -33,11 +33,13 @@ public:
void publish(const std::string &url) override; void publish(const std::string &url) override;
toolkit::EventPoller::Ptr getPoller(); toolkit::EventPoller::Ptr getPoller();
void setOnCreateSocket(toolkit::Socket::onCreateSocket cb); void setOnCreateSocket(toolkit::Socket::onCreateSocket cb);
std::shared_ptr<MediaSource> getSrc() { return _src.lock(); }
const std::string& getUrl() const { return _url; }
private: private:
std::weak_ptr<MediaSource> _src; std::weak_ptr<MediaSource> _src;
toolkit::EventPoller::Ptr _poller; toolkit::EventPoller::Ptr _poller;
toolkit::Socket::onCreateSocket _on_create_socket; toolkit::Socket::onCreateSocket _on_create_socket;
std::string _url;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -19,7 +19,6 @@ PusherProxy::PusherProxy(const MediaSource::Ptr &src, int retry_count, const Eve
: MediaPusher(src, poller) { : MediaPusher(src, poller) {
_retry_count = retry_count; _retry_count = retry_count;
_on_close = [](const SockException &) {}; _on_close = [](const SockException &) {};
_weak_src = src;
_live_secs = 0; _live_secs = 0;
_live_status = 1; _live_status = 1;
_republish_count = 0; _republish_count = 0;
@ -52,7 +51,7 @@ void PusherProxy::publish(const string &dst_url) {
strong_self->_on_publish = nullptr; strong_self->_on_publish = nullptr;
} }
auto src = strong_self->_weak_src.lock(); auto src = strong_self->getSrc();
if (!err) { if (!err) {
// 推流成功 [AUTO-TRANSLATED:28ce6e56] // 推流成功 [AUTO-TRANSLATED:28ce6e56]
// Stream successfully pushed // Stream successfully pushed
@ -87,7 +86,7 @@ void PusherProxy::publish(const string &dst_url) {
TraceL << " live secs " << strong_self->_live_secs; TraceL << " live secs " << strong_self->_live_secs;
} }
auto src = strong_self->_weak_src.lock(); auto src = strong_self->getSrc();
// 推流异常中断,延时重试播放 [AUTO-TRANSLATED:e69e5a05] // 推流异常中断,延时重试播放 [AUTO-TRANSLATED:e69e5a05]
// Stream abnormally interrupted, retry playing with delay // Stream abnormally interrupted, retry playing with delay
if (src && (*failed_cnt < strong_self->_retry_count || strong_self->_retry_count < 0)) { if (src && (*failed_cnt < strong_self->_retry_count || strong_self->_retry_count < 0)) {

View File

@ -77,7 +77,6 @@ private:
std::atomic<int> _live_status; std::atomic<int> _live_status;
std::atomic<uint64_t> _live_secs; std::atomic<uint64_t> _live_secs;
std::atomic<uint64_t> _republish_count; std::atomic<uint64_t> _republish_count;
std::weak_ptr<MediaSource> _weak_src;
std::function<void(const toolkit::SockException &ex)> _on_close; std::function<void(const toolkit::SockException &ex)> _on_close;
std::function<void(const toolkit::SockException &ex)> _on_publish; std::function<void(const toolkit::SockException &ex)> _on_publish;
}; };

View File

@ -126,7 +126,7 @@ bool MP4Recorder::inputFrame(const Frame::Ptr &frame) {
if (_last_dts == 0 || _last_dts > frame->dts()) { if (_last_dts == 0 || _last_dts > frame->dts()) {
// b帧情况下dts时间戳可能回退 [AUTO-TRANSLATED:1de38f77] // b帧情况下dts时间戳可能回退 [AUTO-TRANSLATED:1de38f77]
// In the case of b-frames, the dts timestamp may regress // In the case of b-frames, the dts timestamp may regress
_last_dts = MAX(frame->dts(), _last_dts); _last_dts = MIN(frame->dts(), _last_dts);
} }
auto duration = 5u; // 默认至少一帧5ms auto duration = 5u; // 默认至少一帧5ms
if (frame->dts() > 0 && frame->dts() > _last_dts) { if (frame->dts() > 0 && frame->dts() > _last_dts) {

View File

@ -295,5 +295,15 @@ void RtpServer::updateSSRC(uint32_t ssrc) {
} }
} }
uint32_t RtpServer::getSSRC() const {
if (_ssrc) {
return *_ssrc;
}
if (_tcp_server) {
return (*_tcp_server)[RtpSession::kSSRC];
}
return 0;
}
}//namespace mediakit }//namespace mediakit
#endif//defined(ENABLE_RTPPROXY) #endif//defined(ENABLE_RTPPROXY)

View File

@ -97,6 +97,9 @@ public:
*/ */
void updateSSRC(uint32_t ssrc); void updateSSRC(uint32_t ssrc);
uint32_t getSSRC() const;
int getOnlyTrack() const { return _only_track; }
TcpMode getTcpMode() const { return _tcp_mode; }
private: private:
// tcp主动模式连接服务器成功回调 [AUTO-TRANSLATED:0775844e] // tcp主动模式连接服务器成功回调 [AUTO-TRANSLATED:0775844e]
// tcp active mode connection server success callback // tcp active mode connection server success callback

@ -1 +1 @@
Subproject commit b02d2a4c1abf95db45e50bb77d789defa0fcc4b7 Subproject commit 353af1f60115767e57662107e30935ac6ef178a2