ZLMediaKit/src/Record/MP4Recorder.cpp
2021-08-12 20:37:46 +08:00

147 lines
4.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2016 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.
*/
#ifdef ENABLE_MP4
#include <ctime>
#include <sys/stat.h>
#include "Util/File.h"
#include "Common/config.h"
#include "MP4Recorder.h"
#include "Thread/WorkThreadPool.h"
using namespace toolkit;
namespace mediakit {
MP4Recorder::MP4Recorder(const string &strPath,
const string &strVhost,
const string &strApp,
const string &strStreamId,
size_t max_second) {
_strPath = strPath;
/////record 业务逻辑//////
_info.app = strApp;
_info.stream = strStreamId;
_info.vhost = strVhost;
_info.folder = strPath;
GET_CONFIG(size_t ,recordSec,Record::kFileSecond);
_max_second = max_second ? max_second : recordSec;
}
MP4Recorder::~MP4Recorder() {
closeFile();
}
void MP4Recorder::createFile() {
closeFile();
auto strDate = getTimeStr("%Y-%m-%d");
auto strTime = getTimeStr("%H-%M-%S");
auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4";
auto strFile = _strPath + strDate + "/" + strTime + ".mp4";
/////record 业务逻辑//////
_info.start_time = ::time(NULL);
_info.file_name = strTime + ".mp4";
_info.file_path = strFile;
GET_CONFIG(string,appName,Record::kAppName);
_info.url = appName + "/"
+ _info.app + "/"
+ _info.stream + "/"
+ strDate + "/"
+ strTime + ".mp4";
try {
_muxer = std::make_shared<MP4Muxer>();
_muxer->openMP4(strFileTmp);
for (auto &track :_tracks) {
//添加track
_muxer->addTrack(track);
}
_strFileTmp = strFileTmp;
_strFile = strFile;
} catch (std::exception &ex) {
WarnL << ex.what();
}
}
void MP4Recorder::asyncClose() {
auto muxer = _muxer;
auto strFileTmp = _strFileTmp;
auto strFile = _strFile;
auto info = _info;
WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() mutable{
//获取文件录制时间放在关闭mp4之前是为了忽略关闭mp4执行时间
info.time_len = (float)(::time(NULL) - info.start_time);
//关闭mp4非常耗时所以要放在后台线程执行
muxer->closeMP4();
//获取文件大小
struct stat fileData;
stat(strFileTmp.data(), &fileData);
info.file_size = fileData.st_size;
if (fileData.st_size < 1024) {
//录像文件太小,删除之
File::delete_file(strFileTmp.data());
return;
}
//临时文件名改成正式文件名防止mp4未完成时被访问
rename(strFileTmp.data(),strFile.data());
/////record 业务逻辑//////
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info);
});
}
void MP4Recorder::closeFile() {
if (_muxer) {
asyncClose();
_muxer = nullptr;
}
}
void MP4Recorder::inputFrame(const Frame::Ptr &frame) {
if (_baseSec == 0) {
_baseSec = frame->dts();
}
auto duration = frame->dts() - _baseSec;
if (!_muxer || ((duration > _max_second * 1000) && (!_haveVideo || (_haveVideo && frame->keyFrame())))) {
//成立条件
//1、_muxer为空
//2、到了切片时间并且只有音频
//3、到了切片时间有视频并且遇到视频的关键帧
_baseSec = 0;
createFile();
}
if (_muxer) {
//生成mp4文件
_muxer->inputFrame(frame);
}
}
void MP4Recorder::addTrack(const Track::Ptr & track){
//保存所有的track为创建MP4MuxerFile做准备
_tracks.emplace_back(track);
if(track->getTrackType() == TrackVideo){
_haveVideo = true;
}
}
void MP4Recorder::resetTracks() {
closeFile();
_tracks.clear();
_haveVideo = false;
}
} /* namespace mediakit */
#endif //ENABLE_MP4