diff --git a/api/include/mk_events_objects.h b/api/include/mk_events_objects.h index bdcca23c..2aba7ada 100644 --- a/api/include/mk_events_objects.h +++ b/api/include/mk_events_objects.h @@ -19,25 +19,25 @@ extern "C" { ///////////////////////////////////////////MP4Info///////////////////////////////////////////// //MP4Info对象的C映射 typedef void* mk_mp4_info; -//MP4Info::ui64StartedTime +// GMT 标准时间,单位秒 API_EXPORT uint64_t API_CALL mk_mp4_info_get_start_time(const mk_mp4_info ctx); -//MP4Info::ui64TimeLen -API_EXPORT uint64_t API_CALL mk_mp4_info_get_time_len(const mk_mp4_info ctx); -//MP4Info::ui64FileSize +// 录像长度,单位秒 +API_EXPORT float API_CALL mk_mp4_info_get_time_len(const mk_mp4_info ctx); +// 文件大小,单位 BYTE API_EXPORT uint64_t API_CALL mk_mp4_info_get_file_size(const mk_mp4_info ctx); -//MP4Info::strFilePath +// 文件路径 API_EXPORT const char* API_CALL mk_mp4_info_get_file_path(const mk_mp4_info ctx); -//MP4Info::strFileName +// 文件名称 API_EXPORT const char* API_CALL mk_mp4_info_get_file_name(const mk_mp4_info ctx); -//MP4Info::strFolder +// 文件夹路径 API_EXPORT const char* API_CALL mk_mp4_info_get_folder(const mk_mp4_info ctx); -//MP4Info::strUrl +// 播放路径 API_EXPORT const char* API_CALL mk_mp4_info_get_url(const mk_mp4_info ctx); -//MP4Info::strVhost +// 应用名称 API_EXPORT const char* API_CALL mk_mp4_info_get_vhost(const mk_mp4_info ctx); -//MP4Info::strAppName +// 流 ID API_EXPORT const char* API_CALL mk_mp4_info_get_app(const mk_mp4_info ctx); -//MP4Info::strStreamId +// 虚拟主机 API_EXPORT const char* API_CALL mk_mp4_info_get_stream(const mk_mp4_info ctx); ///////////////////////////////////////////Parser///////////////////////////////////////////// diff --git a/api/source/mk_events_objects.cpp b/api/source/mk_events_objects.cpp index 85f0c9df..d078845b 100644 --- a/api/source/mk_events_objects.cpp +++ b/api/source/mk_events_objects.cpp @@ -22,61 +22,61 @@ using namespace mediakit; API_EXPORT uint64_t API_CALL mk_mp4_info_get_start_time(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->ui64StartedTime; + return info->start_time; } -API_EXPORT uint64_t API_CALL mk_mp4_info_get_time_len(const mk_mp4_info ctx){ +API_EXPORT float API_CALL mk_mp4_info_get_time_len(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->ui64TimeLen; + return info->time_len; } API_EXPORT uint64_t API_CALL mk_mp4_info_get_file_size(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->ui64FileSize; + return info->file_size; } API_EXPORT const char* API_CALL mk_mp4_info_get_file_path(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->strFilePath.c_str(); + return info->file_path.c_str(); } API_EXPORT const char* API_CALL mk_mp4_info_get_file_name(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->strFileName.c_str(); + return info->file_name.c_str(); } API_EXPORT const char* API_CALL mk_mp4_info_get_folder(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->strFolder.c_str(); + return info->folder.c_str(); } API_EXPORT const char* API_CALL mk_mp4_info_get_url(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->strUrl.c_str(); + return info->url.c_str(); } API_EXPORT const char* API_CALL mk_mp4_info_get_vhost(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->strVhost.c_str(); + return info->vhost.c_str(); } API_EXPORT const char* API_CALL mk_mp4_info_get_app(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->strAppName.c_str(); + return info->app.c_str(); } API_EXPORT const char* API_CALL mk_mp4_info_get_stream(const mk_mp4_info ctx){ assert(ctx); RecordInfo *info = (RecordInfo *)ctx; - return info->strStreamId.c_str(); + return info->stream.c_str(); } ///////////////////////////////////////////Parser///////////////////////////////////////////// diff --git a/server/WebHook.cpp b/server/WebHook.cpp index 64c084e0..f195fff3 100644 --- a/server/WebHook.cpp +++ b/server/WebHook.cpp @@ -342,25 +342,29 @@ void installWebHook(){ do_http_hook(hook_stream_not_found,body, nullptr); }); + static auto getRecordInfo = [](const RecordInfo &info) { + ArgsType body; + body["start_time"] = (Json::UInt64) info.start_time; + body["file_size"] = (Json::UInt64) info.file_size; + body["time_len"] = info.time_len; + body["file_path"] = info.file_path; + body["file_name"] = info.file_name; + body["folder"] = info.folder; + body["url"] = info.url; + body["app"] = info.app; + body["stream"] = info.stream; + body["vhost"] = info.vhost; + return body; + }; + #ifdef ENABLE_MP4 //录制mp4文件成功后广播 NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastRecordMP4,[](BroadcastRecordMP4Args){ - if(!hook_enable || hook_record_mp4.empty()){ + if (!hook_enable || hook_record_mp4.empty()) { return; } - ArgsType body; - body["start_time"] = (Json::UInt64)info.ui64StartedTime; - body["time_len"] = (Json::UInt64)info.ui64TimeLen; - body["file_size"] = (Json::UInt64)info.ui64FileSize; - body["file_path"] = info.strFilePath; - body["file_name"] = info.strFileName; - body["folder"] = info.strFolder; - body["url"] = info.strUrl; - body["app"] = info.strAppName; - body["stream"] = info.strStreamId; - body["vhost"] = info.strVhost; //执行hook - do_http_hook(hook_record_mp4,body, nullptr); + do_http_hook(hook_record_mp4, getRecordInfo(info), nullptr); }); #endif //ENABLE_MP4 @@ -368,19 +372,8 @@ void installWebHook(){ if (!hook_enable || hook_record_ts.empty()) { return; } - ArgsType body; - body["start_time"] = (Json::UInt64)info.ui64StartedTime; - body["time_len"] = (Json::UInt64)info.ui64TimeLen; - body["file_size"] = (Json::UInt64)info.ui64FileSize; - body["file_path"] = info.strFilePath; - body["file_name"] = info.strFileName; - body["folder"] = info.strFolder; - body["url"] = info.strUrl; - body["app"] = info.strAppName; - body["stream"] = info.strStreamId; - body["vhost"] = info.strVhost; // 执行 hook - do_http_hook(hook_record_ts, body, nullptr); + do_http_hook(hook_record_ts, getRecordInfo(info), nullptr); }); NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastShellLogin,[](BroadcastShellLoginArgs){ @@ -421,7 +414,6 @@ void installWebHook(){ } strongSrc->close(false); }); - }); /** diff --git a/src/Record/HlsMaker.cpp b/src/Record/HlsMaker.cpp index 26f93e45..a91b3e05 100644 --- a/src/Record/HlsMaker.cpp +++ b/src/Record/HlsMaker.cpp @@ -118,16 +118,12 @@ void HlsMaker::flushLastSegment(bool eof){ seg_dur = 100; } _seg_dur_list.push_back(std::make_tuple(seg_dur, std::move(_last_file_name))); + _last_file_name.clear(); delOldSegment(); makeIndexFile(eof); - _last_file_name.clear(); - onFlushLastSegment(seg_dur); } -void HlsMaker::onFlushLastSegment(uint32_t) { -} - bool HlsMaker::isLive() { return _seg_number != 0; } diff --git a/src/Record/HlsMaker.h b/src/Record/HlsMaker.h index 72be5a88..7eff8e10 100644 --- a/src/Record/HlsMaker.h +++ b/src/Record/HlsMaker.h @@ -22,20 +22,6 @@ using namespace toolkit; namespace mediakit { -class TsInfo { -public: - time_t ui64StartedTime; // GMT 标准时间,单位秒 - time_t ui64TimeLen; // 录像长度,单位毫秒 - off_t ui64FileSize; // 文件大小,单位 BYTE - string strFilePath; // 文件路径 - string strFileName; // 文件名称 - string strFolder; // 文件夹路径 - string strUrl; // 播放路径 - string strAppName; // 应用名称 - string strStreamId; // 流 ID - string strVhost; // vhost -}; - class HlsMaker { public: /** @@ -92,18 +78,18 @@ protected: */ virtual void onWriteHls(const char *data, int len) = 0; + /** + * 上一个 ts 切片写入完成, 可在这里进行通知处理 + * @param duration_ms 上一个 ts 切片的时长, 单位为毫秒 + */ + virtual void onFlushLastSegment(uint32_t duration_ms) {}; + /** * 关闭上个ts切片并且写入m3u8索引 * @param eof HLS直播是否已结束 */ void flushLastSegment(bool eof); - /** - * 上一个 ts 切片写入完成, 可在这里进行通知处理 - * @param duration 上一个 ts 切片的时长, 单位为毫秒 - */ - virtual void onFlushLastSegment(uint32_t duration); - private: /** * 生成m3u8文件 diff --git a/src/Record/HlsMakerImp.cpp b/src/Record/HlsMakerImp.cpp index e20658d5..93959c1b 100644 --- a/src/Record/HlsMakerImp.cpp +++ b/src/Record/HlsMakerImp.cpp @@ -11,7 +11,6 @@ #include #include #include "HlsMakerImp.h" -#include "Thread/WorkThreadPool.h" #include "Util/util.h" #include "Util/uv_errno.h" @@ -32,7 +31,7 @@ HlsMakerImp::HlsMakerImp(const string &m3u8_file, delete[] ptr; }); - _info.strFolder = _path_prefix; + _info.folder = _path_prefix; } HlsMakerImp::~HlsMakerImp() { @@ -65,10 +64,11 @@ string HlsMakerImp::onOpenSegment(int index) { } _file = makeFile(segment_path, true); - _info.ui64StartedTime = ::time(NULL); - _info.strFileName = segment_name; - _info.strFilePath = segment_path; - _info.strUrl = _info.strAppName + "/" + _info.strStreamId + "/" + segment_name; + //保存本切片的元数据 + _info.start_time = ::time(NULL); + _info.file_name = segment_name; + _info.file_path = segment_path; + _info.url = _info.app + "/" + _info.stream + "/" + segment_name; if (!_file) { WarnL << "create file failed," << segment_path << " " << get_uv_errmsg(); @@ -108,22 +108,19 @@ void HlsMakerImp::onWriteHls(const char *data, int len) { //DebugL << "\r\n" << string(data,len); } -void HlsMakerImp::onFlushLastSegment(uint32_t duration) { +void HlsMakerImp::onFlushLastSegment(uint32_t duration_ms) { GET_CONFIG(bool, broadcastRecordTs, Hls::kBroadcastRecordTs); - if (broadcastRecordTs) { - auto info = _info; - info.ui64TimeLen = duration; - WorkThreadPool::Instance().getExecutor()->async([info]() { - struct stat fileData; - stat(info.strFilePath.data(), &fileData); - const_cast(info).ui64FileSize = fileData.st_size; - NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordTs, info); - }); + //关闭ts文件以便获取正确的文件大小 + _file = nullptr; + _info.time_len = duration_ms / 1000.0; + struct stat fileData; + stat(_info.file_path.data(), &fileData); + _info.file_size = fileData.st_size; + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordTs, _info); } } - std::shared_ptr HlsMakerImp::makeFile(const string &file, bool setbuf) { auto file_buf = _file_buf; auto ret = shared_ptr(File::create_file(file.data(), "wb"), [file_buf](FILE *fp) { @@ -139,9 +136,9 @@ std::shared_ptr HlsMakerImp::makeFile(const string &file, bool setbuf) { void HlsMakerImp::setMediaSource(const string &vhost, const string &app, const string &stream_id) { _media_src = std::make_shared(vhost, app, stream_id); - _info.strAppName = app; - _info.strStreamId = stream_id; - _info.strVhost = vhost; + _info.app = app; + _info.stream = stream_id; + _info.vhost = vhost; } HlsMediaSource::Ptr HlsMakerImp::getMediaSource() const { diff --git a/src/Record/HlsMakerImp.h b/src/Record/HlsMakerImp.h index cc0b3d31..155909b7 100644 --- a/src/Record/HlsMakerImp.h +++ b/src/Record/HlsMakerImp.h @@ -16,7 +16,6 @@ #include #include "HlsMaker.h" #include "HlsMediaSource.h" -#include "RecordInfo.h" using namespace std; @@ -56,7 +55,7 @@ protected: void onDelSegment(int index) override; void onWriteSegment(const char *data, int len) override; void onWriteHls(const char *data, int len) override; - void onFlushLastSegment(uint32_t duration) override; + void onFlushLastSegment(uint32_t duration_ms) override; private: std::shared_ptr makeFile(const string &file,bool setbuf = false); @@ -66,10 +65,10 @@ private: string _params; string _path_hls; string _path_prefix; + RecordInfo _info; std::shared_ptr _file; std::shared_ptr _file_buf; HlsMediaSource::Ptr _media_src; - RecordInfo _info; map _segment_file_paths; }; diff --git a/src/Record/MP4Recorder.cpp b/src/Record/MP4Recorder.cpp index a8118333..00268052 100644 --- a/src/Record/MP4Recorder.cpp +++ b/src/Record/MP4Recorder.cpp @@ -25,10 +25,10 @@ MP4Recorder::MP4Recorder(const string& strPath, const string &strStreamId) { _strPath = strPath; /////record 业务逻辑////// - _info.strAppName = strApp; - _info.strStreamId = strStreamId; - _info.strVhost = strVhost; - _info.strFolder = strPath; + _info.app = strApp; + _info.stream = strStreamId; + _info.vhost = strVhost; + _info.folder = strPath; } MP4Recorder::~MP4Recorder() { closeFile(); @@ -42,15 +42,15 @@ void MP4Recorder::createFile() { auto strFile = _strPath + strDate + "/" + strTime + ".mp4"; /////record 业务逻辑////// - _info.ui64StartedTime = ::time(NULL); - _info.strFileName = strTime + ".mp4"; - _info.strFilePath = strFile; + _info.start_time = ::time(NULL); + _info.file_name = strTime + ".mp4"; + _info.file_path = strFile; GET_CONFIG(string,appName,Record::kAppName); - _info.strUrl = appName + "/" - + _info.strAppName + "/" - + _info.strStreamId + "/" - + strDate + "/" - + strTime + ".mp4"; + _info.url = appName + "/" + + _info.app + "/" + + _info.stream + "/" + + strDate + "/" + + strTime + ".mp4"; try { _muxer = std::make_shared(strFileTmp.data()); @@ -73,7 +73,7 @@ void MP4Recorder::asyncClose() { auto info = _info; WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() { //获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间 - const_cast(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime; + const_cast(info).time_len = ::time(NULL) - info.start_time; //关闭mp4非常耗时,所以要放在后台线程执行 muxer->closeMP4(); //临时文件名改成正式文件名,防止mp4未完成时被访问 @@ -81,7 +81,7 @@ void MP4Recorder::asyncClose() { //获取文件大小 struct stat fileData; stat(strFile.data(), &fileData); - const_cast(info).ui64FileSize = fileData.st_size; + const_cast(info).file_size = fileData.st_size; /////record 业务逻辑////// NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info); }); diff --git a/src/Record/MP4Recorder.h b/src/Record/MP4Recorder.h index cc73363d..0270ea62 100644 --- a/src/Record/MP4Recorder.h +++ b/src/Record/MP4Recorder.h @@ -20,7 +20,6 @@ #include "Util/TimeTicker.h" #include "Common/MediaSink.h" #include "MP4Muxer.h" -#include "RecordInfo.h" using namespace toolkit; diff --git a/src/Record/RecordInfo.h b/src/Record/RecordInfo.h deleted file mode 100644 index 30184a6a..00000000 --- a/src/Record/RecordInfo.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2020 The ZLMediaKit project authors. All Rights Reserved. - * - * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit). - * - * Use of this source code is governed by MIT license that can be found in the - * LICENSE file in the root of the source tree. All contributing project authors - * may be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef RECORDINFO_H_ -#define RECORDINFO_H_ - -#include "Common/config.h" - -namespace mediakit { - -class RecordInfo { -public: - time_t ui64StartedTime; // GMT 标准时间,单位秒 - time_t ui64TimeLen; // 录像长度,需要注意 mp4 单位是秒,而 hls ts 单位是毫秒 - off_t ui64FileSize; // 文件大小,单位 BYTE - string strFilePath; // 文件路径 - string strFileName; // 文件名称 - string strFolder; // 文件夹路径 - string strUrl; // 播放路径 - string strAppName; // 应用名称 - string strStreamId; // 流 ID - string strVhost; // vhost -}; - -} // namespace mediakit - -#endif // RECORDINFO_H_ diff --git a/src/Record/Recorder.h b/src/Record/Recorder.h index 670de9f8..fa6e2ac7 100644 --- a/src/Record/Recorder.h +++ b/src/Record/Recorder.h @@ -16,6 +16,20 @@ using namespace std; namespace mediakit { class MediaSinkInterface; +class RecordInfo { +public: + time_t start_time; // GMT 标准时间,单位秒 + float time_len; // 录像长度,单位秒 + off_t file_size; // 文件大小,单位 BYTE + string file_path; // 文件路径 + string file_name; // 文件名称 + string folder; // 文件夹路径 + string url; // 播放路径 + string app; // 应用名称 + string stream; // 流 ID + string vhost; // 虚拟主机 +}; + class Recorder{ public: typedef enum {