Merge pull request #1 from ZLMediaKit/master

同步主线
This commit is contained in:
ljx0305 2023-05-26 14:05:27 +08:00 committed by GitHub
commit 97d53824d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 172 additions and 23 deletions

@ -1 +1 @@
Subproject commit d134fbb9fe0b108dddb66a7bfa35b7b438426411 Subproject commit b30eeca034456417dfca72aa0d2258031013a5e6

View File

@ -1,5 +1,7 @@
![logo](https://raw.githubusercontent.com/ZLMediaKit/ZLMediaKit/master/www/logo.png) ![logo](https://raw.githubusercontent.com/ZLMediaKit/ZLMediaKit/master/www/logo.png)
简体中文 | [English](./README_en.md)
# 一个基于C++11的高性能运营级流媒体服务框架 # 一个基于C++11的高性能运营级流媒体服务框架
[![](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/ZLMediaKit/ZLMediaKit/blob/master/LICENSE) [![](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/ZLMediaKit/ZLMediaKit/blob/master/LICENSE)

View File

@ -1,5 +1,7 @@
![logo](https://raw.githubusercontent.com/zlmediakit/ZLMediaKit/master/www/logo.png) ![logo](https://raw.githubusercontent.com/zlmediakit/ZLMediaKit/master/www/logo.png)
[简体中文](./README.md) | English
# An high-performance, enterprise-level streaming media service framework based on C++11. # An high-performance, enterprise-level streaming media service framework based on C++11.

View File

@ -132,6 +132,12 @@ API_EXPORT void API_CALL mk_media_source_find(const char *schema,
int from_mp4, int from_mp4,
void *user_data, void *user_data,
on_mk_media_source_find_cb cb); on_mk_media_source_find_cb cb);
API_EXPORT const mk_media_source API_CALL mk_media_source_find2(const char *schema,
const char *vhost,
const char *app,
const char *stream,
int from_mp4);
//MediaSource::for_each_media() //MediaSource::for_each_media()
API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_source_find_cb cb, const char *schema, API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_source_find_cb cb, const char *schema,
const char *vhost, const char *app, const char *stream); const char *vhost, const char *app, const char *stream);

View File

@ -82,11 +82,11 @@ API_EXPORT void API_CALL mk_tcp_session_send_buffer(const mk_tcp_session ctx, mk
API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx, const char *data, size_t len); API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx, const char *data, size_t len);
API_EXPORT void API_CALL mk_tcp_session_send_buffer_safe(const mk_tcp_session ctx, mk_buffer buffer); API_EXPORT void API_CALL mk_tcp_session_send_buffer_safe(const mk_tcp_session ctx, mk_buffer buffer);
//创建mk_tcp_session的引用 //创建mk_tcp_session的引用
API_EXPORT mk_tcp_session_ref API_CALL mk_tcp_session_ref_from(const mk_tcp_session ctx); API_EXPORT mk_tcp_session_ref API_CALL mk_tcp_session_ref_from(const mk_tcp_session ctx);
//删除mk_tcp_session的引用 //删除mk_tcp_session的引用
API_EXPORT void mk_tcp_session_ref_release(const mk_tcp_session_ref ref); API_EXPORT void mk_tcp_session_ref_release(const mk_tcp_session_ref ref);
//根据弱引用获取mk_tcp_session如果mk_tcp_session已经销毁那么返回NULL //根据强引用获取mk_tcp_session
API_EXPORT mk_tcp_session mk_tcp_session_from_ref(const mk_tcp_session_ref ref); API_EXPORT mk_tcp_session mk_tcp_session_from_ref(const mk_tcp_session_ref ref);
///////////////////////////////////////////自定义tcp服务///////////////////////////////////////////// ///////////////////////////////////////////自定义tcp服务/////////////////////////////////////////////

View File

@ -248,6 +248,16 @@ API_EXPORT void API_CALL mk_media_source_find(const char *schema,
cb(user_data, (mk_media_source)src.get()); cb(user_data, (mk_media_source)src.get());
} }
API_EXPORT const mk_media_source API_CALL mk_media_source_find2(const char *schema,
const char *vhost,
const char *app,
const char *stream,
int from_mp4) {
assert(schema && vhost && app && stream);
auto src = MediaSource::find(schema, vhost, app, stream, from_mp4);
return (mk_media_source)src.get();
}
API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_source_find_cb cb, const char *schema, API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_source_find_cb cb, const char *schema,
const char *vhost, const char *app, const char *stream) { const char *vhost, const char *app, const char *stream) {
assert(cb); assert(cb);

View File

@ -263,7 +263,7 @@ API_EXPORT void API_CALL mk_media_input_yuv(mk_media ctx, const char *yuv[3], in
} }
API_EXPORT int API_CALL mk_media_input_aac(mk_media ctx, const void *data, int len, uint64_t dts, void *adts) { API_EXPORT int API_CALL mk_media_input_aac(mk_media ctx, const void *data, int len, uint64_t dts, void *adts) {
assert(ctx && data && len > 0 && adts); assert(ctx && data && len > 0);
MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx; MediaHelper::Ptr *obj = (MediaHelper::Ptr *) ctx;
return (*obj)->getChannel()->inputAAC((const char *) data, len, dts, (char *) adts); return (*obj)->getChannel()->inputAAC((const char *) data, len, dts, (char *) adts);
} }

View File

@ -230,6 +230,8 @@ forbidCacheSuffix=
#可以把http代理前真实客户端ip放在http头中https://github.com/ZLMediaKit/ZLMediaKit/issues/1388 #可以把http代理前真实客户端ip放在http头中https://github.com/ZLMediaKit/ZLMediaKit/issues/1388
#切勿暴露此key否则可能导致伪造客户端ip #切勿暴露此key否则可能导致伪造客户端ip
forwarded_ip_header= forwarded_ip_header=
#默认允许所有跨域请求
allow_cross_domains=1
[multicast] [multicast]
#rtp组播截止组播ip地址 #rtp组播截止组播ip地址

View File

@ -327,7 +327,6 @@ EventPoller::Ptr MultiMediaSourceMuxer::getOwnerPoller(MediaSource &sender) {
} }
bool MultiMediaSourceMuxer::onTrackReady(const Track::Ptr &track) { bool MultiMediaSourceMuxer::onTrackReady(const Track::Ptr &track) {
bool ret = false; bool ret = false;
if (_rtmp) { if (_rtmp) {
ret = _rtmp->addTrack(track) ? true : ret; ret = _rtmp->addTrack(track) ? true : ret;
@ -471,7 +470,9 @@ bool MultiMediaSourceMuxer::onTrackFrame(const Frame::Ptr &frame_in) {
// 视频时遇到第一帧配置帧或关键帧则标记为gop开始处 // 视频时遇到第一帧配置帧或关键帧则标记为gop开始处
auto video_key_pos = frame->keyFrame() || frame->configFrame(); auto video_key_pos = frame->keyFrame() || frame->configFrame();
_ring->write(frame, video_key_pos && !_video_key_pos); _ring->write(frame, video_key_pos && !_video_key_pos);
if (!frame->dropAble()) {
_video_key_pos = video_key_pos; _video_key_pos = video_key_pos;
}
} else { } else {
// 没有视频时设置is_key为true目的是关闭gop缓存 // 没有视频时设置is_key为true目的是关闭gop缓存
_ring->write(frame, !haveVideo()); _ring->write(frame, !haveVideo());

View File

@ -159,6 +159,7 @@ const string kNotFound = HTTP_FIELD "notFound";
const string kDirMenu = HTTP_FIELD "dirMenu"; const string kDirMenu = HTTP_FIELD "dirMenu";
const string kForbidCacheSuffix = HTTP_FIELD "forbidCacheSuffix"; const string kForbidCacheSuffix = HTTP_FIELD "forbidCacheSuffix";
const string kForwardedIpHeader = HTTP_FIELD "forwarded_ip_header"; const string kForwardedIpHeader = HTTP_FIELD "forwarded_ip_header";
const string kAllowCrossDomains = HTTP_FIELD "allow_cross_domains";
static onceToken token([]() { static onceToken token([]() {
mINI::Instance()[kSendBufSize] = 64 * 1024; mINI::Instance()[kSendBufSize] = 64 * 1024;
@ -186,6 +187,7 @@ static onceToken token([]() {
<< endl; << endl;
mINI::Instance()[kForbidCacheSuffix] = ""; mINI::Instance()[kForbidCacheSuffix] = "";
mINI::Instance()[kForwardedIpHeader] = ""; mINI::Instance()[kForwardedIpHeader] = "";
mINI::Instance()[kAllowCrossDomains] = 1;
}); });
} // namespace Http } // namespace Http

View File

@ -246,6 +246,8 @@ extern const std::string kDirMenu;
extern const std::string kForbidCacheSuffix; extern const std::string kForbidCacheSuffix;
// 可以把http代理前真实客户端ip放在http头中https://github.com/ZLMediaKit/ZLMediaKit/issues/1388 // 可以把http代理前真实客户端ip放在http头中https://github.com/ZLMediaKit/ZLMediaKit/issues/1388
extern const std::string kForwardedIpHeader; extern const std::string kForwardedIpHeader;
// 是否允许所有跨域请求
extern const std::string kAllowCrossDomains;
} // namespace Http } // namespace Http
////////////SHELL配置/////////// ////////////SHELL配置///////////

View File

@ -39,8 +39,13 @@ void HttpSession::Handle_Req_HEAD(ssize_t &content_len){
void HttpSession::Handle_Req_OPTIONS(ssize_t &content_len) { void HttpSession::Handle_Req_OPTIONS(ssize_t &content_len) {
KeyValue header; KeyValue header;
header.emplace("Allow", "GET, POST, OPTIONS"); header.emplace("Allow", "GET, POST, HEAD, OPTIONS");
GET_CONFIG(bool, allow_cross_domains, Http::kAllowCrossDomains);
if (allow_cross_domains) {
header.emplace("Access-Control-Allow-Origin", "*"); header.emplace("Access-Control-Allow-Origin", "*");
header.emplace("Access-Control-Allow-Headers", "*");
header.emplace("Access-Control-Allow-Methods", "GET, POST, HEAD, OPTIONS");
}
header.emplace("Access-Control-Allow-Credentials", "true"); header.emplace("Access-Control-Allow-Credentials", "true");
header.emplace("Access-Control-Request-Methods", "GET, POST, OPTIONS"); header.emplace("Access-Control-Request-Methods", "GET, POST, OPTIONS");
header.emplace("Access-Control-Request-Headers", "Accept,Accept-Language,Content-Language,Content-Type"); header.emplace("Access-Control-Request-Headers", "Accept,Accept-Language,Content-Language,Content-Type");

View File

@ -13,7 +13,7 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <cstdint>
namespace mediakit { namespace mediakit {
class strCoding { class strCoding {

View File

@ -25,7 +25,8 @@ using namespace std;
namespace mediakit { namespace mediakit {
PlayerProxy::PlayerProxy( PlayerProxy::PlayerProxy(
const string &vhost, const string &app, const string &stream_id, const ProtocolOption &option, int retry_count, const EventPoller::Ptr &poller) const string &vhost, const string &app, const string &stream_id, const ProtocolOption &option, int retry_count,
const EventPoller::Ptr &poller, int reconnect_delay_min, int reconnect_delay_max, int reconnect_delay_step)
: MediaPlayer(poller) : MediaPlayer(poller)
, _option(option) { , _option(option) {
_vhost = vhost; _vhost = vhost;
@ -33,19 +34,66 @@ PlayerProxy::PlayerProxy(
_stream_id = stream_id; _stream_id = stream_id;
_retry_count = retry_count; _retry_count = retry_count;
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;
_live_secs = 0; _live_secs = 0;
_live_status = 1; _live_status = 1;
_repull_count = 0; _repull_count = 0;
_on_close = [](const SockException &) {};
(*this)[Client::kWaitTrackReady] = false; (*this)[Client::kWaitTrackReady] = false;
} }
void PlayerProxy::setPlayCallbackOnce(const function<void(const SockException &ex)> &cb) { void PlayerProxy::setPlayCallbackOnce(function<void(const SockException &ex)> cb) {
_on_play = cb; _on_play = std::move(cb);
} }
void PlayerProxy::setOnClose(const function<void(const SockException &ex)> &cb) { void PlayerProxy::setOnClose(function<void(const SockException &ex)> cb) {
_on_close = cb ? cb : [](const SockException &) {}; _on_close = cb ? std::move(cb) : [](const SockException &) {};
}
void PlayerProxy::setOnDisconnect(std::function<void()> 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::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();
auto tracks = _muxer->getTracks();
for (auto &track : tracks) {
_transtalion_info.stream_info.emplace_back();
auto &back = _transtalion_info.stream_info.back();
back.bitrate = track->getBitRate();
back.codec_type = track->getTrackType();
back.codec_name = track->getCodecName();
switch (back.codec_type) {
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 : {
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;
}
}
} }
void PlayerProxy::play(const string &strUrlTmp) { void PlayerProxy::play(const string &strUrlTmp) {
@ -70,10 +118,13 @@ void PlayerProxy::play(const string &strUrlTmp) {
// 播放成功 // 播放成功
*piFailedCnt = 0; // 连续播放失败次数清0 *piFailedCnt = 0; // 连续播放失败次数清0
strongSelf->onPlaySuccess(); strongSelf->onPlaySuccess();
strongSelf->setTranslationInfo();
strongSelf->_on_connect(strongSelf->_transtalion_info);
InfoL << "play " << strUrlTmp << " success"; InfoL << "play " << strUrlTmp << " success";
} else if (*piFailedCnt < strongSelf->_retry_count || strongSelf->_retry_count < 0) { } else if (*piFailedCnt < strongSelf->_retry_count || strongSelf->_retry_count < 0) {
// 播放失败,延时重试播放 // 播放失败,延时重试播放
strongSelf->_on_disconnect();
strongSelf->rePlay(strUrlTmp, (*piFailedCnt)++); strongSelf->rePlay(strUrlTmp, (*piFailedCnt)++);
} else { } else {
// 达到了最大重试次数,回调关闭 // 达到了最大重试次数,回调关闭
@ -123,7 +174,7 @@ void PlayerProxy::play(const string &strUrlTmp) {
MediaPlayer::play(strUrlTmp); MediaPlayer::play(strUrlTmp);
} catch (std::exception &ex) { } catch (std::exception &ex) {
ErrorL << ex.what(); ErrorL << ex.what();
_on_play_result(SockException(Err_other, ex.what())); onPlayResult(SockException(Err_other, ex.what()));
return; return;
} }
_pull_url = strUrlTmp; _pull_url = strUrlTmp;
@ -157,7 +208,7 @@ PlayerProxy::~PlayerProxy() {
} }
void PlayerProxy::rePlay(const string &strUrl, int iFailedCnt) { void PlayerProxy::rePlay(const string &strUrl, int iFailedCnt) {
auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60 * 1000)); auto iDelay = MAX(_reconnect_delay_min * 1000, MIN(iFailedCnt * _reconnect_delay_step * 1000, _reconnect_delay_max * 1000));
weak_ptr<PlayerProxy> weakSelf = shared_from_this(); weak_ptr<PlayerProxy> weakSelf = shared_from_this();
_timer = std::make_shared<Timer>( _timer = std::make_shared<Timer>(
iDelay / 1000.0f, iDelay / 1000.0f,
@ -216,6 +267,10 @@ float PlayerProxy::getLossRate(MediaSource &sender, TrackType type) {
return getPacketLossRate(type); return getPacketLossRate(type);
} }
TranslationInfo PlayerProxy::getTranslationInfo() {
return _transtalion_info;
}
void PlayerProxy::onPlaySuccess() { void PlayerProxy::onPlaySuccess() {
GET_CONFIG(bool, reset_when_replay, General::kResetWhenRePlay); GET_CONFIG(bool, reset_when_replay, General::kResetWhenRePlay);
if (dynamic_pointer_cast<RtspMediaSource>(_media_src)) { if (dynamic_pointer_cast<RtspMediaSource>(_media_src)) {
@ -269,9 +324,8 @@ int PlayerProxy::getStatus() {
uint64_t PlayerProxy::getLiveSecs() { uint64_t PlayerProxy::getLiveSecs() {
if (_live_status == 0) { if (_live_status == 0) {
return _live_secs + _live_ticker.elapsedTime() / 1000; return _live_secs + _live_ticker.elapsedTime() / 1000;
} else {
return _live_secs;
} }
return _live_secs;
} }
uint64_t PlayerProxy::getRePullCount() { uint64_t PlayerProxy::getRePullCount() {

View File

@ -18,6 +18,45 @@
namespace mediakit { namespace mediakit {
struct StreamInfo
{
TrackType codec_type;
std::string codec_name;
int bitrate;
int audio_sample_rate;
int audio_sample_bit;
int audio_channel;
int video_width;
int video_height;
float video_fps;
StreamInfo()
{
codec_type = TrackInvalid;
codec_name = "none";
bitrate = -1;
audio_sample_rate = -1;
audio_channel = -1;
audio_sample_bit = -1;
video_height = -1;
video_width = -1;
video_fps = -1.0;
}
};
struct TranslationInfo
{
std::vector<StreamInfo> stream_info;
int byte_speed;
uint64_t start_time_stamp;
TranslationInfo()
{
byte_speed = -1;
start_time_stamp = 0;
}
};
class PlayerProxy class PlayerProxy
: public MediaPlayer : public MediaPlayer
, public MediaSourceEvent , public MediaSourceEvent
@ -29,7 +68,7 @@ public:
// 默认一直重试 // 默认一直重试
PlayerProxy( PlayerProxy(
const std::string &vhost, const std::string &app, const std::string &stream_id, const ProtocolOption &option, int retry_count = -1, const std::string &vhost, const std::string &app, const std::string &stream_id, const ProtocolOption &option, int retry_count = -1,
const toolkit::EventPoller::Ptr &poller = nullptr); const toolkit::EventPoller::Ptr &poller = nullptr, int reconnect_delay_min = 2, int reconnect_delay_max = 60, int reconnect_delay_step = 3);
~PlayerProxy() override; ~PlayerProxy() override;
@ -37,13 +76,25 @@ public:
* play结果回调play执行之前有效 * play结果回调play执行之前有效
* @param cb * @param cb
*/ */
void setPlayCallbackOnce(const std::function<void(const toolkit::SockException &ex)> &cb); void setPlayCallbackOnce(std::function<void(const toolkit::SockException &ex)> cb);
/** /**
* *
* @param cb * @param cb
*/ */
void setOnClose(const std::function<void(const toolkit::SockException &ex)> &cb); void setOnClose(std::function<void(const toolkit::SockException &ex)> cb);
/**
* Set a callback for failed server connection
* @param cb
*/
void setOnDisconnect(std::function<void()> cb);
/**
* Set a callback for a successful connection to the server
* @param cb
*/
void setOnConnect(std::function<void(const TranslationInfo&)> cb);
/** /**
* *
@ -60,6 +111,9 @@ public:
uint64_t getLiveSecs(); uint64_t getLiveSecs();
uint64_t getRePullCount(); uint64_t getRePullCount();
// Using this only makes sense after a successful connection to the server
TranslationInfo getTranslationInfo();
private: private:
// MediaSourceEvent override // MediaSourceEvent override
bool close(MediaSource &sender) override; bool close(MediaSource &sender) override;
@ -72,17 +126,24 @@ private:
void rePlay(const std::string &strUrl, int iFailedCnt); void rePlay(const std::string &strUrl, int iFailedCnt);
void onPlaySuccess(); void onPlaySuccess();
void setDirectProxy(); void setDirectProxy();
void setTranslationInfo();
private: private:
ProtocolOption _option; ProtocolOption _option;
int _retry_count; int _retry_count;
int _reconnect_delay_min;
int _reconnect_delay_max;
int _reconnect_delay_step;
std::string _vhost; std::string _vhost;
std::string _app; std::string _app;
std::string _stream_id; std::string _stream_id;
std::string _pull_url; std::string _pull_url;
toolkit::Timer::Ptr _timer; toolkit::Timer::Ptr _timer;
std::function<void()> _on_disconnect;
std::function<void(const TranslationInfo &info)> _on_connect;
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_play; std::function<void(const toolkit::SockException &ex)> _on_play;
TranslationInfo _transtalion_info;
MultiMediaSourceMuxer::Ptr _muxer; MultiMediaSourceMuxer::Ptr _muxer;
toolkit::Ticker _live_ticker; toolkit::Ticker _live_ticker;

View File

@ -14,6 +14,7 @@
#include <string> #include <string>
#include <deque> #include <deque>
#include <tuple> #include <tuple>
#include <cstdint>
namespace mediakit { namespace mediakit {

View File

@ -16,6 +16,7 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <functional> #include <functional>
#include <cstdint>
namespace toolkit { namespace toolkit {
class BufferLikeString; class BufferLikeString;
} }