胡斌

support save total.m3u8 for hls,unfinished

... ... @@ -72,6 +72,8 @@ const char* _srs_version = "XCORE-"RTMP_SIG_SRS_SERVER;
#define SRS_CONF_DEFAULT_MAX_CONNECTIONS 1000
#define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
#define SRS_CONF_DEFAULT_HLS_M3U8_FILE "[app]/[stream].m3u8"
#define SRS_CONF_DEFAULT_HLS_TOTAL_M3U8_FILE "[app]/[stream]_total.m3u8"
#define SRS_CONF_DEFAULT_HLS_TOTAL_FILE "[app]/[stream]_total"
#define SRS_CONF_DEFAULT_HLS_TS_FILE "[app]/[stream]-[seq].ts"
#define SRS_CONF_DEFAULT_HLS_TS_FLOOR false
#define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
... ... @@ -1898,7 +1900,7 @@ int SrsConfig::check_config()
if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
&& m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
&& m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify"
&& m != "hls_wait_keyframe" && m != "hls_dispose"
&& m != "hls_wait_keyframe" && m != "hls_dispose" && m != "hls_total_m3u8_file" && m != "hls_total_file"
) {
ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
... ... @@ -3677,6 +3679,40 @@ string SrsConfig::get_hls_m3u8_file(string vhost)
return conf->arg0();
}
string SrsConfig::get_hls_total_m3u8_file(string vhost)
{
SrsConfDirective* hls = get_hls(vhost);
if (!hls) {
return SRS_CONF_DEFAULT_HLS_TOTAL_M3U8_FILE;
}
SrsConfDirective* conf = hls->get("hls_total_m3u8_file");
if (!conf) {
return SRS_CONF_DEFAULT_HLS_TOTAL_M3U8_FILE;
}
return conf->arg0();
}
string SrsConfig::get_hls_total_file(string vhost)
{
SrsConfDirective* hls = get_hls(vhost);
if (!hls) {
return SRS_CONF_DEFAULT_HLS_TOTAL_FILE;
}
SrsConfDirective* conf = hls->get("hls_total_file");
if (!conf) {
return SRS_CONF_DEFAULT_HLS_TOTAL_FILE;
}
return conf->arg0();
}
string SrsConfig::get_hls_ts_file(string vhost)
{
SrsConfDirective* hls = get_hls(vhost);
... ...
... ... @@ -882,6 +882,14 @@ public:
*/
virtual std::string get_hls_m3u8_file(std::string vhost);
/**
* get the HLS total m3u8 file path template.
*/
virtual std::string get_hls_total_m3u8_file(std::string vhost);
/**
* get the HLS total file path template.
*/
virtual std::string get_hls_total_file(std::string vhost);
/**
* get the HLS ts file path template.
*/
virtual std::string get_hls_ts_file(std::string vhost);
... ...
... ... @@ -387,7 +387,7 @@ int SrsHlsMuxer::initialize()
}
int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
string path, string m3u8_file, string ts_file, double fragment, double window,
string path, string m3u8_file, string total_m3u8_file, string total_file, string ts_file, double fragment, double window,
bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe
) {
int ret = ERROR_SUCCESS;
... ... @@ -412,6 +412,14 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
m3u8_url = srs_path_build_stream(m3u8_file, req->vhost, req->app, req->stream);
m3u8 = path + "/" + m3u8_url;
// generate the total m3u8 dir and path.
total_m3u8_url = srs_path_build_stream(total_m3u8_file, req->vhost, req->app, req->stream);
total_m3u8 = path + "/" + total_m3u8_url;
// generate the m3u8 dir and path.
total_url = srs_path_build_stream(total_file, req->vhost, req->app, req->stream);
total = path + "/" + total_url;
// when update config, reset the history target duration.
max_td = (int)(fragment * _srs_config->get_hls_td_ratio(r->vhost));
... ... @@ -735,6 +743,8 @@ int SrsHlsMuxer::segment_close(string log_desc)
srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64,
log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration,
current->segment_start_dts);
SrsHlsSegment* currentSeg = current;
// close the muxer of finished segment.
srs_freep(current->muxer);
... ... @@ -749,6 +759,63 @@ int SrsHlsMuxer::segment_close(string log_desc)
tmp_file.c_str(), full_path.c_str(), ret);
return ret;
}
SrsFileWriter total_m3u8_writer;
//add segment to total.m3u8
std::stringstream ss;
if(currentSeg->sequence_no == 0){
ret = total_m3u8_writer.open(total_m3u8);
if(ret != ERROR_SUCCESS){
srs_error("open total file %s error:%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64,
total_m3u8.c_str(), log_desc.c_str(), currentSeg->sequence_no, currentSeg->uri.c_str(), currentSeg->duration,
currentSeg->segment_start_dts);
return ret;
}
//write total m3u8 header
ss << "#EXTM3U" << SRS_CONSTS_LF
<< "#EXT-X-VERSION:3" << SRS_CONSTS_LF
<< "#EXT-X-ALLOW-CACHE:YES" << SRS_CONSTS_LF;
srs_verbose("write m3u8 header success.");
}
else{
ret = total_m3u8_writer.open_append(total_m3u8);
if(ret != ERROR_SUCCESS){
srs_error("open total file %s error:%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64,
total_m3u8.c_str(), log_desc.c_str(), currentSeg->sequence_no, currentSeg->uri.c_str(), currentSeg->duration,
currentSeg->segment_start_dts);
return ret;
}
}
if (currentSeg->is_sequence_header) {
// #EXT-X-DISCONTINUITY\n
ss << "#EXT-X-DISCONTINUITY" << SRS_CONSTS_LF;
srs_verbose("write m3u8 segment discontinuity success.");
}
// "#EXTINF:4294967295.208,\n"
ss.precision(3);
ss.setf(std::ios::fixed, std::ios::floatfield);
ss << "#EXTINF:" << currentSeg->duration << ", no desc" << SRS_CONSTS_LF;
srs_verbose("write m3u8 segment info success.");
// {file name}\n
ss << currentSeg->uri << SRS_CONSTS_LF;
srs_verbose("write m3u8 segment uri success.");
// write m3u8 to writer.
std::string m3u8 = ss.str();
if ((ret = total_m3u8_writer.write((char*)m3u8.c_str(), (int)m3u8.length(), NULL)) != ERROR_SUCCESS) {
srs_error("write m3u8 failed. ret=%d", ret);
return ret;
}
srs_info("write total m3u8 %s success.", m3u8_total_file.c_str());
} else {
// reuse current segment index.
_sequence_no--;
... ... @@ -953,6 +1020,8 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
// get the hls path config
std::string path = _srs_config->get_hls_path(vhost);
std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost);
std::string total_m3u8_file = _srs_config->get_hls_total_m3u8_file(vhost);
std::string total_file = _srs_config->get_hls_total_file(vhost);
std::string ts_file = _srs_config->get_hls_ts_file(vhost);
bool cleanup = _srs_config->get_hls_cleanup(vhost);
bool wait_keyframe = _srs_config->get_hls_wait_keyframe(vhost);
... ... @@ -968,7 +1037,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
// open muxer
if ((ret = muxer->update_config(req, entry_prefix,
path, m3u8_file, ts_file, hls_fragment, hls_window, ts_floor, hls_aof_ratio,
path, m3u8_file, total_m3u8_file, total_file, ts_file, hls_fragment, hls_window, ts_floor, hls_aof_ratio,
cleanup, wait_keyframe)) != ERROR_SUCCESS
) {
srs_error("m3u8 muxer update config failed. ret=%d", ret);
... ...
... ... @@ -205,6 +205,10 @@ private:
int max_td;
std::string m3u8;
std::string m3u8_url;
std::string total_m3u8;
std::string total_m3u8_url;
std::string total;
std::string total_url;
private:
// TODO: FIXME: remove it.
bool should_write_cache;
... ... @@ -248,7 +252,7 @@ public:
* when publish, update the config for muxer.
*/
virtual int update_config(SrsRequest* r, std::string entry_prefix,
std::string path, std::string m3u8_file, std::string ts_file,
std::string path, std::string m3u8_file, std::string total_m3u8_file, std::string total_file, std::string ts_file,
double fragment, double window, bool ts_floor, double aof_ratio,
bool cleanup, bool wait_keyframe);
/**
... ...