1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

merge from 2.0release

This commit is contained in:
winlin 2015-07-14 11:32:40 +08:00
commit 5f91fbc970
10 changed files with 97 additions and 34 deletions

View file

@ -1,13 +1,13 @@
#Simple-RTMP-Server #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定位是运营级的互联网直播服务器集群追求更好的概念完整性和最简单实现的代码。<br/>
SRS is industrial-strength live streaming cluster, for the best conceptual integrity and the simplest implementation. 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 github.io: [Centos6-x86_64][centos0], [more...][more0]<br/>
Download from ossrs.net: [Centos6-x86_64][centos1], [more...][more1]<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? ## Why SRS?
@ -1025,5 +1025,6 @@ Winlin
[centos0]: http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-1.0.32.zip [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 [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

View file

@ -38,6 +38,7 @@ int proxy(srs_flv_t flv, srs_rtmp_t ortmp);
int connect_oc(srs_rtmp_t ortmp); int connect_oc(srs_rtmp_t ortmp);
#define RE_PULSE_MS 300 #define RE_PULSE_MS 300
#define RE_PULSE_JITTER_MS 3000
int64_t re_create(); int64_t re_create();
void re_update(int64_t re, int32_t starttime, u_int32_t time); 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); 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. // send by pulse algorithm.
int64_t now = srs_utils_time_ms(); int64_t now = srs_utils_time_ms();
int64_t diff = time - starttime - (now -re); 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)); usleep((useconds_t)(diff * 1000));
} }
} }

View file

@ -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. // http_remux, only one per vhost.
if (get_vhost_http_remux_enabled(vhost)) { if (get_vhost_http_remux_enabled(vhost)) {
for (it = subscribes.begin(); it != subscribes.end(); ++it) { 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; 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;
}

View file

@ -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_segment(std::string plan);
extern bool srs_config_dvr_is_plan_session(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_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 // global config
extern SrsConfig* _srs_config; extern SrsConfig* _srs_config;

View file

@ -164,7 +164,7 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* shared_metadata)
SrsSharedPtrMessage* metadata = shared_metadata->copy(); SrsSharedPtrMessage* metadata = shared_metadata->copy();
// TODO: FIXME: config the jitter of Forwarder. // 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); srs_freep(metadata);
return ret; return ret;
} }
@ -183,7 +183,7 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* shared_audio)
SrsSharedPtrMessage* msg = shared_audio->copy(); SrsSharedPtrMessage* msg = shared_audio->copy();
// TODO: FIXME: config the jitter of Forwarder. // 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); srs_freep(msg);
return ret; return ret;
} }
@ -207,7 +207,7 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* shared_video)
SrsSharedPtrMessage* msg = shared_video->copy(); SrsSharedPtrMessage* msg = shared_video->copy();
// TODO: FIXME: config the jitter of Forwarder. // 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); srs_freep(msg);
return ret; return ret;
} }

View file

@ -53,6 +53,8 @@ using namespace std;
// drop the segment when duration of ts too small. // drop the segment when duration of ts too small.
#define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 #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. // fragment plus the deviation percent.
#define SRS_HLS_FLOOR_REAP_PERCENT 0.3 #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, // update the segment duration, which is nagetive,
// just ignore it. // just ignore it.
if (current_frame_dts < segment_start_dts) { 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; return;
} }
@ -280,7 +287,7 @@ SrsHlsMuxer::SrsHlsMuxer()
previous_floor_ts = 0; previous_floor_ts = 0;
accept_floor_ts = 0; accept_floor_ts = 0;
hls_ts_floor = false; hls_ts_floor = false;
target_duration = 0; max_td = 0;
_sequence_no = 0; _sequence_no = 0;
current = NULL; current = NULL;
acodec = SrsCodecAudioReserved1; 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_url = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream);
m3u8 = path + "/" + m3u8_url; m3u8 = path + "/" + m3u8_url;
// we always keep the target duration increasing. // when update config, reset the history target duration.
int max_td = srs_max(target_duration, (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost))); max_td = (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;
std::string storage = _srs_config->get_hls_storage(r->vhost); std::string storage = _srs_config->get_hls_storage(r->vhost);
if (storage == "ram") { if (storage == "ram") {
@ -699,7 +704,9 @@ int SrsHlsMuxer::segment_close(string log_desc)
srs_assert(it == segments.end()); srs_assert(it == segments.end());
// valid, add to segments if segment duration is ok // 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); segments.push_back(current);
// use async to call the http hooks, for it will cause thread switch. // 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 // rename from tmp to real path
std::string tmp_file = current->full_path + ".tmp"; std::string tmp_file = current->full_path + ".tmp";
if (should_write_file) { if (should_write_file) {
unlink(tmp_file.c_str());
if (unlink(tmp_file.c_str()) < 0) { if (unlink(tmp_file.c_str()) < 0) {
srs_warn("ignore unlink path failed, file=%s.", tmp_file.c_str()); srs_warn("ignore unlink path failed, file=%s.", tmp_file.c_str());
} }
@ -817,6 +823,11 @@ int SrsHlsMuxer::refresh_m3u8()
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
// no segments, also no m3u8, return.
if (segments.size() == 0) {
return ret;
}
std::string temp_m3u8 = m3u8 + ".temp"; std::string temp_m3u8 = m3u8 + ".temp";
if ((ret = _refresh_m3u8(temp_m3u8)) == ERROR_SUCCESS) { if ((ret = _refresh_m3u8(temp_m3u8)) == ERROR_SUCCESS) {
if (should_write_file && rename(temp_m3u8.c_str(), m3u8.c_str()) < 0) { 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. // 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; return ret;
} }
@ -861,6 +876,9 @@ int SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
ss << "#EXT-X-MEDIA-SEQUENCE:" << first->sequence_no << SRS_CONSTS_LF; ss << "#EXT-X-MEDIA-SEQUENCE:" << first->sequence_no << SRS_CONSTS_LF;
srs_verbose("write m3u8 sequence success."); srs_verbose("write m3u8 sequence success.");
// iterator shared for td generation and segemnts wrote.
std::vector<SrsHlsSegment*>::iterator it;
// #EXT-X-TARGETDURATION:4294967295\n // #EXT-X-TARGETDURATION:4294967295\n
/** /**
* @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 25 * @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. * typical target duration is 10 seconds.
*/ */
// @see https://github.com/simple-rtmp-server/srs/issues/304#issuecomment-74000081 // @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) { for (it = segments.begin(); it != segments.end(); ++it) {
SrsHlsSegment* segment = *it; SrsHlsSegment* segment = *it;
target_duration = srs_max(target_duration, (int)ceil(segment->duration)); 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; ss << "#EXT-X-TARGETDURATION:" << target_duration << SRS_CONSTS_LF;
srs_verbose("write m3u8 duration success."); srs_verbose("write m3u8 duration success.");
@ -1335,7 +1355,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio)
} }
// TODO: FIXME: config the jitter of HLS. // 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); srs_error("rtmp jitter correct audio failed. ret=%d", ret);
return ret; return ret;
} }
@ -1393,7 +1413,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video)
} }
// TODO: FIXME: config the jitter of HLS. // 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); srs_error("rtmp jitter correct video failed. ret=%d", ret);
return ret; return ret;
} }

View file

@ -233,7 +233,7 @@ private:
int64_t previous_floor_ts; int64_t previous_floor_ts;
private: private:
int _sequence_no; int _sequence_no;
int target_duration; int max_td;
std::string m3u8; std::string m3u8;
std::string m3u8_url; std::string m3u8_url;
private: private:

View file

@ -805,7 +805,14 @@ int SrsHttpStreamServer::http_mount(SrsSource* s, SrsRequest* r)
entry->cache = new SrsStreamCache(s, r); entry->cache = new SrsStreamCache(s, r);
entry->stream = new SrsLiveStream(s, r, entry->cache); 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->source = s;
tmpl->req = r->copy(); tmpl->req = r->copy();
@ -1170,8 +1177,8 @@ int SrsHttpStreamServer::hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph)
std::string sid = r->get_stream_url(); std::string sid = r->get_stream_url();
// check if the stream is enabled. // check if the stream is enabled.
if (sflvs.find(sid) != sflvs.end()) { if (sflvs.find(sid) != sflvs.end()) {
SrsLiveEntry* entry = sflvs[sid]; SrsLiveEntry* s_entry = sflvs[sid];
if (!entry->stream->entry->enabled) { if (!s_entry->stream->entry->enabled) {
srs_error("stream is disabled, hijack failed. ret=%d", ret); srs_error("stream is disabled, hijack failed. ret=%d", ret);
return ret; return ret;
} }
@ -1228,7 +1235,9 @@ int SrsHttpStreamServer::initialize_flv_streaming()
continue; continue;
} }
initialize_flv_entry(conf->arg0()); if ((ret = initialize_flv_entry(conf->arg0())) != ERROR_SUCCESS) {
return ret;
}
} }
return ret; return ret;
} }

View file

@ -1120,11 +1120,11 @@ int SrsServer::listen_stream_caster()
SrsListener* listener = NULL; SrsListener* listener = NULL;
std::string caster = _srs_config->get_stream_caster_engine(stream_caster); 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); 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); 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); listener = new SrsHttpFlvListener(this, SrsListenerFlv, stream_caster);
} else { } else {
ret = ERROR_STREAM_CASTER_ENGINE; ret = ERROR_STREAM_CASTER_ENGINE;

View file

@ -55,8 +55,8 @@ using namespace std;
// 115 packets is 3s. // 115 packets is 3s.
#define SRS_PURE_AUDIO_GUESS_COUNT 115 #define SRS_PURE_AUDIO_GUESS_COUNT 115
// when got these videos or audios, mix ok. // when got these videos or audios, pure audio or video, mix ok.
#define SRS_MIX_CORRECT_MIX_AV 10 #define SRS_MIX_CORRECT_PURE_AV 10
int _srs_time_jitter_string2int(std::string time_jitter) int _srs_time_jitter_string2int(std::string time_jitter)
{ {
@ -849,12 +849,25 @@ void SrsMixQueue::push(SrsSharedPtrMessage* msg)
SrsSharedPtrMessage* SrsMixQueue::pop() SrsSharedPtrMessage* SrsMixQueue::pop()
{ {
// when got 10+ videos or audios, mix ok. bool mix_ok = false;
// when got 1 video and 1 audio, mix ok.
if (nb_videos < SRS_MIX_CORRECT_MIX_AV && nb_audios < SRS_MIX_CORRECT_MIX_AV) { // pure video
if (nb_videos < 1 || nb_audios < 1) { if (nb_videos >= SRS_MIX_CORRECT_PURE_AV && nb_audios == 0) {
return NULL; 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. // pop the first msg.