mirror of
https://github.com/ossrs/srs.git
synced 2025-02-14 12:21:55 +00:00
For #299, use fragment for dvr FLV/MP4
This commit is contained in:
parent
da4c390d69
commit
8d679a6f9a
5 changed files with 44 additions and 60 deletions
|
@ -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…
Reference in a new issue