ZLMediaKit/src/MediaFile/Mp4Maker.cpp

239 lines
7.5 KiB
C++
Raw Normal View History

2017-10-09 22:11:01 +08:00
/*
2017-09-27 16:20:30 +08:00
* MIT License
*
* Copyright (c) 2016 xiongziliang <771730766@qq.com>
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
2017-04-01 16:35:56 +08:00
#ifdef ENABLE_MP4V2
2017-04-01 16:35:56 +08:00
#include <sys/stat.h>
2017-05-02 17:15:12 +08:00
#include "Common/config.h"
2017-04-01 16:35:56 +08:00
#include "Mp4Maker.h"
2017-04-25 11:35:41 +08:00
#include "MediaRecorder.h"
#include "Util/File.h"
#include "Util/mini.h"
2018-05-22 11:41:20 +08:00
#include "Util/util.h"
2017-04-01 16:35:56 +08:00
#include "Util/NoticeCenter.h"
2018-10-24 17:17:55 +08:00
using namespace toolkit;
2017-04-01 16:35:56 +08:00
2018-10-24 17:17:55 +08:00
namespace mediakit {
2017-04-01 16:35:56 +08:00
string timeStr(const char *fmt) {
std::tm tm_snapshot;
auto time = ::time(NULL);
2018-05-22 11:41:20 +08:00
#if defined(_WIN32)
localtime_s(&tm_snapshot, &time); // thread-safe
2017-04-01 16:35:56 +08:00
#else
localtime_r(&time, &tm_snapshot); // POSIX
2018-05-22 11:41:20 +08:00
#endif
2017-04-01 16:35:56 +08:00
const size_t size = 1024;
char buffer[size];
auto success = std::strftime(buffer, size, fmt, &tm_snapshot);
if (0 == success)
return string(fmt);
return buffer;
}
Mp4Maker::Mp4Maker(const string& strPath,
const string &strVhost,
const string &strApp,
const string &strStreamId,
const PlayerBase::Ptr &pPlayer) {
2017-04-01 16:35:56 +08:00
DebugL << strPath;
2018-10-24 15:43:52 +08:00
_pPlayer = pPlayer;
_strPath = strPath;
2017-04-01 16:35:56 +08:00
/////record 业务逻辑//////
2018-10-24 15:43:52 +08:00
_info.strAppName = strApp;
_info.strStreamId = strStreamId;
_info.strVhost = strVhost;
_info.strFolder = strPath;
2017-04-01 16:35:56 +08:00
//----record 业务逻辑----//
}
Mp4Maker::~Mp4Maker() {
closeFile();
}
void Mp4Maker::inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType){
switch (iType) {
case 1: //P
case 5: { //IDR
2018-10-24 15:43:52 +08:00
if (_strLastVideo.size()) {
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastVideoTime;
2017-09-05 15:20:02 +08:00
iTimeInc = MAX(0,MIN(iTimeInc,500));
if(iTimeInc == 0 || iTimeInc == 500){
2018-10-24 15:43:52 +08:00
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastVideoTime;
2017-09-05 15:20:02 +08:00
}
2018-10-24 15:43:52 +08:00
_inputH264((char *) _strLastVideo.data(), _strLastVideo.size(), iTimeInc, _iLastVideoType);
2017-04-01 16:35:56 +08:00
}
2018-10-24 15:43:52 +08:00
//_strLastVideo.assign(("\x0\x0\x0\x2\x9\xf0"), 6);
2017-04-01 16:35:56 +08:00
uint32_t *p = (uint32_t *) pData;
*p = htonl(ui32Length - 4);
2018-10-24 15:43:52 +08:00
_strLastVideo.assign((char *) pData, ui32Length);
2017-04-01 16:35:56 +08:00
memcpy(pData, "\x00\x00\x00\x01", 4);
2018-10-24 15:43:52 +08:00
_ui32LastVideoTime = ui32TimeStamp;
_iLastVideoType = iType;
2017-04-01 16:35:56 +08:00
}
break;
default:
break;
}
}
void Mp4Maker::inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp){
2018-10-24 15:43:52 +08:00
if (_strLastAudio.size()) {
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastAudioTime;
2017-09-05 15:20:02 +08:00
iTimeInc = MAX(0,MIN(iTimeInc,500));
if(iTimeInc == 0 || iTimeInc == 500){
2018-10-24 15:43:52 +08:00
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastAudioTime;
2017-09-05 15:20:02 +08:00
}
2018-10-24 15:43:52 +08:00
_inputAAC((char *)_strLastAudio.data(), _strLastAudio.size(), iTimeInc);
2017-04-01 16:35:56 +08:00
}
2018-10-24 15:43:52 +08:00
_strLastAudio.assign((char *)pData, ui32Length);
_ui32LastAudioTime = ui32TimeStamp;
2017-04-01 16:35:56 +08:00
}
void Mp4Maker::_inputH264(void* pData, uint32_t ui32Length, uint32_t ui32Duration, int iType) {
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(uint32_t,recordSec,Record::kFileSecond);
2018-02-09 11:42:55 +08:00
2018-10-24 15:43:52 +08:00
if(iType == 5 && (_hMp4 == MP4_INVALID_FILE_HANDLE || _ticker.elapsedTime() > recordSec * 1000)){
2017-04-01 16:35:56 +08:00
//在I帧率处新建MP4文件
//如果文件未创建或者文件超过10分钟则创建新文件
createFile();
}
2018-10-24 15:43:52 +08:00
if (_hVideo != MP4_INVALID_TRACK_ID) {
MP4WriteSample(_hMp4, _hVideo, (uint8_t *) pData, ui32Length,ui32Duration * 90,0,iType == 5);
2017-04-01 16:35:56 +08:00
}
}
void Mp4Maker::_inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32Duration) {
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(uint32_t,recordSec,Record::kFileSecond);
2018-02-09 11:42:55 +08:00
2018-10-23 16:41:25 +08:00
//todo(xzl) 修复此处
//
2018-10-24 15:43:52 +08:00
// if (!_pPlayer->containVideo() && (_hMp4 == MP4_INVALID_FILE_HANDLE || _ticker.elapsedTime() > recordSec * 1000)) {
2018-10-23 16:41:25 +08:00
// //在I帧率处新建MP4文件
// //如果文件未创建或者文件超过10分钟则创建新文件
// createFile();
// }
2018-10-24 15:43:52 +08:00
// if (_hAudio != MP4_INVALID_TRACK_ID) {
// auto duration = ui32Duration * _pPlayer->getAudioSampleRate() /1000.0;
// MP4WriteSample(_hMp4, _hAudio, (uint8_t*)pData + 7, ui32Length - 7,duration,0,false);
2018-10-23 16:41:25 +08:00
// }
2017-04-01 16:35:56 +08:00
}
void Mp4Maker::createFile() {
2018-10-24 15:43:52 +08:00
if(!_pPlayer->isInited()){
2017-04-01 16:35:56 +08:00
return;
}
closeFile();
auto strDate = timeStr("%Y-%m-%d");
auto strTime = timeStr("%H-%M-%S");
2018-10-24 15:43:52 +08:00
auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4";
auto strFile = _strPath + strDate + "/" + strTime + ".mp4";
2017-04-01 16:35:56 +08:00
/////record 业务逻辑//////
2018-10-24 15:43:52 +08:00
_info.ui64StartedTime = ::time(NULL);
_info.strFileName = strTime + ".mp4";
_info.strFilePath = strFile;
2018-02-09 11:42:55 +08:00
2018-10-24 17:17:55 +08:00
GET_CONFIG_AND_REGISTER(string,appName,Record::kAppName);
2018-02-09 11:42:55 +08:00
2018-10-24 15:43:52 +08:00
_info.strUrl = _info.strVhost + "/"
+ appName + "/"
2018-10-24 15:43:52 +08:00
+ _info.strAppName + "/"
+ _info.strStreamId + "/"
2017-04-01 16:35:56 +08:00
+ strDate + "/"
+ strTime + ".mp4";
//----record 业务逻辑----//
2018-05-22 11:41:20 +08:00
#if !defined(_WIN32)
2017-04-01 16:35:56 +08:00
File::createfile_path(strFileTmp.data(), S_IRWXO | S_IRWXG | S_IRWXU);
2018-05-22 11:41:20 +08:00
#else
File::createfile_path(strFileTmp.data(), 0);
#endif
2018-10-24 15:43:52 +08:00
_hMp4 = MP4Create(strFileTmp.data());
if (_hMp4 == MP4_INVALID_FILE_HANDLE) {
2017-04-01 16:35:56 +08:00
WarnL << "创建MP4文件失败:" << strFileTmp;
return;
}
2018-10-24 15:43:52 +08:00
//MP4SetTimeScale(_hMp4, 90000);
_strFileTmp = strFileTmp;
_strFile = strFile;
_ticker.resetTime();
2018-10-23 16:41:25 +08:00
//todo(xzl) 修复此处
2018-10-24 15:43:52 +08:00
// if(_pPlayer->containVideo()){
// auto &sps = _pPlayer->getSps();
// auto &pps = _pPlayer->getPps();
// _hVideo = MP4AddH264VideoTrack(_hMp4, 90000, MP4_INVALID_DURATION,
// _pPlayer->getVideoWidth(), _pPlayer->getVideoHeight(),
2018-10-23 16:41:25 +08:00
// sps[5], sps[6], sps[7], 3);
2018-10-24 15:43:52 +08:00
// if(_hVideo !=MP4_INVALID_TRACK_ID){
// MP4AddH264SequenceParameterSet(_hMp4, _hVideo, (uint8_t *)sps.data() + 4, sps.size() - 4);
// MP4AddH264PictureParameterSet(_hMp4, _hVideo, (uint8_t *)pps.data() + 4, pps.size() - 4);
2018-10-23 16:41:25 +08:00
// }else{
// WarnL << "添加视频通道失败:" << strFileTmp;
// }
// }
2018-10-24 15:43:52 +08:00
// if(_pPlayer->containAudio()){
// _hAudio = MP4AddAudioTrack(_hMp4, _pPlayer->getAudioSampleRate(), MP4_INVALID_DURATION, MP4_MPEG4_AUDIO_TYPE);
// if (_hAudio != MP4_INVALID_TRACK_ID) {
// auto &cfg = _pPlayer->getAudioCfg();
// MP4SetTrackESConfiguration(_hMp4, _hAudio,(uint8_t *)cfg.data(), cfg.size());
2018-10-23 16:41:25 +08:00
// }else{
// WarnL << "添加音频通道失败:" << strFileTmp;
// }
// }
2017-04-01 16:35:56 +08:00
}
void Mp4Maker::closeFile() {
2018-10-24 15:43:52 +08:00
if (_hMp4 != MP4_INVALID_FILE_HANDLE) {
2017-04-01 16:35:56 +08:00
{
TimeTicker();
2018-10-24 15:43:52 +08:00
MP4Close(_hMp4,MP4_CLOSE_DO_NOT_COMPUTE_BITRATE);
2017-04-01 16:35:56 +08:00
}
2018-10-24 15:43:52 +08:00
rename(_strFileTmp.data(),_strFile.data());
_hMp4 = MP4_INVALID_FILE_HANDLE;
_hVideo = MP4_INVALID_TRACK_ID;
_hAudio = MP4_INVALID_TRACK_ID;
2017-04-01 16:35:56 +08:00
/////record 业务逻辑//////
2018-10-24 15:43:52 +08:00
_info.ui64TimeLen = ::time(NULL) - _info.ui64StartedTime;
2017-04-01 16:35:56 +08:00
//获取文件大小
struct stat fileData;
2018-10-24 15:43:52 +08:00
stat(_strFile.data(), &fileData);
_info.ui64FileSize = fileData.st_size;
2017-04-01 16:35:56 +08:00
//----record 业务逻辑----//
2018-10-24 17:17:55 +08:00
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,_info,*this);
2017-04-01 16:35:56 +08:00
}
}
2018-10-24 17:17:55 +08:00
} /* namespace mediakit */
2017-04-01 16:35:56 +08:00
#endif //ENABLE_MP4V2