mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
support live flashP2P(integrated by chnvideo VDN). 0.9.75
This commit is contained in:
parent
b276714573
commit
67e1988b81
11 changed files with 164 additions and 62 deletions
|
@ -157,6 +157,7 @@ Supported operating systems and hardware:
|
||||||
1. Support stream ingester using ffmpeg.
|
1. Support stream ingester using ffmpeg.
|
||||||
1. Support ingest RTSP(RTP, SDP) stream to RTMP.
|
1. Support ingest RTSP(RTP, SDP) stream to RTMP.
|
||||||
1. Support dvr(record live to flv file for vod)
|
1. Support dvr(record live to flv file for vod)
|
||||||
|
1. Support live flashP2P(integrated by chnvideo VDN).
|
||||||
1. [plan] Support file to hls vod stream.
|
1. [plan] Support file to hls vod stream.
|
||||||
1. [plan] Support system full utest on gtest.
|
1. [plan] Support system full utest on gtest.
|
||||||
1. [plan] Support RTMP edge server, push/pull stream from any RTMP server
|
1. [plan] Support RTMP edge server, push/pull stream from any RTMP server
|
||||||
|
@ -184,6 +185,7 @@ Supported operating systems and hardware:
|
||||||
* 2013-10-17, Created.<br/>
|
* 2013-10-17, Created.<br/>
|
||||||
|
|
||||||
## History
|
## History
|
||||||
|
* v1.0, 2014-04-24, support live flashP2P(integrated by chnvideo VDN). 0.9.75
|
||||||
* v1.0, 2014-04-21, support android app to start srs for internal edge. 0.9.72
|
* v1.0, 2014-04-21, support android app to start srs for internal edge. 0.9.72
|
||||||
* v1.0, 2014-04-19, support tool over srs-librtmp to ingest flv/rtmp. 0.9.71
|
* v1.0, 2014-04-19, support tool over srs-librtmp to ingest flv/rtmp. 0.9.71
|
||||||
* v1.0, 2014-04-17, support dvr(record live to flv file for vod). 0.9.69
|
* v1.0, 2014-04-17, support dvr(record live to flv file for vod). 0.9.69
|
||||||
|
|
|
@ -97,7 +97,7 @@ vhost dvr.srs.com {
|
||||||
# start to record to file when encoder publish,
|
# start to record to file when encoder publish,
|
||||||
# reap flv according by specified dvr_plan.
|
# reap flv according by specified dvr_plan.
|
||||||
# http callbacks:
|
# http callbacks:
|
||||||
# @see http callback on_dvr_keyframe on http_hooks section.
|
# @see http callback on_dvr_reap_flv on http_hooks section.
|
||||||
dvr {
|
dvr {
|
||||||
# whether enabled dvr features
|
# whether enabled dvr features
|
||||||
# default: off
|
# default: off
|
||||||
|
@ -325,16 +325,22 @@ vhost hooks.callback.srs.com {
|
||||||
# when dvr got an keyframe, call the hook,
|
# when dvr got an keyframe, call the hook,
|
||||||
# the request in the POST data string is a object encode by json:
|
# the request in the POST data string is a object encode by json:
|
||||||
# {
|
# {
|
||||||
# "action": "on_dvr_keyframe",
|
# "action": "on_dvr_reap_flv",
|
||||||
# "vhost": "video.test.com", "app": "live",
|
# "vhost": "video.test.com", "app": "live",
|
||||||
# "stream": "livestream"
|
# "stream": "livestream",
|
||||||
|
# "segment": {
|
||||||
|
# "cwd": "/usr/local/srs",
|
||||||
|
# "path": "./objs/nginx/html/live/livestream.1398315892865.flv",
|
||||||
|
# "duration": 1001, "offset":0,
|
||||||
|
# "has_keyframe": true, "pts":1398315895958
|
||||||
|
# }
|
||||||
# }
|
# }
|
||||||
# if valid, the hook must return HTTP code 200(Stauts OK) and response
|
# if valid, the hook must return HTTP code 200(Stauts OK) and response
|
||||||
# an int value specifies the error code(0 corresponding to success):
|
# an int value specifies the error code(0 corresponding to success):
|
||||||
# 0
|
# 0
|
||||||
# support multiple api hooks, format:
|
# support multiple api hooks, format:
|
||||||
# on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
# on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
|
||||||
on_dvr_keyframe http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
|
on_dvr_reap_flv http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1560,7 +1560,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
|
||||||
return conf->get("on_stop");
|
return conf->get("on_stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsConfDirective* SrsConfig::get_vhost_on_dvr_keyframe(string vhost)
|
SrsConfDirective* SrsConfig::get_vhost_on_dvr_reap_flv(string vhost)
|
||||||
{
|
{
|
||||||
SrsConfDirective* conf = get_vhost(vhost);
|
SrsConfDirective* conf = get_vhost(vhost);
|
||||||
|
|
||||||
|
@ -1578,7 +1578,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_dvr_keyframe(string vhost)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return conf->get("on_dvr_keyframe");
|
return conf->get("on_dvr_reap_flv");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SrsConfig::get_vhost_enabled(string vhost)
|
bool SrsConfig::get_vhost_enabled(string vhost)
|
||||||
|
|
|
@ -175,7 +175,7 @@ public:
|
||||||
virtual SrsConfDirective* get_vhost_on_unpublish(std::string vhost);
|
virtual SrsConfDirective* get_vhost_on_unpublish(std::string vhost);
|
||||||
virtual SrsConfDirective* get_vhost_on_play(std::string vhost);
|
virtual SrsConfDirective* get_vhost_on_play(std::string vhost);
|
||||||
virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
|
virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
|
||||||
virtual SrsConfDirective* get_vhost_on_dvr_keyframe(std::string vhost);
|
virtual SrsConfDirective* get_vhost_on_dvr_reap_flv(std::string vhost);
|
||||||
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 double get_queue_length(std::string vhost);
|
virtual double get_queue_length(std::string vhost);
|
||||||
|
|
|
@ -138,6 +138,11 @@ int SrsFileStream::write(void* buf, size_t count, ssize_t* pnwrite)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t SrsFileStream::tellg()
|
||||||
|
{
|
||||||
|
return (int64_t)::lseek(fd, 0, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
SrsFlvEncoder::SrsFlvEncoder()
|
SrsFlvEncoder::SrsFlvEncoder()
|
||||||
{
|
{
|
||||||
_fs = NULL;
|
_fs = NULL;
|
||||||
|
@ -209,10 +214,12 @@ int SrsFlvEncoder::write_metadata(char* data, int size)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsFlvEncoder::write_audio(int32_t timestamp, char* data, int size)
|
int SrsFlvEncoder::write_audio(int64_t timestamp, char* data, int size)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
timestamp &= 0x7fffffff;
|
||||||
|
|
||||||
static char tag_header[] = {
|
static char tag_header[] = {
|
||||||
(char)8, // TagType UB [5], 8 = audio
|
(char)8, // TagType UB [5], 8 = audio
|
||||||
(char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
|
(char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
|
||||||
|
@ -238,10 +245,12 @@ int SrsFlvEncoder::write_audio(int32_t timestamp, char* data, int size)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsFlvEncoder::write_video(int32_t timestamp, char* data, int size)
|
int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
timestamp &= 0x7fffffff;
|
||||||
|
|
||||||
static char tag_header[] = {
|
static char tag_header[] = {
|
||||||
(char)9, // TagType UB [5], 9 = video
|
(char)9, // TagType UB [5], 9 = video
|
||||||
(char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
|
(char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
|
||||||
|
@ -303,6 +312,7 @@ SrsFlvSegment::SrsFlvSegment()
|
||||||
has_keyframe = false;
|
has_keyframe = false;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
starttime = -1;
|
starttime = -1;
|
||||||
|
sequence_header_offset = 0;
|
||||||
stream_starttime = 0;
|
stream_starttime = 0;
|
||||||
stream_previous_pkt_time = -1;
|
stream_previous_pkt_time = -1;
|
||||||
stream_duration = 0;
|
stream_duration = 0;
|
||||||
|
@ -313,6 +323,7 @@ void SrsFlvSegment::reset()
|
||||||
has_keyframe = false;
|
has_keyframe = false;
|
||||||
starttime = -1;
|
starttime = -1;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
|
sequence_header_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDvrPlan::SrsDvrPlan()
|
SrsDvrPlan::SrsDvrPlan()
|
||||||
|
@ -396,14 +407,32 @@ int SrsDvrPlan::open_new_segment()
|
||||||
}
|
}
|
||||||
dvr_enabled = true;
|
dvr_enabled = true;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvrPlan::on_dvr_request_sh()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
// the dvr is enabled, notice the source to push the data.
|
// the dvr is enabled, notice the source to push the data.
|
||||||
if ((ret = _source->on_dvr_start()) != ERROR_SUCCESS) {
|
if ((ret = _source->on_dvr_request_sh()) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsDvrPlan::on_video_keyframe()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t SrsDvrPlan::filter_timestamp(int64_t timestamp)
|
||||||
|
{
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
int SrsDvrPlan::on_meta_data(SrsOnMetaDataPacket* metadata)
|
int SrsDvrPlan::on_meta_data(SrsOnMetaDataPacket* metadata)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
@ -438,9 +467,9 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* audio)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t timestamp = audio->header.timestamp;
|
|
||||||
char* payload = (char*)audio->payload;
|
char* payload = (char*)audio->payload;
|
||||||
int size = (int)audio->size;
|
int size = (int)audio->size;
|
||||||
|
int64_t timestamp = filter_timestamp(audio->header.timestamp);
|
||||||
if ((ret = enc->write_audio(timestamp, payload, size)) != ERROR_SUCCESS) {
|
if ((ret = enc->write_audio(timestamp, payload, size)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -460,25 +489,31 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* payload = (char*)video->payload;
|
||||||
|
int size = (int)video->size;
|
||||||
|
|
||||||
|
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||||
|
bool is_key_frame = SrsCodec::video_is_h264((int8_t*)payload, size)
|
||||||
|
&& SrsCodec::video_is_keyframe((int8_t*)payload, size)
|
||||||
|
&& !SrsCodec::video_is_sequence_header((int8_t*)payload, size);
|
||||||
|
if (is_key_frame) {
|
||||||
|
segment->has_keyframe = true;
|
||||||
|
if ((ret = on_video_keyframe()) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t timestamp = video->header.timestamp;
|
int32_t timestamp = filter_timestamp(video->header.timestamp);
|
||||||
char* payload = (char*)video->payload;
|
|
||||||
int size = (int)video->size;
|
|
||||||
if ((ret = enc->write_video(timestamp, payload, size)) != ERROR_SUCCESS) {
|
if ((ret = enc->write_video(timestamp, payload, size)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SRS_AUTO_HTTP_CALLBACK
|
|
||||||
bool is_key_frame = SrsCodec::video_is_keyframe((int8_t*)payload, size);
|
|
||||||
if (is_key_frame) {
|
|
||||||
segment->has_keyframe = true;
|
|
||||||
}
|
|
||||||
srs_verbose("dvr video is key: %d", is_key_frame);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((ret = update_duration(video)) != ERROR_SUCCESS) {
|
if ((ret = update_duration(video)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -503,8 +538,7 @@ int SrsDvrPlan::flv_open(string stream, string path)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = enc->write_header()) != ERROR_SUCCESS) {
|
if ((ret = write_flv_header()) != ERROR_SUCCESS) {
|
||||||
srs_error("write flv header for file %s failed. ret=%d", path.c_str(), ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,10 +565,8 @@ int SrsDvrPlan::flv_close()
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SRS_AUTO_HTTP_CALLBACK
|
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||||
if (segment->has_keyframe) {
|
if ((ret = on_dvr_reap_flv()) != ERROR_SUCCESS) {
|
||||||
if ((ret = on_dvr_keyframe()) != ERROR_SUCCESS) {
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -568,21 +600,33 @@ int SrsDvrPlan::update_duration(SrsSharedPtrMessage* msg)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsDvrPlan::on_dvr_keyframe()
|
int SrsDvrPlan::write_flv_header()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if ((ret = enc->write_header()) != ERROR_SUCCESS) {
|
||||||
|
srs_error("write flv header failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvrPlan::on_dvr_reap_flv()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
#ifdef SRS_AUTO_HTTP_CALLBACK
|
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||||
// HTTP: on_dvr_keyframe
|
// HTTP: on_dvr_reap_flv
|
||||||
SrsConfDirective* on_dvr_keyframe = _srs_config->get_vhost_on_dvr_keyframe(_req->vhost);
|
SrsConfDirective* on_dvr_reap_flv = _srs_config->get_vhost_on_dvr_reap_flv(_req->vhost);
|
||||||
if (!on_dvr_keyframe) {
|
if (!on_dvr_reap_flv) {
|
||||||
srs_info("ignore the empty http callback: on_dvr_keyframe");
|
srs_info("ignore the empty http callback: on_dvr_reap_flv");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < (int)on_dvr_keyframe->args.size(); i++) {
|
for (int i = 0; i < (int)on_dvr_reap_flv->args.size(); i++) {
|
||||||
std::string url = on_dvr_keyframe->args.at(i);
|
std::string url = on_dvr_reap_flv->args.at(i);
|
||||||
SrsHttpHooks::on_dvr_keyframe(url, _req, segment);
|
SrsHttpHooks::on_dvr_reap_flv(url, _req, segment);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -705,7 +749,6 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
|
||||||
SrsDvrHssPlan::SrsDvrHssPlan()
|
SrsDvrHssPlan::SrsDvrHssPlan()
|
||||||
{
|
{
|
||||||
segment_duration = -1;
|
segment_duration = -1;
|
||||||
start_deviation = 0;
|
|
||||||
expect_reap_time = 0;
|
expect_reap_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,8 +791,6 @@ int SrsDvrHssPlan::on_publish()
|
||||||
|
|
||||||
// expect reap flv time
|
// expect reap flv time
|
||||||
expect_reap_time = segment->stream_starttime + segment_duration;
|
expect_reap_time = segment->stream_starttime + segment_duration;
|
||||||
// the start deviation used ensure the segment starttime in nature clock.
|
|
||||||
start_deviation = segment->stream_starttime % 1000;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -763,6 +804,44 @@ void SrsDvrHssPlan::on_unpublish()
|
||||||
dvr_enabled = false;
|
dvr_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsDvrHssPlan::on_meta_data(SrsOnMetaDataPacket* /*metadata*/)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvrHssPlan::write_flv_header()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvrHssPlan::on_dvr_request_sh()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsDvrHssPlan::on_video_keyframe()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
segment->sequence_header_offset = fs->tellg();
|
||||||
|
if ((ret = SrsDvrPlan::on_dvr_request_sh()) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t SrsDvrHssPlan::filter_timestamp(int64_t timestamp)
|
||||||
|
{
|
||||||
|
//return timestamp;
|
||||||
|
srs_assert(segment);
|
||||||
|
srs_verbose("filter timestamp from %"PRId64" to %"PRId64, timestamp, segment->stream_starttime + timestamp);
|
||||||
|
return segment->stream_starttime + timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
int SrsDvrHssPlan::update_duration(SrsSharedPtrMessage* msg)
|
int SrsDvrHssPlan::update_duration(SrsSharedPtrMessage* msg)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
@ -784,10 +863,9 @@ int SrsDvrHssPlan::update_duration(SrsSharedPtrMessage* msg)
|
||||||
// reap if exceed atc expect time.
|
// reap if exceed atc expect time.
|
||||||
if (segment->stream_starttime + segment->stream_duration > expect_reap_time) {
|
if (segment->stream_starttime + segment->stream_duration > expect_reap_time) {
|
||||||
srs_verbose("hss reap start=%"PRId64", duration=%"PRId64", expect=%"PRId64
|
srs_verbose("hss reap start=%"PRId64", duration=%"PRId64", expect=%"PRId64
|
||||||
", segment(start=%"PRId64", adjust=%"PRId64", duration=%"PRId64", file=%s",
|
", segment(start=%"PRId64", duration=%"PRId64", file=%s",
|
||||||
segment->stream_starttime, segment->stream_duration, expect_reap_time,
|
segment->stream_starttime, segment->stream_duration, expect_reap_time,
|
||||||
segment->stream_starttime + segment->starttime,
|
segment->stream_starttime + segment->starttime,
|
||||||
segment->stream_starttime + segment->starttime - start_deviation,
|
|
||||||
segment->duration, segment->path.c_str());
|
segment->duration, segment->path.c_str());
|
||||||
|
|
||||||
// update expect reap time
|
// update expect reap time
|
||||||
|
|
|
@ -62,6 +62,10 @@ public:
|
||||||
* @param pnwrite, return the write size. NULL to ignore.
|
* @param pnwrite, return the write size. NULL to ignore.
|
||||||
*/
|
*/
|
||||||
virtual int write(void* buf, size_t count, ssize_t* pnwrite);
|
virtual int write(void* buf, size_t count, ssize_t* pnwrite);
|
||||||
|
/**
|
||||||
|
* tell current offset of stream.
|
||||||
|
*/
|
||||||
|
virtual int64_t tellg();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,8 +105,8 @@ public:
|
||||||
/**
|
/**
|
||||||
* write audio/video packet.
|
* write audio/video packet.
|
||||||
*/
|
*/
|
||||||
virtual int write_audio(int32_t timestamp, char* data, int size);
|
virtual int write_audio(int64_t timestamp, char* data, int size);
|
||||||
virtual int write_video(int32_t timestamp, char* data, int size);
|
virtual int write_video(int64_t timestamp, char* data, int size);
|
||||||
private:
|
private:
|
||||||
virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
|
virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
|
||||||
};
|
};
|
||||||
|
@ -122,6 +126,10 @@ public:
|
||||||
*/
|
*/
|
||||||
bool has_keyframe;
|
bool has_keyframe;
|
||||||
/**
|
/**
|
||||||
|
* sequence header offset in file.
|
||||||
|
*/
|
||||||
|
int64_t sequence_header_offset;
|
||||||
|
/**
|
||||||
* current segment starttime, RTMP pkt time.
|
* current segment starttime, RTMP pkt time.
|
||||||
*/
|
*/
|
||||||
int64_t starttime;
|
int64_t starttime;
|
||||||
|
@ -184,12 +192,15 @@ protected:
|
||||||
virtual int flv_close();
|
virtual int flv_close();
|
||||||
virtual int open_new_segment();
|
virtual int open_new_segment();
|
||||||
virtual int update_duration(SrsSharedPtrMessage* msg);
|
virtual int update_duration(SrsSharedPtrMessage* msg);
|
||||||
|
virtual int write_flv_header();
|
||||||
|
virtual int on_dvr_request_sh();
|
||||||
|
virtual int on_video_keyframe();
|
||||||
|
virtual int64_t filter_timestamp(int64_t timestamp);
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* when srs reap the flv(close the segment),
|
* when srs reap the flv(close the segment), notice the api.
|
||||||
* if has keyframe, notice the api.
|
|
||||||
*/
|
*/
|
||||||
virtual int on_dvr_keyframe();
|
virtual int on_dvr_reap_flv();
|
||||||
public:
|
public:
|
||||||
static SrsDvrPlan* create_plan(std::string vhost);
|
static SrsDvrPlan* create_plan(std::string vhost);
|
||||||
};
|
};
|
||||||
|
@ -233,8 +244,6 @@ class SrsDvrHssPlan : public SrsDvrPlan
|
||||||
private:
|
private:
|
||||||
// in config, in ms
|
// in config, in ms
|
||||||
int segment_duration;
|
int segment_duration;
|
||||||
// the deviation of starttime of the nature clock time.
|
|
||||||
int start_deviation;
|
|
||||||
int64_t expect_reap_time;
|
int64_t expect_reap_time;
|
||||||
public:
|
public:
|
||||||
SrsDvrHssPlan();
|
SrsDvrHssPlan();
|
||||||
|
@ -243,6 +252,12 @@ public:
|
||||||
virtual int initialize(SrsSource* source, SrsRequest* req);
|
virtual int initialize(SrsSource* source, SrsRequest* req);
|
||||||
virtual int on_publish();
|
virtual int on_publish();
|
||||||
virtual void on_unpublish();
|
virtual void on_unpublish();
|
||||||
|
virtual int on_meta_data(SrsOnMetaDataPacket* metadata);
|
||||||
|
protected:
|
||||||
|
virtual int write_flv_header();
|
||||||
|
virtual int on_dvr_request_sh();
|
||||||
|
virtual int on_video_keyframe();
|
||||||
|
virtual int64_t filter_timestamp(int64_t timestamp);
|
||||||
private:
|
private:
|
||||||
virtual int update_duration(SrsSharedPtrMessage* msg);
|
virtual int update_duration(SrsSharedPtrMessage* msg);
|
||||||
};
|
};
|
||||||
|
|
|
@ -459,7 +459,7 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* segment)
|
void SrsHttpHooks::on_dvr_reap_flv(string url, SrsRequest* req, SrsFlvSegment* segment)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -471,23 +471,24 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s
|
||||||
|
|
||||||
SrsHttpUri uri;
|
SrsHttpUri uri;
|
||||||
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
|
||||||
srs_warn("http uri parse on_dvr_keyframe url failed, ignored. "
|
srs_warn("http uri parse on_dvr_reap_flv url failed, ignored. "
|
||||||
"url=%s, ret=%d", url.c_str(), ret);
|
"url=%s, ret=%d", url.c_str(), ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << JOBJECT_START
|
ss << JOBJECT_START
|
||||||
<< JFIELD_STR("action", "on_dvr_keyframe") << JFIELD_CONT
|
<< JFIELD_STR("action", "on_dvr_reap_flv") << JFIELD_CONT
|
||||||
<< JFIELD_STR("vhost", req->vhost) << JFIELD_CONT
|
<< JFIELD_STR("vhost", req->vhost) << JFIELD_CONT
|
||||||
<< JFIELD_STR("app", req->app) << JFIELD_CONT
|
<< JFIELD_STR("app", req->app) << JFIELD_CONT
|
||||||
<< JFIELD_STR("stream", req->stream) << JFIELD_CONT
|
<< JFIELD_STR("stream", req->stream) << JFIELD_CONT
|
||||||
<< JFIELD_NAME("segment") << JOBJECT_START
|
<< JFIELD_NAME("segment") << JOBJECT_START
|
||||||
<< JFIELD_STR("cwd", _srs_config->get_cwd()) << JFIELD_CONT
|
<< JFIELD_STR("cwd", _srs_config->get_cwd()) << JFIELD_CONT
|
||||||
<< JFIELD_STR("path", segment->path) << JFIELD_CONT
|
<< JFIELD_STR("path", segment->path) << JFIELD_CONT
|
||||||
<< JFIELD_ORG("pts", segment->stream_starttime + segment->starttime) << JFIELD_CONT
|
|
||||||
<< JFIELD_ORG("duration", segment->duration) << JFIELD_CONT
|
<< JFIELD_ORG("duration", segment->duration) << JFIELD_CONT
|
||||||
<< JFIELD_ORG("offset", 0)
|
<< JFIELD_ORG("offset", segment->sequence_header_offset) << JFIELD_CONT
|
||||||
|
<< JFIELD_ORG("has_keyframe", (segment->has_keyframe? "true":"false")) << JFIELD_CONT
|
||||||
|
<< JFIELD_ORG("pts", segment->stream_starttime + segment->starttime)
|
||||||
<< JOBJECT_END
|
<< JOBJECT_END
|
||||||
<< JOBJECT_END;
|
<< JOBJECT_END;
|
||||||
std::string data = ss.str();
|
std::string data = ss.str();
|
||||||
|
@ -495,7 +496,7 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s
|
||||||
|
|
||||||
SrsHttpClient http;
|
SrsHttpClient http;
|
||||||
if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
|
if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
|
||||||
srs_warn("http post on_dvr_keyframe uri failed, ignored. "
|
srs_warn("http post on_dvr_reap_flv uri failed, ignored. "
|
||||||
"url=%s, request=%s, response=%s, ret=%d",
|
"url=%s, request=%s, response=%s, ret=%d",
|
||||||
url.c_str(), data.c_str(), res.c_str(), ret);
|
url.c_str(), data.c_str(), res.c_str(), ret);
|
||||||
return;
|
return;
|
||||||
|
@ -503,12 +504,12 @@ void SrsHttpHooks::on_dvr_keyframe(string url, SrsRequest* req, SrsFlvSegment* s
|
||||||
|
|
||||||
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
|
||||||
ret = ERROR_HTTP_DATA_INVLIAD;
|
ret = ERROR_HTTP_DATA_INVLIAD;
|
||||||
srs_warn("http hook on_dvr_keyframe validate failed, ignored. "
|
srs_warn("http hook on_dvr_reap_flv validate failed, ignored. "
|
||||||
"res=%s, ret=%d", res.c_str(), ret);
|
"res=%s, ret=%d", res.c_str(), ret);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_info("http hook on_dvr_keyframe success. "
|
srs_info("http hook on_dvr_reap_flv success. "
|
||||||
"url=%s, request=%s, response=%s, ret=%d",
|
"url=%s, request=%s, response=%s, ret=%d",
|
||||||
url.c_str(), data.c_str(), res.c_str(), ret);
|
url.c_str(), data.c_str(), res.c_str(), ret);
|
||||||
|
|
||||||
|
|
|
@ -124,12 +124,12 @@ public:
|
||||||
static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req);
|
static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* on_dvr_keyframe hook, when dvr get keyframe.
|
* on_dvr_reap_flv hook, when dvr close flv file.
|
||||||
* @param url the api server url, to process the event.
|
* @param url the api server url, to process the event.
|
||||||
* ignore if empty.
|
* ignore if empty.
|
||||||
* @param segment the current flv segment.
|
* @param segment the current flv segment.
|
||||||
*/
|
*/
|
||||||
static void on_dvr_keyframe(std::string url, SrsRequest* req, SrsFlvSegment* segment);
|
static void on_dvr_reap_flv(std::string url, SrsRequest* req, SrsFlvSegment* segment);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -721,14 +721,14 @@ int SrsSource::on_hls_start()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsSource::on_dvr_start()
|
int SrsSource::on_dvr_request_sh()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
#ifdef SRS_AUTO_DVR
|
#ifdef SRS_AUTO_DVR
|
||||||
// feed the dvr the metadata/sequence header,
|
// feed the dvr the metadata/sequence header,
|
||||||
// when reload to start dvr, dvr will never get the sequence header in stream,
|
// when reload to start dvr, dvr will never get the sequence header in stream,
|
||||||
// use the SrsSource.on_dvr_start to push the sequence header to DVR.
|
// use the SrsSource.on_dvr_request_sh to push the sequence header to DVR.
|
||||||
if (cache_metadata) {
|
if (cache_metadata) {
|
||||||
char* payload = (char*)cache_metadata->payload;
|
char* payload = (char*)cache_metadata->payload;
|
||||||
int size = (int)cache_metadata->size;
|
int size = (int)cache_metadata->size;
|
||||||
|
|
|
@ -288,7 +288,7 @@ public:
|
||||||
// for the SrsHls to callback to request the sequence headers.
|
// for the SrsHls to callback to request the sequence headers.
|
||||||
virtual int on_hls_start();
|
virtual int on_hls_start();
|
||||||
// for the SrsDvr to callback to request the sequence headers.
|
// for the SrsDvr to callback to request the sequence headers.
|
||||||
virtual int on_dvr_start();
|
virtual int on_dvr_request_sh();
|
||||||
public:
|
public:
|
||||||
virtual bool can_publish();
|
virtual bool can_publish();
|
||||||
virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
|
virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
|
||||||
|
|
|
@ -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 "74"
|
#define VERSION_REVISION "75"
|
||||||
#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…
Add table
Add a link
Reference in a new issue