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

@ -45,6 +45,7 @@ class SrsJsonAny;
class SrsJsonObject;
class SrsThread;
class SrsMp4Encoder;
class SrsFragment;
#include <srs_app_source.hpp>
#include <srs_app_reload.hpp>
@ -60,33 +61,22 @@ protected:
SrsFileWriter* fs;
// Whether wait keyframe to reap segment.
bool wait_keyframe;
// The duration in ms of current segment.
int64_t duration;
private:
// The path of current segment flv file path.
std::string path;
std::string tmp_dvr_file;
// The FLV/MP4 fragment file.
SrsFragment* fragment;
private:
SrsRequest* req;
SrsDvrPlan* plan;
private:
SrsRtmpJitter* jitter;
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:
SrsDvrSegmenter();
virtual ~SrsDvrSegmenter();
public:
// Initialize the segment.
virtual int initialize(SrsDvrPlan* p, SrsRequest* r);
// Get the current dvr path.
virtual std::string get_path();
// Get the duration in ms of segment.
virtual int64_t get_duration();
// Get the current framgnet.
virtual SrsFragment* current();
// 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.

@ -90,6 +90,22 @@ int SrsFragment::unlink_file()
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()
{
return filepath + ".tmp";

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

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

Loading…
Cancel
Save