From 3209ad29e08ab2e13c9e05f697b1483742c00b5b Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 6 Feb 2017 20:58:52 +0800 Subject: [PATCH] for #738, refine code for DVR mp4. --- trunk/src/app/srs_app_dvr.cpp | 153 ++++++++++--------------------- trunk/src/app/srs_app_dvr.hpp | 77 ++++++---------- trunk/src/app/srs_app_hls.cpp | 17 ---- trunk/src/app/srs_app_hls.hpp | 4 - trunk/src/app/srs_app_source.cpp | 56 ++--------- trunk/src/app/srs_app_source.hpp | 2 - 6 files changed, 83 insertions(+), 226 deletions(-) diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp index 74ddaaaae..35ee8bd7c 100644 --- a/trunk/src/app/srs_app_dvr.cpp +++ b/trunk/src/app/srs_app_dvr.cpp @@ -44,9 +44,6 @@ using namespace std; #include #include -// update the flv duration and filesize every this interval in ms. -#define SRS_DVR_UPDATE_DURATION_INTERVAL 60000 - SrsDvrSegmenter::SrsDvrSegmenter() { req = NULL; @@ -87,9 +84,9 @@ string SrsDvrSegmenter::get_path() return path; } -bool SrsDvrSegmenter::is_overflow(int64_t max_duration) +int64_t SrsDvrSegmenter::get_duration() { - return duration >= max_duration; + return duration; } int SrsDvrSegmenter::open() @@ -108,6 +105,8 @@ int SrsDvrSegmenter::open() return ret; } + tmp_dvr_file = path + ".tmp"; + // create dir first. std::string dir = srs_path_dirname(path); if ((ret = srs_create_dir_recursively(dir)) != ERROR_SUCCESS) { @@ -117,13 +116,9 @@ int SrsDvrSegmenter::open() srs_info("create dir=%s ok", dir.c_str()); // create jitter. - if ((ret = create_jitter()) != ERROR_SUCCESS) { - srs_error("create jitter failed, path=%s. ret=%d", path.c_str(), ret); - return ret; - } - - // generate the tmp flv path. - tmp_dvr_file = path + ".tmp"; + srs_freep(jitter); + jitter = new SrsRtmpJitter(); + duration = 0; // open file writer, in append or create mode. if ((ret = fs->open(tmp_dvr_file)) != ERROR_SUCCESS) { @@ -158,8 +153,7 @@ int SrsDvrSegmenter::write_audio(SrsSharedPtrMessage* shared_audio) return ret; } - int64_t timestamp = plan->filter_timestamp(audio->timestamp); - if ((ret = encode_audio(audio, timestamp)) != ERROR_SUCCESS) { + if ((ret = encode_audio(audio)) != ERROR_SUCCESS) { return ret; } @@ -183,15 +177,7 @@ int SrsDvrSegmenter::write_video(SrsSharedPtrMessage* shared_video) bool is_sequence_header = SrsFlvCodec::video_is_sequence_header(payload, size); bool is_key_frame = SrsFlvCodec::video_is_h264(payload, size) && SrsFlvCodec::video_is_keyframe(payload, size) && !is_sequence_header; - if (is_key_frame) { - if ((ret = plan->on_video_keyframe()) != ERROR_SUCCESS) { - return ret; - } - } - srs_verbose("dvr video is key: %d", is_key_frame); - - int64_t timestamp = plan->filter_timestamp(video->timestamp); - if ((ret = encode_video(video, timestamp, is_sequence_header, is_key_frame)) != ERROR_SUCCESS) { + if ((ret = encode_video(video, is_sequence_header, is_key_frame)) != ERROR_SUCCESS) { return ret; } @@ -253,18 +239,6 @@ string SrsDvrSegmenter::generate_path() return flv_path; } -int SrsDvrSegmenter::create_jitter() -{ - int ret = ERROR_SUCCESS; - - srs_freep(jitter); - jitter = new SrsRtmpJitter(); - - duration = 0; - - return ret; -} - int SrsDvrSegmenter::on_reload_vhost_dvr(std::string vhost) { int ret = ERROR_SUCCESS; @@ -447,13 +421,13 @@ int SrsDvrFlvSegmenter::encode_metadata(SrsSharedPtrMessage* metadata) return ret; } -int SrsDvrFlvSegmenter::encode_audio(SrsSharedPtrMessage* audio, int64_t dts) +int SrsDvrFlvSegmenter::encode_audio(SrsSharedPtrMessage* audio) { int ret = ERROR_SUCCESS; char* payload = audio->payload; int size = audio->size; - if ((ret = enc->write_audio(dts, payload, size)) != ERROR_SUCCESS) { + if ((ret = enc->write_audio(audio->timestamp, payload, size)) != ERROR_SUCCESS) { return ret; } @@ -464,7 +438,7 @@ int SrsDvrFlvSegmenter::encode_audio(SrsSharedPtrMessage* audio, int64_t dts) return ret; } -int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe) +int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video, bool sh, bool keyframe) { int ret = ERROR_SUCCESS; @@ -489,7 +463,7 @@ int SrsDvrFlvSegmenter::encode_video(SrsSharedPtrMessage* video, int64_t dts, bo char* payload = video->payload; int size = video->size; - if ((ret = enc->write_video(dts, payload, size)) != ERROR_SUCCESS) { + if ((ret = enc->write_video(video->timestamp, payload, size)) != ERROR_SUCCESS) { return ret; } @@ -557,13 +531,13 @@ int SrsDvrMp4Segmenter::encode_metadata(SrsSharedPtrMessage* metadata) return ret; } -int SrsDvrMp4Segmenter::encode_audio(SrsSharedPtrMessage* audio, int64_t dts) +int SrsDvrMp4Segmenter::encode_audio(SrsSharedPtrMessage* audio) { int ret = ERROR_SUCCESS; return ret; } -int SrsDvrMp4Segmenter::encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe) +int SrsDvrMp4Segmenter::encode_video(SrsSharedPtrMessage* video, bool sh, bool keyframe) { int ret = ERROR_SUCCESS; return ret; @@ -644,10 +618,11 @@ SrsDvrPlan::~SrsDvrPlan() srs_freep(async); } -int SrsDvrPlan::initialize(SrsDvrSegmenter* s, SrsRequest* r) +int SrsDvrPlan::initialize(SrsOriginHub* h, SrsDvrSegmenter* s, SrsRequest* r) { int ret = ERROR_SUCCESS; + hub = h; req = r; segment = s; @@ -662,16 +637,6 @@ int SrsDvrPlan::initialize(SrsDvrSegmenter* s, SrsRequest* r) return ret; } -int SrsDvrPlan::on_video_keyframe() -{ - return ERROR_SUCCESS; -} - -int64_t SrsDvrPlan::filter_timestamp(int64_t timestamp) -{ - return timestamp; -} - int SrsDvrPlan::on_meta_data(SrsSharedPtrMessage* shared_metadata) { int ret = ERROR_SUCCESS; @@ -795,28 +760,27 @@ void SrsDvrSessionPlan::on_unpublish() SrsDvrSegmentPlan::SrsDvrSegmentPlan() { - segment_duration = -1; - metadata = sh_video = sh_audio = NULL; + cduration = -1; + wait_keyframe = false; } SrsDvrSegmentPlan::~SrsDvrSegmentPlan() { - srs_freep(sh_video); - srs_freep(sh_audio); - srs_freep(metadata); } -int SrsDvrSegmentPlan::initialize(SrsDvrSegmenter* s, SrsRequest* req) +int SrsDvrSegmentPlan::initialize(SrsOriginHub* h, SrsDvrSegmenter* s, SrsRequest* r) { int ret = ERROR_SUCCESS; - if ((ret = SrsDvrPlan::initialize(s, req)) != ERROR_SUCCESS) { + if ((ret = SrsDvrPlan::initialize(h, s, r)) != ERROR_SUCCESS) { return ret; } - segment_duration = _srs_config->get_dvr_duration(req->vhost); + wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost); + + cduration = _srs_config->get_dvr_duration(req->vhost); // to ms - segment_duration *= 1000; + cduration *= 1000; return ret; } @@ -851,28 +815,9 @@ void SrsDvrSegmentPlan::on_unpublish() { } -int SrsDvrSegmentPlan::on_meta_data(SrsSharedPtrMessage* shared_metadata) -{ - int ret = ERROR_SUCCESS; - - srs_freep(metadata); - metadata = shared_metadata->copy(); - - if ((ret = SrsDvrPlan::on_meta_data(shared_metadata)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} - int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* shared_audio) { int ret = ERROR_SUCCESS; - - if (SrsFlvCodec::audio_is_sequence_header(shared_audio->payload, shared_audio->size)) { - srs_freep(sh_audio); - sh_audio = shared_audio->copy(); - } if ((ret = update_duration(shared_audio)) != ERROR_SUCCESS) { return ret; @@ -889,11 +834,6 @@ int SrsDvrSegmentPlan::on_video(SrsSharedPtrMessage* shared_video) { int ret = ERROR_SUCCESS; - if (SrsFlvCodec::video_is_sequence_header(shared_video->payload, shared_video->size)) { - srs_freep(sh_video); - sh_video = shared_video->copy(); - } - if ((ret = update_duration(shared_video)) != ERROR_SUCCESS) { return ret; } @@ -912,13 +852,13 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) srs_assert(segment); // ignore if duration ok. - if (segment_duration <= 0 || !segment->is_overflow(segment_duration)) { + if (cduration <= 0 || segment->get_duration() < cduration) { return ret; } // when wait keyframe, ignore if no frame arrived. // @see https://github.com/ossrs/srs/issues/177 - if (_srs_config->get_dvr_wait_keyframe(req->vhost)) { + if (wait_keyframe) { if (!msg->is_video()) { return ret; } @@ -944,16 +884,27 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) } // update sequence header - if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) { - return ret; - } - if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) { + if ((ret = hub->on_dvr_request_sh()) != ERROR_SUCCESS) { return ret; } - if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) { + + return ret; +} + +int SrsDvrSegmentPlan::on_reload_vhost_dvr(string vhost) +{ + int ret = ERROR_SUCCESS; + + if (req->vhost != vhost) { return ret; } + wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost); + + cduration = _srs_config->get_dvr_duration(req->vhost); + // to ms + cduration *= 1000; + return ret; } @@ -997,7 +948,7 @@ int SrsDvr::initialize(SrsOriginHub* h, SrsRequest* r) segmenter = new SrsDvrFlvSegmenter(); } - if ((ret = plan->initialize(segmenter, r)) != ERROR_SUCCESS) { + if ((ret = plan->initialize(hub, segmenter, r)) != ERROR_SUCCESS) { return ret; } @@ -1029,8 +980,7 @@ void SrsDvr::on_unpublish() plan->on_unpublish(); } -// TODO: FIXME: source should use shared message instead. -int SrsDvr::on_meta_data(SrsOnMetaDataPacket* m) +int SrsDvr::on_meta_data(SrsSharedPtrMessage* metadata) { int ret = ERROR_SUCCESS; @@ -1039,18 +989,7 @@ int SrsDvr::on_meta_data(SrsOnMetaDataPacket* m) return ret; } - int size = 0; - char* payload = NULL; - if ((ret = m->encode(size, payload)) != ERROR_SUCCESS) { - return ret; - } - - SrsSharedPtrMessage metadata; - if ((ret = metadata.create(NULL, payload, size)) != ERROR_SUCCESS) { - return ret; - } - - if ((ret = plan->on_meta_data(&metadata)) != ERROR_SUCCESS) { + if ((ret = plan->on_meta_data(metadata)) != ERROR_SUCCESS) { return ret; } diff --git a/trunk/src/app/srs_app_dvr.hpp b/trunk/src/app/srs_app_dvr.hpp index 81a2875a8..eb47d13d4 100644 --- a/trunk/src/app/srs_app_dvr.hpp +++ b/trunk/src/app/srs_app_dvr.hpp @@ -39,7 +39,6 @@ class SrsOriginHub; class SrsRequest; class SrsBuffer; class SrsRtmpJitter; -class SrsOnMetaDataPacket; class SrsSharedPtrMessage; class SrsFileWriter; class SrsFlvEncoder; @@ -68,9 +67,11 @@ protected: private: // The path of current segment flv file path. std::string path; + std::string tmp_dvr_file; +private: SrsRequest* req; SrsDvrPlan* plan; - std::string tmp_dvr_file; +private: SrsRtmpJitter* jitter; SrsRtmpJitterAlgorithm jitter_algorithm; public: @@ -81,8 +82,8 @@ public: virtual int initialize(SrsDvrPlan* p, SrsRequest* r); // Get the current dvr path. virtual std::string get_path(); - // Whether segment is overflow. - virtual bool is_overflow(int64_t max_duration); + // Get the duration in ms of segment. + virtual int64_t get_duration(); // Open new segment file. // @param use_tmp_file Whether use tmp file for DVR, and rename when close. // @remark Ignore when file is already open. @@ -105,19 +106,12 @@ public: protected: virtual int open_encoder() = 0; virtual int encode_metadata(SrsSharedPtrMessage* metadata) = 0; - virtual int encode_audio(SrsSharedPtrMessage* audio, int64_t dts) = 0; - virtual int encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe) = 0; + virtual int encode_audio(SrsSharedPtrMessage* audio) = 0; + virtual int encode_video(SrsSharedPtrMessage* video, bool sh, bool keyframe) = 0; virtual int close_encoder() = 0; private: - /** - * generate the flv segment path. - */ + // Generate the flv segment path. virtual std::string generate_path(); - /** - * create flv jitter. load jitter when flv exists. - * @param target_exists whether loads the jitter from exists flv file. - */ - virtual int create_jitter(); // interface ISrsReloadHandler public: virtual int on_reload_vhost_dvr(std::string vhost); @@ -161,8 +155,8 @@ public: protected: virtual int open_encoder(); virtual int encode_metadata(SrsSharedPtrMessage* metadata); - virtual int encode_audio(SrsSharedPtrMessage* audio, int64_t dts); - virtual int encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe); + virtual int encode_audio(SrsSharedPtrMessage* audio); + virtual int encode_video(SrsSharedPtrMessage* video, bool sh, bool keyframe); virtual int close_encoder(); private: // When update the duration of segment by rtmp msg. @@ -185,8 +179,8 @@ public: protected: virtual int open_encoder(); virtual int encode_metadata(SrsSharedPtrMessage* metadata); - virtual int encode_audio(SrsSharedPtrMessage* audio, int64_t dts); - virtual int encode_video(SrsSharedPtrMessage* video, int64_t dts, bool sh, bool keyframe); + virtual int encode_audio(SrsSharedPtrMessage* audio); + virtual int encode_video(SrsSharedPtrMessage* video, bool sh, bool keyframe); virtual int close_encoder(); }; @@ -208,17 +202,14 @@ public: }; /** -* the plan for dvr. -* use to control the following dvr params: -* 1. filename: the filename for record file. -* 2. reap flv: when to reap the flv and start new piece. + * The DVR plan, when and how to reap segment. */ -// TODO: FIXME: the plan is too fat, refine me. -class SrsDvrPlan +class SrsDvrPlan : public ISrsReloadHandler { public: SrsRequest* req; protected: + SrsOriginHub* hub; SrsDvrSegmenter* segment; SrsAsyncCallWorker* async; bool dvr_enabled; @@ -226,36 +217,23 @@ public: SrsDvrPlan(); virtual ~SrsDvrPlan(); public: - virtual int initialize(SrsDvrSegmenter* s, SrsRequest* r); + virtual int initialize(SrsOriginHub* h, SrsDvrSegmenter* s, SrsRequest* r); virtual int on_publish() = 0; virtual void on_unpublish() = 0; - /** - * when got metadata. - */ virtual int on_meta_data(SrsSharedPtrMessage* shared_metadata); - /** - * @param shared_audio, directly ptr, copy it if need to save it. - */ virtual int on_audio(SrsSharedPtrMessage* shared_audio); - /** - * @param shared_video, directly ptr, copy it if need to save it. - */ virtual int on_video(SrsSharedPtrMessage* shared_video); // Internal interface for segmenter. public: // When segmenter close a segment. virtual int on_reap_segment(); - // When segmenter got a keyframe. - virtual int on_video_keyframe(); - // The plan may need to process the timestamp. - virtual int64_t filter_timestamp(int64_t timestamp); public: static int create_plan(std::string vhost, SrsDvrPlan** pplan); }; /** -* session plan: reap flv when session complete(unpublish) -*/ + * The DVR session plan: reap flv when session complete(unpublish) + */ class SrsDvrSessionPlan : public SrsDvrPlan { public: @@ -267,33 +245,32 @@ public: }; /** -* segment plan: reap flv when duration exceed. -*/ + * The DVR segment plan: reap flv when duration exceed. + */ class SrsDvrSegmentPlan : public SrsDvrPlan { private: // in config, in ms - int segment_duration; - SrsSharedPtrMessage* sh_audio; - SrsSharedPtrMessage* sh_video; - SrsSharedPtrMessage* metadata; + int cduration; + bool wait_keyframe; public: SrsDvrSegmentPlan(); virtual ~SrsDvrSegmentPlan(); public: - virtual int initialize(SrsDvrSegmenter* s, SrsRequest* req); + virtual int initialize(SrsOriginHub* h, SrsDvrSegmenter* s, SrsRequest* r); virtual int on_publish(); virtual void on_unpublish(); - virtual int on_meta_data(SrsSharedPtrMessage* shared_metadata); virtual int on_audio(SrsSharedPtrMessage* shared_audio); virtual int on_video(SrsSharedPtrMessage* shared_video); private: virtual int update_duration(SrsSharedPtrMessage* msg); +// interface ISrsReloadHandler +public: + virtual int on_reload_vhost_dvr(std::string vhost); }; /** * DVR(Digital Video Recorder) to record RTMP stream to flv/mp4 file. - * TODO: FIXME: add utest for it. */ class SrsDvr : public ISrsReloadHandler { @@ -330,7 +307,7 @@ public: /** * get some information from metadata, it's optinal. */ - virtual int on_meta_data(SrsOnMetaDataPacket* m); + virtual int on_meta_data(SrsSharedPtrMessage* metadata); /** * mux the audio packets to dvr. * @param shared_audio, directly ptr, copy it if need to save it. diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 9adacaad5..2e52a0dd5 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -1265,23 +1265,6 @@ void SrsHls::on_unpublish() hls_enabled = false; } -int SrsHls::on_meta_data(SrsAmf0Object* metadata) -{ - int ret = ERROR_SUCCESS; - - if (!metadata) { - srs_trace("no metadata persent, hls ignored it."); - return ret; - } - - if (metadata->count() <= 0) { - srs_trace("no metadata persent, hls ignored it."); - return ret; - } - - return ret; -} - int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio) { int ret = ERROR_SUCCESS; diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index 0b5535054..fb265c35b 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -405,10 +405,6 @@ public: */ virtual void on_unpublish(); /** - * get some information from metadata, it's optinal. - */ - virtual int on_meta_data(SrsAmf0Object* metadata); - /** * mux the audio packets to ts. * @param shared_audio, directly ptr, copy it if need to save it. */ diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 0dd1ad14c..4e11ef9cb 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -927,27 +927,6 @@ int SrsOriginHub::cycle() return ret; } -int SrsOriginHub::on_original_metadata(SrsOnMetaDataPacket* metadata) -{ - int ret = ERROR_SUCCESS; - -#ifdef SRS_AUTO_HLS - if (metadata && (ret = hls->on_meta_data(metadata->metadata)) != ERROR_SUCCESS) { - srs_error("hls process onMetaData message failed. ret=%d", ret); - return ret; - } -#endif - -#ifdef SRS_AUTO_DVR - if (metadata && (ret = dvr->on_meta_data(metadata)) != ERROR_SUCCESS) { - srs_error("dvr process onMetaData message failed. ret=%d", ret); - return ret; - } -#endif - - return ret; -} - int SrsOriginHub::on_meta_data(SrsSharedPtrMessage* shared_metadata) { int ret = ERROR_SUCCESS; @@ -964,6 +943,13 @@ int SrsOriginHub::on_meta_data(SrsSharedPtrMessage* shared_metadata) } } +#ifdef SRS_AUTO_DVR + if ((ret = dvr->on_meta_data(shared_metadata)) != ERROR_SUCCESS) { + srs_error("dvr process onMetaData message failed. ret=%d", ret); + return ret; + } +#endif + return ret; } @@ -1245,26 +1231,9 @@ int SrsOriginHub::on_dvr_request_sh() // feed the dvr the metadata/sequence header, // when reload to start dvr, dvr will never get the sequence header in stream, // use the SrsSource.on_dvr_request_sh to push the sequence header to DVR. - if (cache_metadata) { - char* payload = cache_metadata->payload; - int size = cache_metadata->size; - - SrsBuffer stream; - if ((ret = stream.initialize(payload, size)) != ERROR_SUCCESS) { - srs_error("dvr decode metadata stream failed. ret=%d", ret); - return ret; - } - - SrsOnMetaDataPacket pkt; - if ((ret = pkt.decode(&stream)) != ERROR_SUCCESS) { - srs_error("dvr decode metadata packet failed."); - return ret; - } - - if ((ret = dvr->on_meta_data(&pkt)) != ERROR_SUCCESS) { - srs_error("dvr process onMetaData message failed. ret=%d", ret); - return ret; - } + if (cache_metadata && (ret = dvr->on_meta_data(cache_metadata)) != ERROR_SUCCESS) { + srs_error("dvr process onMetaData message failed. ret=%d", ret); + return ret; } if (cache_sh_video && (ret = dvr->on_video(cache_sh_video)) != ERROR_SUCCESS) { @@ -1976,11 +1945,6 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata { int ret = ERROR_SUCCESS; - // Notify hub about the original metadata. - if ((ret = hub->on_original_metadata(metadata)) != ERROR_SUCCESS) { - return ret; - } - // if allow atc_auto and bravo-atc detected, open atc for vhost. SrsAmf0Any* prop = NULL; atc = _srs_config->get_atc(req->vhost); diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 3da900fd6..56b3128a9 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -456,8 +456,6 @@ public: // for example, dispose hls in cycle. virtual int cycle(); public: - // When got a original metadata. - virtual int on_original_metadata(SrsOnMetaDataPacket* metadata); // When got a parsed metadata. virtual int on_meta_data(SrsSharedPtrMessage* shared_metadata); // When got a parsed audio packet.