mirror of
https://github.com/ossrs/srs.git
synced 2025-02-14 20:31:56 +00:00
fix #108: disable the time jitter for encoder non-monotonical stream. 0.9.133
This commit is contained in:
parent
f173345e15
commit
1970e18ed6
13 changed files with 206 additions and 28 deletions
|
@ -241,6 +241,7 @@ Supported operating systems and hardware:
|
||||||
* 2013-10-17, Created.<br/>
|
* 2013-10-17, Created.<br/>
|
||||||
|
|
||||||
## History
|
## 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-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-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
|
* 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
|
||||||
|
|
|
@ -187,6 +187,18 @@ vhost dvr.srs.com {
|
||||||
# the param for plan(segment), in seconds.
|
# the param for plan(segment), in seconds.
|
||||||
# default: 30
|
# default: 30
|
||||||
dvr_duration 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;
|
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 for atc.
|
||||||
vhost atc.srs.com {
|
vhost atc.srs.com {
|
||||||
# vhost for atc for hls/hds/rtmp backup.
|
# vhost for atc for hls/hds/rtmp backup.
|
||||||
|
|
|
@ -41,6 +41,7 @@ using namespace std;
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
#include <srs_protocol_utility.hpp>
|
#include <srs_protocol_utility.hpp>
|
||||||
#include <srs_core_autofree.hpp>
|
#include <srs_core_autofree.hpp>
|
||||||
|
#include <srs_app_source.hpp>
|
||||||
|
|
||||||
#define SRS_WIKI_URL_LOG "https://github.com/winlinvip/simple-rtmp-server/wiki/SrsLog"
|
#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());
|
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
|
// forward, only one per vhost
|
||||||
if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) {
|
if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) {
|
||||||
for (it = subscribes.begin(); it != subscribes.end(); ++it) {
|
for (it = subscribes.begin(); it != subscribes.end(); ++it) {
|
||||||
|
@ -1788,6 +1800,23 @@ bool SrsConfig::get_atc_auto(string vhost)
|
||||||
return true;
|
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)
|
double SrsConfig::get_queue_length(string vhost)
|
||||||
{
|
{
|
||||||
SrsConfDirective* conf = get_vhost(vhost);
|
SrsConfDirective* conf = get_vhost(vhost);
|
||||||
|
@ -2636,6 +2665,23 @@ int SrsConfig::get_dvr_duration(string vhost)
|
||||||
return ::atoi(conf->arg0().c_str());
|
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()
|
SrsConfDirective* SrsConfig::get_http_api()
|
||||||
{
|
{
|
||||||
return root->get("http_api");
|
return root->get("http_api");
|
||||||
|
|
|
@ -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_HSS "hss"
|
||||||
#define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION
|
#define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION
|
||||||
#define SRS_CONF_DEFAULT_DVR_DURATION 30
|
#define SRS_CONF_DEFAULT_DVR_DURATION 30
|
||||||
|
#define SRS_CONF_DEFAULT_TIME_JITTER "full"
|
||||||
// in ms, for HLS aac sync time.
|
// in ms, for HLS aac sync time.
|
||||||
#define SRS_CONF_DEFAULT_AAC_SYNC 100
|
#define SRS_CONF_DEFAULT_AAC_SYNC 100
|
||||||
// in ms, for HLS aac flush the audio
|
// in ms, for HLS aac flush the audio
|
||||||
|
@ -200,6 +201,7 @@ public:
|
||||||
virtual bool get_gop_cache(std::string vhost);
|
virtual bool get_gop_cache(std::string vhost);
|
||||||
virtual bool get_atc(std::string vhost);
|
virtual bool get_atc(std::string vhost);
|
||||||
virtual bool get_atc_auto(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 double get_queue_length(std::string vhost);
|
||||||
virtual SrsConfDirective* get_forward(std::string vhost);
|
virtual SrsConfDirective* get_forward(std::string vhost);
|
||||||
virtual SrsConfDirective* get_refer(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_path(std::string vhost);
|
||||||
virtual std::string get_dvr_plan(std::string vhost);
|
virtual std::string get_dvr_plan(std::string vhost);
|
||||||
virtual int get_dvr_duration(std::string vhost);
|
virtual int get_dvr_duration(std::string vhost);
|
||||||
|
virtual int get_dvr_time_jitter(std::string vhost);
|
||||||
// http api section
|
// http api section
|
||||||
private:
|
private:
|
||||||
virtual SrsConfDirective* get_http_api();
|
virtual SrsConfDirective* get_http_api();
|
||||||
|
|
|
@ -70,10 +70,15 @@ SrsDvrPlan::SrsDvrPlan()
|
||||||
fs = new SrsFileStream();
|
fs = new SrsFileStream();
|
||||||
enc = new SrsFlvEncoder();
|
enc = new SrsFlvEncoder();
|
||||||
segment = new SrsFlvSegment();
|
segment = new SrsFlvSegment();
|
||||||
|
jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
|
||||||
|
|
||||||
|
_srs_config->subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDvrPlan::~SrsDvrPlan()
|
SrsDvrPlan::~SrsDvrPlan()
|
||||||
{
|
{
|
||||||
|
_srs_config->unsubscribe(this);
|
||||||
|
|
||||||
srs_freep(jitter);
|
srs_freep(jitter);
|
||||||
srs_freep(fs);
|
srs_freep(fs);
|
||||||
srs_freep(enc);
|
srs_freep(enc);
|
||||||
|
@ -86,6 +91,8 @@ int SrsDvrPlan::initialize(SrsSource* source, SrsRequest* req)
|
||||||
|
|
||||||
_source = source;
|
_source = source;
|
||||||
_req = req;
|
_req = req;
|
||||||
|
|
||||||
|
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(_req->vhost);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -198,7 +205,7 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* audio)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
|
if ((jitter->correct(audio, 0, 0, jitter_algorithm)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +247,7 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
|
||||||
srs_verbose("dvr video is key: %d", is_key_frame);
|
srs_verbose("dvr video is key: %d", is_key_frame);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
|
if ((jitter->correct(video, 0, 0, jitter_algorithm)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +263,15 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
|
||||||
return ret;
|
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 SrsDvrPlan::flv_open(string stream, string path)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
|
@ -42,6 +42,9 @@ class SrsSharedPtrMessage;
|
||||||
class SrsFileStream;
|
class SrsFileStream;
|
||||||
class SrsFlvEncoder;
|
class SrsFlvEncoder;
|
||||||
|
|
||||||
|
#include <srs_app_source.hpp>
|
||||||
|
#include <srs_app_reload.hpp>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a piece of flv segment.
|
* a piece of flv segment.
|
||||||
*/
|
*/
|
||||||
|
@ -93,21 +96,23 @@ public:
|
||||||
* 2. reap flv: when to reap the flv and start new piece.
|
* 2. reap flv: when to reap the flv and start new piece.
|
||||||
*/
|
*/
|
||||||
// TODO: FIXME: the plan is too fat, refine me.
|
// TODO: FIXME: the plan is too fat, refine me.
|
||||||
class SrsDvrPlan
|
class SrsDvrPlan : public ISrsReloadHandler
|
||||||
{
|
{
|
||||||
protected:
|
private:
|
||||||
/**
|
/**
|
||||||
* the underlayer dvr stream.
|
* the underlayer dvr stream.
|
||||||
* if close, the flv is reap and closed.
|
* if close, the flv is reap and closed.
|
||||||
* if open, new flv file is crote.
|
* if open, new flv file is crote.
|
||||||
*/
|
*/
|
||||||
SrsFileStream* fs;
|
|
||||||
SrsFlvEncoder* enc;
|
SrsFlvEncoder* enc;
|
||||||
bool dvr_enabled;
|
|
||||||
SrsSource* _source;
|
SrsSource* _source;
|
||||||
SrsRequest* _req;
|
|
||||||
SrsRtmpJitter* jitter;
|
SrsRtmpJitter* jitter;
|
||||||
|
SrsRtmpJitterAlgorithm jitter_algorithm;
|
||||||
|
protected:
|
||||||
SrsFlvSegment* segment;
|
SrsFlvSegment* segment;
|
||||||
|
SrsRequest* _req;
|
||||||
|
bool dvr_enabled;
|
||||||
|
SrsFileStream* fs;
|
||||||
public:
|
public:
|
||||||
SrsDvrPlan();
|
SrsDvrPlan();
|
||||||
virtual ~SrsDvrPlan();
|
virtual ~SrsDvrPlan();
|
||||||
|
@ -118,6 +123,9 @@ public:
|
||||||
virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
|
virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
|
||||||
virtual int on_audio(SrsSharedPtrMessage* audio);
|
virtual int on_audio(SrsSharedPtrMessage* audio);
|
||||||
virtual int on_video(SrsSharedPtrMessage* video);
|
virtual int on_video(SrsSharedPtrMessage* video);
|
||||||
|
// interface ISrsReloadHandler
|
||||||
|
public:
|
||||||
|
virtual int on_reload_vhost_dvr(std::string vhost);
|
||||||
protected:
|
protected:
|
||||||
virtual int flv_open(std::string stream, std::string path);
|
virtual int flv_open(std::string stream, std::string path);
|
||||||
virtual int flv_close();
|
virtual int flv_close();
|
||||||
|
|
|
@ -162,7 +162,7 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* metadata)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
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);
|
srs_freep(metadata);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* msg)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
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);
|
srs_freep(msg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* msg)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
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);
|
srs_freep(msg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1411,7 +1411,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio)
|
||||||
return hls_cache->on_sequence_header(muxer);
|
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);
|
srs_error("rtmp jitter correct audio failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1456,7 +1456,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* video)
|
||||||
return hls_cache->on_sequence_header(muxer);
|
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);
|
srs_error("rtmp jitter correct video failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,11 @@ int ISrsReloadHandler::on_reload_vhost_queue_length(string /*vhost*/)
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ISrsReloadHandler::on_reload_vhost_time_jitter(string /*vhost*/)
|
||||||
|
{
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int ISrsReloadHandler::on_reload_vhost_forward(string /*vhost*/)
|
int ISrsReloadHandler::on_reload_vhost_forward(string /*vhost*/)
|
||||||
{
|
{
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
|
|
@ -61,6 +61,7 @@ public:
|
||||||
virtual int on_reload_vhost_atc(std::string vhost);
|
virtual int on_reload_vhost_atc(std::string vhost);
|
||||||
virtual int on_reload_vhost_gop_cache(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_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_forward(std::string vhost);
|
||||||
virtual int on_reload_vhost_hls(std::string vhost);
|
virtual int on_reload_vhost_hls(std::string vhost);
|
||||||
virtual int on_reload_vhost_dvr(std::string vhost);
|
virtual int on_reload_vhost_dvr(std::string vhost);
|
||||||
|
|
|
@ -45,6 +45,17 @@ using namespace std;
|
||||||
#define CONST_MAX_JITTER_MS 500
|
#define CONST_MAX_JITTER_MS 500
|
||||||
#define DEFAULT_FRAME_TIME_MS 40
|
#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()
|
SrsRtmpJitter::SrsRtmpJitter()
|
||||||
{
|
{
|
||||||
last_pkt_correct_time = last_pkt_time = 0;
|
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;
|
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.
|
// set to 0 for metadata.
|
||||||
if (!msg->header.is_video() && !msg->header.is_audio()) {
|
if (!msg->header.is_video() && !msg->header.is_audio()) {
|
||||||
msg->header.timestamp = 0;
|
msg->header.timestamp = 0;
|
||||||
|
@ -266,12 +294,12 @@ int SrsConsumer::get_time()
|
||||||
return jitter->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;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
if (!atc) {
|
if (!atc) {
|
||||||
if ((ret = jitter->correct(msg, tba, tbv)) != ERROR_SUCCESS) {
|
if ((ret = jitter->correct(msg, tba, tbv, ag)) != ERROR_SUCCESS) {
|
||||||
srs_freep(msg);
|
srs_freep(msg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +412,7 @@ void SrsGopCache::clear()
|
||||||
cached_video_count = 0;
|
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;
|
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) {
|
for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
|
||||||
SrsSharedPtrMessage* msg = *it;
|
SrsSharedPtrMessage* msg = *it;
|
||||||
SrsSharedPtrMessage* copy = msg->copy();
|
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);
|
srs_error("dispatch cached gop failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -464,6 +492,7 @@ void SrsSource::destroy()
|
||||||
SrsSource::SrsSource(SrsRequest* req)
|
SrsSource::SrsSource(SrsRequest* req)
|
||||||
{
|
{
|
||||||
_req = req->copy();
|
_req = req->copy();
|
||||||
|
jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
|
||||||
|
|
||||||
#ifdef SRS_AUTO_HLS
|
#ifdef SRS_AUTO_HLS
|
||||||
hls = new SrsHls(this);
|
hls = new SrsHls(this);
|
||||||
|
@ -549,6 +578,8 @@ int SrsSource::initialize()
|
||||||
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
||||||
publish_edge->set_queue_size(queue_size);
|
publish_edge->set_queue_size(queue_size);
|
||||||
|
|
||||||
|
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,6 +661,19 @@ int SrsSource::on_reload_vhost_queue_length(string vhost)
|
||||||
return ret;
|
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 SrsSource::on_reload_vhost_forward(string vhost)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
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) {
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
||||||
SrsConsumer* consumer = *it;
|
SrsConsumer* consumer = *it;
|
||||||
SrsSharedPtrMessage* copy = cache_metadata->copy();
|
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);
|
srs_error("dispatch the metadata failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -992,7 +1036,7 @@ int SrsSource::on_audio(SrsMessage* audio)
|
||||||
for (int i = 0; i < (int)consumers.size(); i++) {
|
for (int i = 0; i < (int)consumers.size(); i++) {
|
||||||
SrsConsumer* consumer = consumers.at(i);
|
SrsConsumer* consumer = consumers.at(i);
|
||||||
SrsSharedPtrMessage* copy = msg->copy();
|
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);
|
srs_error("dispatch the audio failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1082,7 +1126,7 @@ int SrsSource::on_video(SrsMessage* video)
|
||||||
for (int i = 0; i < (int)consumers.size(); i++) {
|
for (int i = 0; i < (int)consumers.size(); i++) {
|
||||||
SrsConsumer* consumer = consumers.at(i);
|
SrsConsumer* consumer = consumers.at(i);
|
||||||
SrsSharedPtrMessage* copy = msg->copy();
|
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);
|
srs_error("dispatch the video failed. ret=%d", ret);
|
||||||
return 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.
|
// 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);
|
srs_error("dispatch metadata failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_info("dispatch metadata success");
|
srs_info("dispatch metadata success");
|
||||||
|
|
||||||
// copy sequence header
|
// 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);
|
srs_error("dispatch video sequence header failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_info("dispatch video sequence header success");
|
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);
|
srs_error("dispatch audio sequence header failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_info("dispatch audio sequence header success");
|
srs_info("dispatch audio sequence header success");
|
||||||
|
|
||||||
// copy gop cache to client.
|
// 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,20 @@ class SrsEncoder;
|
||||||
#endif
|
#endif
|
||||||
class SrsStream;
|
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,
|
* time jitter detect and correct,
|
||||||
* to ensure the rtmp stream is monotonically.
|
* to ensure the rtmp stream is monotonically.
|
||||||
|
@ -74,8 +88,12 @@ public:
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* detect the time jitter and correct it.
|
* 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.
|
* get current client time, the last packet time.
|
||||||
*/
|
*/
|
||||||
|
@ -160,8 +178,9 @@ public:
|
||||||
* used to calc the audio time delta if time-jitter detected.
|
* used to calc the audio time delta if time-jitter detected.
|
||||||
* @param tbv timebase of video.
|
* @param tbv timebase of video.
|
||||||
* used to calc the video time delta if time-jitter detected.
|
* 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.
|
* get packets in consumer queue.
|
||||||
* @pmsgs SrsMessages*[], used to store the msgs, user must alloc it.
|
* @pmsgs SrsMessages*[], used to store the msgs, user must alloc it.
|
||||||
|
@ -209,7 +228,7 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual int cache(SrsSharedPtrMessage* msg);
|
virtual int cache(SrsSharedPtrMessage* msg);
|
||||||
virtual void clear();
|
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,
|
* used for atc to get the time of gop cache,
|
||||||
* the atc will adjust the sequence header timestamp to gop cache.
|
* the atc will adjust the sequence header timestamp to gop cache.
|
||||||
|
@ -249,6 +268,8 @@ private:
|
||||||
SrsRequest* _req;
|
SrsRequest* _req;
|
||||||
// to delivery stream to clients.
|
// to delivery stream to clients.
|
||||||
std::vector<SrsConsumer*> consumers;
|
std::vector<SrsConsumer*> consumers;
|
||||||
|
// the time jitter algorithm for vhost.
|
||||||
|
SrsRtmpJitterAlgorithm jitter_algorithm;
|
||||||
// hls handler.
|
// hls handler.
|
||||||
#ifdef SRS_AUTO_HLS
|
#ifdef SRS_AUTO_HLS
|
||||||
SrsHls* hls;
|
SrsHls* hls;
|
||||||
|
@ -310,6 +331,7 @@ public:
|
||||||
virtual int on_reload_vhost_atc(std::string vhost);
|
virtual int on_reload_vhost_atc(std::string vhost);
|
||||||
virtual int on_reload_vhost_gop_cache(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_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_forward(std::string vhost);
|
||||||
virtual int on_reload_vhost_hls(std::string vhost);
|
virtual int on_reload_vhost_hls(std::string vhost);
|
||||||
virtual int on_reload_vhost_dvr(std::string vhost);
|
virtual int on_reload_vhost_dvr(std::string vhost);
|
||||||
|
|
|
@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// current release version
|
// current release version
|
||||||
#define VERSION_MAJOR "0"
|
#define VERSION_MAJOR "0"
|
||||||
#define VERSION_MINOR "9"
|
#define VERSION_MINOR "9"
|
||||||
#define VERSION_REVISION "132"
|
#define VERSION_REVISION "133"
|
||||||
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
|
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
|
||||||
// server info.
|
// server info.
|
||||||
#define RTMP_SIG_SRS_KEY "SRS"
|
#define RTMP_SIG_SRS_KEY "SRS"
|
||||||
|
|
Loading…
Reference in a new issue