diff --git a/src/Record/MP4Reader.cpp b/src/Record/MP4Reader.cpp index a0766b56..b5d43aee 100644 --- a/src/Record/MP4Reader.cpp +++ b/src/Record/MP4Reader.cpp @@ -15,23 +15,27 @@ using namespace toolkit; namespace mediakit { -MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath ) { +MP4Reader::MP4Reader(const string &vhost, const string &app, const string &stream_id, const string &file_path) { _poller = WorkThreadPool::Instance().getPoller(); - _file_path = filePath; - if(_file_path.empty()){ - GET_CONFIG(string,recordPath,Record::kFilePath); - GET_CONFIG(bool,enableVhost,General::kEnableVhost); - if(enableVhost){ - _file_path = strVhost + "/" + strApp + "/" + strId; - }else{ - _file_path = strApp + "/" + strId; + _file_path = file_path; + if (_file_path.empty()) { + GET_CONFIG(string, recordPath, Record::kFilePath); + GET_CONFIG(bool, enableVhost, General::kEnableVhost); + if (enableVhost) { + _file_path = vhost + "/" + app + "/" + stream_id; + } else { + _file_path = app + "/" + stream_id; } - _file_path = File::absolutePath(_file_path,recordPath); + _file_path = File::absolutePath(_file_path, recordPath); } _demuxer = std::make_shared(); _demuxer->openMP4(_file_path); - _muxer = std::make_shared(strVhost, strApp, strId, _demuxer->getDurationMS() / 1000.0f, true, true, false, false); + + if (stream_id.empty()) { + return; + } + _muxer = std::make_shared(vhost, app, stream_id, _demuxer->getDurationMS() / 1000.0f, true, true, false, false); auto tracks = _demuxer->getTracks(false); if(tracks.empty()){ throw std::runtime_error(StrPrinter << "该mp4文件没有有效的track:" << _file_path); @@ -60,14 +64,16 @@ bool MP4Reader::readSample() { if (!frame) { continue; } - _muxer->inputFrame(frame); + if (_muxer) { + _muxer->inputFrame(frame); + } if (frame->dts() > getCurrentStamp()) { break; } } GET_CONFIG(bool, fileRepeat, Record::kFileRepeat); - if (eof && fileRepeat) { + if (eof && (fileRepeat || _file_repeat)) { //需要从头开始看 seekTo(0); return true; @@ -76,10 +82,14 @@ bool MP4Reader::readSample() { return !eof; } -void MP4Reader::startReadMP4() { +void MP4Reader::stopReadMP4() { + _timer = nullptr; +} + +void MP4Reader::startReadMP4(const EventPoller::Ptr &poller, uint64_t sample_ms, bool ref_self, bool file_repeat) { GET_CONFIG(uint32_t, sampleMS, Record::kSampleMS); auto strongSelf = shared_from_this(); - _muxer->setMediaListener(strongSelf); + if (_muxer) { _muxer->setMediaListener(strongSelf); } //先获取关键帧 seekTo(0); @@ -88,10 +98,28 @@ void MP4Reader::startReadMP4() { readSample(); //启动定时器 - _timer = std::make_shared(sampleMS / 1000.0f, [strongSelf]() { - lock_guard lck(strongSelf->_mtx); - return strongSelf->readSample(); - }, _poller); + if (ref_self) { + _timer = std::make_shared((sample_ms ? sample_ms : sampleMS) / 1000.0f, [strongSelf]() { + lock_guard lck(strongSelf->_mtx); + return strongSelf->readSample(); + }, poller ? poller : _poller); + } else { + weak_ptr weak_self = strongSelf; + _timer = std::make_shared((sample_ms ? sample_ms : sampleMS) / 1000.0f, [weak_self]() { + auto strongSelf = weak_self.lock(); + if (!strongSelf) { + return false; + } + lock_guard lck(strongSelf->_mtx); + return strongSelf->readSample(); + }, poller ? poller : _poller); + } + + _file_repeat = file_repeat; +} + +const MP4Demuxer::Ptr &MP4Reader::getDemuxer() const { + return _demuxer; } uint32_t MP4Reader::getCurrentStamp() { @@ -102,7 +130,7 @@ void MP4Reader::setCurrentStamp(uint32_t new_stamp){ auto old_stamp = getCurrentStamp(); _seek_to = new_stamp; _seek_ticker.resetTime(); - if (old_stamp != new_stamp) { + if (old_stamp != new_stamp && _muxer) { //时间轴未拖动时不操作 _muxer->setTimeStamp(new_stamp); } @@ -170,7 +198,9 @@ bool MP4Reader::seekTo(uint32_t ui32Stamp) { } if(keyFrame || frame->keyFrame() || frame->configFrame()){ //定位到key帧 - _muxer->inputFrame(frame); + if (_muxer) { + _muxer->inputFrame(frame); + } //设置当前时间戳 setCurrentStamp(frame->dts()); return true; diff --git a/src/Record/MP4Reader.h b/src/Record/MP4Reader.h index 909fcd70..4978e78a 100644 --- a/src/Record/MP4Reader.h +++ b/src/Record/MP4Reader.h @@ -23,18 +23,21 @@ public: /** * 流化一个mp4文件,使之转换成RtspMediaSource和RtmpMediaSource - * @param strVhost 虚拟主机 - * @param strApp 应用名 - * @param strId 流id - * @param filePath 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件 + * @param vhost 虚拟主机 + * @param app 应用名 + * @param stream_id 流id + * @param file_path 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件 */ - MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath = ""); + MP4Reader(const string &vhost, const string &app, const string &stream_id, const string &file_path = ""); /** * 开始流化MP4文件,需要指出的是,MP4Reader对象一经过调用startReadMP4方法,它的强引用会自持有, * 意思是在文件流化结束之前或中断之前,MP4Reader对象是不会被销毁的(不管有没有被外部对象持有) */ - void startReadMP4(); + void startReadMP4(const EventPoller::Ptr &poller = nullptr, uint64_t sample_ms = 0, bool ref_self = true, bool file_repeat = false); + void stopReadMP4(); + + const MP4Demuxer::Ptr& getDemuxer() const; private: //MediaSourceEvent override @@ -53,6 +56,7 @@ private: bool seekTo(uint32_t ui32Stamp); private: + bool _file_repeat = false; bool _have_video = false; bool _paused = false; float _speed = 1.0;