正在显示
7 个修改的文件
包含
65 行增加
和
16 行删除
| @@ -562,6 +562,7 @@ Supported operating systems and hardware: | @@ -562,6 +562,7 @@ Supported operating systems and hardware: | ||
| 562 | 562 | ||
| 563 | ### SRS 2.0 history | 563 | ### SRS 2.0 history |
| 564 | 564 | ||
| 565 | +* 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. | ||
| 565 | * v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts. | 566 | * v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts. |
| 566 | * v2.0, 2015-04-10, refine the hls deviation for floor algorithm. | 567 | * v2.0, 2015-04-10, refine the hls deviation for floor algorithm. |
| 567 | * 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. | 568 | * 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. |
| @@ -618,6 +618,11 @@ vhost with-hls.srs.com { | @@ -618,6 +618,11 @@ vhost with-hls.srs.com { | ||
| 618 | # @remark only used when on_hls_notify is config. | 618 | # @remark only used when on_hls_notify is config. |
| 619 | # default: 64 | 619 | # default: 64 |
| 620 | hls_nb_notify 64; | 620 | hls_nb_notify 64; |
| 621 | + # whether wait keyframe to reap segment, | ||
| 622 | + # if off, reap segment when duration exceed the fragment, | ||
| 623 | + # if on, reap segment when duration exceed and got keyframe. | ||
| 624 | + # default: on | ||
| 625 | + hls_wait_keyframe on; | ||
| 621 | 626 | ||
| 622 | # on_hls, never config in here, should config in http_hooks. | 627 | # on_hls, never config in here, should config in http_hooks. |
| 623 | # for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com | 628 | # for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com |
| @@ -1487,7 +1487,7 @@ int SrsConfig::check_config() | @@ -1487,7 +1487,7 @@ int SrsConfig::check_config() | ||
| 1487 | string m = conf->at(j)->name.c_str(); | 1487 | string m = conf->at(j)->name.c_str(); |
| 1488 | if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" | 1488 | if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" |
| 1489 | && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec" | 1489 | && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec" |
| 1490 | - && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify" | 1490 | + && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify" && m != "hls_wait_keyframe" |
| 1491 | ) { | 1491 | ) { |
| 1492 | ret = ERROR_SYSTEM_CONFIG_INVALID; | 1492 | ret = ERROR_SYSTEM_CONFIG_INVALID; |
| 1493 | srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); | 1493 | srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); |
| @@ -3451,6 +3451,23 @@ bool SrsConfig::get_hls_cleanup(string vhost) | @@ -3451,6 +3451,23 @@ bool SrsConfig::get_hls_cleanup(string vhost) | ||
| 3451 | return SRS_CONF_PERFER_TRUE(conf->arg0()); | 3451 | return SRS_CONF_PERFER_TRUE(conf->arg0()); |
| 3452 | } | 3452 | } |
| 3453 | 3453 | ||
| 3454 | +bool SrsConfig::get_hls_wait_keyframe(string vhost) | ||
| 3455 | +{ | ||
| 3456 | + SrsConfDirective* hls = get_hls(vhost); | ||
| 3457 | + | ||
| 3458 | + if (!hls) { | ||
| 3459 | + return SRS_CONF_DEFAULT_HLS_WAIT_KEYFRAME; | ||
| 3460 | + } | ||
| 3461 | + | ||
| 3462 | + SrsConfDirective* conf = hls->get("hls_wait_keyframe"); | ||
| 3463 | + | ||
| 3464 | + if (!conf || conf->arg0().empty()) { | ||
| 3465 | + return SRS_CONF_DEFAULT_HLS_WAIT_KEYFRAME; | ||
| 3466 | + } | ||
| 3467 | + | ||
| 3468 | + return SRS_CONF_PERFER_TRUE(conf->arg0()); | ||
| 3469 | +} | ||
| 3470 | + | ||
| 3454 | SrsConfDirective *SrsConfig::get_hds(const string &vhost) | 3471 | SrsConfDirective *SrsConfig::get_hds(const string &vhost) |
| 3455 | { | 3472 | { |
| 3456 | SrsConfDirective* conf = get_vhost(vhost); | 3473 | SrsConfDirective* conf = get_vhost(vhost); |
| @@ -63,6 +63,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -63,6 +63,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 63 | #define SRS_CONF_DEFAULT_HLS_ACODEC "aac" | 63 | #define SRS_CONF_DEFAULT_HLS_ACODEC "aac" |
| 64 | #define SRS_CONF_DEFAULT_HLS_VCODEC "h264" | 64 | #define SRS_CONF_DEFAULT_HLS_VCODEC "h264" |
| 65 | #define SRS_CONF_DEFAULT_HLS_CLEANUP true | 65 | #define SRS_CONF_DEFAULT_HLS_CLEANUP true |
| 66 | +#define SRS_CONF_DEFAULT_HLS_WAIT_KEYFRAME true | ||
| 66 | #define SRS_CONF_DEFAULT_HLS_NB_NOTIFY 64 | 67 | #define SRS_CONF_DEFAULT_HLS_NB_NOTIFY 64 |
| 67 | #define SRS_CONF_DEFAULT_DVR_PATH "./objs/nginx/html/[app]/[stream].[timestamp].flv" | 68 | #define SRS_CONF_DEFAULT_DVR_PATH "./objs/nginx/html/[app]/[stream].[timestamp].flv" |
| 68 | #define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session" | 69 | #define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session" |
| @@ -961,6 +962,10 @@ public: | @@ -961,6 +962,10 @@ public: | ||
| 961 | */ | 962 | */ |
| 962 | virtual bool get_hls_cleanup(std::string vhost); | 963 | virtual bool get_hls_cleanup(std::string vhost); |
| 963 | /** | 964 | /** |
| 965 | + * whether reap the ts when got keyframe. | ||
| 966 | + */ | ||
| 967 | + virtual bool get_hls_wait_keyframe(std::string vhost); | ||
| 968 | + /** | ||
| 964 | * get the size of bytes to read from cdn network, for the on_hls_notify callback, | 969 | * get the size of bytes to read from cdn network, for the on_hls_notify callback, |
| 965 | * that is, to read max bytes of the bytes from the callback, or timeout or error. | 970 | * that is, to read max bytes of the bytes from the callback, or timeout or error. |
| 966 | */ | 971 | */ |
| @@ -267,6 +267,7 @@ SrsHlsMuxer::SrsHlsMuxer() | @@ -267,6 +267,7 @@ SrsHlsMuxer::SrsHlsMuxer() | ||
| 267 | hls_aof_ratio = 1.0; | 267 | hls_aof_ratio = 1.0; |
| 268 | deviation_ts = 0; | 268 | deviation_ts = 0; |
| 269 | hls_cleanup = true; | 269 | hls_cleanup = true; |
| 270 | + hls_wait_keyframe = true; | ||
| 270 | previous_floor_ts = 0; | 271 | previous_floor_ts = 0; |
| 271 | accept_floor_ts = 0; | 272 | accept_floor_ts = 0; |
| 272 | hls_ts_floor = false; | 273 | hls_ts_floor = false; |
| @@ -335,7 +336,7 @@ int SrsHlsMuxer::initialize(ISrsHlsHandler* h) | @@ -335,7 +336,7 @@ int SrsHlsMuxer::initialize(ISrsHlsHandler* h) | ||
| 335 | 336 | ||
| 336 | int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | 337 | int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, |
| 337 | string path, string m3u8_file, string ts_file, double fragment, double window, | 338 | string path, string m3u8_file, string ts_file, double fragment, double window, |
| 338 | - bool ts_floor, double aof_ratio, bool cleanup | 339 | + bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe |
| 339 | ) { | 340 | ) { |
| 340 | int ret = ERROR_SUCCESS; | 341 | int ret = ERROR_SUCCESS; |
| 341 | 342 | ||
| @@ -349,6 +350,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | @@ -349,6 +350,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, | ||
| 349 | hls_aof_ratio = aof_ratio; | 350 | hls_aof_ratio = aof_ratio; |
| 350 | hls_ts_floor = ts_floor; | 351 | hls_ts_floor = ts_floor; |
| 351 | hls_cleanup = cleanup; | 352 | hls_cleanup = cleanup; |
| 353 | + hls_wait_keyframe = wait_keyframe; | ||
| 352 | previous_floor_ts = 0; | 354 | previous_floor_ts = 0; |
| 353 | accept_floor_ts = 0; | 355 | accept_floor_ts = 0; |
| 354 | hls_window = window; | 356 | hls_window = window; |
| @@ -542,6 +544,11 @@ bool SrsHlsMuxer::is_segment_overflow() | @@ -542,6 +544,11 @@ bool SrsHlsMuxer::is_segment_overflow() | ||
| 542 | return current->duration >= hls_fragment + deviation; | 544 | return current->duration >= hls_fragment + deviation; |
| 543 | } | 545 | } |
| 544 | 546 | ||
| 547 | +bool SrsHlsMuxer::wait_keyframe() | ||
| 548 | +{ | ||
| 549 | + return hls_wait_keyframe; | ||
| 550 | +} | ||
| 551 | + | ||
| 545 | bool SrsHlsMuxer::is_segment_absolutely_overflow() | 552 | bool SrsHlsMuxer::is_segment_absolutely_overflow() |
| 546 | { | 553 | { |
| 547 | // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-83553950 | 554 | // @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 | @@ -862,6 +869,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment | ||
| 862 | std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost); | 869 | std::string m3u8_file = _srs_config->get_hls_m3u8_file(vhost); |
| 863 | std::string ts_file = _srs_config->get_hls_ts_file(vhost); | 870 | std::string ts_file = _srs_config->get_hls_ts_file(vhost); |
| 864 | bool cleanup = _srs_config->get_hls_cleanup(vhost); | 871 | bool cleanup = _srs_config->get_hls_cleanup(vhost); |
| 872 | + bool wait_keyframe = _srs_config->get_hls_wait_keyframe(vhost); | ||
| 865 | // the audio overflow, for pure audio to reap segment. | 873 | // the audio overflow, for pure audio to reap segment. |
| 866 | double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost); | 874 | double hls_aof_ratio = _srs_config->get_hls_aof_ratio(vhost); |
| 867 | // whether use floor(timestamp/hls_fragment) for variable timestamp | 875 | // whether use floor(timestamp/hls_fragment) for variable timestamp |
| @@ -873,7 +881,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment | @@ -873,7 +881,7 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment | ||
| 873 | // open muxer | 881 | // open muxer |
| 874 | if ((ret = muxer->update_config(req, entry_prefix, | 882 | if ((ret = muxer->update_config(req, entry_prefix, |
| 875 | path, m3u8_file, ts_file, hls_fragment, hls_window, ts_floor, hls_aof_ratio, | 883 | path, m3u8_file, ts_file, hls_fragment, hls_window, ts_floor, hls_aof_ratio, |
| 876 | - cleanup)) != ERROR_SUCCESS | 884 | + cleanup, wait_keyframe)) != ERROR_SUCCESS |
| 877 | ) { | 885 | ) { |
| 878 | srs_error("m3u8 muxer update config failed. ret=%d", ret); | 886 | srs_error("m3u8 muxer update config failed. ret=%d", ret); |
| 879 | return ret; | 887 | return ret; |
| @@ -883,9 +891,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment | @@ -883,9 +891,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment | ||
| 883 | srs_error("m3u8 muxer open segment failed. ret=%d", ret); | 891 | srs_error("m3u8 muxer open segment failed. ret=%d", ret); |
| 884 | return ret; | 892 | return ret; |
| 885 | } | 893 | } |
| 886 | - srs_trace("hls: win=%.2f, frag=%.2f, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d", | 894 | + srs_trace("hls: win=%.2f, frag=%.2f, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d, clean=%d, waitk=%d", |
| 887 | hls_window, hls_fragment, entry_prefix.c_str(), path.c_str(), m3u8_file.c_str(), | 895 | hls_window, hls_fragment, entry_prefix.c_str(), path.c_str(), m3u8_file.c_str(), |
| 888 | - ts_file.c_str(), hls_aof_ratio, ts_floor); | 896 | + ts_file.c_str(), hls_aof_ratio, ts_floor, cleanup, wait_keyframe); |
| 889 | 897 | ||
| 890 | return ret; | 898 | return ret; |
| 891 | } | 899 | } |
| @@ -972,17 +980,25 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | @@ -972,17 +980,25 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t | ||
| 972 | return ret; | 980 | return ret; |
| 973 | } | 981 | } |
| 974 | 982 | ||
| 975 | - // new segment when: | ||
| 976 | - // 1. base on gop(IDR). | ||
| 977 | - // 2. some gops duration overflow. | ||
| 978 | - if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && muxer->is_segment_overflow()) { | ||
| 979 | - if (!sample->has_idr) { | ||
| 980 | - srs_warn("hls: ts starts without IDR, first nalu=%d, idr=%d", sample->first_nalu_type, sample->has_idr); | ||
| 981 | - } | ||
| 982 | - if ((ret = reap_segment("video", muxer, cache->video->dts)) != ERROR_SUCCESS) { | 983 | + // when segment overflow, reap if possible. |
| 984 | + if (muxer->is_segment_overflow()) { | ||
| 985 | + // do reap ts if any of: | ||
| 986 | + // a. wait keyframe and got keyframe. | ||
| 987 | + // b. always reap when not wait keyframe. | ||
| 988 | + if (!muxer->wait_keyframe() || sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) { | ||
| 989 | + // when wait keyframe, there must exists idr frame in sample. | ||
| 990 | + if (!sample->has_idr && muxer->wait_keyframe()) { | ||
| 991 | + srs_warn("hls: ts starts without IDR, first nalu=%d, idr=%d", sample->first_nalu_type, sample->has_idr); | ||
| 992 | + } | ||
| 993 | + | ||
| 994 | + // reap the segment, which will also flush the video. | ||
| 995 | + if ((ret = reap_segment("video", muxer, cache->video->dts)) != ERROR_SUCCESS) { | ||
| 996 | + return ret; | ||
| 997 | + } | ||
| 998 | + | ||
| 999 | + // the video must be flushed, just return. | ||
| 983 | return ret; | 1000 | return ret; |
| 984 | } | 1001 | } |
| 985 | - return ret; | ||
| 986 | } | 1002 | } |
| 987 | 1003 | ||
| 988 | // flush video when got one | 1004 | // flush video when got one |
| @@ -207,6 +207,7 @@ private: | @@ -207,6 +207,7 @@ private: | ||
| 207 | std::string hls_path; | 207 | std::string hls_path; |
| 208 | std::string hls_ts_file; | 208 | std::string hls_ts_file; |
| 209 | bool hls_cleanup; | 209 | bool hls_cleanup; |
| 210 | + bool hls_wait_keyframe; | ||
| 210 | std::string m3u8_dir; | 211 | std::string m3u8_dir; |
| 211 | double hls_aof_ratio; | 212 | double hls_aof_ratio; |
| 212 | double hls_fragment; | 213 | double hls_fragment; |
| @@ -270,7 +271,7 @@ public: | @@ -270,7 +271,7 @@ public: | ||
| 270 | virtual int update_config(SrsRequest* r, std::string entry_prefix, | 271 | virtual int update_config(SrsRequest* r, std::string entry_prefix, |
| 271 | std::string path, std::string m3u8_file, std::string ts_file, | 272 | std::string path, std::string m3u8_file, std::string ts_file, |
| 272 | double fragment, double window, bool ts_floor, double aof_ratio, | 273 | double fragment, double window, bool ts_floor, double aof_ratio, |
| 273 | - bool cleanup); | 274 | + bool cleanup, bool wait_keyframe); |
| 274 | /** | 275 | /** |
| 275 | * open a new segment(a new ts file), | 276 | * open a new segment(a new ts file), |
| 276 | * @param segment_start_dts use to calc the segment duration, | 277 | * @param segment_start_dts use to calc the segment duration, |
| @@ -284,6 +285,10 @@ public: | @@ -284,6 +285,10 @@ public: | ||
| 284 | */ | 285 | */ |
| 285 | virtual bool is_segment_overflow(); | 286 | virtual bool is_segment_overflow(); |
| 286 | /** | 287 | /** |
| 288 | + * whether wait keyframe to reap the ts. | ||
| 289 | + */ | ||
| 290 | + virtual bool wait_keyframe(); | ||
| 291 | + /** | ||
| 287 | * whether segment absolutely overflow, for pure audio to reap segment, | 292 | * whether segment absolutely overflow, for pure audio to reap segment, |
| 288 | * that is whether the current segment duration>=2*(the segment in config) | 293 | * that is whether the current segment duration>=2*(the segment in config) |
| 289 | * @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-71155184 | 294 | * @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-71155184 |
| @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 31 | // current release version | 31 | // current release version |
| 32 | #define VERSION_MAJOR 2 | 32 | #define VERSION_MAJOR 2 |
| 33 | #define VERSION_MINOR 0 | 33 | #define VERSION_MINOR 0 |
| 34 | -#define VERSION_REVISION 159 | 34 | +#define VERSION_REVISION 160 |
| 35 | 35 | ||
| 36 | // server info. | 36 | // server info. |
| 37 | #define RTMP_SIG_SRS_KEY "SRS" | 37 | #define RTMP_SIG_SRS_KEY "SRS" |
-
请 注册 或 登录 后发表评论