mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 19:31:53 +00:00
merge from 2.0release
This commit is contained in:
commit
5f91fbc970
10 changed files with 97 additions and 34 deletions
|
@ -1,13 +1,13 @@
|
|||
#Simple-RTMP-Server
|
||||
|
||||
SRS/3.0,开发代号:[OuXuli](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Product#release30)
|
||||
SRS/3.0, [OuXuli](https://github.com/simple-rtmp-server/srs/wiki/v1_CN_Product#release30)
|
||||
|
||||
SRS定位是运营级的互联网直播服务器集群,追求更好的概念完整性和最简单实现的代码。<br/>
|
||||
SRS is industrial-strength live streaming cluster, for the best conceptual integrity and the simplest implementation.
|
||||
|
||||
Download from github.io: [Centos6-x86_64][centos0], [more...][more0]<br/>
|
||||
Download from ossrs.net: [Centos6-x86_64][centos1], [more...][more1]<br/>
|
||||
Contact by QQ or Skype, read [Contact][contact]
|
||||
Website for SRS/2.0, read SRS 2.0 [Chinese][srs2_CN] or [English][srs2_EN].
|
||||
|
||||
## Why SRS?
|
||||
|
||||
|
@ -1025,5 +1025,6 @@ Winlin
|
|||
[centos0]: http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-1.0.32.zip
|
||||
[centos1]: http://www.ossrs.net/srs.release/releases/files/SRS-CentOS6-x86_64-1.0.32.zip
|
||||
|
||||
|
||||
[srs2_CN]: https://github.com/simple-rtmp-server/srs/wiki/v2_CN_Home
|
||||
[srs2_EN]: https://github.com/simple-rtmp-server/srs/wiki/v2_EN_Home
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ int proxy(srs_flv_t flv, srs_rtmp_t ortmp);
|
|||
int connect_oc(srs_rtmp_t ortmp);
|
||||
|
||||
#define RE_PULSE_MS 300
|
||||
#define RE_PULSE_JITTER_MS 3000
|
||||
int64_t re_create();
|
||||
void re_update(int64_t re, int32_t starttime, u_int32_t time);
|
||||
void re_cleanup(int64_t re, int32_t starttime, u_int32_t time);
|
||||
|
@ -256,7 +257,7 @@ void re_update(int64_t re, int32_t starttime, u_int32_t time)
|
|||
// send by pulse algorithm.
|
||||
int64_t now = srs_utils_time_ms();
|
||||
int64_t diff = time - starttime - (now -re);
|
||||
if (diff > RE_PULSE_MS) {
|
||||
if (diff > RE_PULSE_MS && diff < RE_PULSE_JITTER_MS) {
|
||||
usleep((useconds_t)(diff * 1000));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -853,6 +853,7 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root)
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: reload new http_remux in on_vhost_add
|
||||
// http_remux, only one per vhost.
|
||||
if (get_vhost_http_remux_enabled(vhost)) {
|
||||
for (it = subscribes.begin(); it != subscribes.end(); ++it) {
|
||||
|
@ -4417,3 +4418,18 @@ bool srs_config_dvr_is_plan_append(string plan)
|
|||
{
|
||||
return plan == SRS_CONF_DEFAULT_DVR_PLAN_APPEND;
|
||||
}
|
||||
|
||||
bool srs_stream_caster_is_udp(string caster)
|
||||
{
|
||||
return caster == SRS_CONF_DEFAULT_STREAM_CASTER_MPEGTS_OVER_UDP;
|
||||
}
|
||||
|
||||
bool srs_stream_caster_is_rtsp(string caster)
|
||||
{
|
||||
return caster == SRS_CONF_DEFAULT_STREAM_CASTER_RTSP;
|
||||
}
|
||||
|
||||
bool srs_stream_caster_is_flv(string caster)
|
||||
{
|
||||
return caster == SRS_CONF_DEFAULT_STREAM_CASTER_FLV;
|
||||
}
|
||||
|
|
|
@ -1143,6 +1143,9 @@ extern bool srs_config_ingest_is_stream(std::string type);
|
|||
extern bool srs_config_dvr_is_plan_segment(std::string plan);
|
||||
extern bool srs_config_dvr_is_plan_session(std::string plan);
|
||||
extern bool srs_config_dvr_is_plan_append(std::string plan);
|
||||
extern bool srs_stream_caster_is_udp(std::string caster);
|
||||
extern bool srs_stream_caster_is_rtsp(std::string caster);
|
||||
extern bool srs_stream_caster_is_flv(std::string caster);
|
||||
|
||||
// global config
|
||||
extern SrsConfig* _srs_config;
|
||||
|
|
|
@ -164,7 +164,7 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* shared_metadata)
|
|||
SrsSharedPtrMessage* metadata = shared_metadata->copy();
|
||||
|
||||
// TODO: FIXME: config the jitter of Forwarder.
|
||||
if ((ret = jitter->correct(metadata, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
|
||||
if ((ret = jitter->correct(metadata, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
|
||||
srs_freep(metadata);
|
||||
return ret;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* shared_audio)
|
|||
SrsSharedPtrMessage* msg = shared_audio->copy();
|
||||
|
||||
// TODO: FIXME: config the jitter of Forwarder.
|
||||
if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
|
||||
if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
|
||||
srs_freep(msg);
|
||||
return ret;
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* shared_video)
|
|||
SrsSharedPtrMessage* msg = shared_video->copy();
|
||||
|
||||
// TODO: FIXME: config the jitter of Forwarder.
|
||||
if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
|
||||
if ((ret = jitter->correct(msg, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
|
||||
srs_freep(msg);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ using namespace std;
|
|||
|
||||
// drop the segment when duration of ts too small.
|
||||
#define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
|
||||
// when hls timestamp jump, reset it.
|
||||
#define SRS_AUTO_HLS_SEGMENT_TIMESTAMP_JUMP_MS 300
|
||||
|
||||
// fragment plus the deviation percent.
|
||||
#define SRS_HLS_FLOOR_REAP_PERCENT 0.3
|
||||
|
@ -161,6 +163,11 @@ void SrsHlsSegment::update_duration(int64_t current_frame_dts)
|
|||
// update the segment duration, which is nagetive,
|
||||
// just ignore it.
|
||||
if (current_frame_dts < segment_start_dts) {
|
||||
// for atc and timestamp jump, reset the start dts.
|
||||
if (current_frame_dts < segment_start_dts - SRS_AUTO_HLS_SEGMENT_TIMESTAMP_JUMP_MS * 90) {
|
||||
srs_warn("hls timestamp jump %"PRId64"=>%"PRId64, segment_start_dts, current_frame_dts);
|
||||
segment_start_dts = current_frame_dts;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -280,7 +287,7 @@ SrsHlsMuxer::SrsHlsMuxer()
|
|||
previous_floor_ts = 0;
|
||||
accept_floor_ts = 0;
|
||||
hls_ts_floor = false;
|
||||
target_duration = 0;
|
||||
max_td = 0;
|
||||
_sequence_no = 0;
|
||||
current = NULL;
|
||||
acodec = SrsCodecAudioReserved1;
|
||||
|
@ -400,10 +407,8 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
|
|||
m3u8_url = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream);
|
||||
m3u8 = path + "/" + m3u8_url;
|
||||
|
||||
// we always keep the target duration increasing.
|
||||
int max_td = srs_max(target_duration, (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost)));
|
||||
srs_info("hls update target duration %d=>%d, aof=%.2f", target_duration, max_td, aof_ratio);
|
||||
target_duration = max_td;
|
||||
// when update config, reset the history target duration.
|
||||
max_td = (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost));
|
||||
|
||||
std::string storage = _srs_config->get_hls_storage(r->vhost);
|
||||
if (storage == "ram") {
|
||||
|
@ -699,7 +704,9 @@ int SrsHlsMuxer::segment_close(string log_desc)
|
|||
srs_assert(it == segments.end());
|
||||
|
||||
// valid, add to segments if segment duration is ok
|
||||
if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) {
|
||||
// when too small, it maybe not enough data to play.
|
||||
// when too large, it maybe timestamp corrupt.
|
||||
if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS && (int)current->duration <= max_td) {
|
||||
segments.push_back(current);
|
||||
|
||||
// use async to call the http hooks, for it will cause thread switch.
|
||||
|
@ -750,7 +757,6 @@ int SrsHlsMuxer::segment_close(string log_desc)
|
|||
// rename from tmp to real path
|
||||
std::string tmp_file = current->full_path + ".tmp";
|
||||
if (should_write_file) {
|
||||
unlink(tmp_file.c_str());
|
||||
if (unlink(tmp_file.c_str()) < 0) {
|
||||
srs_warn("ignore unlink path failed, file=%s.", tmp_file.c_str());
|
||||
}
|
||||
|
@ -817,6 +823,11 @@ int SrsHlsMuxer::refresh_m3u8()
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// no segments, also no m3u8, return.
|
||||
if (segments.size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string temp_m3u8 = m3u8 + ".temp";
|
||||
if ((ret = _refresh_m3u8(temp_m3u8)) == ERROR_SUCCESS) {
|
||||
if (should_write_file && rename(temp_m3u8.c_str(), m3u8.c_str()) < 0) {
|
||||
|
@ -826,7 +837,11 @@ int SrsHlsMuxer::refresh_m3u8()
|
|||
}
|
||||
|
||||
// remove the temp file.
|
||||
unlink(temp_m3u8.c_str());
|
||||
if (srs_path_exists(temp_m3u8)) {
|
||||
if (unlink(temp_m3u8.c_str()) < 0) {
|
||||
srs_warn("ignore remove m3u8 failed, %s", temp_m3u8.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -861,6 +876,9 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
|
|||
ss << "#EXT-X-MEDIA-SEQUENCE:" << first->sequence_no << SRS_CONSTS_LF;
|
||||
srs_verbose("write m3u8 sequence success.");
|
||||
|
||||
// iterator shared for td generation and segemnts wrote.
|
||||
std::vector<SrsHlsSegment*>::iterator it;
|
||||
|
||||
// #EXT-X-TARGETDURATION:4294967295\n
|
||||
/**
|
||||
* @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 25
|
||||
|
@ -871,11 +889,13 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
|
|||
* typical target duration is 10 seconds.
|
||||
*/
|
||||
// @see https://github.com/simple-rtmp-server/srs/issues/304#issuecomment-74000081
|
||||
std::vector<SrsHlsSegment*>::iterator it;
|
||||
int target_duration = 0;
|
||||
for (it = segments.begin(); it != segments.end(); ++it) {
|
||||
SrsHlsSegment* segment = *it;
|
||||
target_duration = srs_max(target_duration, (int)ceil(segment->duration));
|
||||
}
|
||||
target_duration = srs_max(target_duration, max_td);
|
||||
|
||||
ss << "#EXT-X-TARGETDURATION:" << target_duration << SRS_CONSTS_LF;
|
||||
srs_verbose("write m3u8 duration success.");
|
||||
|
||||
|
@ -1335,7 +1355,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio)
|
|||
}
|
||||
|
||||
// TODO: FIXME: config the jitter of HLS.
|
||||
if ((ret = jitter->correct(audio, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
|
||||
if ((ret = jitter->correct(audio, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
|
||||
srs_error("rtmp jitter correct audio failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1393,7 +1413,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video)
|
|||
}
|
||||
|
||||
// TODO: FIXME: config the jitter of HLS.
|
||||
if ((ret = jitter->correct(video, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
|
||||
if ((ret = jitter->correct(video, SrsRtmpJitterAlgorithmOFF)) != ERROR_SUCCESS) {
|
||||
srs_error("rtmp jitter correct video failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ private:
|
|||
int64_t previous_floor_ts;
|
||||
private:
|
||||
int _sequence_no;
|
||||
int target_duration;
|
||||
int max_td;
|
||||
std::string m3u8;
|
||||
std::string m3u8_url;
|
||||
private:
|
||||
|
|
|
@ -805,7 +805,14 @@ int SrsHttpStreamServer::http_mount(SrsSource* s, SrsRequest* r)
|
|||
entry->cache = new SrsStreamCache(s, r);
|
||||
entry->stream = new SrsLiveStream(s, r, entry->cache);
|
||||
|
||||
srs_assert(!tmpl->req);
|
||||
// TODO: FIXME: maybe refine the logic of http remux service.
|
||||
// if user push streams followed:
|
||||
// rtmp://test.com/live/stream1
|
||||
// rtmp://test.com/live/stream2
|
||||
// and they will using the same template, such as: [vhost]/[app]/[stream].flv
|
||||
// so, need to free last request object, otherwise, it will cause memory leak.
|
||||
srs_freep(tmpl->req);
|
||||
|
||||
tmpl->source = s;
|
||||
tmpl->req = r->copy();
|
||||
|
||||
|
@ -1170,8 +1177,8 @@ int SrsHttpStreamServer::hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph)
|
|||
std::string sid = r->get_stream_url();
|
||||
// check if the stream is enabled.
|
||||
if (sflvs.find(sid) != sflvs.end()) {
|
||||
SrsLiveEntry* entry = sflvs[sid];
|
||||
if (!entry->stream->entry->enabled) {
|
||||
SrsLiveEntry* s_entry = sflvs[sid];
|
||||
if (!s_entry->stream->entry->enabled) {
|
||||
srs_error("stream is disabled, hijack failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1228,7 +1235,9 @@ int SrsHttpStreamServer::initialize_flv_streaming()
|
|||
continue;
|
||||
}
|
||||
|
||||
initialize_flv_entry(conf->arg0());
|
||||
if ((ret = initialize_flv_entry(conf->arg0())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1120,11 +1120,11 @@ int SrsServer::listen_stream_caster()
|
|||
SrsListener* listener = NULL;
|
||||
|
||||
std::string caster = _srs_config->get_stream_caster_engine(stream_caster);
|
||||
if (caster == SRS_CONF_DEFAULT_STREAM_CASTER_MPEGTS_OVER_UDP) {
|
||||
if (srs_stream_caster_is_udp(caster)) {
|
||||
listener = new SrsUdpCasterListener(this, SrsListenerMpegTsOverUdp, stream_caster);
|
||||
} else if (caster == SRS_CONF_DEFAULT_STREAM_CASTER_RTSP) {
|
||||
} else if (srs_stream_caster_is_rtsp(caster)) {
|
||||
listener = new SrsRtspListener(this, SrsListenerRtsp, stream_caster);
|
||||
} else if (caster == SRS_CONF_DEFAULT_STREAM_CASTER_FLV) {
|
||||
} else if (srs_stream_caster_is_flv(caster)) {
|
||||
listener = new SrsHttpFlvListener(this, SrsListenerFlv, stream_caster);
|
||||
} else {
|
||||
ret = ERROR_STREAM_CASTER_ENGINE;
|
||||
|
|
|
@ -55,8 +55,8 @@ using namespace std;
|
|||
// 115 packets is 3s.
|
||||
#define SRS_PURE_AUDIO_GUESS_COUNT 115
|
||||
|
||||
// when got these videos or audios, mix ok.
|
||||
#define SRS_MIX_CORRECT_MIX_AV 10
|
||||
// when got these videos or audios, pure audio or video, mix ok.
|
||||
#define SRS_MIX_CORRECT_PURE_AV 10
|
||||
|
||||
int _srs_time_jitter_string2int(std::string time_jitter)
|
||||
{
|
||||
|
@ -849,12 +849,25 @@ void SrsMixQueue::push(SrsSharedPtrMessage* msg)
|
|||
|
||||
SrsSharedPtrMessage* SrsMixQueue::pop()
|
||||
{
|
||||
// when got 10+ videos or audios, mix ok.
|
||||
// when got 1 video and 1 audio, mix ok.
|
||||
if (nb_videos < SRS_MIX_CORRECT_MIX_AV && nb_audios < SRS_MIX_CORRECT_MIX_AV) {
|
||||
if (nb_videos < 1 || nb_audios < 1) {
|
||||
return NULL;
|
||||
}
|
||||
bool mix_ok = false;
|
||||
|
||||
// pure video
|
||||
if (nb_videos >= SRS_MIX_CORRECT_PURE_AV && nb_audios == 0) {
|
||||
mix_ok = true;
|
||||
}
|
||||
|
||||
// pure audio
|
||||
if (nb_audios >= SRS_MIX_CORRECT_PURE_AV && nb_videos == 0) {
|
||||
mix_ok = true;
|
||||
}
|
||||
|
||||
// got 1 video and 1 audio, mix ok.
|
||||
if (nb_videos >= 1 && nb_audios >= 1) {
|
||||
mix_ok = true;
|
||||
}
|
||||
|
||||
if (!mix_ok) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// pop the first msg.
|
||||
|
|
Loading…
Reference in a new issue