Compare commits

...

8 Commits

Author SHA1 Message Date
imp_rayjay
546476ddfe
Merge 6119ac9c53 into cc590254a6 2024-10-28 13:00:01 +08:00
xiongguangjie
cc590254a6 fix compile error for ci
Some checks failed
Android / build (push) Has been cancelled
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
Linux / build (push) Has been cancelled
macOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-10-28 10:59:37 +08:00
xiongguangjie
b9a1f0d9b5 update zltoolkit fix #3979 2024-10-28 10:59:37 +08:00
xia-chu
18d5fb71f3 增强hls点播功能,每个切片文件夹生成一个m3u8索引文件
Some checks failed
Android / build (push) Has been cancelled
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
Linux / build (push) Has been cancelled
macOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-10-26 16:42:06 +08:00
sbkyy
5c80c75ed9
修复video stack相关功能bug
Some checks are pending
Android / build (push) Waiting to run
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Docker / build (push) Waiting to run
Linux / build (push) Waiting to run
macOS / build (push) Waiting to run
Windows / build (push) Waiting to run
/index/api/stack/reset 在相同url和通分辨率多次调用channel析构没画面的问题
是在 VideoStackManager::parseParams 函数里 多次 (*params)[i * cols + j] =
nullptr; 导致 channel 计数器为0,析构没画面。

同时修复cpu占用过高问题。
2024-10-26 09:20:24 +08:00
rayjay
6119ac9c53 rtp推流增加PCM音频的处理 2024-03-28 11:21:23 +08:00
rayjay
a33c1d5a08 Merge branch 'master' of https://github.com/ZLMediaKit/ZLMediaKit 2024-03-28 11:15:19 +08:00
rayjay
e7e157c312 打包mjepg rtp的时候增加支持DRI(原先只在解包的时候支持,打包的时候并不支持) 2024-02-19 11:20:06 +08:00
7 changed files with 94 additions and 24 deletions

@ -1 +1 @@
Subproject commit 08c094ea14f259ecf0c356e6243cb47ee96ce292 Subproject commit 9e319b70557f3ece0372a0d05f31a6560292556a

View File

@ -139,8 +139,8 @@ listen_ip=::
fileBufSize=65536 fileBufSize=65536
#hls最大切片时间 #hls最大切片时间
segDur=2 segDur=2
#m3u8索引中,hls保留切片个数(实际保留切片个数大2~3个) #m3u8索引中,hls保留切片个数(实际保留切片个数+segRetain个)
#如果设置为0则不删除切片,而是保存为点播 #如果设置为0则不删除切片且m3u8文件全量记录切片列表
segNum=3 segNum=3
#HLS切片延迟个数大于0将生成hls_delay.m3u8文件0则不生成 #HLS切片延迟个数大于0将生成hls_delay.m3u8文件0则不生成
segDelay=0 segDelay=0
@ -150,10 +150,8 @@ segRetain=5
broadcastRecordTs=0 broadcastRecordTs=0
#直播hls文件删除延时单位秒issue: #913 #直播hls文件删除延时单位秒issue: #913
deleteDelaySec=10 deleteDelaySec=10
#是否保留hls文件此功能部分等效于segNum=0的情况 #此选项开启后m3u8文件还是表现为直播但是切片文件会被全部保留为点播用
#不同的是这个保留不会在m3u8文件中体现 #segDur设置为0或segKeep设置为1的情况下每个切片文件夹下会生成一个vod.m3u8文件用于点播该时间段的录像
#0为不保留不起作用
#1为保留则不删除hls文件如果开启此功能注意磁盘大小或者定期手动清理hls文件
segKeep=0 segKeep=0
#如果设置为1则第一个切片长度强制设置为1个GOP。当GOP小于segDur可以提高首屏速度 #如果设置为1则第一个切片长度强制设置为1个GOP。当GOP小于segDur可以提高首屏速度
fastRegister=0 fastRegister=0

View File

@ -23,7 +23,11 @@
INSTANCE_IMP(VideoStackManager) INSTANCE_IMP(VideoStackManager)
Param::~Param() { VideoStackManager::Instance().unrefChannel(id, width, height, pixfmt); } Param::~Param() {
auto strongChn= weak_chn.lock();
if (!strongChn) { return; }
VideoStackManager::Instance().unrefChannel(id, width, height, pixfmt);
}
Channel::Channel(const std::string& id, int width, int height, AVPixelFormat pixfmt) Channel::Channel(const std::string& id, int width, int height, AVPixelFormat pixfmt)
: _id(id), _width(width), _height(height), _pixfmt(pixfmt) { : _id(id), _width(width), _height(height), _pixfmt(pixfmt) {
@ -278,6 +282,8 @@ void VideoStack::start() {
_dev->inputYUV((char**)_buffer->get()->data, _buffer->get()->linesize, pts); _dev->inputYUV((char**)_buffer->get()->data, _buffer->get()->linesize, pts);
pts += frameInterval; pts += frameInterval;
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} }
} }
}); });

View File

@ -122,9 +122,9 @@ void HlsMaker::inputData(const char *data, size_t len, uint64_t timestamp, bool
void HlsMaker::delOldSegment() { void HlsMaker::delOldSegment() {
GET_CONFIG(uint32_t, segDelay, Hls::kSegmentDelay); GET_CONFIG(uint32_t, segDelay, Hls::kSegmentDelay);
if (_seg_number == 0) { if (_seg_number == 0 || _seg_keep) {
// 如果设置为保留0个切片则认为是保存为点播 [AUTO-TRANSLATED:5bf20108] // 如果设置为保留0个切片则认为是保存为点播;或者设置为一直保存,就不删除 [AUTO-TRANSLATED:5bf20108]
// If set to keep 0 slices, it is considered to be saved as on-demand // If set to keep 0 or all slices, it is considered to be saved as on-demand
return; return;
} }
// 在hls m3u8索引文件中,我们保存的切片个数跟_seg_number相关设置一致 [AUTO-TRANSLATED:b14b5b98] // 在hls m3u8索引文件中,我们保存的切片个数跟_seg_number相关设置一致 [AUTO-TRANSLATED:b14b5b98]
@ -132,11 +132,6 @@ void HlsMaker::delOldSegment() {
if (_file_index > _seg_number + segDelay) { if (_file_index > _seg_number + segDelay) {
_seg_dur_list.pop_front(); _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); GET_CONFIG(uint32_t, segRetain, Hls::kSegmentRetain);
// 但是实际保存的切片个数比m3u8所述多若干个,这样做的目的是防止播放器在切片删除前能下载完毕 [AUTO-TRANSLATED:1688f857] // 但是实际保存的切片个数比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 // 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

View File

@ -9,6 +9,7 @@
*/ */
#include <ctime> #include <ctime>
#include <iomanip>
#include <sys/stat.h> #include <sys/stat.h>
#include "HlsMakerImp.h" #include "HlsMakerImp.h"
#include "Util/util.h" #include "Util/util.h"
@ -49,6 +50,10 @@ HlsMakerImp::~HlsMakerImp() {
} catch (std::exception &ex) { } catch (std::exception &ex) {
WarnL << ex.what(); WarnL << ex.what();
} }
if (!isLive() || isKeep()) {
saveCurrentDir();
}
} }
void HlsMakerImp::clearCache() { void HlsMakerImp::clearCache() {
@ -99,17 +104,66 @@ void HlsMakerImp::clearCache(bool immediately, bool eof) {
_segment_file_paths.clear(); _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 HlsMakerImp::onOpenSegment(uint64_t index) {
string segment_name, segment_path; string segment_name, segment_path;
{ {
auto strDate = getTimeStr("%Y-%m-%d"); auto strDate = getTimeStr("%Y-%m-%d");
auto strHour = getTimeStr("%H"); auto strHour = getTimeStr("%H");
auto strTime = getTimeStr("%M-%S"); 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; segment_path = _path_prefix + "/" + segment_name;
if (isLive()) { if (isLive()) {
// 直播
_segment_file_paths.emplace(index, segment_path); _segment_file_paths.emplace(index, segment_path);
} }
if (!isLive() || isKeep()) {
// 目录将发生变更保留ts切片时每个目录都生成一个m3u8文件
if (!_current_dir.empty() && current_dir != _current_dir) {
saveCurrentDir();
}
_current_dir = std::move(current_dir);
}
} }
_file = makeFile(segment_path, true); _file = makeFile(segment_path, true);
@ -139,13 +193,14 @@ void HlsMakerImp::onDelSegment(uint64_t index) {
} }
void HlsMakerImp::onWriteInitSegment(const char *data, size_t len) { 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"; string init_seg_path = _path_prefix + "/init.mp4";
_file = makeFile(init_seg_path); auto file = makeFile(init_seg_path);
if (file) {
if (_file) { fwrite(data, len, 1, file.get());
fwrite(data, len, 1, _file.get());
_path_init = std::move(init_seg_path); _path_init = std::move(init_seg_path);
_file = nullptr;
} else { } else {
WarnL << "Create file failed," << init_seg_path << " " << get_uv_errmsg(); WarnL << "Create file failed," << init_seg_path << " " << get_uv_errmsg();
} }
@ -178,7 +233,9 @@ void HlsMakerImp::onFlushLastSegment(uint64_t duration_ms) {
// 关闭并flush文件到磁盘 [AUTO-TRANSLATED:9798ec4d] // 关闭并flush文件到磁盘 [AUTO-TRANSLATED:9798ec4d]
// Close and flush file to disk // Close and flush file to disk
_file = nullptr; _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); GET_CONFIG(bool, broadcastRecordTs, Hls::kBroadcastRecordTs);
if (broadcastRecordTs) { if (broadcastRecordTs) {
_info.time_len = duration_ms / 1000.0f; _info.time_len = duration_ms / 1000.0f;

View File

@ -63,6 +63,7 @@ protected:
private: private:
std::shared_ptr<FILE> makeFile(const std::string &file,bool setbuf = false); std::shared_ptr<FILE> makeFile(const std::string &file,bool setbuf = false);
void clearCache(bool immediately, bool eof); void clearCache(bool immediately, bool eof);
void saveCurrentDir();
private: private:
int _buf_size; int _buf_size;
@ -71,12 +72,15 @@ private:
std::string _path_hls_delay; std::string _path_hls_delay;
std::string _path_init; std::string _path_init;
std::string _path_prefix; std::string _path_prefix;
std::string _current_dir;
std::string _current_dir_init_file;
RecordInfo _info; RecordInfo _info;
std::shared_ptr<FILE> _file; std::shared_ptr<FILE> _file;
std::shared_ptr<char> _file_buf; std::shared_ptr<char> _file_buf;
HlsMediaSource::Ptr _media_src; HlsMediaSource::Ptr _media_src;
toolkit::EventPoller::Ptr _poller; toolkit::EventPoller::Ptr _poller;
std::map<uint64_t/*index*/,std::string/*file_path*/> _segment_file_paths; std::map<uint64_t/*index*/,std::string/*file_path*/> _segment_file_paths;
std::deque<std::tuple<int,std::string> > _current_dir_seg_list;
}; };
}//namespace mediakit }//namespace mediakit

View File

@ -105,6 +105,16 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) {
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId()); _rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
break; break;
} }
case Rtsp::PT_L16_Mono: {
//L16
ref = std::make_shared<RtpReceiverImp>(16000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
auto track = Factory::getTrackByCodecId(CodecL16, 16000, 1, 16);
CHECK(track);
track->setIndex(pt);
_interface->addTrack(track);
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
break;
}
default: { default: {
if (pt == opus_pt) { if (pt == opus_pt) {
// opus负载 [AUTO-TRANSLATED:defa6a8d] // opus负载 [AUTO-TRANSLATED:defa6a8d]