mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 04:31:37 +08:00
MP4Demuxer: 提高MP4解复用器接口灵活度
This commit is contained in:
parent
5bffc98541
commit
283188bedb
@ -15,23 +15,27 @@
|
|||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
namespace mediakit {
|
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();
|
_poller = WorkThreadPool::Instance().getPoller();
|
||||||
_file_path = filePath;
|
_file_path = file_path;
|
||||||
if (_file_path.empty()) {
|
if (_file_path.empty()) {
|
||||||
GET_CONFIG(string, recordPath, Record::kFilePath);
|
GET_CONFIG(string, recordPath, Record::kFilePath);
|
||||||
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
|
GET_CONFIG(bool, enableVhost, General::kEnableVhost);
|
||||||
if (enableVhost) {
|
if (enableVhost) {
|
||||||
_file_path = strVhost + "/" + strApp + "/" + strId;
|
_file_path = vhost + "/" + app + "/" + stream_id;
|
||||||
} else {
|
} else {
|
||||||
_file_path = strApp + "/" + strId;
|
_file_path = app + "/" + stream_id;
|
||||||
}
|
}
|
||||||
_file_path = File::absolutePath(_file_path, recordPath);
|
_file_path = File::absolutePath(_file_path, recordPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
_demuxer = std::make_shared<MP4Demuxer>();
|
_demuxer = std::make_shared<MP4Demuxer>();
|
||||||
_demuxer->openMP4(_file_path);
|
_demuxer->openMP4(_file_path);
|
||||||
_muxer = std::make_shared<MultiMediaSourceMuxer>(strVhost, strApp, strId, _demuxer->getDurationMS() / 1000.0f, true, true, false, false);
|
|
||||||
|
if (stream_id.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_muxer = std::make_shared<MultiMediaSourceMuxer>(vhost, app, stream_id, _demuxer->getDurationMS() / 1000.0f, true, true, false, false);
|
||||||
auto tracks = _demuxer->getTracks(false);
|
auto tracks = _demuxer->getTracks(false);
|
||||||
if(tracks.empty()){
|
if(tracks.empty()){
|
||||||
throw std::runtime_error(StrPrinter << "该mp4文件没有有效的track:" << _file_path);
|
throw std::runtime_error(StrPrinter << "该mp4文件没有有效的track:" << _file_path);
|
||||||
@ -60,14 +64,16 @@ bool MP4Reader::readSample() {
|
|||||||
if (!frame) {
|
if (!frame) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (_muxer) {
|
||||||
_muxer->inputFrame(frame);
|
_muxer->inputFrame(frame);
|
||||||
|
}
|
||||||
if (frame->dts() > getCurrentStamp()) {
|
if (frame->dts() > getCurrentStamp()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GET_CONFIG(bool, fileRepeat, Record::kFileRepeat);
|
GET_CONFIG(bool, fileRepeat, Record::kFileRepeat);
|
||||||
if (eof && fileRepeat) {
|
if (eof && (fileRepeat || _file_repeat)) {
|
||||||
//需要从头开始看
|
//需要从头开始看
|
||||||
seekTo(0);
|
seekTo(0);
|
||||||
return true;
|
return true;
|
||||||
@ -76,10 +82,14 @@ bool MP4Reader::readSample() {
|
|||||||
return !eof;
|
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);
|
GET_CONFIG(uint32_t, sampleMS, Record::kSampleMS);
|
||||||
auto strongSelf = shared_from_this();
|
auto strongSelf = shared_from_this();
|
||||||
_muxer->setMediaListener(strongSelf);
|
if (_muxer) { _muxer->setMediaListener(strongSelf); }
|
||||||
|
|
||||||
//先获取关键帧
|
//先获取关键帧
|
||||||
seekTo(0);
|
seekTo(0);
|
||||||
@ -88,10 +98,28 @@ void MP4Reader::startReadMP4() {
|
|||||||
readSample();
|
readSample();
|
||||||
|
|
||||||
//启动定时器
|
//启动定时器
|
||||||
_timer = std::make_shared<Timer>(sampleMS / 1000.0f, [strongSelf]() {
|
if (ref_self) {
|
||||||
|
_timer = std::make_shared<Timer>((sample_ms ? sample_ms : sampleMS) / 1000.0f, [strongSelf]() {
|
||||||
lock_guard<recursive_mutex> lck(strongSelf->_mtx);
|
lock_guard<recursive_mutex> lck(strongSelf->_mtx);
|
||||||
return strongSelf->readSample();
|
return strongSelf->readSample();
|
||||||
}, _poller);
|
}, poller ? poller : _poller);
|
||||||
|
} else {
|
||||||
|
weak_ptr<MP4Reader> weak_self = strongSelf;
|
||||||
|
_timer = std::make_shared<Timer>((sample_ms ? sample_ms : sampleMS) / 1000.0f, [weak_self]() {
|
||||||
|
auto strongSelf = weak_self.lock();
|
||||||
|
if (!strongSelf) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lock_guard<recursive_mutex> 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() {
|
uint32_t MP4Reader::getCurrentStamp() {
|
||||||
@ -102,7 +130,7 @@ void MP4Reader::setCurrentStamp(uint32_t new_stamp){
|
|||||||
auto old_stamp = getCurrentStamp();
|
auto old_stamp = getCurrentStamp();
|
||||||
_seek_to = new_stamp;
|
_seek_to = new_stamp;
|
||||||
_seek_ticker.resetTime();
|
_seek_ticker.resetTime();
|
||||||
if (old_stamp != new_stamp) {
|
if (old_stamp != new_stamp && _muxer) {
|
||||||
//时间轴未拖动时不操作
|
//时间轴未拖动时不操作
|
||||||
_muxer->setTimeStamp(new_stamp);
|
_muxer->setTimeStamp(new_stamp);
|
||||||
}
|
}
|
||||||
@ -170,7 +198,9 @@ bool MP4Reader::seekTo(uint32_t ui32Stamp) {
|
|||||||
}
|
}
|
||||||
if(keyFrame || frame->keyFrame() || frame->configFrame()){
|
if(keyFrame || frame->keyFrame() || frame->configFrame()){
|
||||||
//定位到key帧
|
//定位到key帧
|
||||||
|
if (_muxer) {
|
||||||
_muxer->inputFrame(frame);
|
_muxer->inputFrame(frame);
|
||||||
|
}
|
||||||
//设置当前时间戳
|
//设置当前时间戳
|
||||||
setCurrentStamp(frame->dts());
|
setCurrentStamp(frame->dts());
|
||||||
return true;
|
return true;
|
||||||
|
@ -23,18 +23,21 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 流化一个mp4文件,使之转换成RtspMediaSource和RtmpMediaSource
|
* 流化一个mp4文件,使之转换成RtspMediaSource和RtmpMediaSource
|
||||||
* @param strVhost 虚拟主机
|
* @param vhost 虚拟主机
|
||||||
* @param strApp 应用名
|
* @param app 应用名
|
||||||
* @param strId 流id
|
* @param stream_id 流id
|
||||||
* @param filePath 文件路径,如果为空则根据配置文件和上面参数自动生成,否则使用指定的文件
|
* @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方法,它的强引用会自持有,
|
* 开始流化MP4文件,需要指出的是,MP4Reader对象一经过调用startReadMP4方法,它的强引用会自持有,
|
||||||
* 意思是在文件流化结束之前或中断之前,MP4Reader对象是不会被销毁的(不管有没有被外部对象持有)
|
* 意思是在文件流化结束之前或中断之前,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:
|
private:
|
||||||
//MediaSourceEvent override
|
//MediaSourceEvent override
|
||||||
@ -53,6 +56,7 @@ private:
|
|||||||
bool seekTo(uint32_t ui32Stamp);
|
bool seekTo(uint32_t ui32Stamp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _file_repeat = false;
|
||||||
bool _have_video = false;
|
bool _have_video = false;
|
||||||
bool _paused = false;
|
bool _paused = false;
|
||||||
float _speed = 1.0;
|
float _speed = 1.0;
|
||||||
|
Loading…
Reference in New Issue
Block a user