1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

fix #381, support reap hls/ts by gop or not. 2.0.160.

This commit is contained in:
winlin 2015-04-13 10:32:32 +08:00
parent d2c63d818b
commit dcac9c69d5
7 changed files with 65 additions and 16 deletions

View file

@ -562,6 +562,7 @@ Supported operating systems and hardware:
### SRS 2.0 history ### SRS 2.0 history
* v2.0, 2015-04-13, for [#381](https://github.com/winlinvip/simple-rtmp-server/issues/381), support reap hls/ts by gop or not. 2.0.160.
* v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts. * v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts.
* v2.0, 2015-04-10, refine the hls deviation for floor algorithm. * v2.0, 2015-04-10, refine the hls deviation for floor algorithm.
* v2.0, 2015-04-08, for [#375](https://github.com/winlinvip/simple-rtmp-server/issues/375), fix hls bug, keep cc continous between ts files. 2.0.159. * v2.0, 2015-04-08, for [#375](https://github.com/winlinvip/simple-rtmp-server/issues/375), fix hls bug, keep cc continous between ts files. 2.0.159.

View file

@ -618,6 +618,11 @@ vhost with-hls.srs.com {
# @remark only used when on_hls_notify is config. # @remark only used when on_hls_notify is config.
# default: 64 # default: 64
hls_nb_notify 64; hls_nb_notify 64;
# whether wait keyframe to reap segment,
# if off, reap segment when duration exceed the fragment,
# if on, reap segment when duration exceed and got keyframe.
# default: on
hls_wait_keyframe on;
# on_hls, never config in here, should config in http_hooks. # on_hls, never config in here, should config in http_hooks.
# for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com # for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com

View file

@ -1487,7 +1487,7 @@ int SrsConfig::check_config()
string m = conf->at(j)->name.c_str(); string m = conf->at(j)->name.c_str();
if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" 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_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_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify" && m != "hls_wait_keyframe"
) { ) {
ret = ERROR_SYSTEM_CONFIG_INVALID; ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
@ -3451,6 +3451,23 @@ bool SrsConfig::get_hls_cleanup(string vhost)
return SRS_CONF_PERFER_TRUE(conf->arg0()); return SRS_CONF_PERFER_TRUE(conf->arg0());
} }
bool SrsConfig::get_hls_wait_keyframe(string vhost)
{
SrsConfDirective* hls = get_hls(vhost);
if (!hls) {
return SRS_CONF_DEFAULT_HLS_WAIT_KEYFRAME;
}
SrsConfDirective* conf = hls->get("hls_wait_keyframe");
if (!conf || conf->arg0().empty()) {
return SRS_CONF_DEFAULT_HLS_WAIT_KEYFRAME;
}
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
SrsConfDirective *SrsConfig::get_hds(const string &vhost) SrsConfDirective *SrsConfig::get_hds(const string &vhost)
{ {
SrsConfDirective* conf = get_vhost(vhost); SrsConfDirective* conf = get_vhost(vhost);

View file

@ -63,6 +63,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SRS_CONF_DEFAULT_HLS_ACODEC "aac" #define SRS_CONF_DEFAULT_HLS_ACODEC "aac"
#define SRS_CONF_DEFAULT_HLS_VCODEC "h264" #define SRS_CONF_DEFAULT_HLS_VCODEC "h264"
#define SRS_CONF_DEFAULT_HLS_CLEANUP true #define SRS_CONF_DEFAULT_HLS_CLEANUP true
#define SRS_CONF_DEFAULT_HLS_WAIT_KEYFRAME true
#define SRS_CONF_DEFAULT_HLS_NB_NOTIFY 64 #define SRS_CONF_DEFAULT_HLS_NB_NOTIFY 64
#define SRS_CONF_DEFAULT_DVR_PATH "./objs/nginx/html/[app]/[stream].[timestamp].flv" #define SRS_CONF_DEFAULT_DVR_PATH "./objs/nginx/html/[app]/[stream].[timestamp].flv"
#define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session" #define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session"
@ -960,6 +961,10 @@ public:
* whether cleanup the old ts files. * whether cleanup the old ts files.
*/ */
virtual bool get_hls_cleanup(std::string vhost); virtual bool get_hls_cleanup(std::string vhost);
/**
* whether reap the ts when got keyframe.
*/
virtual bool get_hls_wait_keyframe(std::string vhost);
/** /**
* get the size of bytes to read from cdn network, for the on_hls_notify callback, * get the size of bytes to read from cdn network, for the on_hls_notify callback,
* that is, to read max bytes of the bytes from the callback, or timeout or error. * that is, to read max bytes of the bytes from the callback, or timeout or error.

View file

@ -267,6 +267,7 @@ SrsHlsMuxer::SrsHlsMuxer()
hls_aof_ratio = 1.0; hls_aof_ratio = 1.0;
deviation_ts = 0; deviation_ts = 0;
hls_cleanup = true; hls_cleanup = true;
hls_wait_keyframe = true;
previous_floor_ts = 0; previous_floor_ts = 0;
accept_floor_ts = 0; accept_floor_ts = 0;
hls_ts_floor = false; hls_ts_floor = false;
@ -335,7 +336,7 @@ int SrsHlsMuxer::initialize(ISrsHlsHandler* h)
int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, 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 ts_file, double fragment, double window,
bool ts_floor, double aof_ratio, bool cleanup bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe
) { ) {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
@ -349,6 +350,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
hls_aof_ratio = aof_ratio; hls_aof_ratio = aof_ratio;
hls_ts_floor = ts_floor; hls_ts_floor = ts_floor;
hls_cleanup = cleanup; hls_cleanup = cleanup;
hls_wait_keyframe = wait_keyframe;
previous_floor_ts = 0; previous_floor_ts = 0;
accept_floor_ts = 0; accept_floor_ts = 0;
hls_window = window; hls_window = window;
@ -542,6 +544,11 @@ bool SrsHlsMuxer::is_segment_overflow()
return current->duration >= hls_fragment + deviation; return current->duration >= hls_fragment + deviation;
} }
bool SrsHlsMuxer::wait_keyframe()
{
return hls_wait_keyframe;
}
bool SrsHlsMuxer::is_segment_absolutely_overflow() bool SrsHlsMuxer::is_segment_absolutely_overflow()
{ {
// @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-83553950 // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-83553950
@ -862,6 +869,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost); std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost);
std::string ts_file = _srs_config->get_hls_ts_file(vhost); std::string ts_file = _srs_config->get_hls_ts_file(vhost);
bool cleanup = _srs_config->get_hls_cleanup(vhost); bool cleanup = _srs_config->get_hls_cleanup(vhost);
bool wait_keyframe = _srs_config->get_hls_wait_keyframe(vhost);
// the audio overflow, for pure audio to reap segment. // the audio overflow, for pure audio to reap segment.
double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost); double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost);
// whether use floor(timestamp/hls_fragment) for variable timestamp // whether use floor(timestamp/hls_fragment) for variable timestamp
@ -873,7 +881,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
// open muxer // open muxer
if ((ret = muxer->update_config(req, entry_prefix, 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, ts_file, hls_fragment, hls_window, ts_floor, hls_aof_ratio,
cleanup)) != ERROR_SUCCESS cleanup, wait_keyframe)) != ERROR_SUCCESS
) { ) {
srs_error("m3u8 muxer update config failed. ret=%d", ret); srs_error("m3u8 muxer update config failed. ret=%d", ret);
return ret; return ret;
@ -883,9 +891,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
srs_error("m3u8 muxer open segment failed. ret=%d", ret); srs_error("m3u8 muxer open segment failed. ret=%d", ret);
return ret; return ret;
} }
srs_trace("hls: win=%.2f, frag=%.2f, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d", srs_trace("hls: win=%.2f, frag=%.2f, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d, clean=%d, waitk=%d",
hls_window, hls_fragment, entry_prefix.c_str(), path.c_str(), m3u8_file.c_str(), hls_window, hls_fragment, entry_prefix.c_str(), path.c_str(), m3u8_file.c_str(),
ts_file.c_str(), hls_aof_ratio, ts_floor); ts_file.c_str(), hls_aof_ratio, ts_floor, cleanup, wait_keyframe);
return ret; return ret;
} }
@ -972,17 +980,25 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
return ret; return ret;
} }
// new segment when: // when segment overflow, reap if possible.
// 1. base on gop(IDR). if (muxer->is_segment_overflow()) {
// 2. some gops duration overflow. // do reap ts if any of:
if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && muxer->is_segment_overflow()) { // a. wait keyframe and got keyframe.
if (!sample->has_idr) { // b. always reap when not wait keyframe.
srs_warn("hls: ts starts without IDR, first nalu=%d, idr=%d", sample->first_nalu_type, sample->has_idr); if (!muxer->wait_keyframe() || sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) {
} // when wait keyframe, there must exists idr frame in sample.
if ((ret = reap_segment("video", muxer, cache->video->dts)) != ERROR_SUCCESS) { if (!sample->has_idr && muxer->wait_keyframe()) {
srs_warn("hls: ts starts without IDR, first nalu=%d, idr=%d", sample->first_nalu_type, sample->has_idr);
}
// reap the segment, which will also flush the video.
if ((ret = reap_segment("video", muxer, cache->video->dts)) != ERROR_SUCCESS) {
return ret;
}
// the video must be flushed, just return.
return ret; return ret;
} }
return ret;
} }
// flush video when got one // flush video when got one

View file

@ -207,6 +207,7 @@ private:
std::string hls_path; std::string hls_path;
std::string hls_ts_file; std::string hls_ts_file;
bool hls_cleanup; bool hls_cleanup;
bool hls_wait_keyframe;
std::string m3u8_dir; std::string m3u8_dir;
double hls_aof_ratio; double hls_aof_ratio;
double hls_fragment; double hls_fragment;
@ -270,7 +271,7 @@ public:
virtual int update_config(SrsRequest* r, std::string entry_prefix, 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 ts_file,
double fragment, double window, bool ts_floor, double aof_ratio, double fragment, double window, bool ts_floor, double aof_ratio,
bool cleanup); bool cleanup, bool wait_keyframe);
/** /**
* open a new segment(a new ts file), * open a new segment(a new ts file),
* @param segment_start_dts use to calc the segment duration, * @param segment_start_dts use to calc the segment duration,
@ -283,6 +284,10 @@ public:
* that is whether the current segment duration>=(the segment in config) * that is whether the current segment duration>=(the segment in config)
*/ */
virtual bool is_segment_overflow(); virtual bool is_segment_overflow();
/**
* whether wait keyframe to reap the ts.
*/
virtual bool wait_keyframe();
/** /**
* whether segment absolutely overflow, for pure audio to reap segment, * whether segment absolutely overflow, for pure audio to reap segment,
* that is whether the current segment duration>=2*(the segment in config) * that is whether the current segment duration>=2*(the segment in config)

View file

@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version // current release version
#define VERSION_MAJOR 2 #define VERSION_MAJOR 2
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_REVISION 159 #define VERSION_REVISION 160
// server info. // server info.
#define RTMP_SIG_SRS_KEY "SRS" #define RTMP_SIG_SRS_KEY "SRS"