diff --git a/README.md b/README.md
index 5f2b3181c..0905b7677 100755
--- a/README.md
+++ b/README.md
@@ -241,6 +241,7 @@ Supported operating systems and hardware:
* 2013-10-17, Created.
## History
+* v1.0, 2014-06-25, fix [#108](https://github.com/winlinvip/simple-rtmp-server/issues/108), disable the time jitter for encoder non-monotonical stream. 0.9.133
* v1.0, 2014-06-23, support report summaries in heartbeat. 0.9.132
* v1.0, 2014-06-22, performance refine, support [3k+](https://github.com/winlinvip/simple-rtmp-server/wiki/Performance#%E6%80%A7%E8%83%BD%E4%BE%8B%E8%A1%8C%E6%8A%A5%E5%91%8A4k) connections(270kbps). 0.9.130
* v1.0, 2014-06-21, support edge [token traverse](https://github.com/winlinvip/simple-rtmp-server/wiki/DRM#tokentraverse), fix [#104](https://github.com/winlinvip/simple-rtmp-server/issues/104). 0.9.129
diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf
index 782822311..4e4870c12 100644
--- a/trunk/conf/full.conf
+++ b/trunk/conf/full.conf
@@ -187,6 +187,18 @@ vhost dvr.srs.com {
# the param for plan(segment), in seconds.
# default: 30
dvr_duration 30;
+ # about the stream monotonically increasing:
+ # 1. video timestamp is monotonically increasing,
+ # 2. audio timestamp is monotonically increasing,
+ # 3. video and audio timestamp is interleaved monotonically increasing.
+ # it's specified by RTMP specification, @see 3. Byte Order, Alignment, and Time Format
+ # however, some encoder cannot provides this feature, please set this to off to ignore time jitter.
+ # the time jitter algorithm:
+ # 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
+ # 2. zero, only ensure sttream start at zero, ignore timestamp jitter.
+ # 3. off, disable the time jitter algorithm, like atc.
+ # default: full
+ time_jitter full;
}
}
@@ -906,6 +918,22 @@ vhost chunksize.srs.com {
chunk_size 128;
}
+# vhost for time jitter
+vhost jitter.srs.com {
+ # about the stream monotonically increasing:
+ # 1. video timestamp is monotonically increasing,
+ # 2. audio timestamp is monotonically increasing,
+ # 3. video and audio timestamp is interleaved monotonically increasing.
+ # it's specified by RTMP specification, @see 3. Byte Order, Alignment, and Time Format
+ # however, some encoder cannot provides this feature, please set this to off to ignore time jitter.
+ # the time jitter algorithm:
+ # 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
+ # 2. zero, only ensure sttream start at zero, ignore timestamp jitter.
+ # 3. off, disable the time jitter algorithm, like atc.
+ # default: full
+ time_jitter full;
+}
+
# vhost for atc.
vhost atc.srs.com {
# vhost for atc for hls/hds/rtmp backup.
diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp
index 1ae191a7d..9aa331557 100644
--- a/trunk/src/app/srs_app_config.cpp
+++ b/trunk/src/app/srs_app_config.cpp
@@ -41,6 +41,7 @@ using namespace std;
#include
#include
#include
+#include
#define SRS_WIKI_URL_LOG "https://github.com/winlinvip/simple-rtmp-server/wiki/SrsLog"
@@ -947,6 +948,17 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root)
}
srs_trace("vhost %s reload queue_length success.", vhost.c_str());
}
+ // time_jitter, only one per vhost
+ if (!srs_directive_equals(new_vhost->get("time_jitter"), old_vhost->get("time_jitter"))) {
+ for (it = subscribes.begin(); it != subscribes.end(); ++it) {
+ ISrsReloadHandler* subscribe = *it;
+ if ((ret = subscribe->on_reload_vhost_time_jitter(vhost)) != ERROR_SUCCESS) {
+ srs_error("vhost %s notify subscribes time_jitter failed. ret=%d", vhost.c_str(), ret);
+ return ret;
+ }
+ }
+ srs_trace("vhost %s reload time_jitter success.", vhost.c_str());
+ }
// forward, only one per vhost
if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) {
for (it = subscribes.begin(); it != subscribes.end(); ++it) {
@@ -1788,6 +1800,23 @@ bool SrsConfig::get_atc_auto(string vhost)
return true;
}
+int SrsConfig::get_time_jitter(string vhost)
+{
+ SrsConfDirective* dvr = get_vhost(vhost);
+
+ std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER;
+
+ if (dvr) {
+ SrsConfDirective* conf = dvr->get("time_jitter");
+
+ if (conf) {
+ time_jitter = conf->arg0();
+ }
+ }
+
+ return _srs_time_jitter_string2int(time_jitter);
+}
+
double SrsConfig::get_queue_length(string vhost)
{
SrsConfDirective* conf = get_vhost(vhost);
@@ -2636,6 +2665,23 @@ int SrsConfig::get_dvr_duration(string vhost)
return ::atoi(conf->arg0().c_str());
}
+int SrsConfig::get_dvr_time_jitter(string vhost)
+{
+ SrsConfDirective* dvr = get_dvr(vhost);
+
+ std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER;
+
+ if (dvr) {
+ SrsConfDirective* conf = dvr->get("time_jitter");
+
+ if (conf) {
+ time_jitter = conf->arg0();
+ }
+ }
+
+ return _srs_time_jitter_string2int(time_jitter);
+}
+
SrsConfDirective* SrsConfig::get_http_api()
{
return root->get("http_api");
diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp
index 3d8df3c93..883948952 100644
--- a/trunk/src/app/srs_app_config.hpp
+++ b/trunk/src/app/srs_app_config.hpp
@@ -49,6 +49,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SRS_CONF_DEFAULT_DVR_PLAN_HSS "hss"
#define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION
#define SRS_CONF_DEFAULT_DVR_DURATION 30
+#define SRS_CONF_DEFAULT_TIME_JITTER "full"
// in ms, for HLS aac sync time.
#define SRS_CONF_DEFAULT_AAC_SYNC 100
// in ms, for HLS aac flush the audio
@@ -200,6 +201,7 @@ public:
virtual bool get_gop_cache(std::string vhost);
virtual bool get_atc(std::string vhost);
virtual bool get_atc_auto(std::string vhost);
+ virtual int get_time_jitter(std::string vhost);
virtual double get_queue_length(std::string vhost);
virtual SrsConfDirective* get_forward(std::string vhost);
virtual SrsConfDirective* get_refer(std::string vhost);
@@ -272,6 +274,7 @@ public:
virtual std::string get_dvr_path(std::string vhost);
virtual std::string get_dvr_plan(std::string vhost);
virtual int get_dvr_duration(std::string vhost);
+ virtual int get_dvr_time_jitter(std::string vhost);
// http api section
private:
virtual SrsConfDirective* get_http_api();
diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp
index f605e4372..6ffb10f06 100644
--- a/trunk/src/app/srs_app_dvr.cpp
+++ b/trunk/src/app/srs_app_dvr.cpp
@@ -70,10 +70,15 @@ SrsDvrPlan::SrsDvrPlan()
fs = new SrsFileStream();
enc = new SrsFlvEncoder();
segment = new SrsFlvSegment();
+ jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
+
+ _srs_config->subscribe(this);
}
SrsDvrPlan::~SrsDvrPlan()
{
+ _srs_config->unsubscribe(this);
+
srs_freep(jitter);
srs_freep(fs);
srs_freep(enc);
@@ -86,6 +91,8 @@ int SrsDvrPlan::initialize(SrsSource* source, SrsRequest* req)
_source = source;
_req = req;
+
+ jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(_req->vhost);
return ret;
}
@@ -198,7 +205,7 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* audio)
return ret;
}
- if ((jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
+ if ((jitter->correct(audio, 0, 0, jitter_algorithm)) != ERROR_SUCCESS) {
return ret;
}
@@ -240,7 +247,7 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
srs_verbose("dvr video is key: %d", is_key_frame);
#endif
- if ((jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
+ if ((jitter->correct(video, 0, 0, jitter_algorithm)) != ERROR_SUCCESS) {
return ret;
}
@@ -256,6 +263,15 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
return ret;
}
+int SrsDvrPlan::on_reload_vhost_dvr(std::string vhost)
+{
+ int ret = ERROR_SUCCESS;
+
+ jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(_req->vhost);
+
+ return ret;
+}
+
int SrsDvrPlan::flv_open(string stream, string path)
{
int ret = ERROR_SUCCESS;
diff --git a/trunk/src/app/srs_app_dvr.hpp b/trunk/src/app/srs_app_dvr.hpp
index eeb57c36c..1a05fe9b2 100644
--- a/trunk/src/app/srs_app_dvr.hpp
+++ b/trunk/src/app/srs_app_dvr.hpp
@@ -42,6 +42,9 @@ class SrsSharedPtrMessage;
class SrsFileStream;
class SrsFlvEncoder;
+#include
+#include
+
/**
* a piece of flv segment.
*/
@@ -93,21 +96,23 @@ public:
* 2. reap flv: when to reap the flv and start new piece.
*/
// TODO: FIXME: the plan is too fat, refine me.
-class SrsDvrPlan
+class SrsDvrPlan : public ISrsReloadHandler
{
-protected:
+private:
/**
* the underlayer dvr stream.
* if close, the flv is reap and closed.
* if open, new flv file is crote.
*/
- SrsFileStream* fs;
SrsFlvEncoder* enc;
- bool dvr_enabled;
SrsSource* _source;
- SrsRequest* _req;
SrsRtmpJitter* jitter;
+ SrsRtmpJitterAlgorithm jitter_algorithm;
+protected:
SrsFlvSegment* segment;
+ SrsRequest* _req;
+ bool dvr_enabled;
+ SrsFileStream* fs;
public:
SrsDvrPlan();
virtual ~SrsDvrPlan();
@@ -118,6 +123,9 @@ public:
virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
virtual int on_audio(SrsSharedPtrMessage* audio);
virtual int on_video(SrsSharedPtrMessage* video);
+// interface ISrsReloadHandler
+public:
+ virtual int on_reload_vhost_dvr(std::string vhost);
protected:
virtual int flv_open(std::string stream, std::string path);
virtual int flv_close();
diff --git a/trunk/src/app/srs_app_forward.cpp b/trunk/src/app/srs_app_forward.cpp
index d4db40e38..fce33a4fa 100644
--- a/trunk/src/app/srs_app_forward.cpp
+++ b/trunk/src/app/srs_app_forward.cpp
@@ -162,7 +162,7 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* metadata)
{
int ret = ERROR_SUCCESS;
- if ((ret = jitter->correct(metadata, 0, 0)) != ERROR_SUCCESS) {
+ if ((ret = jitter->correct(metadata, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_freep(metadata);
return ret;
}
@@ -178,7 +178,7 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* msg)
{
int ret = ERROR_SUCCESS;
- if ((ret = jitter->correct(msg, 0, 0)) != ERROR_SUCCESS) {
+ if ((ret = jitter->correct(msg, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_freep(msg);
return ret;
}
@@ -194,7 +194,7 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* msg)
{
int ret = ERROR_SUCCESS;
- if ((ret = jitter->correct(msg, 0, 0)) != ERROR_SUCCESS) {
+ if ((ret = jitter->correct(msg, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_freep(msg);
return ret;
}
diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp
index 6d91026d4..c93bb0276 100644
--- a/trunk/src/app/srs_app_hls.cpp
+++ b/trunk/src/app/srs_app_hls.cpp
@@ -1411,7 +1411,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio)
return hls_cache->on_sequence_header(muxer);
}
- if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
+ if ((ret = jitter->correct(audio, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_error("rtmp jitter correct audio failed. ret=%d", ret);
return ret;
}
@@ -1456,7 +1456,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* video)
return hls_cache->on_sequence_header(muxer);
}
- if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
+ if ((ret = jitter->correct(video, 0, 0, SrsRtmpJitterAlgorithmFULL)) != ERROR_SUCCESS) {
srs_error("rtmp jitter correct video failed. ret=%d", ret);
return ret;
}
diff --git a/trunk/src/app/srs_app_reload.cpp b/trunk/src/app/srs_app_reload.cpp
index b640162d6..b3ddfadb8 100644
--- a/trunk/src/app/srs_app_reload.cpp
+++ b/trunk/src/app/srs_app_reload.cpp
@@ -120,6 +120,11 @@ int ISrsReloadHandler::on_reload_vhost_queue_length(string /*vhost*/)
return ERROR_SUCCESS;
}
+int ISrsReloadHandler::on_reload_vhost_time_jitter(string /*vhost*/)
+{
+ return ERROR_SUCCESS;
+}
+
int ISrsReloadHandler::on_reload_vhost_forward(string /*vhost*/)
{
return ERROR_SUCCESS;
diff --git a/trunk/src/app/srs_app_reload.hpp b/trunk/src/app/srs_app_reload.hpp
index 798a11ab2..a7eb1e9aa 100644
--- a/trunk/src/app/srs_app_reload.hpp
+++ b/trunk/src/app/srs_app_reload.hpp
@@ -61,6 +61,7 @@ public:
virtual int on_reload_vhost_atc(std::string vhost);
virtual int on_reload_vhost_gop_cache(std::string vhost);
virtual int on_reload_vhost_queue_length(std::string vhost);
+ virtual int on_reload_vhost_time_jitter(std::string vhost);
virtual int on_reload_vhost_forward(std::string vhost);
virtual int on_reload_vhost_hls(std::string vhost);
virtual int on_reload_vhost_dvr(std::string vhost);
diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp
index ed86e9147..58542672e 100644
--- a/trunk/src/app/srs_app_source.cpp
+++ b/trunk/src/app/srs_app_source.cpp
@@ -45,6 +45,17 @@ using namespace std;
#define CONST_MAX_JITTER_MS 500
#define DEFAULT_FRAME_TIME_MS 40
+int _srs_time_jitter_string2int(std::string time_jitter)
+{
+ if (time_jitter == "full") {
+ return SrsRtmpJitterAlgorithmFULL;
+ } else if (time_jitter == "zero") {
+ return SrsRtmpJitterAlgorithmZERO;
+ } else {
+ return SrsRtmpJitterAlgorithmOFF;
+ }
+}
+
SrsRtmpJitter::SrsRtmpJitter()
{
last_pkt_correct_time = last_pkt_time = 0;
@@ -54,10 +65,27 @@ SrsRtmpJitter::~SrsRtmpJitter()
{
}
-int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv)
+int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJitterAlgorithm ag)
{
int ret = ERROR_SUCCESS;
+
+ // all jitter correct features is disabled, ignore.
+ if (ag == SrsRtmpJitterAlgorithmOFF) {
+ return ret;
+ }
+
+ // start at zero, but donot ensure monotonically increasing.
+ if (ag == SrsRtmpJitterAlgorithmZERO) {
+ if (last_pkt_correct_time <= 0) {
+ last_pkt_correct_time = msg->header.timestamp;
+ }
+ msg->header.timestamp -= last_pkt_correct_time;
+ return ret;
+ }
+
+ // full jitter algorithm, do jitter correct.
+
// set to 0 for metadata.
if (!msg->header.is_video() && !msg->header.is_audio()) {
msg->header.timestamp = 0;
@@ -266,12 +294,12 @@ int SrsConsumer::get_time()
return jitter->get_time();
}
-int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv)
+int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm ag)
{
int ret = ERROR_SUCCESS;
if (!atc) {
- if ((ret = jitter->correct(msg, tba, tbv)) != ERROR_SUCCESS) {
+ if ((ret = jitter->correct(msg, tba, tbv, ag)) != ERROR_SUCCESS) {
srs_freep(msg);
return ret;
}
@@ -384,7 +412,7 @@ void SrsGopCache::clear()
cached_video_count = 0;
}
-int SrsGopCache::dump(SrsConsumer* consumer, bool atc, int tba, int tbv)
+int SrsGopCache::dump(SrsConsumer* consumer, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm jitter_algorithm)
{
int ret = ERROR_SUCCESS;
@@ -392,7 +420,7 @@ int SrsGopCache::dump(SrsConsumer* consumer, bool atc, int tba, int tbv)
for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
SrsSharedPtrMessage* msg = *it;
SrsSharedPtrMessage* copy = msg->copy();
- if ((ret = consumer->enqueue(copy, atc, tba, tbv)) != ERROR_SUCCESS) {
+ if ((ret = consumer->enqueue(copy, atc, tba, tbv, jitter_algorithm)) != ERROR_SUCCESS) {
srs_error("dispatch cached gop failed. ret=%d", ret);
return ret;
}
@@ -464,6 +492,7 @@ void SrsSource::destroy()
SrsSource::SrsSource(SrsRequest* req)
{
_req = req->copy();
+ jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
#ifdef SRS_AUTO_HLS
hls = new SrsHls(this);
@@ -549,6 +578,8 @@ int SrsSource::initialize()
double queue_size = _srs_config->get_queue_length(_req->vhost);
publish_edge->set_queue_size(queue_size);
+ jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost);
+
return ret;
}
@@ -630,6 +661,19 @@ int SrsSource::on_reload_vhost_queue_length(string vhost)
return ret;
}
+int SrsSource::on_reload_vhost_time_jitter(string vhost)
+{
+ int ret = ERROR_SUCCESS;
+
+ if (_req->vhost != vhost) {
+ return ret;
+ }
+
+ jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost);
+
+ return ret;
+}
+
int SrsSource::on_reload_vhost_forward(string vhost)
{
int ret = ERROR_SUCCESS;
@@ -928,7 +972,7 @@ int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata)
for (it = consumers.begin(); it != consumers.end(); ++it) {
SrsConsumer* consumer = *it;
SrsSharedPtrMessage* copy = cache_metadata->copy();
- if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
+ if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
srs_error("dispatch the metadata failed. ret=%d", ret);
return ret;
}
@@ -992,7 +1036,7 @@ int SrsSource::on_audio(SrsMessage* audio)
for (int i = 0; i < (int)consumers.size(); i++) {
SrsConsumer* consumer = consumers.at(i);
SrsSharedPtrMessage* copy = msg->copy();
- if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
+ if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
srs_error("dispatch the audio failed. ret=%d", ret);
return ret;
}
@@ -1082,7 +1126,7 @@ int SrsSource::on_video(SrsMessage* video)
for (int i = 0; i < (int)consumers.size(); i++) {
SrsConsumer* consumer = consumers.at(i);
SrsSharedPtrMessage* copy = msg->copy();
- if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
+ if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
srs_error("dispatch the video failed. ret=%d", ret);
return ret;
}
@@ -1328,28 +1372,32 @@ void SrsSource::on_unpublish()
}
}
+ int tba = sample_rate;
+ int tbv = frame_rate;
+ SrsRtmpJitterAlgorithm ag = jitter_algorithm;
+
// copy metadata.
- if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
+ if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
srs_error("dispatch metadata failed. ret=%d", ret);
return ret;
}
srs_info("dispatch metadata success");
// copy sequence header
- if (cache_sh_video && (ret = consumer->enqueue(cache_sh_video->copy(), atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
+ if (cache_sh_video && (ret = consumer->enqueue(cache_sh_video->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
srs_error("dispatch video sequence header failed. ret=%d", ret);
return ret;
}
srs_info("dispatch video sequence header success");
- if (cache_sh_audio && (ret = consumer->enqueue(cache_sh_audio->copy(), atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
+ if (cache_sh_audio && (ret = consumer->enqueue(cache_sh_audio->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
srs_error("dispatch audio sequence header failed. ret=%d", ret);
return ret;
}
srs_info("dispatch audio sequence header success");
// copy gop cache to client.
- if ((ret = gop_cache->dump(consumer, atc, sample_rate, frame_rate)) != ERROR_SUCCESS) {
+ if ((ret = gop_cache->dump(consumer, atc, tba, tbv, ag)) != ERROR_SUCCESS) {
return ret;
}
diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp
index e35296d06..ef3731740 100644
--- a/trunk/src/app/srs_app_source.hpp
+++ b/trunk/src/app/srs_app_source.hpp
@@ -59,6 +59,20 @@ class SrsEncoder;
#endif
class SrsStream;
+/**
+* the time jitter algorithm:
+* 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
+* 2. zero, only ensure sttream start at zero, ignore timestamp jitter.
+* 3. off, disable the time jitter algorithm, like atc.
+*/
+enum SrsRtmpJitterAlgorithm
+{
+ SrsRtmpJitterAlgorithmFULL = 0x01,
+ SrsRtmpJitterAlgorithmZERO,
+ SrsRtmpJitterAlgorithmOFF
+};
+int _srs_time_jitter_string2int(std::string time_jitter);
+
/**
* time jitter detect and correct,
* to ensure the rtmp stream is monotonically.
@@ -74,8 +88,12 @@ public:
public:
/**
* detect the time jitter and correct it.
+ * @param tba, the audio timebase, used to calc the "right" delta if jitter detected.
+ * @param tbv, the video timebase, used to calc the "right" delta if jitter detected.
+ * @param start_at_zero whether ensure stream start at zero.
+ * @param mono_increasing whether ensure stream is monotonically inscreasing.
*/
- virtual int correct(SrsSharedPtrMessage* msg, int tba, int tbv);
+ virtual int correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJitterAlgorithm ag);
/**
* get current client time, the last packet time.
*/
@@ -160,8 +178,9 @@ public:
* used to calc the audio time delta if time-jitter detected.
* @param tbv timebase of video.
* used to calc the video time delta if time-jitter detected.
+ * @param ag the algorithm of time jitter.
*/
- virtual int enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv);
+ virtual int enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm ag);
/**
* get packets in consumer queue.
* @pmsgs SrsMessages*[], used to store the msgs, user must alloc it.
@@ -209,7 +228,7 @@ public:
*/
virtual int cache(SrsSharedPtrMessage* msg);
virtual void clear();
- virtual int dump(SrsConsumer* consumer, bool atc, int tba, int tbv);
+ virtual int dump(SrsConsumer* consumer, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm jitter_algorithm);
/**
* used for atc to get the time of gop cache,
* the atc will adjust the sequence header timestamp to gop cache.
@@ -249,6 +268,8 @@ private:
SrsRequest* _req;
// to delivery stream to clients.
std::vector consumers;
+ // the time jitter algorithm for vhost.
+ SrsRtmpJitterAlgorithm jitter_algorithm;
// hls handler.
#ifdef SRS_AUTO_HLS
SrsHls* hls;
@@ -310,6 +331,7 @@ public:
virtual int on_reload_vhost_atc(std::string vhost);
virtual int on_reload_vhost_gop_cache(std::string vhost);
virtual int on_reload_vhost_queue_length(std::string vhost);
+ virtual int on_reload_vhost_time_jitter(std::string vhost);
virtual int on_reload_vhost_forward(std::string vhost);
virtual int on_reload_vhost_hls(std::string vhost);
virtual int on_reload_vhost_dvr(std::string vhost);
diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp
index aa2cc5ae9..a90ab17fe 100644
--- a/trunk/src/core/srs_core.hpp
+++ b/trunk/src/core/srs_core.hpp
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR "0"
#define VERSION_MINOR "9"
-#define VERSION_REVISION "132"
+#define VERSION_REVISION "133"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info.
#define RTMP_SIG_SRS_KEY "SRS"