mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-21 01:13:37 +08:00
合并pr(添加录制ts完成通知): #479
This commit is contained in:
parent
0fce108de5
commit
f84981dc75
@ -19,25 +19,25 @@ extern "C" {
|
|||||||
///////////////////////////////////////////MP4Info/////////////////////////////////////////////
|
///////////////////////////////////////////MP4Info/////////////////////////////////////////////
|
||||||
//MP4Info对象的C映射
|
//MP4Info对象的C映射
|
||||||
typedef void* mk_mp4_info;
|
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);
|
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);
|
API_EXPORT float API_CALL mk_mp4_info_get_time_len(const mk_mp4_info ctx);
|
||||||
//MP4Info::ui64FileSize
|
// 文件大小,单位 BYTE
|
||||||
API_EXPORT uint64_t API_CALL mk_mp4_info_get_file_size(const mk_mp4_info ctx);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
API_EXPORT const char* API_CALL mk_mp4_info_get_stream(const mk_mp4_info ctx);
|
||||||
|
|
||||||
///////////////////////////////////////////Parser/////////////////////////////////////////////
|
///////////////////////////////////////////Parser/////////////////////////////////////////////
|
||||||
|
@ -22,61 +22,61 @@ using namespace mediakit;
|
|||||||
API_EXPORT uint64_t API_CALL mk_mp4_info_get_start_time(const mk_mp4_info ctx){
|
API_EXPORT uint64_t API_CALL mk_mp4_info_get_start_time(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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){
|
API_EXPORT uint64_t API_CALL mk_mp4_info_get_file_size(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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){
|
API_EXPORT const char* API_CALL mk_mp4_info_get_file_path(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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){
|
API_EXPORT const char* API_CALL mk_mp4_info_get_file_name(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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){
|
API_EXPORT const char* API_CALL mk_mp4_info_get_folder(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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){
|
API_EXPORT const char* API_CALL mk_mp4_info_get_url(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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){
|
API_EXPORT const char* API_CALL mk_mp4_info_get_vhost(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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){
|
API_EXPORT const char* API_CALL mk_mp4_info_get_app(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)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){
|
API_EXPORT const char* API_CALL mk_mp4_info_get_stream(const mk_mp4_info ctx){
|
||||||
assert(ctx);
|
assert(ctx);
|
||||||
RecordInfo *info = (RecordInfo *)ctx;
|
RecordInfo *info = (RecordInfo *)ctx;
|
||||||
return info->strStreamId.c_str();
|
return info->stream.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////Parser/////////////////////////////////////////////
|
///////////////////////////////////////////Parser/////////////////////////////////////////////
|
||||||
|
@ -342,25 +342,29 @@ void installWebHook(){
|
|||||||
do_http_hook(hook_stream_not_found,body, nullptr);
|
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
|
#ifdef ENABLE_MP4
|
||||||
//录制mp4文件成功后广播
|
//录制mp4文件成功后广播
|
||||||
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastRecordMP4,[](BroadcastRecordMP4Args){
|
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastRecordMP4,[](BroadcastRecordMP4Args){
|
||||||
if(!hook_enable || hook_record_mp4.empty()){
|
if (!hook_enable || hook_record_mp4.empty()) {
|
||||||
return;
|
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
|
//执行hook
|
||||||
do_http_hook(hook_record_mp4,body, nullptr);
|
do_http_hook(hook_record_mp4, getRecordInfo(info), nullptr);
|
||||||
});
|
});
|
||||||
#endif //ENABLE_MP4
|
#endif //ENABLE_MP4
|
||||||
|
|
||||||
@ -368,19 +372,8 @@ void installWebHook(){
|
|||||||
if (!hook_enable || hook_record_ts.empty()) {
|
if (!hook_enable || hook_record_ts.empty()) {
|
||||||
return;
|
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
|
// 执行 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){
|
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastShellLogin,[](BroadcastShellLoginArgs){
|
||||||
@ -421,7 +414,6 @@ void installWebHook(){
|
|||||||
}
|
}
|
||||||
strongSrc->close(false);
|
strongSrc->close(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,16 +118,12 @@ void HlsMaker::flushLastSegment(bool eof){
|
|||||||
seg_dur = 100;
|
seg_dur = 100;
|
||||||
}
|
}
|
||||||
_seg_dur_list.push_back(std::make_tuple(seg_dur, std::move(_last_file_name)));
|
_seg_dur_list.push_back(std::make_tuple(seg_dur, std::move(_last_file_name)));
|
||||||
|
_last_file_name.clear();
|
||||||
delOldSegment();
|
delOldSegment();
|
||||||
makeIndexFile(eof);
|
makeIndexFile(eof);
|
||||||
_last_file_name.clear();
|
|
||||||
|
|
||||||
onFlushLastSegment(seg_dur);
|
onFlushLastSegment(seg_dur);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HlsMaker::onFlushLastSegment(uint32_t) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HlsMaker::isLive() {
|
bool HlsMaker::isLive() {
|
||||||
return _seg_number != 0;
|
return _seg_number != 0;
|
||||||
}
|
}
|
||||||
|
@ -22,20 +22,6 @@ using namespace toolkit;
|
|||||||
|
|
||||||
namespace mediakit {
|
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 {
|
class HlsMaker {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -92,18 +78,18 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual void onWriteHls(const char *data, int len) = 0;
|
virtual void onWriteHls(const char *data, int len) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上一个 ts 切片写入完成, 可在这里进行通知处理
|
||||||
|
* @param duration_ms 上一个 ts 切片的时长, 单位为毫秒
|
||||||
|
*/
|
||||||
|
virtual void onFlushLastSegment(uint32_t duration_ms) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭上个ts切片并且写入m3u8索引
|
* 关闭上个ts切片并且写入m3u8索引
|
||||||
* @param eof HLS直播是否已结束
|
* @param eof HLS直播是否已结束
|
||||||
*/
|
*/
|
||||||
void flushLastSegment(bool eof);
|
void flushLastSegment(bool eof);
|
||||||
|
|
||||||
/**
|
|
||||||
* 上一个 ts 切片写入完成, 可在这里进行通知处理
|
|
||||||
* @param duration 上一个 ts 切片的时长, 单位为毫秒
|
|
||||||
*/
|
|
||||||
virtual void onFlushLastSegment(uint32_t duration);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* 生成m3u8文件
|
* 生成m3u8文件
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "HlsMakerImp.h"
|
#include "HlsMakerImp.h"
|
||||||
#include "Thread/WorkThreadPool.h"
|
|
||||||
#include "Util/util.h"
|
#include "Util/util.h"
|
||||||
#include "Util/uv_errno.h"
|
#include "Util/uv_errno.h"
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ HlsMakerImp::HlsMakerImp(const string &m3u8_file,
|
|||||||
delete[] ptr;
|
delete[] ptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
_info.strFolder = _path_prefix;
|
_info.folder = _path_prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
HlsMakerImp::~HlsMakerImp() {
|
HlsMakerImp::~HlsMakerImp() {
|
||||||
@ -65,10 +64,11 @@ string HlsMakerImp::onOpenSegment(int index) {
|
|||||||
}
|
}
|
||||||
_file = makeFile(segment_path, true);
|
_file = makeFile(segment_path, true);
|
||||||
|
|
||||||
_info.ui64StartedTime = ::time(NULL);
|
//保存本切片的元数据
|
||||||
_info.strFileName = segment_name;
|
_info.start_time = ::time(NULL);
|
||||||
_info.strFilePath = segment_path;
|
_info.file_name = segment_name;
|
||||||
_info.strUrl = _info.strAppName + "/" + _info.strStreamId + "/" + segment_name;
|
_info.file_path = segment_path;
|
||||||
|
_info.url = _info.app + "/" + _info.stream + "/" + segment_name;
|
||||||
|
|
||||||
if (!_file) {
|
if (!_file) {
|
||||||
WarnL << "create file failed," << segment_path << " " << get_uv_errmsg();
|
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);
|
//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);
|
GET_CONFIG(bool, broadcastRecordTs, Hls::kBroadcastRecordTs);
|
||||||
|
|
||||||
if (broadcastRecordTs) {
|
if (broadcastRecordTs) {
|
||||||
auto info = _info;
|
//关闭ts文件以便获取正确的文件大小
|
||||||
info.ui64TimeLen = duration;
|
_file = nullptr;
|
||||||
WorkThreadPool::Instance().getExecutor()->async([info]() {
|
_info.time_len = duration_ms / 1000.0;
|
||||||
struct stat fileData;
|
struct stat fileData;
|
||||||
stat(info.strFilePath.data(), &fileData);
|
stat(_info.file_path.data(), &fileData);
|
||||||
const_cast<RecordInfo&>(info).ui64FileSize = fileData.st_size;
|
_info.file_size = fileData.st_size;
|
||||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordTs, info);
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordTs, _info);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<FILE> HlsMakerImp::makeFile(const string &file, bool setbuf) {
|
std::shared_ptr<FILE> HlsMakerImp::makeFile(const string &file, bool setbuf) {
|
||||||
auto file_buf = _file_buf;
|
auto file_buf = _file_buf;
|
||||||
auto ret = shared_ptr<FILE>(File::create_file(file.data(), "wb"), [file_buf](FILE *fp) {
|
auto ret = shared_ptr<FILE>(File::create_file(file.data(), "wb"), [file_buf](FILE *fp) {
|
||||||
@ -139,9 +136,9 @@ std::shared_ptr<FILE> HlsMakerImp::makeFile(const string &file, bool setbuf) {
|
|||||||
|
|
||||||
void HlsMakerImp::setMediaSource(const string &vhost, const string &app, const string &stream_id) {
|
void HlsMakerImp::setMediaSource(const string &vhost, const string &app, const string &stream_id) {
|
||||||
_media_src = std::make_shared<HlsMediaSource>(vhost, app, stream_id);
|
_media_src = std::make_shared<HlsMediaSource>(vhost, app, stream_id);
|
||||||
_info.strAppName = app;
|
_info.app = app;
|
||||||
_info.strStreamId = stream_id;
|
_info.stream = stream_id;
|
||||||
_info.strVhost = vhost;
|
_info.vhost = vhost;
|
||||||
}
|
}
|
||||||
|
|
||||||
HlsMediaSource::Ptr HlsMakerImp::getMediaSource() const {
|
HlsMediaSource::Ptr HlsMakerImp::getMediaSource() const {
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "HlsMaker.h"
|
#include "HlsMaker.h"
|
||||||
#include "HlsMediaSource.h"
|
#include "HlsMediaSource.h"
|
||||||
#include "RecordInfo.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -56,7 +55,7 @@ protected:
|
|||||||
void onDelSegment(int index) override;
|
void onDelSegment(int index) override;
|
||||||
void onWriteSegment(const char *data, int len) override;
|
void onWriteSegment(const char *data, int len) override;
|
||||||
void onWriteHls(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:
|
private:
|
||||||
std::shared_ptr<FILE> makeFile(const string &file,bool setbuf = false);
|
std::shared_ptr<FILE> makeFile(const string &file,bool setbuf = false);
|
||||||
@ -66,10 +65,10 @@ private:
|
|||||||
string _params;
|
string _params;
|
||||||
string _path_hls;
|
string _path_hls;
|
||||||
string _path_prefix;
|
string _path_prefix;
|
||||||
|
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;
|
||||||
RecordInfo _info;
|
|
||||||
map<int /*index*/,string/*file_path*/> _segment_file_paths;
|
map<int /*index*/,string/*file_path*/> _segment_file_paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,10 +25,10 @@ MP4Recorder::MP4Recorder(const string& strPath,
|
|||||||
const string &strStreamId) {
|
const string &strStreamId) {
|
||||||
_strPath = strPath;
|
_strPath = strPath;
|
||||||
/////record 业务逻辑//////
|
/////record 业务逻辑//////
|
||||||
_info.strAppName = strApp;
|
_info.app = strApp;
|
||||||
_info.strStreamId = strStreamId;
|
_info.stream = strStreamId;
|
||||||
_info.strVhost = strVhost;
|
_info.vhost = strVhost;
|
||||||
_info.strFolder = strPath;
|
_info.folder = strPath;
|
||||||
}
|
}
|
||||||
MP4Recorder::~MP4Recorder() {
|
MP4Recorder::~MP4Recorder() {
|
||||||
closeFile();
|
closeFile();
|
||||||
@ -42,15 +42,15 @@ void MP4Recorder::createFile() {
|
|||||||
auto strFile = _strPath + strDate + "/" + strTime + ".mp4";
|
auto strFile = _strPath + strDate + "/" + strTime + ".mp4";
|
||||||
|
|
||||||
/////record 业务逻辑//////
|
/////record 业务逻辑//////
|
||||||
_info.ui64StartedTime = ::time(NULL);
|
_info.start_time = ::time(NULL);
|
||||||
_info.strFileName = strTime + ".mp4";
|
_info.file_name = strTime + ".mp4";
|
||||||
_info.strFilePath = strFile;
|
_info.file_path = strFile;
|
||||||
GET_CONFIG(string,appName,Record::kAppName);
|
GET_CONFIG(string,appName,Record::kAppName);
|
||||||
_info.strUrl = appName + "/"
|
_info.url = appName + "/"
|
||||||
+ _info.strAppName + "/"
|
+ _info.app + "/"
|
||||||
+ _info.strStreamId + "/"
|
+ _info.stream + "/"
|
||||||
+ strDate + "/"
|
+ strDate + "/"
|
||||||
+ strTime + ".mp4";
|
+ strTime + ".mp4";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_muxer = std::make_shared<MP4Muxer>(strFileTmp.data());
|
_muxer = std::make_shared<MP4Muxer>(strFileTmp.data());
|
||||||
@ -73,7 +73,7 @@ void MP4Recorder::asyncClose() {
|
|||||||
auto info = _info;
|
auto info = _info;
|
||||||
WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() {
|
WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() {
|
||||||
//获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间
|
//获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间
|
||||||
const_cast<RecordInfo&>(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime;
|
const_cast<RecordInfo&>(info).time_len = ::time(NULL) - info.start_time;
|
||||||
//关闭mp4非常耗时,所以要放在后台线程执行
|
//关闭mp4非常耗时,所以要放在后台线程执行
|
||||||
muxer->closeMP4();
|
muxer->closeMP4();
|
||||||
//临时文件名改成正式文件名,防止mp4未完成时被访问
|
//临时文件名改成正式文件名,防止mp4未完成时被访问
|
||||||
@ -81,7 +81,7 @@ void MP4Recorder::asyncClose() {
|
|||||||
//获取文件大小
|
//获取文件大小
|
||||||
struct stat fileData;
|
struct stat fileData;
|
||||||
stat(strFile.data(), &fileData);
|
stat(strFile.data(), &fileData);
|
||||||
const_cast<RecordInfo&>(info).ui64FileSize = fileData.st_size;
|
const_cast<RecordInfo&>(info).file_size = fileData.st_size;
|
||||||
/////record 业务逻辑//////
|
/////record 业务逻辑//////
|
||||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info);
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info);
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "Util/TimeTicker.h"
|
#include "Util/TimeTicker.h"
|
||||||
#include "Common/MediaSink.h"
|
#include "Common/MediaSink.h"
|
||||||
#include "MP4Muxer.h"
|
#include "MP4Muxer.h"
|
||||||
#include "RecordInfo.h"
|
|
||||||
|
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
|
@ -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_
|
|
@ -16,6 +16,20 @@ using namespace std;
|
|||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
class MediaSinkInterface;
|
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{
|
class Recorder{
|
||||||
public:
|
public:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
Loading…
Reference in New Issue
Block a user