MP4 reader supports loading multi files
Some checks failed
Android / build (push) Has been cancelled
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
Linux / build (push) Has been cancelled
macOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled

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

View File

@ -38,15 +38,24 @@ Frame::Ptr Frame::getCacheAbleFrame(const Frame::Ptr &frame){
return std::make_shared<FrameCacheAble>(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()); setIndex(frame->getIndex());
_frame = std::move(frame); _frame = std::move(frame);
}
FrameStamp::FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp)
: FrameStamp(std::move(frame)) {
// kModifyStampSystem时采用系统时间戳kModifyStampRelative采用相对时间戳 [AUTO-TRANSLATED:54dd5685] // kModifyStampSystem时采用系统时间戳kModifyStampRelative采用相对时间戳 [AUTO-TRANSLATED:54dd5685]
// When using kModifyStampSystem, the system timestamp is used, and when using kModifyStampRelative, the relative timestamp is used. // 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); 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) { TrackType getTrackType(CodecId codecId) {
switch (codecId) { switch (codecId) {
#define XX(name, type, value, str, mpeg_id, mp4_id) case name : return type; #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 { class FrameStamp : public Frame {
public: public:
using Ptr = std::shared_ptr<FrameStamp>; using Ptr = std::shared_ptr<FrameStamp>;
FrameStamp(Frame::Ptr frame);
FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp); FrameStamp(Frame::Ptr frame, Stamp &stamp, int modify_stamp);
~FrameStamp() override {} ~FrameStamp() override {}
@ -538,6 +539,7 @@ public:
char *data() const override { return _frame->data(); } char *data() const override { return _frame->data(); }
size_t size() const override { return _frame->size(); } size_t size() const override { return _frame->size(); }
CodecId getCodecId() const override { return _frame->getCodecId(); } CodecId getCodecId() const override { return _frame->getCodecId(); }
void setStamp(int64_t dts, int64_t pts);
private: private:
int64_t _dts; int64_t _dts;

View File

@ -9,7 +9,10 @@
*/ */
#ifdef ENABLE_MP4 #ifdef ENABLE_MP4
#include <algorithm>
#include "MP4Demuxer.h" #include "MP4Demuxer.h"
#include "Util/File.h"
#include "Util/logger.h" #include "Util/logger.h"
#include "Extension/Factory.h" #include "Extension/Factory.h"
@ -189,5 +192,90 @@ uint64_t MP4Demuxer::getDurationMS() const {
return _duration_ms; 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 (;;) {
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()) {
// 切换到下一个文件
if (++_it == _demuxers.end()) {
// 已经是最后一个文件了
eof = true;
return nullptr;
}
// 下一个文件从头开始播放
_it->second->seekTo(0);
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 }//namespace mediakit
#endif// ENABLE_MP4 #endif// ENABLE_MP4

View File

@ -11,9 +11,12 @@
#ifndef ZLMEDIAKIT_MP4DEMUXER_H #ifndef ZLMEDIAKIT_MP4DEMUXER_H
#define ZLMEDIAKIT_MP4DEMUXER_H #define ZLMEDIAKIT_MP4DEMUXER_H
#ifdef ENABLE_MP4 #ifdef ENABLE_MP4
#include <map>
#include "MP4.h" #include "MP4.h"
#include "Extension/Track.h" #include "Extension/Track.h"
#include "Util/ResourcePool.h" #include "Util/ResourcePool.h"
namespace mediakit { namespace mediakit {
class MP4Demuxer : public TrackSource { class MP4Demuxer : public TrackSource {
@ -103,6 +106,56 @@ private:
toolkit::ResourcePool<toolkit::BufferRaw> _buffer_pool; 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文件路径; 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 }//namespace mediakit
#endif//ENABLE_MP4 #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); _file_path = File::absolutePath(_file_path, recordPath);
} }
_demuxer = std::make_shared<MP4Demuxer>(); _demuxer = std::make_shared<MultiMP4Demuxer>();
_demuxer->openMP4(_file_path); _demuxer->openMP4(_file_path);
if (tuple.stream.empty()) { 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; _file_repeat = file_repeat;
} }
const MP4Demuxer::Ptr &MP4Reader::getDemuxer() const { const MultiMP4Demuxer::Ptr &MP4Reader::getDemuxer() const {
return _demuxer; return _demuxer;
} }

View File

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