提炼MP4相关接口和代码

This commit is contained in:
xiongziliang 2020-09-20 19:45:04 +08:00
parent 2dd1046131
commit 071d0a9fd1
9 changed files with 179 additions and 61 deletions

View File

@ -18,6 +18,8 @@
using namespace toolkit; using namespace toolkit;
namespace mediakit { namespace mediakit {
/////////////////////////////////////////////////mp4_writer_t/////////////////////////////////////////////////
struct mp4_writer_t { struct mp4_writer_t {
int is_fmp4; int is_fmp4;
union { union {
@ -102,28 +104,32 @@ int mp4_writer_init_segment(mp4_writer_t* mp4){
} }
} }
/////////////////////////////////////////////////MP4FileIO/////////////////////////////////////////////////
static struct mov_buffer_t s_io = { static struct mov_buffer_t s_io = {
[](void *ctx, void *data, uint64_t bytes) { [](void *ctx, void *data, uint64_t bytes) {
MP4File *thiz = (MP4File *) ctx; MP4FileIO *thiz = (MP4FileIO *) ctx;
return thiz->onRead(data, bytes); return thiz->onRead(data, bytes);
}, },
[](void *ctx, const void *data, uint64_t bytes) { [](void *ctx, const void *data, uint64_t bytes) {
MP4File *thiz = (MP4File *) ctx; MP4FileIO *thiz = (MP4FileIO *) ctx;
return thiz->onWrite(data, bytes); return thiz->onWrite(data, bytes);
}, },
[](void *ctx, uint64_t offset) { [](void *ctx, uint64_t offset) {
MP4File *thiz = (MP4File *) ctx; MP4FileIO *thiz = (MP4FileIO *) ctx;
return thiz->onSeek(offset); return thiz->onSeek(offset);
}, },
[](void *ctx) { [](void *ctx) {
MP4File *thiz = (MP4File *) ctx; MP4FileIO *thiz = (MP4FileIO *) ctx;
return thiz->onTell(); return thiz->onTell();
} }
}; };
MP4File::Writer MP4File::createWriter(int flags, bool is_fmp4){ MP4FileIO::Writer MP4FileIO::createWriter(int flags, bool is_fmp4){
Writer writer; Writer writer;
writer.reset(mp4_writer_create(is_fmp4, &s_io,this, flags),[](mp4_writer_t *ptr){ Ptr self = shared_from_this();
//保存自己的强引用,防止提前释放
writer.reset(mp4_writer_create(is_fmp4, &s_io,this, flags),[self](mp4_writer_t *ptr){
if(ptr){ if(ptr){
mp4_writer_destroy(ptr); mp4_writer_destroy(ptr);
} }
@ -134,9 +140,11 @@ MP4File::Writer MP4File::createWriter(int flags, bool is_fmp4){
return writer; return writer;
} }
MP4File::Reader MP4File::createReader(){ MP4FileIO::Reader MP4FileIO::createReader(){
Reader reader; Reader reader;
reader.reset(mov_reader_create(&s_io,this),[](mov_reader_t *ptr){ Ptr self = shared_from_this();
//保存自己的强引用,防止提前释放
reader.reset(mov_reader_create(&s_io,this),[self](mov_reader_t *ptr){
if(ptr){ if(ptr){
mov_reader_destroy(ptr); mov_reader_destroy(ptr);
} }
@ -147,6 +155,8 @@ MP4File::Reader MP4File::createReader(){
return reader; return reader;
} }
/////////////////////////////////////////////////////MP4FileDisk/////////////////////////////////////////////////////////
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#define fseek64 _fseeki64 #define fseek64 _fseeki64
#define ftell64 _ftelli64 #define ftell64 _ftelli64
@ -155,7 +165,7 @@ MP4File::Reader MP4File::createReader(){
#define ftell64 ftell #define ftell64 ftell
#endif #endif
void MP4File::openFile(const char *file,const char *mode) { void MP4FileDisk::openFile(const char *file, const char *mode) {
//创建文件 //创建文件
auto fp = File::create_file(file, mode); auto fp = File::create_file(file, mode);
if(!fp){ if(!fp){
@ -183,26 +193,26 @@ void MP4File::openFile(const char *file,const char *mode) {
}); });
} }
void MP4File::closeFile() { void MP4FileDisk::closeFile() {
_file = nullptr; _file = nullptr;
} }
int MP4File::onRead(void *data, uint64_t bytes) { int MP4FileDisk::onRead(void *data, uint64_t bytes) {
if (bytes == fread(data, 1, bytes, _file.get())){ if (bytes == fread(data, 1, bytes, _file.get())){
return 0; return 0;
} }
return 0 != ferror(_file.get()) ? ferror(_file.get()) : -1 /*EOF*/; return 0 != ferror(_file.get()) ? ferror(_file.get()) : -1 /*EOF*/;
} }
int MP4File::onWrite(const void *data, uint64_t bytes) { int MP4FileDisk::onWrite(const void *data, uint64_t bytes) {
return bytes == fwrite(data, 1, bytes, _file.get()) ? 0 : ferror(_file.get()); return bytes == fwrite(data, 1, bytes, _file.get()) ? 0 : ferror(_file.get());
} }
int MP4File::onSeek(uint64_t offset) { int MP4FileDisk::onSeek(uint64_t offset) {
return fseek64(_file.get(), offset, SEEK_SET); return fseek64(_file.get(), offset, SEEK_SET);
} }
uint64_t MP4File::onTell() { uint64_t MP4FileDisk::onTell() {
return ftell64(_file.get()); return ftell64(_file.get());
} }

View File

@ -23,6 +23,7 @@
using namespace std; using namespace std;
namespace mediakit { namespace mediakit {
//以下是fmp4/mov的通用接口简单包装了ireader/media-server的接口
typedef struct mp4_writer_t mp4_writer_t; typedef struct mp4_writer_t mp4_writer_t;
mp4_writer_t* mp4_writer_create(int is_fmp4, const struct mov_buffer_t *buffer, void* param, int flags); mp4_writer_t* mp4_writer_create(int is_fmp4, const struct mov_buffer_t *buffer, void* param, int flags);
void mp4_writer_destroy(mp4_writer_t* mp4); void mp4_writer_destroy(mp4_writer_t* mp4);
@ -34,23 +35,84 @@ int mp4_writer_write_l(mp4_writer_t* mp4, int track, const void* data, size_t by
int mp4_writer_save_segment(mp4_writer_t* mp4); int mp4_writer_save_segment(mp4_writer_t* mp4);
int mp4_writer_init_segment(mp4_writer_t* mp4); int mp4_writer_init_segment(mp4_writer_t* mp4);
class MP4File { //mp4文件IO的抽象接口类
class MP4FileIO : public std::enable_shared_from_this<MP4FileIO> {
public: public:
friend struct mov_buffer_t; using Ptr = std::shared_ptr<MP4FileIO>;
typedef std::shared_ptr<mp4_writer_t> Writer; using Writer = std::shared_ptr<mp4_writer_t>;
typedef std::shared_ptr<mov_reader_t> Reader; using Reader = std::shared_ptr<mov_reader_t>;
MP4File() = default;
virtual ~MP4File() = default;
Writer createWriter(int flags, bool is_fmp4 = false); MP4FileIO() = default;
Reader createReader(); virtual ~MP4FileIO() = default;
/**
* mp4复用器
* @param flags 0MOV_FLAG_FASTSTARTMOV_FLAG_SEGMENT
* @param is_fmp4 fmp4还是普通mp4
* @return mp4复用器
*/
virtual Writer createWriter(int flags, bool is_fmp4 = false);
/**
* mp4解复用器
* @return mp4解复用器
*/
virtual Reader createReader();
/**
*
*/
virtual uint64_t onTell() = 0;
/**
* seek至文件某处
* @param offset
* @return (0)
*/
virtual int onSeek(uint64_t offset) = 0;
/**
*
* @param data
* @param bytes
* @return (0)
*/
virtual int onRead(void *data, uint64_t bytes) = 0;
/**
*
* @param data
* @param bytes
* @return (0)
*/
virtual int onWrite(const void *data, uint64_t bytes) = 0;
};
//磁盘MP4文件类
class MP4FileDisk : public MP4FileIO {
public:
using Ptr = std::shared_ptr<MP4FileDisk>;
MP4FileDisk() = default;
~MP4FileDisk() override = default;
/**
*
* @param file
* @param mode fopen的方式
*/
void openFile(const char *file, const char *mode); void openFile(const char *file, const char *mode);
/**
*
*/
void closeFile(); void closeFile();
int onRead(void* data, uint64_t bytes); protected:
int onWrite(const void* data, uint64_t bytes); uint64_t onTell() override;
int onSeek( uint64_t offset); int onSeek(uint64_t offset) override;
uint64_t onTell(); int onRead(void *data, uint64_t bytes) override;
int onWrite(const void *data, uint64_t bytes) override;
private: private:
std::shared_ptr<FILE> _file; std::shared_ptr<FILE> _file;
}; };

View File

@ -19,18 +19,20 @@
using namespace toolkit; using namespace toolkit;
namespace mediakit { namespace mediakit {
MP4Demuxer::MP4Demuxer(const char *file) { MP4Demuxer::MP4Demuxer() {}
openFile(file,"rb+");
_mov_reader = createReader();
getAllTracks();
_duration_ms = mov_reader_getduration(_mov_reader.get());
}
MP4Demuxer::~MP4Demuxer() { MP4Demuxer::~MP4Demuxer() {
_mov_reader = nullptr; _mov_reader = nullptr;
closeFile(); closeFile();
} }
void MP4Demuxer::openMP4(const string &file){
openFile(file.data(),"rb+");
_mov_reader = createReader();
getAllTracks();
_duration_ms = mov_reader_getduration(_mov_reader.get());
}
int MP4Demuxer::getAllTracks() { int MP4Demuxer::getAllTracks() {
static mov_reader_trackinfo_t s_on_track = { static mov_reader_trackinfo_t s_on_track = {
[](void *param, uint32_t track, uint8_t object, int width, int height, const void *extra, size_t bytes) { [](void *param, uint32_t track, uint8_t object, int width, int height, const void *extra, size_t bytes) {

View File

@ -16,22 +16,58 @@
#include "Util/ResourcePool.h" #include "Util/ResourcePool.h"
namespace mediakit { namespace mediakit {
class MP4Demuxer : public MP4File, public TrackSource{ class MP4Demuxer : public MP4FileDisk, public TrackSource{
public: public:
typedef std::shared_ptr<MP4Demuxer> Ptr; typedef std::shared_ptr<MP4Demuxer> Ptr;
MP4Demuxer(const char *file);
/**
* mp4解复用器
*/
MP4Demuxer();
~MP4Demuxer() override; ~MP4Demuxer() override;
/**
*
* @param file mp4文件路径
*/
void openMP4(const string &file);
/**
*
* @param stamp_ms
* @return
*/
int64_t seekTo(int64_t stamp_ms); int64_t seekTo(int64_t stamp_ms);
/**
*
* @param keyFrame
* @param eof
* @return ,
*/
Frame::Ptr readFrame(bool &keyFrame, bool &eof); Frame::Ptr readFrame(bool &keyFrame, bool &eof);
/**
* Track信息
* @param trackReady track为就绪状态
* @return Track
*/
vector<Track::Ptr> getTracks(bool trackReady) const override; vector<Track::Ptr> getTracks(bool trackReady) const override;
/**
*
* @return
*/
uint64_t getDurationMS() const; uint64_t getDurationMS() const;
private: private:
int getAllTracks(); int getAllTracks();
void onVideoTrack(uint32_t track_id, uint8_t object, int width, int height, const void *extra, size_t bytes); void onVideoTrack(uint32_t track_id, uint8_t object, int width, int height, const void *extra, size_t bytes);
void onAudioTrack(uint32_t track_id, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void *extra, size_t bytes); void onAudioTrack(uint32_t track_id, uint8_t object, int channel_count, int bit_per_sample, int sample_rate, const void *extra, size_t bytes);
Frame::Ptr makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int64_t pts, int64_t dts); Frame::Ptr makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int64_t pts, int64_t dts);
private: private:
MP4File::Reader _mov_reader; Reader _mov_reader;
uint64_t _duration_ms = 0; uint64_t _duration_ms = 0;
map<int, Track::Ptr> _track_to_codec; map<int, Track::Ptr> _track_to_codec;
ResourcePool<BufferRaw> _buffer_pool; ResourcePool<BufferRaw> _buffer_pool;

View File

@ -14,21 +14,20 @@
#include "Extension/H264.h" #include "Extension/H264.h"
namespace mediakit{ namespace mediakit{
MP4Muxer::MP4Muxer(const char *file) { MP4Muxer::MP4Muxer() {}
_file_name = file;
openMP4();
}
MP4Muxer::~MP4Muxer() { MP4Muxer::~MP4Muxer() {
closeMP4(); closeMP4();
} }
void MP4Muxer::openMP4(){ void MP4Muxer::openMP4(const string &file){
_file_name = file;
closeMP4(); closeMP4();
openFile(_file_name.data(), "wb+"); openFile(_file_name.data(), "wb+");
GET_CONFIG(bool, mp4FastStart, Record::kFastStart); GET_CONFIG(bool, mp4FastStart, Record::kFastStart);
_mov_writter = createWriter(mp4FastStart ? MOV_FLAG_FASTSTART : 0, false); _mov_writter = createWriter(mp4FastStart ? MOV_FLAG_FASTSTART : 0, false);
} }
void MP4Muxer::closeMP4(){ void MP4Muxer::closeMP4(){
_mov_writter = nullptr; _mov_writter = nullptr;
closeFile(); closeFile();
@ -38,7 +37,7 @@ void MP4Muxer::resetTracks() {
_codec_to_trackid.clear(); _codec_to_trackid.clear();
_started = false; _started = false;
_have_video = false; _have_video = false;
openMP4(); openMP4(_file_name);
} }
void MP4Muxer::inputFrame(const Frame::Ptr &frame) { void MP4Muxer::inputFrame(const Frame::Ptr &frame) {

View File

@ -23,11 +23,11 @@
namespace mediakit{ namespace mediakit{
class MP4Muxer : public MediaSinkInterface, public MP4File{ class MP4Muxer : public MediaSinkInterface, public MP4FileDisk{
public: public:
typedef std::shared_ptr<MP4Muxer> Ptr; typedef std::shared_ptr<MP4Muxer> Ptr;
MP4Muxer(const char *file); MP4Muxer();
~MP4Muxer() override; ~MP4Muxer() override;
/** /**
@ -44,13 +44,18 @@ public:
*/ */
void resetTracks() override ; void resetTracks() override ;
/**
* mp4
* @param file
*/
void openMP4(const string &file);
/** /**
* () * ()
*/ */
void closeMP4(); void closeMP4();
private: private:
void openMP4();
void stampSync(); void stampSync();
private: private:
@ -62,8 +67,8 @@ private:
List<Frame::Ptr> _frameCached; List<Frame::Ptr> _frameCached;
bool _started = false; bool _started = false;
bool _have_video = false; bool _have_video = false;
MP4File::Writer _mov_writter;
string _file_name; string _file_name;
Writer _mov_writter;
}; };
}//namespace mediakit }//namespace mediakit

View File

@ -29,7 +29,8 @@ MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &
strFileName = File::absolutePath(strFileName,recordPath); strFileName = File::absolutePath(strFileName,recordPath);
} }
_demuxer = std::make_shared<MP4Demuxer>(strFileName.data()); _demuxer = std::make_shared<MP4Demuxer>();
_demuxer->openMP4(strFileName);
_mediaMuxer.reset(new MultiMediaSourceMuxer(strVhost, strApp, strId, _demuxer->getDurationMS() / 1000.0, true, true, false, false)); _mediaMuxer.reset(new MultiMediaSourceMuxer(strVhost, strApp, strId, _demuxer->getDurationMS() / 1000.0, true, true, false, false));
auto tracks = _demuxer->getTracks(false); auto tracks = _demuxer->getTracks(false);
if(tracks.empty()){ if(tracks.empty()){

View File

@ -35,6 +35,7 @@ public:
* ,MP4Reader对象是不会被销毁的() * ,MP4Reader对象是不会被销毁的()
*/ */
void startReadMP4(); void startReadMP4();
private: private:
//MediaSourceEvent override //MediaSourceEvent override
bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override; bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override;
@ -45,15 +46,16 @@ private:
uint32_t getCurrentStamp(); uint32_t getCurrentStamp();
void setCurrentStamp(uint32_t ui32Stamp); void setCurrentStamp(uint32_t ui32Stamp);
bool seekTo(uint32_t ui32Stamp); bool seekTo(uint32_t ui32Stamp);
private: private:
recursive_mutex _mtx; bool _have_video = false;
MultiMediaSourceMuxer::Ptr _mediaMuxer;
uint32_t _seek_to; uint32_t _seek_to;
recursive_mutex _mtx;
Ticker _seek_ticker; Ticker _seek_ticker;
Timer::Ptr _timer; Timer::Ptr _timer;
EventPoller::Ptr _poller; EventPoller::Ptr _poller;
MP4Demuxer::Ptr _demuxer; MP4Demuxer::Ptr _demuxer;
bool _have_video = false; MultiMediaSourceMuxer::Ptr _mediaMuxer;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -53,7 +53,8 @@ void MP4Recorder::createFile() {
+ strTime + ".mp4"; + strTime + ".mp4";
try { try {
_muxer = std::make_shared<MP4Muxer>(strFileTmp.data()); _muxer = std::make_shared<MP4Muxer>();
_muxer->openMP4(strFileTmp);
for (auto &track :_tracks) { for (auto &track :_tracks) {
//添加track //添加track
_muxer->addTrack(track); _muxer->addTrack(track);