mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 19:00:01 +08:00
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
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:
parent
e4025a6811
commit
61a93fab6a
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user