mirror of
https://gitee.com/xia-chu/ZLMediaKit.git
synced 2026-05-21 09:07:49 +08:00
Compare commits
3 Commits
a13063c5e4
...
22a8a9a2ec
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22a8a9a2ec | ||
|
|
3b54168b44 | ||
|
|
4e170e9281 |
@ -46,7 +46,8 @@
|
||||
"path": [
|
||||
"index",
|
||||
"api",
|
||||
"getApiList"
|
||||
"stack",
|
||||
"stop"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
@ -56,7 +57,44 @@
|
||||
},
|
||||
{
|
||||
"key": "id",
|
||||
"value": "stack_test"
|
||||
"value": "stack_test",
|
||||
"description": "多屏拼接id"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "重置多屏拼接(stack/reset)",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\r\n \"gapv\": 0.002,\r\n \"gaph\": 0.001,\r\n \"width\": 1920,\r\n \"url\": [\r\n [\r\n \"rtsp://kkem.me/live/test3\",\r\n \"rtsp://kkem.me/live/cy1\",\r\n \"rtsp://kkem.me/live/cy1\",\r\n \"rtsp://kkem.me/live/cy2\"\r\n ],\r\n [\r\n \"rtsp://kkem.me/live/cy1\",\r\n \"rtsp://kkem.me/live/cy5\",\r\n \"rtsp://kkem.me/live/cy3\",\r\n \"rtsp://kkem.me/live/cy4\"\r\n ],\r\n [\r\n \"rtsp://kkem.me/live/cy5\",\r\n \"rtsp://kkem.me/live/cy6\",\r\n \"rtsp://kkem.me/live/cy7\",\r\n \"rtsp://kkem.me/live/cy8\"\r\n ],\r\n [\r\n \"rtsp://kkem.me/live/cy9\",\r\n \"rtsp://kkem.me/live/cy10\",\r\n \"rtsp://kkem.me/live/cy11\",\r\n \"rtsp://kkem.me/live/cy12\"\r\n ]\r\n ],\r\n \"id\": \"89\",\r\n \"row\": 4,\r\n \"col\": 4,\r\n \"height\": 1080,\r\n \"span\": [\r\n [\r\n [\r\n 0,\r\n 0\r\n ],\r\n [\r\n 1,\r\n 1\r\n ]\r\n ],\r\n [\r\n [\r\n 3,\r\n 0\r\n ],\r\n [\r\n 3,\r\n 1\r\n ]\r\n ],\r\n [\r\n [\r\n 2,\r\n 3\r\n ],\r\n [\r\n 3,\r\n 3\r\n ]\r\n ]\r\n ]\r\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{ZLMediaKit_URL}}/index/api/stack/reset?secret={{ZLMediaKit_secret}}",
|
||||
"host": [
|
||||
"{{ZLMediaKit_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"index",
|
||||
"api",
|
||||
"stack",
|
||||
"reset"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "secret",
|
||||
"value": "{{ZLMediaKit_secret}}",
|
||||
"description": "api操作密钥(配置文件配置)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -875,6 +913,12 @@
|
||||
"description": "推流重试次数,不传此参数或传值<=0时,则无限重试",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"key": "force",
|
||||
"value": null,
|
||||
"description": "是否强制添加代理,默认0,设置为1时如果拉流失败也会不断重试",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"key": "latency",
|
||||
"value": null,
|
||||
@ -1226,19 +1270,19 @@
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "获取流信息(getMp4RecordFile)",
|
||||
"name": "获取录像文件列表(getMP4RecordFile)",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{ZLMediaKit_URL}}/index/api/getMp4RecordFile?secret={{ZLMediaKit_secret}}&vhost={{defaultVhost}}&app=proxy&stream=2&customized_path=/www&period=2020-05-26",
|
||||
"raw": "{{ZLMediaKit_URL}}/index/api/getMP4RecordFile?secret={{ZLMediaKit_secret}}&vhost={{defaultVhost}}&app=proxy&stream=2&customized_path=/www&period=2020-05-26",
|
||||
"host": [
|
||||
"{{ZLMediaKit_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"index",
|
||||
"api",
|
||||
"getMp4RecordFile"
|
||||
"getMP4RecordFile"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
@ -2951,6 +2995,246 @@
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "下载程序二进制文件(downloadBin)",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{ZLMediaKit_URL}}/index/api/downloadBin?secret={{ZLMediaKit_secret}}",
|
||||
"host": [
|
||||
"{{ZLMediaKit_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"index",
|
||||
"api",
|
||||
"downloadBin"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "secret",
|
||||
"value": "{{ZLMediaKit_secret}}",
|
||||
"description": "api操作密钥(配置文件配置)"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "WebRTC交互(webrtc)",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{ZLMediaKit_URL}}/index/api/webrtc?secret={{ZLMediaKit_secret}}&type=play&app=live&stream=test",
|
||||
"host": [
|
||||
"{{ZLMediaKit_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"index",
|
||||
"api",
|
||||
"webrtc"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "type",
|
||||
"value": "play",
|
||||
"description": "webrtc类型,play为播放,push为推流,echo为回显测试"
|
||||
},
|
||||
{
|
||||
"key": "app",
|
||||
"value": "live",
|
||||
"description": "应用名"
|
||||
},
|
||||
{
|
||||
"key": "stream",
|
||||
"value": "test",
|
||||
"description": "流id"
|
||||
},
|
||||
{
|
||||
"key": "preferred_tcp",
|
||||
"value": null,
|
||||
"description": "是否webrtc over tcp优先模式",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"key": "cand_udp",
|
||||
"value": "test",
|
||||
"description": "指定zlm服务器udp candidate",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"key": "cand_tcp",
|
||||
"value": null,
|
||||
"description": "指定zlm服务器tcp candidate",
|
||||
"disabled": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "WebRTC交互接口,body为SDP offer"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "WebRTC-WHIP推流(whip)",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/sdp"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{ZLMediaKit_URL}}/index/api/whip?app=live&stream=test",
|
||||
"host": [
|
||||
"{{ZLMediaKit_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"index",
|
||||
"api",
|
||||
"whip"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "app",
|
||||
"value": "live",
|
||||
"description": "应用名"
|
||||
},
|
||||
{
|
||||
"key": "stream",
|
||||
"value": "test",
|
||||
"description": "流id"
|
||||
},
|
||||
{
|
||||
"key": "preferred_tcp",
|
||||
"value": null,
|
||||
"description": "是否webrtc over tcp优先模式",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"key": "cand_udp",
|
||||
"value": "test",
|
||||
"description": "指定zlm服务器udp candidate",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"key": "cand_tcp",
|
||||
"value": null,
|
||||
"description": "指定zlm服务器tcp candidate",
|
||||
"disabled": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "WebRTC WHIP标准推流接口,body为SDP offer"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "WebRTC-WHEP播放(whep)",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/sdp"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{ZLMediaKit_URL}}/index/api/whep?app=live&stream=test",
|
||||
"host": [
|
||||
"{{ZLMediaKit_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"index",
|
||||
"api",
|
||||
"whep"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "app",
|
||||
"value": "live",
|
||||
"description": "应用名"
|
||||
},
|
||||
{
|
||||
"key": "stream",
|
||||
"value": "test",
|
||||
"description": "流id"
|
||||
},
|
||||
{
|
||||
"key": "preferred_tcp",
|
||||
"value": null,
|
||||
"description": "是否webrtc over tcp优先模式",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"key": "cand_udp",
|
||||
"value": "test",
|
||||
"description": "指定zlm服务器udp candidate",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"key": "cand_tcp",
|
||||
"value": null,
|
||||
"description": "指定zlm服务器tcp candidate",
|
||||
"disabled": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "WebRTC WHEP标准播放接口,body为SDP offer"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "WebRTC-删除连接(delete_webrtc)",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{ZLMediaKit_URL}}/index/api/delete_webrtc?id=&token=",
|
||||
"host": [
|
||||
"{{ZLMediaKit_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"index",
|
||||
"api",
|
||||
"delete_webrtc"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": "",
|
||||
"description": "WebRTC连接的唯一标识"
|
||||
},
|
||||
{
|
||||
"key": "token",
|
||||
"value": "",
|
||||
"description": "删除操作的验证token"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "删除WebRTC连接,需要使用DELETE方法。id和token由whip/whep接口返回的Location头中获取。"
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "登录(login)",
|
||||
"request": {
|
||||
|
||||
@ -379,10 +379,53 @@ Value ToJson(const PusherProxy::Ptr& p) {
|
||||
return item;
|
||||
}
|
||||
|
||||
Json::Value dumpTracks(const std::vector<Track::Ptr> &tracks) {
|
||||
Json::Value ret(arrayValue);
|
||||
for (auto &track : tracks) {
|
||||
Value obj;
|
||||
auto codec_type = track->getTrackType();
|
||||
obj["codec_id"] = track->getCodecId();
|
||||
obj["codec_id_name"] = track->getCodecName();
|
||||
obj["ready"] = track->ready();
|
||||
obj["codec_type"] = codec_type;
|
||||
obj["frames"] = track->getFrames();
|
||||
obj["duration"] = track->getDuration();
|
||||
switch (codec_type) {
|
||||
case TrackAudio: {
|
||||
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
|
||||
obj["sample_rate"] = audio_track->getAudioSampleRate();
|
||||
obj["channels"] = audio_track->getAudioChannel();
|
||||
obj["sample_bit"] = audio_track->getAudioSampleBit();
|
||||
break;
|
||||
}
|
||||
case TrackVideo: {
|
||||
auto video_track = dynamic_pointer_cast<VideoTrack>(track);
|
||||
obj["width"] = video_track->getVideoWidth();
|
||||
obj["height"] = video_track->getVideoHeight();
|
||||
obj["key_frames"] = video_track->getVideoKeyFrames();
|
||||
int gop_size = video_track->getVideoGopSize();
|
||||
int gop_interval_ms = video_track->getVideoGopInterval();
|
||||
float fps = video_track->getVideoFps();
|
||||
if (fps <= 1 && gop_interval_ms) {
|
||||
fps = gop_size * 1000.0 / gop_interval_ms;
|
||||
}
|
||||
obj["fps"] = round(fps);
|
||||
obj["gop_size"] = gop_size;
|
||||
obj["gop_interval_ms"] = gop_interval_ms;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
ret.append(obj);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value ToJson(const PlayerProxy::Ptr& p) {
|
||||
Value item;
|
||||
item["url"] = p->getUrl();
|
||||
item["status"] = p->getStatus();
|
||||
item["status_str"] = p->getStatusStr();
|
||||
item["liveSecs"] = p->getLiveSecs();
|
||||
item["rePullCount"] = p->getRePullCount();
|
||||
item["totalReaderCount"] = p->totalReaderCount();
|
||||
@ -390,10 +433,11 @@ Value ToJson(const PlayerProxy::Ptr& p) {
|
||||
item["totalBytes"] = (Json::UInt64) p->getRecvTotalBytes();
|
||||
|
||||
dumpMediaTuple(p->getMediaTuple(), item["src"]);
|
||||
item["tracks"] = dumpTracks(p->getTracks(false));
|
||||
return item;
|
||||
}
|
||||
|
||||
Value makeMediaSourceJson(MediaSource &media){
|
||||
Value makeMediaSourceJson(MediaSource &media) {
|
||||
Value item;
|
||||
item["schema"] = media.getSchema();
|
||||
dumpMediaTuple(media.getMediaTuple(), item);
|
||||
@ -421,17 +465,13 @@ Value makeMediaSourceJson(MediaSource &media){
|
||||
auto current_thread = false;
|
||||
try { current_thread = media.getOwnerPoller()->isCurrentThread();} catch (...) {}
|
||||
float last_loss = -1;
|
||||
for(auto &track : media.getTracks(false)){
|
||||
Value obj;
|
||||
auto codec_type = track->getTrackType();
|
||||
obj["codec_id"] = track->getCodecId();
|
||||
obj["codec_id_name"] = track->getCodecName();
|
||||
obj["ready"] = track->ready();
|
||||
obj["codec_type"] = codec_type;
|
||||
if (current_thread) {
|
||||
auto tracks = dumpTracks(media.getTracks(false));
|
||||
if (current_thread) {
|
||||
for (auto &obj : tracks) {
|
||||
// rtp推流只有一个统计器,但是可能有多个track,如果短时间多次获取间隔丢包率,第二次会获取为-1 [AUTO-TRANSLATED:5bfbc951]
|
||||
// RTP push stream has only one statistics, but may have multiple tracks. If you get the interval packet loss rate multiple times in a short time, the second time will get -1
|
||||
auto loss = media.getLossRate(codec_type);
|
||||
// RTP push stream has only one statistics, but may have multiple tracks. If you get the interval packet loss rate multiple times in a short time,
|
||||
// the second time will get -1
|
||||
auto loss = media.getLossRate(getTrackType(static_cast<CodecId>(obj["codec_type"].asInt())));
|
||||
if (loss == -1) {
|
||||
loss = last_loss;
|
||||
} else {
|
||||
@ -439,37 +479,8 @@ Value makeMediaSourceJson(MediaSource &media){
|
||||
}
|
||||
obj["loss"] = loss;
|
||||
}
|
||||
obj["frames"] = track->getFrames();
|
||||
obj["duration"] = track->getDuration();
|
||||
switch(codec_type){
|
||||
case TrackAudio : {
|
||||
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
|
||||
obj["sample_rate"] = audio_track->getAudioSampleRate();
|
||||
obj["channels"] = audio_track->getAudioChannel();
|
||||
obj["sample_bit"] = audio_track->getAudioSampleBit();
|
||||
break;
|
||||
}
|
||||
case TrackVideo : {
|
||||
auto video_track = dynamic_pointer_cast<VideoTrack>(track);
|
||||
obj["width"] = video_track->getVideoWidth();
|
||||
obj["height"] = video_track->getVideoHeight();
|
||||
obj["key_frames"] = video_track->getVideoKeyFrames();
|
||||
int gop_size = video_track->getVideoGopSize();
|
||||
int gop_interval_ms = video_track->getVideoGopInterval();
|
||||
float fps = video_track->getVideoFps();
|
||||
if (fps <= 1 && gop_interval_ms) {
|
||||
fps = gop_size * 1000.0 / gop_interval_ms;
|
||||
}
|
||||
obj["fps"] = round(fps);
|
||||
obj["gop_size"] = gop_size;
|
||||
obj["gop_interval_ms"] = gop_interval_ms;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
item["tracks"].append(obj);
|
||||
}
|
||||
item["tracks"] = std::move(tracks);
|
||||
return item;
|
||||
}
|
||||
|
||||
@ -583,7 +594,7 @@ void getStatisticJson(const function<void(Value &val)> &cb) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void addStreamProxy(const MediaTuple &tuple, const string &url, int retry_count,
|
||||
void addStreamProxy(const MediaTuple &tuple, const string &url, int retry_count, bool force,
|
||||
const ProtocolOption &option, int rtp_type, float timeout_sec, const mINI &args,
|
||||
const function<void(const SockException &ex, const string &key)> &cb) {
|
||||
auto key = tuple.shortUrl();
|
||||
@ -615,11 +626,18 @@ void addStreamProxy(const MediaTuple &tuple, const string &url, int retry_count,
|
||||
|
||||
// 开始播放,如果播放失败或者播放中止,将会自动重试若干次,默认一直重试 [AUTO-TRANSLATED:ac8499e5]
|
||||
// Start playing. If playback fails or is stopped, it will automatically retry several times, by default it will retry indefinitely
|
||||
player->setPlayCallbackOnce([cb, key](const SockException &ex) {
|
||||
if (ex) {
|
||||
s_player_proxy.erase(key);
|
||||
player->setPlayCallbackOnce([cb, key, force](const SockException &ex) {
|
||||
if (force) {
|
||||
// 强制添加成功
|
||||
cb(SockException(), key);
|
||||
} else {
|
||||
// 非强制添加
|
||||
if (ex) {
|
||||
// 失败则移除记录
|
||||
s_player_proxy.erase(key);
|
||||
}
|
||||
cb(ex, key);
|
||||
}
|
||||
cb(ex, key);
|
||||
});
|
||||
|
||||
// 被主动关闭拉流 [AUTO-TRANSLATED:41a19476]
|
||||
@ -1264,6 +1282,7 @@ void installWebApi() {
|
||||
addStreamProxy(tuple,
|
||||
allArgs["url"],
|
||||
retry_count,
|
||||
allArgs["force"],
|
||||
option,
|
||||
allArgs["rtp_type"],
|
||||
allArgs["timeout_sec"],
|
||||
|
||||
@ -248,7 +248,7 @@ uint16_t openRtpServer(uint16_t local_port, const mediakit::MediaTuple &tuple, i
|
||||
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,
|
||||
void addStreamProxy(const mediakit::MediaTuple &tuple, const std::string &url, int retry_count, bool force,
|
||||
const mediakit::ProtocolOption &option, int rtp_type, float timeout_sec, const toolkit::mINI &args,
|
||||
const std::function<void(const toolkit::SockException &ex, const std::string &key)> &cb);
|
||||
|
||||
|
||||
@ -321,7 +321,7 @@ static void pullStreamFromOrigin(const vector<string> &urls, size_t index, size_
|
||||
option.enable_hls = option.enable_hls || (args.schema == HLS_SCHEMA);
|
||||
option.enable_mp4 = false;
|
||||
|
||||
addStreamProxy(args, url, retry_count, option, Rtsp::RTP_TCP, timeout_sec, mINI{}, [=](const SockException &ex, const string &key) mutable {
|
||||
addStreamProxy(args, url, retry_count, false, option, Rtsp::RTP_TCP, timeout_sec, mINI{}, [=](const SockException &ex, const string &key) mutable {
|
||||
if (!ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -46,6 +46,10 @@ void TsPlayerImp::onPlayResult(const SockException &ex) {
|
||||
}
|
||||
|
||||
void TsPlayerImp::onShutdown(const SockException &ex) {
|
||||
if (!ex) {
|
||||
// http-ts拉流,如果为eof正常断开,那么强制为异常状态
|
||||
const_cast<SockException &>(ex).reset(Err_other, ex.what());
|
||||
}
|
||||
while (_demuxer) {
|
||||
try {
|
||||
// shared_from_this()可能抛异常 [AUTO-TRANSLATED:6af9bd3c]
|
||||
|
||||
@ -32,7 +32,7 @@ PlayerProxy::PlayerProxy(
|
||||
setOnClose(nullptr);
|
||||
setOnConnect(nullptr);
|
||||
setOnDisconnect(nullptr);
|
||||
|
||||
|
||||
_reconnect_delay_min = reconnect_delay_min > 0 ? reconnect_delay_min : 2;
|
||||
_reconnect_delay_max = reconnect_delay_max > 0 ? reconnect_delay_max : 60;
|
||||
_reconnect_delay_step = reconnect_delay_step > 0 ? reconnect_delay_step : 3;
|
||||
@ -51,15 +51,14 @@ void PlayerProxy::setOnClose(function<void(const SockException &ex)> cb) {
|
||||
}
|
||||
|
||||
void PlayerProxy::setOnDisconnect(std::function<void()> cb) {
|
||||
_on_disconnect = cb ? std::move(cb) : [] () {};
|
||||
_on_disconnect = cb ? std::move(cb) : []() {};
|
||||
}
|
||||
|
||||
void PlayerProxy::setOnConnect(std::function<void(const TranslationInfo&)> cb) {
|
||||
_on_connect = cb ? std::move(cb) : [](const TranslationInfo&) {};
|
||||
void PlayerProxy::setOnConnect(std::function<void(const TranslationInfo &)> cb) {
|
||||
_on_connect = cb ? std::move(cb) : [](const TranslationInfo &) {};
|
||||
}
|
||||
|
||||
void PlayerProxy::setTranslationInfo()
|
||||
{
|
||||
void PlayerProxy::setTranslationInfo() {
|
||||
_transtalion_info.byte_speed = _media_src ? _media_src->getBytesSpeed() : -1;
|
||||
_transtalion_info.start_time_stamp = _media_src ? _media_src->getCreateStamp() : 0;
|
||||
_transtalion_info.stream_info.clear();
|
||||
@ -72,22 +71,21 @@ void PlayerProxy::setTranslationInfo()
|
||||
back.codec_type = track->getTrackType();
|
||||
back.codec_name = track->getCodecName();
|
||||
switch (back.codec_type) {
|
||||
case TrackAudio : {
|
||||
case TrackAudio: {
|
||||
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
|
||||
back.audio_sample_rate = audio_track->getAudioSampleRate();
|
||||
back.audio_channel = audio_track->getAudioChannel();
|
||||
back.audio_sample_bit = audio_track->getAudioSampleBit();
|
||||
break;
|
||||
}
|
||||
case TrackVideo : {
|
||||
case TrackVideo: {
|
||||
auto video_track = dynamic_pointer_cast<VideoTrack>(track);
|
||||
back.video_width = video_track->getVideoWidth();
|
||||
back.video_height = video_track->getVideoHeight();
|
||||
back.video_fps = video_track->getVideoFps();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,6 +110,7 @@ void PlayerProxy::play(const string &strUrlTmp) {
|
||||
}
|
||||
if (err) {
|
||||
NOTICE_EMIT(BroadcastPlayerProxyFailedArgs, Broadcast::kBroadcastPlayerProxyFailed, *strongSelf, err);
|
||||
strongSelf->_status = std::make_shared<std::string>(std::string("play failed: ") + err.what());
|
||||
}
|
||||
if (strongSelf->_on_play) {
|
||||
strongSelf->_on_play(err);
|
||||
@ -120,7 +119,8 @@ void PlayerProxy::play(const string &strUrlTmp) {
|
||||
|
||||
if (!err) {
|
||||
// 取消定时器,避免hls拉流索引文件因为网络波动失败重连成功后出现循环重试的情况 [AUTO-TRANSLATED:91e5f0c8]
|
||||
// Cancel the timer to avoid the situation where the hls stream index file fails to reconnect due to network fluctuations and then retries in a loop after successful reconnection
|
||||
// Cancel the timer to avoid the situation where the hls stream index file fails to reconnect due to network fluctuations and then retries in a loop
|
||||
// after successful reconnection
|
||||
strongSelf->_timer.reset();
|
||||
strongSelf->_live_ticker.resetTime();
|
||||
strongSelf->_live_status = 0;
|
||||
@ -129,9 +129,10 @@ void PlayerProxy::play(const string &strUrlTmp) {
|
||||
*piFailedCnt = 0; // 连续播放失败次数清0
|
||||
strongSelf->onPlaySuccess();
|
||||
strongSelf->setTranslationInfo();
|
||||
strongSelf->_on_connect(strongSelf->_transtalion_info);
|
||||
strongSelf->_on_connect(strongSelf->_transtalion_info);
|
||||
|
||||
InfoL << "play " << strUrlTmp << " success";
|
||||
strongSelf->_status = std::make_shared<std::string>("playing");
|
||||
} else if (*piFailedCnt < strongSelf->_retry_count || strongSelf->_retry_count < 0) {
|
||||
// 播放失败,延时重试播放 [AUTO-TRANSLATED:d7537c9c]
|
||||
// Play failed, retry playing with delay
|
||||
@ -151,6 +152,11 @@ void PlayerProxy::play(const string &strUrlTmp) {
|
||||
if (err) {
|
||||
NOTICE_EMIT(BroadcastPlayerProxyFailedArgs, Broadcast::kBroadcastPlayerProxyFailed, *strongSelf, err);
|
||||
}
|
||||
if (strongSelf->_on_play) {
|
||||
strongSelf->_on_play(err);
|
||||
strongSelf->_on_play = nullptr;
|
||||
}
|
||||
strongSelf->_status = std::make_shared<std::string>(std::string("play shutdown: ") + err.what());
|
||||
|
||||
// 注销直接拉流代理产生的流:#532 [AUTO-TRANSLATED:c6343a3b]
|
||||
// Unregister the stream generated by the direct stream proxy: #532
|
||||
@ -190,8 +196,10 @@ void PlayerProxy::play(const string &strUrlTmp) {
|
||||
}
|
||||
});
|
||||
try {
|
||||
_status = std::make_shared<std::string>("connecting");
|
||||
MediaPlayer::play(strUrlTmp);
|
||||
} catch (std::exception &ex) {
|
||||
_status = std::make_shared<std::string>(std::string("play failed: ") + ex.what());
|
||||
ErrorL << ex.what();
|
||||
onPlayResult(SockException(Err_other, ex.what()));
|
||||
return;
|
||||
@ -291,7 +299,7 @@ float PlayerProxy::getLossRate(MediaSource &sender, TrackType type) {
|
||||
return getPacketLossRate(type);
|
||||
}
|
||||
|
||||
toolkit::EventPoller::Ptr PlayerProxy::getOwnerPoller(MediaSource &sender) {
|
||||
toolkit::EventPoller::Ptr PlayerProxy::getOwnerPoller(MediaSource &sender) {
|
||||
return getPoller();
|
||||
}
|
||||
|
||||
@ -314,10 +322,10 @@ void PlayerProxy::onPlaySuccess() {
|
||||
// rtmp拉流代理 [AUTO-TRANSLATED:21173335]
|
||||
// Rtmp stream proxy
|
||||
if (reset_when_replay || !_muxer) {
|
||||
auto old = _option.enable_rtmp;
|
||||
auto old = _option.enable_rtmp;
|
||||
_option.enable_rtmp = false;
|
||||
_muxer = std::make_shared<MultiMediaSourceMuxer>(_tuple, getDuration(), _option);
|
||||
_option.enable_rtmp = old;
|
||||
_option.enable_rtmp = old;
|
||||
}
|
||||
} else {
|
||||
// 其他拉流代理 [AUTO-TRANSLATED:e5f2e45d]
|
||||
@ -362,6 +370,12 @@ void PlayerProxy::onPlaySuccess() {
|
||||
int PlayerProxy::getStatus() {
|
||||
return _live_status.load();
|
||||
}
|
||||
|
||||
std::string PlayerProxy::getStatusStr() const {
|
||||
auto status = _status;
|
||||
return status ? *status : "unknown";
|
||||
}
|
||||
|
||||
uint64_t PlayerProxy::getLiveSecs() {
|
||||
if (_live_status == 0) {
|
||||
return _live_secs + _live_ticker.elapsedTime() / 1000;
|
||||
|
||||
@ -129,6 +129,7 @@ public:
|
||||
int totalReaderCount();
|
||||
|
||||
int getStatus();
|
||||
std::string getStatusStr() const;
|
||||
uint64_t getLiveSecs();
|
||||
uint64_t getRePullCount();
|
||||
|
||||
@ -155,6 +156,7 @@ private:
|
||||
void setTranslationInfo();
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::string> _status;
|
||||
int _retry_count;
|
||||
int _reconnect_delay_min;
|
||||
int _reconnect_delay_max;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user