mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 19:31:53 +00:00
For #299, add dash files.
This commit is contained in:
parent
7fd221ef63
commit
5e419c66f8
17 changed files with 354 additions and 123 deletions
|
@ -943,6 +943,16 @@ vhost exec.srs.com {
|
|||
}
|
||||
}
|
||||
|
||||
# The vhost for MPEG-DASH.
|
||||
vhost dash.srs.com {
|
||||
dash {
|
||||
# Whether DASH is enabled.
|
||||
# Transmux RTMP to DASH if on.
|
||||
# default: off
|
||||
enabled on;
|
||||
}
|
||||
}
|
||||
|
||||
# the vhost with hls specified.
|
||||
vhost hls.srs.com {
|
||||
hls {
|
||||
|
|
|
@ -1353,6 +1353,18 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root)
|
|||
srs_trace("vhost %s reload forward success.", vhost.c_str());
|
||||
}
|
||||
|
||||
// To reload DASH.
|
||||
if (!srs_directive_equals(new_vhost->get("dash"), old_vhost->get("dash"))) {
|
||||
for (it = subscribes.begin(); it != subscribes.end(); ++it) {
|
||||
ISrsReloadHandler* subscribe = *it;
|
||||
if ((ret = subscribe->on_reload_vhost_dash(vhost)) != ERROR_SUCCESS) {
|
||||
srs_error("Reload vhost %s dash failed, ret=%d", vhost.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
srs_trace("Reload vhost %s dash ok.", vhost.c_str());
|
||||
}
|
||||
|
||||
// hls, only one per vhost
|
||||
// @remark, the hls_on_error directly support reload.
|
||||
if (!srs_directive_equals(new_vhost->get("hls"), old_vhost->get("hls"))) {
|
||||
|
@ -3808,7 +3820,7 @@ int SrsConfig::check_config()
|
|||
&& n != "dvr" && n != "ingest" && n != "hls" && n != "http_hooks"
|
||||
&& n != "refer" && n != "forward" && n != "transcode" && n != "bandcheck"
|
||||
&& n != "play" && n != "publish" && n != "cluster"
|
||||
&& n != "security" && n != "http_remux"
|
||||
&& n != "security" && n != "http_remux" && n != "dash"
|
||||
&& n != "http_static" && n != "hds" && n != "exec"
|
||||
&& n != "in_ack_size" && n != "out_ack_size"
|
||||
) {
|
||||
|
@ -3819,7 +3831,7 @@ int SrsConfig::check_config()
|
|||
// for each sub directives of vhost.
|
||||
if (n == "dvr") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "dvr_apply" && m != "dvr_path" && m != "dvr_plan"
|
||||
&& m != "dvr_duration" && m != "dvr_wait_keyframe" && m != "time_jitter"
|
||||
) {
|
||||
|
@ -3830,7 +3842,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "refer") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "all" && m != "publish" && m != "play") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost refer directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -3839,7 +3851,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "exec") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "publish") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost exec directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -3848,7 +3860,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "play") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "time_jitter" && m != "mix_correct" && m != "atc" && m != "atc_auto" && m != "mw_latency"
|
||||
&& m != "gop_cache" && m != "queue_length" && m != "send_min_interval" && m != "reduce_sequence_header"
|
||||
) {
|
||||
|
@ -3859,7 +3871,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "cluster") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "mode" && m != "origin" && m != "token_traverse" && m != "vhost" && m != "debug_srs_upnode") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost cluster directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -3868,7 +3880,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "publish") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "mr" && m != "mr_latency" && m != "firstpkt_timeout" && m != "normal_timeout" && m != "parse_sps") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost publish directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -3877,7 +3889,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "ingest") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "input" && m != "ffmpeg" && m != "engine") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost ingest directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -3886,7 +3898,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "http_static") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "mount" && m != "dir") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost http directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -3895,16 +3907,25 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "http_remux") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "mount" && m != "fast_cache") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost http_remux directive %s, ret=%d", m.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else if (n == "dash") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("Illegal directive %s in vhost.dash, ret=%d", m.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else if (n == "hls") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
|
||||
&& m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
|
||||
&& m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify"
|
||||
|
@ -3922,7 +3943,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "http_hooks") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
|
||||
&& m != "on_unpublish" && m != "on_play" && m != "on_stop"
|
||||
&& m != "on_dvr" && m != "on_hls" && m != "on_hls_notify"
|
||||
|
@ -3934,7 +3955,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "forward") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "destination") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost forward directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -3979,7 +4000,7 @@ int SrsConfig::check_config()
|
|||
}
|
||||
} else if (n == "bandcheck") {
|
||||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name.c_str();
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "key" && m != "interval" && m != "limit_kbps") {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost bandcheck directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -5944,15 +5965,33 @@ string SrsConfig::get_ffmpeg_log_dir()
|
|||
return conf->arg0();
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_dash(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_vhost(vhost);
|
||||
return conf? conf->get("dash") : NULL;
|
||||
}
|
||||
|
||||
bool SrsConfig::get_dash_enabled(string vhost)
|
||||
{
|
||||
static bool DEFAULT = false;
|
||||
|
||||
SrsConfDirective* conf = get_dash(vhost);
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("enabled");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return SRS_CONF_PERFER_FALSE(conf->arg0());
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_hls(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_vhost(vhost);
|
||||
|
||||
if (!conf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf->get("hls");
|
||||
return conf? conf->get("hls") : NULL;
|
||||
}
|
||||
|
||||
bool SrsConfig::get_hls_enabled(string vhost)
|
||||
|
|
|
@ -1134,6 +1134,12 @@ public:
|
|||
* @remark, /dev/null to disable it.
|
||||
*/
|
||||
virtual std::string get_ffmpeg_log_dir();
|
||||
// The MPEG-DASH section.
|
||||
private:
|
||||
virtual SrsConfDirective* get_dash(std::string vhost);
|
||||
public:
|
||||
// Whether DASH is enabled.
|
||||
virtual bool get_dash_enabled(std::string vhost);
|
||||
// hls section
|
||||
private:
|
||||
/**
|
||||
|
|
|
@ -23,4 +23,80 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include <srs_app_dash.hpp>
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_app_source.hpp>
|
||||
#include <srs_app_config.hpp>
|
||||
#include <srs_rtmp_stack.hpp>
|
||||
|
||||
SrsMpegDash::SrsMpegDash()
|
||||
{
|
||||
hub = NULL;
|
||||
req = NULL;
|
||||
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
SrsMpegDash::~SrsMpegDash()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsMpegDash::initialize(SrsOriginHub* h, SrsRequest* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
hub = h;
|
||||
req = r;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsMpegDash::on_publish()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// Prevent duplicated publish.
|
||||
if (enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!_srs_config->get_dash_enabled(req->vhost)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
enabled = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsMpegDash::on_audio(SrsSharedPtrMessage* shared_audio)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsMpegDash::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsMpegDash::on_unpublish()
|
||||
{
|
||||
// Prevent duplicated unpublish.
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,4 +29,34 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
*/
|
||||
#include <srs_core.hpp>
|
||||
|
||||
class SrsRequest;
|
||||
class SrsOriginHub;
|
||||
class SrsSharedPtrMessage;
|
||||
|
||||
/**
|
||||
* The MPEG-DASH encoder, transmux RTMP to DASH.
|
||||
*/
|
||||
class SrsMpegDash
|
||||
{
|
||||
private:
|
||||
bool enabled;
|
||||
private:
|
||||
SrsRequest* req;
|
||||
SrsOriginHub* hub;
|
||||
public:
|
||||
SrsMpegDash();
|
||||
virtual ~SrsMpegDash();
|
||||
public:
|
||||
// Initalize the encoder.
|
||||
virtual int initialize(SrsOriginHub* h, SrsRequest* r);
|
||||
// When stream start publishing.
|
||||
virtual int on_publish();
|
||||
// When got an shared audio message.
|
||||
virtual int on_audio(SrsSharedPtrMessage* shared_audio);
|
||||
// When got an shared video message.
|
||||
virtual int on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header);
|
||||
// When stream stop publishing.
|
||||
virtual void on_unpublish();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1019,7 +1019,7 @@ int SrsDvr::initialize(SrsOriginHub* h, SrsRequest* r)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvr::on_publish(bool fetch_sequence_header)
|
||||
int SrsDvr::on_publish()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -1032,10 +1032,6 @@ int SrsDvr::on_publish(bool fetch_sequence_header)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (fetch_sequence_header && (ret = hub->on_dvr_request_sh()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1088,11 +1084,21 @@ int SrsDvr::on_reload_vhost_dvr_apply(string vhost)
|
|||
bool v = srs_config_apply_filter(conf, req);
|
||||
|
||||
// the apply changed, republish the dvr.
|
||||
if (v != actived) {
|
||||
actived = v;
|
||||
|
||||
on_unpublish();
|
||||
return on_publish(true);
|
||||
if (v == actived) {
|
||||
return ret;
|
||||
}
|
||||
actived = v;
|
||||
|
||||
on_unpublish();
|
||||
if (!actived) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = on_publish()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = hub->on_dvr_request_sh()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -289,7 +289,7 @@ public:
|
|||
* when encoder start to publish RTMP stream.
|
||||
* @param fetch_sequence_header whether fetch sequence from source.
|
||||
*/
|
||||
virtual int on_publish(bool fetch_sequence_header);
|
||||
virtual int on_publish();
|
||||
/**
|
||||
* the unpublish event.,
|
||||
* when encoder stop(unpublish) to publish RTMP stream.
|
||||
|
|
|
@ -260,7 +260,7 @@ private:
|
|||
string path;
|
||||
};
|
||||
|
||||
SrsHds::SrsHds(SrsSource *s)
|
||||
SrsHds::SrsHds()
|
||||
: currentSegment(NULL)
|
||||
, fragment_index(1)
|
||||
, video_sh(NULL)
|
||||
|
@ -273,7 +273,6 @@ SrsHds::SrsHds(SrsSource *s)
|
|||
|
||||
SrsHds::~SrsHds()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int SrsHds::on_publish(SrsRequest *req)
|
||||
|
|
|
@ -38,8 +38,8 @@ class SrsSource;
|
|||
class SrsHds
|
||||
{
|
||||
public:
|
||||
SrsHds(SrsSource* s);
|
||||
~SrsHds();
|
||||
SrsHds();
|
||||
virtual ~SrsHds();
|
||||
|
||||
int on_publish(SrsRequest* req);
|
||||
int on_unpublish();
|
||||
|
|
|
@ -1118,8 +1118,8 @@ SrsHls::SrsHls()
|
|||
req = NULL;
|
||||
hub = NULL;
|
||||
|
||||
hls_enabled = false;
|
||||
hls_can_dispose = false;
|
||||
enabled = false;
|
||||
disposable = false;
|
||||
last_update_time = 0;
|
||||
|
||||
codec = new SrsAvcAacCodec();
|
||||
|
@ -1127,7 +1127,7 @@ SrsHls::SrsHls()
|
|||
jitter = new SrsRtmpJitter();
|
||||
|
||||
muxer = new SrsHlsMuxer();
|
||||
hls_cache = new SrsHlsCache();
|
||||
cache = new SrsHlsCache();
|
||||
|
||||
pprint = SrsPithyPrint::create_hls();
|
||||
stream_dts = 0;
|
||||
|
@ -1140,14 +1140,14 @@ SrsHls::~SrsHls()
|
|||
srs_freep(jitter);
|
||||
|
||||
srs_freep(muxer);
|
||||
srs_freep(hls_cache);
|
||||
srs_freep(cache);
|
||||
|
||||
srs_freep(pprint);
|
||||
}
|
||||
|
||||
void SrsHls::dispose()
|
||||
{
|
||||
if (hls_enabled) {
|
||||
if (enabled) {
|
||||
on_unpublish();
|
||||
}
|
||||
|
||||
|
@ -1177,10 +1177,10 @@ int SrsHls::cycle()
|
|||
}
|
||||
last_update_time = srs_get_system_time_ms();
|
||||
|
||||
if (!hls_can_dispose) {
|
||||
if (!disposable) {
|
||||
return ret;
|
||||
}
|
||||
hls_can_dispose = false;
|
||||
disposable = false;
|
||||
|
||||
srs_trace("hls cycle to dispose hls %s, timeout=%dms", req->get_stream_url().c_str(), hls_dispose);
|
||||
dispose();
|
||||
|
@ -1202,7 +1202,7 @@ int SrsHls::initialize(SrsOriginHub* h, SrsRequest* r)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHls::on_publish(bool fetch_sequence_header)
|
||||
int SrsHls::on_publish()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -1210,36 +1210,23 @@ int SrsHls::on_publish(bool fetch_sequence_header)
|
|||
last_update_time = srs_get_system_time_ms();
|
||||
|
||||
// support multiple publish.
|
||||
if (hls_enabled) {
|
||||
if (enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string vhost = req->vhost;
|
||||
if (!_srs_config->get_hls_enabled(vhost)) {
|
||||
if (!_srs_config->get_hls_enabled(req->vhost)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = hls_cache->on_publish(muxer, req, stream_dts)) != ERROR_SUCCESS) {
|
||||
if ((ret = cache->on_publish(muxer, req, stream_dts)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// if enabled, open the muxer.
|
||||
hls_enabled = true;
|
||||
enabled = true;
|
||||
|
||||
// ok, the hls can be dispose, or need to be dispose.
|
||||
hls_can_dispose = true;
|
||||
|
||||
// when publish, don't need to fetch sequence header, which is old and maybe corrupt.
|
||||
// when reload, we must fetch the sequence header from source cache.
|
||||
if (fetch_sequence_header) {
|
||||
// notice the source to get the cached sequence header.
|
||||
// when reload to start hls, hls will never get the sequence header in stream,
|
||||
// use the SrsSource.on_hls_start to push the sequence header to HLS.
|
||||
if ((ret = hub->on_hls_start()) != ERROR_SUCCESS) {
|
||||
srs_error("callback source hls start failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
disposable = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1249,22 +1236,22 @@ void SrsHls::on_unpublish()
|
|||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// support multiple unpublish.
|
||||
if (!hls_enabled) {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ret = hls_cache->on_unpublish(muxer)) != ERROR_SUCCESS) {
|
||||
if ((ret = cache->on_unpublish(muxer)) != ERROR_SUCCESS) {
|
||||
srs_error("ignore m3u8 muxer flush/close audio failed. ret=%d", ret);
|
||||
}
|
||||
|
||||
hls_enabled = false;
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!hls_enabled) {
|
||||
if (!enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1302,7 +1289,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio)
|
|||
|
||||
// ignore sequence header
|
||||
if (acodec == SrsCodecAudioAAC && sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) {
|
||||
return hls_cache->on_sequence_header(muxer);
|
||||
return cache->on_sequence_header(muxer);
|
||||
}
|
||||
|
||||
// TODO: FIXME: config the jitter of HLS.
|
||||
|
@ -1317,7 +1304,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio)
|
|||
// for pure audio, we need to update the stream dts also.
|
||||
stream_dts = dts;
|
||||
|
||||
if ((ret = hls_cache->write_audio(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
|
||||
if ((ret = cache->write_audio(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
|
||||
srs_error("hls cache write audio failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1329,7 +1316,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!hls_enabled) {
|
||||
if (!enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1366,7 +1353,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps)
|
|||
// ignore sequence header
|
||||
if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame
|
||||
&& sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
|
||||
return hls_cache->on_sequence_header(muxer);
|
||||
return cache->on_sequence_header(muxer);
|
||||
}
|
||||
|
||||
// TODO: FIXME: config the jitter of HLS.
|
||||
|
@ -1377,7 +1364,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps)
|
|||
|
||||
int64_t dts = video->timestamp * 90;
|
||||
stream_dts = dts;
|
||||
if ((ret = hls_cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
|
||||
if ((ret = cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
|
||||
srs_error("hls cache write video failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -351,11 +351,11 @@ class SrsHls
|
|||
{
|
||||
private:
|
||||
SrsHlsMuxer* muxer;
|
||||
SrsHlsCache* hls_cache;
|
||||
SrsHlsCache* cache;
|
||||
private:
|
||||
SrsRequest* req;
|
||||
bool hls_enabled;
|
||||
bool hls_can_dispose;
|
||||
bool enabled;
|
||||
bool disposable;
|
||||
int64_t last_update_time;
|
||||
private:
|
||||
SrsOriginHub* hub;
|
||||
|
@ -393,7 +393,7 @@ public:
|
|||
* for the muxer object not destroyed.
|
||||
* @param fetch_sequence_header whether fetch sequence from source.
|
||||
*/
|
||||
virtual int on_publish(bool fetch_sequence_header);
|
||||
virtual int on_publish();
|
||||
/**
|
||||
* the unpublish event, only close the muxer, donot destroy the
|
||||
* muxer, for when we continue to publish, the m3u8 will continue.
|
||||
|
|
|
@ -147,7 +147,7 @@ void SrsFastLog::verbose(const char* tag, int context_id, const char* fmt, ...)
|
|||
}
|
||||
|
||||
int size = 0;
|
||||
if (!generate_header(false, tag, context_id, "verb", &size)) {
|
||||
if (!generate_header(false, tag, context_id, "Verb", &size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ void SrsFastLog::info(const char* tag, int context_id, const char* fmt, ...)
|
|||
}
|
||||
|
||||
int size = 0;
|
||||
if (!generate_header(false, tag, context_id, "debug", &size)) {
|
||||
if (!generate_header(false, tag, context_id, "Debug", &size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ void SrsFastLog::trace(const char* tag, int context_id, const char* fmt, ...)
|
|||
}
|
||||
|
||||
int size = 0;
|
||||
if (!generate_header(false, tag, context_id, "trace", &size)) {
|
||||
if (!generate_header(false, tag, context_id, "Trace", &size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ void SrsFastLog::warn(const char* tag, int context_id, const char* fmt, ...)
|
|||
}
|
||||
|
||||
int size = 0;
|
||||
if (!generate_header(true, tag, context_id, "warn", &size)) {
|
||||
if (!generate_header(true, tag, context_id, "Warn", &size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ void SrsFastLog::error(const char* tag, int context_id, const char* fmt, ...)
|
|||
}
|
||||
|
||||
int size = 0;
|
||||
if (!generate_header(true, tag, context_id, "error", &size)) {
|
||||
if (!generate_header(true, tag, context_id, "Error", &size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,11 @@ int ISrsReloadHandler::on_reload_vhost_forward(string /*vhost*/)
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int ISrsReloadHandler::on_reload_vhost_dash(string /*vhost*/)
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int ISrsReloadHandler::on_reload_vhost_hls(string /*vhost*/)
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
virtual int on_reload_vhost_removed(std::string vhost);
|
||||
virtual int on_reload_vhost_play(std::string vhost);
|
||||
virtual int on_reload_vhost_forward(std::string vhost);
|
||||
virtual int on_reload_vhost_dash(std::string vhost);
|
||||
virtual int on_reload_vhost_hls(std::string vhost);
|
||||
virtual int on_reload_vhost_hds(std::string vhost);
|
||||
virtual int on_reload_vhost_dvr(std::string vhost);
|
||||
|
|
|
@ -47,6 +47,7 @@ using namespace std;
|
|||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_protocol_utility.hpp>
|
||||
#include <srs_app_ng_exec.hpp>
|
||||
#include <srs_app_dash.hpp>
|
||||
|
||||
#define CONST_MAX_JITTER_MS 250
|
||||
#define CONST_MAX_JITTER_MS_NEG -250
|
||||
|
@ -836,19 +837,20 @@ SrsSharedPtrMessage* SrsMixQueue::pop()
|
|||
return msg;
|
||||
}
|
||||
|
||||
SrsOriginHub::SrsOriginHub(SrsSource* s)
|
||||
SrsOriginHub::SrsOriginHub()
|
||||
{
|
||||
source = s;
|
||||
source = NULL;
|
||||
req = NULL;
|
||||
is_active = false;
|
||||
|
||||
hls = new SrsHls();
|
||||
dash = new SrsMpegDash();
|
||||
dvr = new SrsDvr();
|
||||
#ifdef SRS_AUTO_TRANSCODE
|
||||
encoder = new SrsEncoder();
|
||||
#endif
|
||||
#ifdef SRS_AUTO_HDS
|
||||
hds = new SrsHds(s);
|
||||
hds = new SrsHds();
|
||||
#endif
|
||||
ng_exec = new SrsNgExec();
|
||||
|
||||
|
@ -870,6 +872,7 @@ SrsOriginHub::~SrsOriginHub()
|
|||
srs_freep(ng_exec);
|
||||
|
||||
srs_freep(hls);
|
||||
srs_freep(dash);
|
||||
srs_freep(dvr);
|
||||
#ifdef SRS_AUTO_TRANSCODE
|
||||
srs_freep(encoder);
|
||||
|
@ -879,16 +882,21 @@ SrsOriginHub::~SrsOriginHub()
|
|||
#endif
|
||||
}
|
||||
|
||||
int SrsOriginHub::initialize(SrsRequest* r)
|
||||
int SrsOriginHub::initialize(SrsSource* s, SrsRequest* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
req = r;
|
||||
source = s;
|
||||
|
||||
if ((ret = hls->initialize(this, req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = dash->initialize(this, req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = dvr->initialize(this, req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -899,6 +907,8 @@ int SrsOriginHub::initialize(SrsRequest* r)
|
|||
void SrsOriginHub::dispose()
|
||||
{
|
||||
hls->dispose();
|
||||
|
||||
// TODO: Support dispose DASH.
|
||||
}
|
||||
|
||||
int SrsOriginHub::cycle()
|
||||
|
@ -909,6 +919,8 @@ int SrsOriginHub::cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
// TODO: Support cycle DASH.
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -967,6 +979,12 @@ int SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio)
|
|||
}
|
||||
}
|
||||
|
||||
if ((ret = dash->on_audio(msg)) != ERROR_SUCCESS) {
|
||||
srs_warn("DASH failed, ignore and disable it. ret=%d", ret);
|
||||
dash->on_unpublish();
|
||||
ret = ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if ((ret = dvr->on_audio(msg)) != ERROR_SUCCESS) {
|
||||
srs_warn("dvr process audio message failed, ignore and disable dvr. ret=%d", ret);
|
||||
|
||||
|
@ -1034,6 +1052,12 @@ int SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_h
|
|||
}
|
||||
}
|
||||
|
||||
if ((ret = dash->on_video(msg, is_sequence_header)) != ERROR_SUCCESS) {
|
||||
srs_warn("DASH failed, ignore and disable it. ret=%d", ret);
|
||||
dash->on_unpublish();
|
||||
ret = ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if ((ret = dvr->on_video(msg)) != ERROR_SUCCESS) {
|
||||
srs_warn("dvr process video message failed, ignore and disable dvr. ret=%d", ret);
|
||||
|
||||
|
@ -1088,12 +1112,17 @@ int SrsOriginHub::on_publish()
|
|||
}
|
||||
#endif
|
||||
|
||||
if ((ret = hls->on_publish(false)) != ERROR_SUCCESS) {
|
||||
if ((ret = hls->on_publish()) != ERROR_SUCCESS) {
|
||||
srs_error("start hls failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = dvr->on_publish(false)) != ERROR_SUCCESS) {
|
||||
if ((ret = dash->on_publish()) != ERROR_SUCCESS) {
|
||||
srs_error("Start DASH failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = dvr->on_publish()) != ERROR_SUCCESS) {
|
||||
srs_error("start dvr failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1129,6 +1158,7 @@ void SrsOriginHub::on_unpublish()
|
|||
#endif
|
||||
|
||||
hls->on_unpublish();
|
||||
dash->on_unpublish();
|
||||
dvr->on_unpublish();
|
||||
|
||||
#ifdef SRS_AUTO_HDS
|
||||
|
@ -1164,29 +1194,6 @@ int SrsOriginHub::on_forwarder_start(SrsForwarder* forwarder)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsOriginHub::on_hls_start()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
|
||||
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
|
||||
|
||||
// feed the hls the metadata/sequence header,
|
||||
// when reload to start hls, hls will never get the sequence header in stream,
|
||||
// use the SrsSource.on_hls_start to push the sequence header to HLS.
|
||||
// TODO: maybe need to decode the metadata?
|
||||
if (cache_sh_video && (ret = hls->on_video(cache_sh_video, true)) != ERROR_SUCCESS) {
|
||||
srs_error("hls process video sequence header message failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (cache_sh_audio && (ret = hls->on_audio(cache_sh_audio)) != ERROR_SUCCESS) {
|
||||
srs_error("hls process audio sequence header message failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsOriginHub::on_dvr_request_sh()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
@ -1243,6 +1250,40 @@ int SrsOriginHub::on_reload_vhost_forward(string vhost)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsOriginHub::on_reload_vhost_dash(string vhost)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (req->vhost != vhost) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
dash->on_unpublish();
|
||||
|
||||
// Don't start DASH when source is not active.
|
||||
if (!is_active) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = dash->on_publish()) != ERROR_SUCCESS) {
|
||||
srs_error("DASH start failed, ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
|
||||
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
|
||||
if (cache_sh_video && (ret = dash->on_video(cache_sh_video, true)) != ERROR_SUCCESS) {
|
||||
srs_error("DASH consume video failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (cache_sh_audio && (ret = dash->on_audio(cache_sh_audio)) != ERROR_SUCCESS) {
|
||||
srs_error("DASH consume audio failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsOriginHub::on_reload_vhost_hls(string vhost)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
@ -1255,17 +1296,38 @@ int SrsOriginHub::on_reload_vhost_hls(string vhost)
|
|||
|
||||
hls->on_unpublish();
|
||||
|
||||
// Don't start forwarders when source is not active.
|
||||
// Don't start HLS when source is not active.
|
||||
if (!is_active) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = hls->on_publish(true)) != ERROR_SUCCESS) {
|
||||
if ((ret = hls->on_publish()) != ERROR_SUCCESS) {
|
||||
srs_error("hls publish failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
srs_trace("vhost %s hls reload success", vhost.c_str());
|
||||
|
||||
// when publish, don't need to fetch sequence header, which is old and maybe corrupt.
|
||||
// when reload, we must fetch the sequence header from source cache.
|
||||
// notice the source to get the cached sequence header.
|
||||
// when reload to start hls, hls will never get the sequence header in stream,
|
||||
// use the SrsSource.on_hls_start to push the sequence header to HLS.
|
||||
SrsSharedPtrMessage* cache_sh_video = source->meta->vsh();
|
||||
SrsSharedPtrMessage* cache_sh_audio = source->meta->ash();
|
||||
|
||||
// feed the hls the metadata/sequence header,
|
||||
// when reload to start hls, hls will never get the sequence header in stream,
|
||||
// use the SrsSource.on_hls_start to push the sequence header to HLS.
|
||||
// TODO: maybe need to decode the metadata?
|
||||
if (cache_sh_video && (ret = hls->on_video(cache_sh_video, true)) != ERROR_SUCCESS) {
|
||||
srs_error("hls process video sequence header message failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (cache_sh_audio && (ret = hls->on_audio(cache_sh_audio)) != ERROR_SUCCESS) {
|
||||
srs_error("hls process audio sequence header message failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1282,7 +1344,7 @@ int SrsOriginHub::on_reload_vhost_hds(string vhost)
|
|||
#ifdef SRS_AUTO_HDS
|
||||
hds->on_unpublish();
|
||||
|
||||
// Don't start forwarders when source is not active.
|
||||
// Don't start HDS when source is not active.
|
||||
if (!is_active) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -1310,7 +1372,7 @@ int SrsOriginHub::on_reload_vhost_dvr(string vhost)
|
|||
// cleanup dvr
|
||||
dvr->on_unpublish();
|
||||
|
||||
// Don't start forwarders when source is not active.
|
||||
// Don't start DVR when source is not active.
|
||||
if (!is_active) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -1321,11 +1383,15 @@ int SrsOriginHub::on_reload_vhost_dvr(string vhost)
|
|||
}
|
||||
|
||||
// start to publish by new plan.
|
||||
if ((ret = dvr->on_publish(true)) != ERROR_SUCCESS) {
|
||||
if ((ret = dvr->on_publish()) != ERROR_SUCCESS) {
|
||||
srs_error("dvr publish failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = on_dvr_request_sh()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_trace("vhost %s dvr reload success", vhost.c_str());
|
||||
|
||||
return ret;
|
||||
|
@ -1344,7 +1410,7 @@ int SrsOriginHub::on_reload_vhost_transcode(string vhost)
|
|||
#ifdef SRS_AUTO_TRANSCODE
|
||||
encoder->on_unpublish();
|
||||
|
||||
// Don't start forwarders when source is not active.
|
||||
// Don't start transcode when source is not active.
|
||||
if (!is_active) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -1371,7 +1437,7 @@ int SrsOriginHub::on_reload_vhost_exec(string vhost)
|
|||
|
||||
ng_exec->on_unpublish();
|
||||
|
||||
// Don't start forwarders when source is not active.
|
||||
// Don't start exec when source is not active.
|
||||
if (!is_active) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -1712,7 +1778,7 @@ SrsSource::SrsSource()
|
|||
publish_edge = new SrsPublishEdge();
|
||||
gop_cache = new SrsGopCache();
|
||||
aggregate_stream = new SrsBuffer();
|
||||
hub = new SrsOriginHub(this);
|
||||
hub = new SrsOriginHub();
|
||||
meta = new SrsMetaCache();
|
||||
|
||||
is_monotonically_increase = false;
|
||||
|
@ -1790,7 +1856,7 @@ int SrsSource::initialize(SrsRequest* r, ISrsSourceHandler* h)
|
|||
req = r->copy();
|
||||
atc = _srs_config->get_atc(req->vhost);
|
||||
|
||||
if ((ret = hub->initialize(req)) != ERROR_SUCCESS) {
|
||||
if ((ret = hub->initialize(this, req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ class SrsConnection;
|
|||
class SrsMessageHeader;
|
||||
class SrsHls;
|
||||
class SrsDvr;
|
||||
class SrsMpegDash;
|
||||
#ifdef SRS_AUTO_TRANSCODE
|
||||
class SrsEncoder;
|
||||
#endif
|
||||
|
@ -422,6 +423,8 @@ private:
|
|||
private:
|
||||
// hls handler.
|
||||
SrsHls* hls;
|
||||
// The DASH encoder.
|
||||
SrsMpegDash* dash;
|
||||
// dvr handler.
|
||||
SrsDvr* dvr;
|
||||
// transcoding handler.
|
||||
|
@ -437,12 +440,12 @@ private:
|
|||
// to forward stream to other servers
|
||||
std::vector<SrsForwarder*> forwarders;
|
||||
public:
|
||||
SrsOriginHub(SrsSource* s);
|
||||
SrsOriginHub();
|
||||
virtual ~SrsOriginHub();
|
||||
public:
|
||||
// Initialize the hub with source and request.
|
||||
// @param r The request object, managed by source.
|
||||
virtual int initialize(SrsRequest* r);
|
||||
virtual int initialize(SrsSource* s, SrsRequest* r);
|
||||
// Dispose the hub, release utilities resource,
|
||||
// for example, delete all HLS pieces.
|
||||
virtual void dispose();
|
||||
|
@ -461,17 +464,16 @@ public:
|
|||
virtual int on_publish();
|
||||
// When stop publish stream.
|
||||
virtual void on_unpublish();
|
||||
// for the tools callback
|
||||
// Internal callback.
|
||||
public:
|
||||
// for the SrsForwarder to callback to request the sequence headers.
|
||||
virtual int on_forwarder_start(SrsForwarder* forwarder);
|
||||
// for the SrsHls to callback to request the sequence headers.
|
||||
virtual int on_hls_start();
|
||||
// for the SrsDvr to callback to request the sequence headers.
|
||||
virtual int on_dvr_request_sh();
|
||||
// interface ISrsReloadHandler
|
||||
public:
|
||||
virtual int on_reload_vhost_forward(std::string vhost);
|
||||
virtual int on_reload_vhost_dash(std::string vhost);
|
||||
virtual int on_reload_vhost_hls(std::string vhost);
|
||||
virtual int on_reload_vhost_hds(std::string vhost);
|
||||
virtual int on_reload_vhost_dvr(std::string vhost);
|
||||
|
|
|
@ -164,7 +164,10 @@ int main(int argc, char** argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
srs_trace(ss.str().c_str());
|
||||
string sss = ss.str();
|
||||
if (!sss.empty()) {
|
||||
srs_trace(sss.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// we check the config when the log initialized.
|
||||
|
@ -202,6 +205,7 @@ void show_macro_features()
|
|||
|
||||
// rch(rtmp complex handshake)
|
||||
ss << ", rch:" << srs_bool2switch(SRS_AUTO_SSL_BOOL);
|
||||
ss << ", dash:" << "on";
|
||||
ss << ", hls:" << srs_bool2switch(SRS_AUTO_HLS_BOOL);
|
||||
ss << ", hds:" << srs_bool2switch(SRS_AUTO_HDS_BOOL);
|
||||
// hc(http callback)
|
||||
|
|
Loading…
Reference in a new issue