MP4 reader supports loading multi files

This commit is contained in:
xia-chu 2024-10-13 00:25:40 +08:00
parent e4025a6811
commit b41fecbf7b
6 changed files with 156 additions and 6 deletions

View File

@ -38,15 +38,24 @@ Frame::Ptr Frame::getCacheAbleFrame(const Frame::Ptr &frame){
return std::make_shared<FrameCacheAble>(frame);
}
FrameStamp::FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp)
{
FrameStamp::FrameStamp(Frame::Ptr frame) {
setIndex(frame->getIndex());
_frame = std::move(frame);
}
FrameStamp::FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp)
: FrameStamp(std::move(frame)) {
// kModifyStampSystem时采用系统时间戳kModifyStampRelative采用相对时间戳 [AUTO-TRANSLATED:54dd5685]
// When using kModifyStampSystem, the system timestamp is used, and when using kModifyStampRelative, the relative timestamp is used.
stamp.revise(_frame->dts(), _frame->pts(), _dts, _pts, modify_stamp == ProtocolOption::kModifyStampSystem);
}
void FrameStamp::setStamp(int64_t dts, int64_t pts) {
_dts = dts;
_pts = pts;
}
TrackType getTrackType(CodecId codecId) {
switch (codecId) {
#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return type;

View File

@ -524,6 +524,7 @@ private:
class FrameStamp : public Frame {
public:
using Ptr = std::shared_ptr<FrameStamp>;
FrameStamp(Frame::Ptr frame);
FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp);
~FrameStamp() override {}
@ -538,6 +539,7 @@ public:
char *data() const override { return _frame->data(); }
size_t size() const override { return _frame->size(); }
CodecId getCodecId() const override { return _frame->getCodecId(); }
void setStamp(int64_t dts, int64_t pts);
private:
int64_t _dts;

View File

@ -10,6 +10,7 @@
#ifdef ENABLE_MP4
#include "MP4Demuxer.h"
#include "Util/File.h"
#include "Util/logger.h"
#include "Extension/Factory.h"
@ -189,5 +190,90 @@ uint64_t MP4Demuxer::getDurationMS() const {
return _duration_ms;
}
/////////////////////////////////////////////////////////////////////////////////
void MultiMP4Demuxer::openMP4(const string &files_string) {
std::vector<std::string> files;
if (File::is_dir(files_string)) {
File::scanDir(files_string, [&](const string &path, bool is_dir) {
if (!is_dir) {
files.emplace_back(path);
}
return true;
});
std::sort(files.begin(), files.end());
} else {
files = split(files_string, ";");
}
uint64_t duration_ms = 0;
for (auto &file : files) {
auto demuxer = std::make_shared<MP4Demuxer>();
demuxer->openMP4(file);
_demuxers.emplace(duration_ms, demuxer);
duration_ms += demuxer->getDurationMS();
}
CHECK(!_demuxers.empty());
_it = _demuxers.begin();
for (auto &track : _it->second->getTracks(false)) {
_tracks.emplace(track->getIndex(), track->clone());
}
}
uint64_t MultiMP4Demuxer::getDurationMS() const {
return _demuxers.empty() ? 0 : _demuxers.rbegin()->first + _demuxers.rbegin()->second->getDurationMS();
}
void MultiMP4Demuxer::closeMP4() {
_demuxers.clear();
_it = _demuxers.end();
_tracks.clear();
}
int64_t MultiMP4Demuxer::seekTo(int64_t stamp_ms) {
if (stamp_ms >= (int64_t)getDurationMS()) {
return -1;
}
_it = std::prev(_demuxers.upper_bound(stamp_ms));
return _it->first + _it->second->seekTo(stamp_ms - _it->first);
}
Frame::Ptr MultiMP4Demuxer::readFrame(bool &keyFrame, bool &eof) {
for (;;) {
if (_it == _demuxers.end()) {
eof = true;
return nullptr;
}
auto ret = _it->second->readFrame(keyFrame, eof);
if (ret) {
auto it = _tracks.find(ret->getIndex());
if (it != _tracks.end()) {
auto ret2 = std::make_shared<FrameStamp>(ret);
ret2->setStamp(_it->first + ret->dts(), _it->first + ret->pts());
ret = std::move(ret2);
it->second->inputFrame(ret);
}
}
if (eof && _it != _demuxers.end()) {
// 这个文件读完了,重置它
_it->second->seekTo(0);
// 不是最后一个文件, 切换到下一个文件
++_it;
continue;
}
return ret;
}
}
std::vector<Track::Ptr> MultiMP4Demuxer::getTracks(bool trackReady) const {
std::vector<Track::Ptr> ret;
for (auto &pr : _tracks) {
if (!trackReady || pr.second->ready()) {
ret.emplace_back(pr.second);
}
}
return ret;
}
}//namespace mediakit
#endif// ENABLE_MP4

View File

@ -11,9 +11,12 @@
#ifndef ZLMEDIAKIT_MP4DEMUXER_H
#define ZLMEDIAKIT_MP4DEMUXER_H
#ifdef ENABLE_MP4
#include <map>
#include "MP4.h"
#include "Extension/Track.h"
#include "Util/ResourcePool.h"
namespace mediakit {
class MP4Demuxer : public TrackSource {
@ -103,6 +106,56 @@ private:
toolkit::ResourcePool<toolkit::BufferRaw> _buffer_pool;
};
class MultiMP4Demuxer : public TrackSource {
public:
using Ptr = std::shared_ptr<MultiMP4Demuxer>;
~MultiMP4Demuxer() override = default;
/**
* mp4文件mp4看待
* @param file mp4文件路径
*/
void openMP4(const std::string &file);
/**
* @brief mp4
*/
void closeMP4();
/**
*
* @param stamp_ms
* @return
*/
int64_t seekTo(int64_t stamp_ms);
/**
*
* @param keyFrame
* @param eof
* @return ,
*/
Frame::Ptr readFrame(bool &keyFrame, bool &eof);
/**
* Track信息
* @param trackReady track为就绪状态
* @return Track信息
*/
std::vector<Track::Ptr> getTracks(bool trackReady) const override;
/**
*
* @return
*/
uint64_t getDurationMS() const;
private:
std::map<int, Track::Ptr> _tracks;
std::map<uint64_t, MP4Demuxer::Ptr>::iterator _it;
std::map<uint64_t, MP4Demuxer::Ptr> _demuxers;
};
}//namespace mediakit
#endif//ENABLE_MP4

View File

@ -54,7 +54,7 @@ void MP4Reader::setup(const MediaTuple &tuple, const std::string &file_path, con
_file_path = File::absolutePath(_file_path, recordPath);
}
_demuxer = std::make_shared<MP4Demuxer>();
_demuxer = std::make_shared<MultiMP4Demuxer>();
_demuxer->openMP4(_file_path);
if (tuple.stream.empty()) {
@ -164,7 +164,7 @@ void MP4Reader::startReadMP4(uint64_t sample_ms, bool ref_self, bool file_repeat
_file_repeat = file_repeat;
}
const MP4Demuxer::Ptr &MP4Reader::getDemuxer() const {
const MultiMP4Demuxer::Ptr &MP4Reader::getDemuxer() const {
return _demuxer;
}

View File

@ -68,7 +68,7 @@ public:
* [AUTO-TRANSLATED:4f0dfc29]
*/
const MP4Demuxer::Ptr& getDemuxer() const;
const MultiMP4Demuxer::Ptr& getDemuxer() const;
private:
//MediaSourceEvent override
@ -100,7 +100,7 @@ private:
std::recursive_mutex _mtx;
toolkit::Ticker _seek_ticker;
toolkit::Timer::Ptr _timer;
MP4Demuxer::Ptr _demuxer;
MultiMP4Demuxer::Ptr _demuxer;
MultiMediaSourceMuxer::Ptr _muxer;
toolkit::EventPoller::Ptr _poller;
};