For #299, use fragment for dvr FLV/MP4

pull/816/head
winlin 8 years ago
parent da4c390d69
commit 8d679a6f9a

@ -41,16 +41,15 @@ using namespace std;
#include <srs_protocol_json.hpp> #include <srs_protocol_json.hpp>
#include <srs_app_utility.hpp> #include <srs_app_utility.hpp>
#include <srs_kernel_mp4.hpp> #include <srs_kernel_mp4.hpp>
#include <srs_app_fragment.hpp>
SrsDvrSegmenter::SrsDvrSegmenter() SrsDvrSegmenter::SrsDvrSegmenter()
{ {
req = NULL; req = NULL;
jitter = NULL; jitter = NULL;
plan = NULL; plan = NULL;
duration = 0;
stream_previous_pkt_time = -1;
path = ""; fragment = new SrsFragment();
fs = new SrsFileWriter(); fs = new SrsFileWriter();
jitter_algorithm = SrsRtmpJitterAlgorithmOFF; jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
@ -61,6 +60,7 @@ SrsDvrSegmenter::~SrsDvrSegmenter()
{ {
_srs_config->unsubscribe(this); _srs_config->unsubscribe(this);
srs_freep(fragment);
srs_freep(jitter); srs_freep(jitter);
srs_freep(fs); srs_freep(fs);
} }
@ -78,14 +78,9 @@ int SrsDvrSegmenter::initialize(SrsDvrPlan* p, SrsRequest* r)
return ret; return ret;
} }
string SrsDvrSegmenter::get_path() SrsFragment* SrsDvrSegmenter::current()
{ {
return path; return fragment;
}
int64_t SrsDvrSegmenter::get_duration()
{
return duration;
} }
int SrsDvrSegmenter::open() int SrsDvrSegmenter::open()
@ -97,32 +92,25 @@ int SrsDvrSegmenter::open()
return ret; return ret;
} }
path = generate_path(); string path = generate_path();
if (srs_path_exists(path)) { if (srs_path_exists(path)) {
ret = ERROR_DVR_CANNOT_APPEND; ret = ERROR_DVR_CANNOT_APPEND;
srs_error("DVR can't append to exists path=%s. ret=%d", path.c_str(), ret); srs_error("DVR can't append to exists path=%s. ret=%d", path.c_str(), ret);
return ret; return ret;
} }
fragment->set_path(path);
tmp_dvr_file = path + ".tmp";
// create dir first. // create dir first.
std::string dir = srs_path_dirname(path); if ((ret = fragment->create_dir()) != ERROR_SUCCESS) {
if ((ret = srs_create_dir_recursively(dir)) != ERROR_SUCCESS) {
srs_error("create dir=%s failed. ret=%d", dir.c_str(), ret);
return ret; return ret;
} }
srs_info("create dir=%s ok", dir.c_str());
// create jitter. // create jitter.
srs_freep(jitter); srs_freep(jitter);
jitter = new SrsRtmpJitter(); jitter = new SrsRtmpJitter();
duration = 0;
// fresh stream starting.
stream_previous_pkt_time = -1;
// open file writer, in append or create mode. // open file writer, in append or create mode.
string tmp_dvr_file = fragment->tmppath();
if ((ret = fs->open(tmp_dvr_file)) != ERROR_SUCCESS) { if ((ret = fs->open(tmp_dvr_file)) != ERROR_SUCCESS) {
srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret); srs_error("open file stream for file %s failed. ret=%d", path.c_str(), ret);
return ret; return ret;
@ -205,13 +193,8 @@ int SrsDvrSegmenter::close()
fs->close(); fs->close();
// when tmp flv file exists, reap it. // when tmp flv file exists, reap it.
if (tmp_dvr_file != path) { if ((ret = fragment->rename()) != ERROR_SUCCESS) {
if (rename(tmp_dvr_file.c_str(), path.c_str()) < 0) { return ret;
ret = ERROR_SYSTEM_FILE_RENAME;
srs_error("rename flv file failed, %s => %s. ret=%d",
tmp_dvr_file.c_str(), path.c_str(), ret);
return ret;
}
} }
// TODO: FIXME: the http callback is async, which will trigger thread switch, // TODO: FIXME: the http callback is async, which will trigger thread switch,
@ -228,16 +211,7 @@ int SrsDvrSegmenter::on_update_duration(SrsSharedPtrMessage* msg)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
// no previous packet or timestamp overflow. fragment->append(msg->timestamp);
if (stream_previous_pkt_time < 0 || stream_previous_pkt_time > msg->timestamp) {
stream_previous_pkt_time = msg->timestamp;
}
// collect segment and stream duration, timestamp overflow is ok.
duration += msg->timestamp - stream_previous_pkt_time;
// update previous packet time
stream_previous_pkt_time = msg->timestamp;
return ret; return ret;
} }
@ -326,7 +300,7 @@ int SrsDvrFlvSegmenter::refresh_metadata()
} }
// duration to buf // duration to buf
SrsAmf0Any* dur = SrsAmf0Any::number((double)duration / 1000.0); SrsAmf0Any* dur = SrsAmf0Any::number((double)fragment->duration() / 1000.0);
SrsAutoFree(SrsAmf0Any, dur); SrsAutoFree(SrsAmf0Any, dur);
stream.skip(-1 * stream.pos()); stream.skip(-1 * stream.pos());
@ -747,7 +721,11 @@ int SrsDvrPlan::on_reap_segment()
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
int cid = _srs_context->get_id(); int cid = _srs_context->get_id();
if ((ret = async->execute(new SrsDvrAsyncCallOnDvr(cid, req, segment->get_path()))) != ERROR_SUCCESS) {
SrsFragment* fragment = segment->current();
string fullpath = fragment->fullpath();
if ((ret = async->execute(new SrsDvrAsyncCallOnDvr(cid, req, fullpath))) != ERROR_SUCCESS) {
return ret; return ret;
} }
@ -916,7 +894,8 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
srs_assert(segment); srs_assert(segment);
// ignore if duration ok. // ignore if duration ok.
if (cduration <= 0 || segment->get_duration() < cduration) { SrsFragment* fragment = segment->current();
if (cduration <= 0 || fragment->duration() < cduration) {
return ret; return ret;
} }

@ -45,6 +45,7 @@ class SrsJsonAny;
class SrsJsonObject; class SrsJsonObject;
class SrsThread; class SrsThread;
class SrsMp4Encoder; class SrsMp4Encoder;
class SrsFragment;
#include <srs_app_source.hpp> #include <srs_app_source.hpp>
#include <srs_app_reload.hpp> #include <srs_app_reload.hpp>
@ -60,33 +61,22 @@ protected:
SrsFileWriter* fs; SrsFileWriter* fs;
// Whether wait keyframe to reap segment. // Whether wait keyframe to reap segment.
bool wait_keyframe; bool wait_keyframe;
// The duration in ms of current segment. // The FLV/MP4 fragment file.
int64_t duration; SrsFragment* fragment;
private:
// The path of current segment flv file path.
std::string path;
std::string tmp_dvr_file;
private: private:
SrsRequest* req; SrsRequest* req;
SrsDvrPlan* plan; SrsDvrPlan* plan;
private: private:
SrsRtmpJitter* jitter; SrsRtmpJitter* jitter;
SrsRtmpJitterAlgorithm jitter_algorithm; SrsRtmpJitterAlgorithm jitter_algorithm;
private:
// The previous stream RTMP pkt time in ms, used to calc the duration.
// for the RTMP timestamp will overflow.
// TODO: FIXME: Use utility object to calc it.
int64_t stream_previous_pkt_time;
public: public:
SrsDvrSegmenter(); SrsDvrSegmenter();
virtual ~SrsDvrSegmenter(); virtual ~SrsDvrSegmenter();
public: public:
// Initialize the segment. // Initialize the segment.
virtual int initialize(SrsDvrPlan* p, SrsRequest* r); virtual int initialize(SrsDvrPlan* p, SrsRequest* r);
// Get the current dvr path. // Get the current framgnet.
virtual std::string get_path(); virtual SrsFragment* current();
// Get the duration in ms of segment.
virtual int64_t get_duration();
// Open new segment file. // Open new segment file.
// @param use_tmp_file Whether use tmp file for DVR, and rename when close. // @param use_tmp_file Whether use tmp file for DVR, and rename when close.
// @remark Ignore when file is already open. // @remark Ignore when file is already open.

@ -90,6 +90,22 @@ int SrsFragment::unlink_file()
return ret; return ret;
} }
int SrsFragment::create_dir()
{
int ret = ERROR_SUCCESS;
std::string segment_dir = srs_path_dirname(filepath);
if ((ret = srs_create_dir_recursively(segment_dir)) != ERROR_SUCCESS) {
srs_error("Create dir %s failed. ret=%d", segment_dir.c_str(), ret);
return ret;
}
srs_info("Create dir %s ok", segment_dir.c_str());
return ret;
}
string SrsFragment::tmppath() string SrsFragment::tmppath()
{ {
return filepath + ".tmp"; return filepath + ".tmp";

@ -67,6 +67,8 @@ public:
// Unlink the fragment, to delete the file. // Unlink the fragment, to delete the file.
// @remark Ignore any error. // @remark Ignore any error.
virtual int unlink_file(); virtual int unlink_file();
// Create the dir for file recursively.
virtual int create_dir();
public: public:
// Get the temporary path for file. // Get the temporary path for file.
virtual std::string tmppath(); virtual std::string tmppath();

@ -423,12 +423,9 @@ int SrsHlsMuxer::segment_open()
current->uri += ts_url; current->uri += ts_url;
// create dir recursively for hls. // create dir recursively for hls.
std::string ts_dir = srs_path_dirname(current->fullpath()); if ((ret = current->create_dir()) != ERROR_SUCCESS) {
if ((ret = srs_create_dir_recursively(ts_dir)) != ERROR_SUCCESS) {
srs_error("create app dir %s failed. ret=%d", ts_dir.c_str(), ret);
return ret; return ret;
} }
srs_info("create ts dir %s ok", ts_dir.c_str());
// open temp ts file. // open temp ts file.
std::string tmp_file = current->tmppath(); std::string tmp_file = current->tmppath();

Loading…
Cancel
Save