From 30c6f975f1fb2c93613bd2ff8d68726d6fb7d161 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Sat, 26 Oct 2024 14:26:39 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=A2=9E=E5=BC=BAhls=E7=82=B9=E6=92=AD?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=AF=8F=E4=B8=AA=E5=88=87=E7=89=87?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=E7=94=9F=E6=88=90=E4=B8=80=E4=B8=AA?= =?UTF-8?q?m3u8=E7=B4=A2=E5=BC=95=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/config.ini | 10 +++---- src/Record/HlsMaker.cpp | 11 ++----- src/Record/HlsMakerImp.cpp | 60 +++++++++++++++++++++++++++++++++----- src/Record/HlsMakerImp.h | 3 ++ 4 files changed, 63 insertions(+), 21 deletions(-) diff --git a/conf/config.ini b/conf/config.ini index ea241a6a..a46739dd 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -139,8 +139,8 @@ listen_ip=:: fileBufSize=65536 #hls最大切片时间 segDur=2 -#m3u8索引中,hls保留切片个数(实际保留切片个数大2~3个) -#如果设置为0,则不删除切片,而是保存为点播 +#m3u8索引中,hls保留切片个数(实际保留切片个数+segRetain个) +#如果设置为0,则不删除切片且m3u8文件全量记录切片列表 segNum=3 #HLS切片延迟个数,大于0将生成hls_delay.m3u8文件,0则不生成 segDelay=0 @@ -150,10 +150,8 @@ segRetain=5 broadcastRecordTs=0 #直播hls文件删除延时,单位秒,issue: #913 deleteDelaySec=10 -#是否保留hls文件,此功能部分等效于segNum=0的情况 -#不同的是这个保留不会在m3u8文件中体现 -#0为不保留,不起作用 -#1为保留,则不删除hls文件,如果开启此功能,注意磁盘大小,或者定期手动清理hls文件 +#此选项开启后m3u8文件还是表现为直播,但是切片文件会被全部保留为点播用 +#segDur设置为0或segKeep设置为1的情况下,每个切片文件夹下会生成一个vod.m3u8文件用于点播该时间段的录像 segKeep=0 #如果设置为1,则第一个切片长度强制设置为1个GOP。当GOP小于segDur,可以提高首屏速度 fastRegister=0 diff --git a/src/Record/HlsMaker.cpp b/src/Record/HlsMaker.cpp index b26d3bcb..9905b4be 100644 --- a/src/Record/HlsMaker.cpp +++ b/src/Record/HlsMaker.cpp @@ -122,9 +122,9 @@ void HlsMaker::inputData(const char *data, size_t len, uint64_t timestamp, bool void HlsMaker::delOldSegment() { GET_CONFIG(uint32_t, segDelay, Hls::kSegmentDelay); - if (_seg_number == 0) { - // 如果设置为保留0个切片,则认为是保存为点播 [AUTO-TRANSLATED:5bf20108] - // If set to keep 0 slices, it is considered to be saved as on-demand + if (_seg_number == 0 || _seg_keep) { + // 如果设置为保留0个切片,则认为是保存为点播;或者设置为一直保存,就不删除 [AUTO-TRANSLATED:5bf20108] + // If set to keep 0 or all slices, it is considered to be saved as on-demand return; } // 在hls m3u8索引文件中,我们保存的切片个数跟_seg_number相关设置一致 [AUTO-TRANSLATED:b14b5b98] @@ -132,11 +132,6 @@ void HlsMaker::delOldSegment() { if (_file_index > _seg_number + segDelay) { _seg_dur_list.pop_front(); } - // 如果设置为一直保存,就不删除 [AUTO-TRANSLATED:7c622e24] - // If set to always save, it will not be deleted - if (_seg_keep) { - return; - } GET_CONFIG(uint32_t, segRetain, Hls::kSegmentRetain); // 但是实际保存的切片个数比m3u8所述多若干个,这样做的目的是防止播放器在切片删除前能下载完毕 [AUTO-TRANSLATED:1688f857] // However, the actual number of slices saved is a few more than what is stated in the m3u8, this is done to prevent the player from downloading the slices before they are deleted diff --git a/src/Record/HlsMakerImp.cpp b/src/Record/HlsMakerImp.cpp index 002902f4..e76e8e1d 100644 --- a/src/Record/HlsMakerImp.cpp +++ b/src/Record/HlsMakerImp.cpp @@ -105,11 +105,54 @@ string HlsMakerImp::onOpenSegment(uint64_t index) { auto strDate = getTimeStr("%Y-%m-%d"); auto strHour = getTimeStr("%H"); auto strTime = getTimeStr("%M-%S"); - segment_name = StrPrinter << strDate + "/" + strHour + "/" + strTime << "_" << index << (isFmp4() ? ".mp4" : ".ts"); + auto current_dir = strDate + "/" + strHour + "/"; + segment_name = current_dir + strTime + "_" + std::to_string(index) + (isFmp4() ? ".mp4" : ".ts"); segment_path = _path_prefix + "/" + segment_name; if (isLive()) { + // 直播 _segment_file_paths.emplace(index, segment_path); } + if (!isLive() || isKeep()) { + // 目录将发生变更,保留ts切片时,每个目录都生成一个m3u8文件 + if (!_current_dir.empty() && current_dir != _current_dir) { + /** 写入该目录的init.mp4文件以及m3u8文件 **/ + + if (isFmp4()) { + // 写入init.mp4文件 + File::saveFile(_current_dir_init_file, _path_prefix + "/" + _current_dir + "init.mp4"); + } + + int maxSegmentDuration = 0; + for (auto &tp : _current_dir_seg_list) { + int dur = std::get<0>(tp); + if (dur > maxSegmentDuration) { + maxSegmentDuration = dur; + } + } + + string index_str; + index_str.reserve(2048); + index_str += "#EXTM3U\n"; + index_str += (isFmp4() ? "#EXT-X-VERSION:7\n" : "#EXT-X-VERSION:4\n"); + index_str += "#EXT-X-ALLOW-CACHE:YES\n"; + index_str += "#EXT-X-TARGETDURATION:" + std::to_string((maxSegmentDuration + 999) / 1000) + "\n"; + index_str += "#EXT-X-MEDIA-SEQUENCE:0\n"; + if (isFmp4()) { + index_str += "#EXT-X-MAP:URI=\"init.mp4\"\n"; + } + stringstream ss; + for (auto &t : _current_dir_seg_list) { + ss << "#EXTINF:" << std::setprecision(3) << std::get<0>(t) / 1000.0 << ",\n" << std::get<1>(t) << "\n"; + } + _current_dir_seg_list.clear(); + index_str += ss.str(); + index_str += "#EXT-X-ENDLIST\n"; + + /** 写入该目录的m3u8文件 **/ + File::saveFile(index_str, _path_prefix + "/" + _current_dir + (isFmp4() ? "vod.fmp4.m3u8" : "vod.m3u8")); + } + _current_dir = std::move(current_dir); + } } _file = makeFile(segment_path, true); @@ -139,13 +182,14 @@ void HlsMakerImp::onDelSegment(uint64_t index) { } void HlsMakerImp::onWriteInitSegment(const char *data, size_t len) { + if (!isLive() || isKeep()) { + _current_dir_init_file.assign(data, len); + } string init_seg_path = _path_prefix + "/init.mp4"; - _file = makeFile(init_seg_path); - - if (_file) { - fwrite(data, len, 1, _file.get()); + auto file = makeFile(init_seg_path); + if (file) { + fwrite(data, len, 1, file.get()); _path_init = std::move(init_seg_path); - _file = nullptr; } else { WarnL << "Create file failed," << init_seg_path << " " << get_uv_errmsg(); } @@ -178,7 +222,9 @@ void HlsMakerImp::onFlushLastSegment(uint64_t duration_ms) { // 关闭并flush文件到磁盘 [AUTO-TRANSLATED:9798ec4d] // Close and flush file to disk _file = nullptr; - + if (!isLive() || isKeep()) { + _current_dir_seg_list.emplace_back(duration_ms, _info.file_name.erase(0, _current_dir.size())); + } GET_CONFIG(bool, broadcastRecordTs, Hls::kBroadcastRecordTs); if (broadcastRecordTs) { _info.time_len = duration_ms / 1000.0f; diff --git a/src/Record/HlsMakerImp.h b/src/Record/HlsMakerImp.h index e82be46b..995d5163 100644 --- a/src/Record/HlsMakerImp.h +++ b/src/Record/HlsMakerImp.h @@ -71,12 +71,15 @@ private: std::string _path_hls_delay; std::string _path_init; std::string _path_prefix; + std::string _current_dir; + std::string _current_dir_init_file; RecordInfo _info; std::shared_ptr _file; std::shared_ptr _file_buf; HlsMediaSource::Ptr _media_src; toolkit::EventPoller::Ptr _poller; std::map _segment_file_paths; + std::deque > _current_dir_seg_list; }; }//namespace mediakit From 34dbbab4bbe90c3440d7756c29717e83f5459bf1 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Sat, 26 Oct 2024 16:37:04 +0800 Subject: [PATCH 2/3] =?UTF-8?q?hls=E5=BC=80=E5=90=AF=E7=82=B9=E6=92=AD?= =?UTF-8?q?=E5=90=8E=EF=BC=8C=E7=A1=AE=E4=BF=9D=E5=AA=92=E4=BD=93=E6=B3=A8?= =?UTF-8?q?=E9=94=80=E6=97=B6=E5=86=99=E5=85=A5m3u8=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E8=87=B3=E5=BD=93=E5=89=8D=E6=96=87=E4=BB=B6=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Record/HlsMakerImp.cpp | 82 +++++++++++++++++++++----------------- src/Record/HlsMakerImp.h | 1 + 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/src/Record/HlsMakerImp.cpp b/src/Record/HlsMakerImp.cpp index e76e8e1d..670b223c 100644 --- a/src/Record/HlsMakerImp.cpp +++ b/src/Record/HlsMakerImp.cpp @@ -49,6 +49,10 @@ HlsMakerImp::~HlsMakerImp() { } catch (std::exception &ex) { WarnL << ex.what(); } + + if (!isLive() || isKeep()) { + saveCurrentDir(); + } } void HlsMakerImp::clearCache() { @@ -99,11 +103,51 @@ void HlsMakerImp::clearCache(bool immediately, bool eof) { _segment_file_paths.clear(); } +/** 写入该目录的init.mp4文件以及m3u8文件 **/ +void HlsMakerImp::saveCurrentDir() { + if (_current_dir.empty() || _current_dir_seg_list.empty()) { + return; + } + if (isFmp4()) { + // 写入init.mp4文件 + File::saveFile(_current_dir_init_file, _path_prefix + "/" + _current_dir + "init.mp4"); + } + + int maxSegmentDuration = 0; + for (auto &tp : _current_dir_seg_list) { + int dur = std::get<0>(tp); + if (dur > maxSegmentDuration) { + maxSegmentDuration = dur; + } + } + + string index_str; + index_str.reserve(2048); + index_str += "#EXTM3U\n"; + index_str += (isFmp4() ? "#EXT-X-VERSION:7\n" : "#EXT-X-VERSION:4\n"); + index_str += "#EXT-X-ALLOW-CACHE:YES\n"; + index_str += "#EXT-X-TARGETDURATION:" + std::to_string((maxSegmentDuration + 999) / 1000) + "\n"; + index_str += "#EXT-X-MEDIA-SEQUENCE:0\n"; + if (isFmp4()) { + index_str += "#EXT-X-MAP:URI=\"init.mp4\"\n"; + } + stringstream ss; + for (auto &t : _current_dir_seg_list) { + ss << "#EXTINF:" << std::setprecision(3) << std::get<0>(t) / 1000.0 << ",\n" << std::get<1>(t) << "\n"; + } + _current_dir_seg_list.clear(); + index_str += ss.str(); + index_str += "#EXT-X-ENDLIST\n"; + + /** 写入该目录的m3u8文件 **/ + File::saveFile(index_str, _path_prefix + "/" + _current_dir + (isFmp4() ? "vod.fmp4.m3u8" : "vod.m3u8")); +} + string HlsMakerImp::onOpenSegment(uint64_t index) { string segment_name, segment_path; { auto strDate = getTimeStr("%Y-%m-%d"); - auto strHour = getTimeStr("%H"); + auto strHour = getTimeStr("%H/%M"); auto strTime = getTimeStr("%M-%S"); auto current_dir = strDate + "/" + strHour + "/"; segment_name = current_dir + strTime + "_" + std::to_string(index) + (isFmp4() ? ".mp4" : ".ts"); @@ -115,41 +159,7 @@ string HlsMakerImp::onOpenSegment(uint64_t index) { if (!isLive() || isKeep()) { // 目录将发生变更,保留ts切片时,每个目录都生成一个m3u8文件 if (!_current_dir.empty() && current_dir != _current_dir) { - /** 写入该目录的init.mp4文件以及m3u8文件 **/ - - if (isFmp4()) { - // 写入init.mp4文件 - File::saveFile(_current_dir_init_file, _path_prefix + "/" + _current_dir + "init.mp4"); - } - - int maxSegmentDuration = 0; - for (auto &tp : _current_dir_seg_list) { - int dur = std::get<0>(tp); - if (dur > maxSegmentDuration) { - maxSegmentDuration = dur; - } - } - - string index_str; - index_str.reserve(2048); - index_str += "#EXTM3U\n"; - index_str += (isFmp4() ? "#EXT-X-VERSION:7\n" : "#EXT-X-VERSION:4\n"); - index_str += "#EXT-X-ALLOW-CACHE:YES\n"; - index_str += "#EXT-X-TARGETDURATION:" + std::to_string((maxSegmentDuration + 999) / 1000) + "\n"; - index_str += "#EXT-X-MEDIA-SEQUENCE:0\n"; - if (isFmp4()) { - index_str += "#EXT-X-MAP:URI=\"init.mp4\"\n"; - } - stringstream ss; - for (auto &t : _current_dir_seg_list) { - ss << "#EXTINF:" << std::setprecision(3) << std::get<0>(t) / 1000.0 << ",\n" << std::get<1>(t) << "\n"; - } - _current_dir_seg_list.clear(); - index_str += ss.str(); - index_str += "#EXT-X-ENDLIST\n"; - - /** 写入该目录的m3u8文件 **/ - File::saveFile(index_str, _path_prefix + "/" + _current_dir + (isFmp4() ? "vod.fmp4.m3u8" : "vod.m3u8")); + saveCurrentDir(); } _current_dir = std::move(current_dir); } diff --git a/src/Record/HlsMakerImp.h b/src/Record/HlsMakerImp.h index 995d5163..aa1b9efe 100644 --- a/src/Record/HlsMakerImp.h +++ b/src/Record/HlsMakerImp.h @@ -63,6 +63,7 @@ protected: private: std::shared_ptr makeFile(const std::string &file,bool setbuf = false); void clearCache(bool immediately, bool eof); + void saveCurrentDir(); private: int _buf_size; From 610ac62e905058cdd9e821cee423a7c65af44cbd Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 28 Oct 2024 11:01:24 +0800 Subject: [PATCH 3/3] Translate comments in src/Record/HlsMakerImp.cpp --- src/Record/HlsMakerImp.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Record/HlsMakerImp.cpp b/src/Record/HlsMakerImp.cpp index 2ee2e961..eab84367 100644 --- a/src/Record/HlsMakerImp.cpp +++ b/src/Record/HlsMakerImp.cpp @@ -104,13 +104,17 @@ void HlsMakerImp::clearCache(bool immediately, bool eof) { _segment_file_paths.clear(); } -/** 写入该目录的init.mp4文件以及m3u8文件 **/ +/** 写入该目录的init.mp4文件以及m3u8文件 * + /** Write the init.mp4 file and m3u8 file to this directory * + * [AUTO-TRANSLATED:ef690a98] + */ void HlsMakerImp::saveCurrentDir() { if (_current_dir.empty() || _current_dir_seg_list.empty()) { return; } if (isFmp4()) { - // 写入init.mp4文件 + // 写入init.mp4文件 [AUTO-TRANSLATED:cc6d6776] + // Write the init.mp4 file File::saveFile(_current_dir_init_file, _path_prefix + "/" + _current_dir + "init.mp4"); } @@ -140,7 +144,10 @@ void HlsMakerImp::saveCurrentDir() { index_str += ss.str(); index_str += "#EXT-X-ENDLIST\n"; - /** 写入该目录的m3u8文件 **/ + /** 写入该目录的m3u8文件 * + /** Write the m3u8 file to this directory * + * [AUTO-TRANSLATED:5350a9d3] + */ File::saveFile(index_str, _path_prefix + "/" + _current_dir + (isFmp4() ? "vod.fmp4.m3u8" : "vod.m3u8")); } @@ -148,17 +155,19 @@ string HlsMakerImp::onOpenSegment(uint64_t index) { string segment_name, segment_path; { auto strDate = getTimeStr("%Y-%m-%d"); - auto strHour = getTimeStr("%H/%M"); + auto strHour = getTimeStr("%H"); auto strTime = getTimeStr("%M-%S"); auto current_dir = strDate + "/" + strHour + "/"; segment_name = current_dir + strTime + "_" + std::to_string(index) + (isFmp4() ? ".mp4" : ".ts"); segment_path = _path_prefix + "/" + segment_name; if (isLive()) { - // 直播 + // 直播 [AUTO-TRANSLATED:079c0cbc] + // Live broadcast _segment_file_paths.emplace(index, segment_path); } if (!isLive() || isKeep()) { - // 目录将发生变更,保留ts切片时,每个目录都生成一个m3u8文件 + // 目录将发生变更,保留ts切片时,每个目录都生成一个m3u8文件 [AUTO-TRANSLATED:8bd19092] + // The directory will change, when keeping the ts slices, an m3u8 file is generated for each directory if (!_current_dir.empty() && current_dir != _current_dir) { saveCurrentDir(); }