MP4Recorder.cpp 3.92 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
xiongziliang committed
3 4 5
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
xiongziliang committed
6 7 8
 * 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.
xiongziliang committed
9
 */
xzl committed
10

xiongziliang committed
11
#ifdef ENABLE_MP4
12
#include <ctime>
xzl committed
13
#include <sys/stat.h>
xiongziliang committed
14
#include "Common/config.h"
xiongziliang committed
15
#include "MP4Recorder.h"
16
#include "Thread/WorkThreadPool.h"
17

18 19 20 21
using namespace toolkit;

namespace mediakit {

xiongziliang committed
22
MP4Recorder::MP4Recorder(const string& strPath,
23 24 25 26 27
                   const string &strVhost,
                   const string &strApp,
                   const string &strStreamId) {
    _strPath = strPath;
    /////record 业务逻辑//////
28 29 30 31
    _info.app = strApp;
    _info.stream = strStreamId;
    _info.vhost = strVhost;
    _info.folder = strPath;
xzl committed
32
}
xiongziliang committed
33
MP4Recorder::~MP4Recorder() {
34
    closeFile();
xzl committed
35 36
}

xiongziliang committed
37
void MP4Recorder::createFile() {
38 39 40 41 42 43 44
    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 业务逻辑//////
45 46 47
    _info.start_time = ::time(NULL);
    _info.file_name = strTime + ".mp4";
    _info.file_path = strFile;
48
    GET_CONFIG(string,appName,Record::kAppName);
49 50 51 52 53
    _info.url = appName + "/"
                + _info.app + "/"
                + _info.stream + "/"
                + strDate + "/"
                + strTime + ".mp4";
54

55
    try {
56 57 58
        _muxer = std::make_shared<MP4Muxer>();
        _muxer->openMP4(strFileTmp);
        for (auto &track :_tracks) {
59 60
            //添加track
            _muxer->addTrack(track);
61 62 63 64
        }
        _strFileTmp = strFileTmp;
        _strFile = strFile;
        _createFileTicker.resetTime();
65
    } catch (std::exception &ex) {
66 67
        WarnL << ex.what();
    }
xzl committed
68 69
}

xiongziliang committed
70
void MP4Recorder::asyncClose() {
71 72 73 74 75 76
    auto muxer = _muxer;
    auto strFileTmp = _strFileTmp;
    auto strFile = _strFile;
    auto info = _info;
    WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() {
        //获取文件录制时间,放在关闭mp4之前是为了忽略关闭mp4执行时间
77
        const_cast<RecordInfo&>(info).time_len = ::time(NULL) - info.start_time;
78
        //关闭mp4非常耗时,所以要放在后台线程执行
79
        muxer->closeMP4();
80 81 82 83 84
        //临时文件名改成正式文件名,防止mp4未完成时被访问
        rename(strFileTmp.data(),strFile.data());
        //获取文件大小
        struct stat fileData;
        stat(strFile.data(), &fileData);
85
        const_cast<RecordInfo&>(info).file_size = fileData.st_size;
86 87 88
        /////record 业务逻辑//////
        NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info);
    });
89 90
}

xiongziliang committed
91
void MP4Recorder::closeFile() {
92 93 94 95
    if (_muxer) {
        asyncClose();
        _muxer = nullptr;
    }
xzl committed
96 97
}

xiongziliang committed
98
void MP4Recorder::inputFrame(const Frame::Ptr &frame) {
99 100 101 102 103 104 105 106 107 108 109 110 111 112
    GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
    if(!_muxer || ((_createFileTicker.elapsedTime() > recordSec * 1000) &&
                  (!_haveVideo || (_haveVideo && frame->keyFrame()))) ){
        //成立条件
        //1、_muxer为空
        //2、到了切片时间,并且只有音频
        //3、到了切片时间,有视频并且遇到视频的关键帧
        createFile();
    }

    if(_muxer){
        //生成mp4文件
        _muxer->inputFrame(frame);
    }
113 114
}

xiongziliang committed
115
void MP4Recorder::addTrack(const Track::Ptr & track){
116 117 118 119 120
    //保存所有的track,为创建MP4MuxerFile做准备
    _tracks.emplace_back(track);
    if(track->getTrackType() == TrackVideo){
        _haveVideo = true;
    }
121 122
}

123
void MP4Recorder::resetTracks() {
124 125 126 127
    closeFile();
    _tracks.clear();
    _haveVideo = false;
    _createFileTicker.resetTime();
128 129
}

xiongziliang committed
130
} /* namespace mediakit */
xzl committed
131 132


xiongziliang committed
133
#endif //ENABLE_MP4