From fe42ea30fc530cbf8a02b3a96848d7b9607172fe Mon Sep 17 00:00:00 2001 From: ziyue <1213642868@qq.com> Date: Thu, 15 Jul 2021 11:16:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86flv=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtmp/FlvMuxer.cpp | 151 +++++++++++++++++------------------------- src/Rtmp/FlvMuxer.h | 17 ++--- src/Rtmp/Rtmp.h | 38 +++++++++++ 3 files changed, 108 insertions(+), 98 deletions(-) diff --git a/src/Rtmp/FlvMuxer.cpp b/src/Rtmp/FlvMuxer.cpp index 7f09d963..49cc349b 100644 --- a/src/Rtmp/FlvMuxer.cpp +++ b/src/Rtmp/FlvMuxer.cpp @@ -16,23 +16,17 @@ namespace mediakit { - -FlvMuxer::FlvMuxer() { -} -FlvMuxer::~FlvMuxer() { -} - -void FlvMuxer::start(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &media) { - if(!media){ +void FlvMuxer::start(const EventPoller::Ptr &poller, const RtmpMediaSource::Ptr &media) { + if (!media) { throw std::runtime_error("RtmpMediaSource 无效"); } - if(!poller->isCurrentThread()){ + if (!poller->isCurrentThread()) { weak_ptr weakSelf = getSharedPtr(); //延时两秒启动录制,目的是为了等待config帧收集完毕 - poller->doDelayTask(2000,[weakSelf,poller,media](){ + poller->doDelayTask(2000, [weakSelf, poller, media]() { auto strongSelf = weakSelf.lock(); - if(strongSelf){ - strongSelf->start(poller,media); + if (strongSelf) { + strongSelf->start(poller, media); } return 0; }); @@ -43,9 +37,9 @@ void FlvMuxer::start(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr & std::weak_ptr weakSelf = getSharedPtr(); _ring_reader = media->getRing()->attach(poller); - _ring_reader->setDetachCB([weakSelf](){ + _ring_reader->setDetachCB([weakSelf]() { auto strongSelf = weakSelf.lock(); - if(!strongSelf){ + if (!strongSelf) { return; } strongSelf->onDetach(); @@ -53,15 +47,15 @@ void FlvMuxer::start(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr & //音频同步于视频 _stamp[0].syncTo(_stamp[1]); - _ring_reader->setReadCB([weakSelf](const RtmpMediaSource::RingDataType &pkt){ + _ring_reader->setReadCB([weakSelf](const RtmpMediaSource::RingDataType &pkt) { auto strongSelf = weakSelf.lock(); - if(!strongSelf){ + if (!strongSelf) { return; } size_t i = 0; auto size = pkt->size(); - pkt->for_each([&](const RtmpPacket::Ptr &rtmp){ + pkt->for_each([&](const RtmpPacket::Ptr &rtmp) { strongSelf->onWriteRtmp(rtmp, ++i == size); }); }); @@ -75,38 +69,36 @@ BufferRaw::Ptr FlvMuxer::obtainBuffer(const void *data, size_t len) { void FlvMuxer::onWriteFlvHeader(const RtmpMediaSource::Ptr &mediaSrc) { //发送flv文件头 - char flv_file_header[] = "FLV\x1\x5\x0\x0\x0\x9"; // have audio and have video - bool is_have_audio = false,is_have_video = false; + auto buffer = BufferRaw::create(); + buffer->setCapacity(sizeof(FLVHeader)); + buffer->setSize(sizeof(FLVHeader)); - mediaSrc->getConfigFrame([&](const RtmpPacket::Ptr &pkt){ - if(pkt->type_id == MSG_VIDEO){ - is_have_video = true; + FLVHeader *header = (FLVHeader *) buffer->data(); + memset(header, 0, sizeof(FLVHeader)); + header->flv[0] = 'F'; + header->flv[1] = 'L'; + header->flv[2] = 'V'; + header->version = 1; + header->length = htonl(9); + + mediaSrc->getConfigFrame([&](const RtmpPacket::Ptr &pkt) { + if (pkt->type_id == MSG_VIDEO) { + header->have_video = 1; } - if(pkt->type_id == MSG_AUDIO){ - is_have_audio = true; + if (pkt->type_id == MSG_AUDIO) { + header->have_audio = 1; } }); - if (is_have_audio && is_have_video) { - flv_file_header[4] = 0x05; - } else if (is_have_audio && !is_have_video) { - flv_file_header[4] = 0x04; - } else if (!is_have_audio && is_have_video) { - flv_file_header[4] = 0x01; - } else { - flv_file_header[4] = 0x00; - } - //flv header - onWrite(obtainBuffer(flv_file_header, sizeof(flv_file_header) - 1), false); + onWrite(buffer, false); - auto size = htonl(0); //PreviousTagSize0 Always 0 - onWrite(obtainBuffer((char *)&size,4), false); - + auto size = htonl(0); + onWrite(obtainBuffer((char *) &size, 4), false); auto &metadata = mediaSrc->getMetaData(); - if(metadata){ + if (metadata) { //在有metadata的情况下才发送metadata //其实metadata没什么用,有些推流器不产生metadata AMFEncoder invoke; @@ -115,96 +107,82 @@ void FlvMuxer::onWriteFlvHeader(const RtmpMediaSource::Ptr &mediaSrc) { } //config frame - mediaSrc->getConfigFrame([&](const RtmpPacket::Ptr &pkt){ + mediaSrc->getConfigFrame([&](const RtmpPacket::Ptr &pkt) { onWriteRtmp(pkt, true); }); } - - -#if defined(_WIN32) -#pragma pack(push, 1) -#endif // defined(_WIN32) - -class RtmpTagHeader { -public: - uint8_t type = 0; - uint8_t data_size[3] = {0}; - uint8_t timestamp[3] = {0}; - uint8_t timestamp_ex = 0; - uint8_t streamid[3] = {0}; /* Always 0. */ -}PACKED; - -#if defined(_WIN32) -#pragma pack(pop) -#endif // defined(_WIN32) - -void FlvMuxer::onWriteFlvTag(const RtmpPacket::Ptr &pkt, uint32_t time_stamp , bool flush) { +void FlvMuxer::onWriteFlvTag(const RtmpPacket::Ptr &pkt, uint32_t time_stamp, bool flush) { onWriteFlvTag(pkt->type_id, pkt, time_stamp, flush); } void FlvMuxer::onWriteFlvTag(uint8_t type, const Buffer::Ptr &buffer, uint32_t time_stamp, bool flush) { RtmpTagHeader header; header.type = type; - set_be24(header.data_size, (uint32_t)buffer->size()); - header.timestamp_ex = (uint8_t) ((time_stamp >> 24) & 0xff); + set_be24(header.data_size, (uint32_t) buffer->size()); + header.timestamp_ex = (time_stamp >> 24) & 0xff; set_be24(header.timestamp, time_stamp & 0xFFFFFF); + //tag header - onWrite(obtainBuffer((char *)&header, sizeof(header)), false); + onWrite(obtainBuffer((char *) &header, sizeof(header)), false); + //tag data onWrite(buffer, false); - uint32_t size = htonl((uint32_t)(buffer->size() + sizeof(header))); + //PreviousTagSize - onWrite(obtainBuffer((char *)&size,4), flush); + uint32_t size = htonl((uint32_t) (buffer->size() + sizeof(header))); + onWrite(obtainBuffer((char *) &size, 4), flush); } -void FlvMuxer::onWriteRtmp(const RtmpPacket::Ptr &pkt,bool flush) { +void FlvMuxer::onWriteRtmp(const RtmpPacket::Ptr &pkt, bool flush) { int64_t dts_out; _stamp[pkt->type_id % 2].revise(pkt->time_stamp, 0, dts_out, dts_out); - onWriteFlvTag(pkt, (uint32_t)dts_out,flush); + onWriteFlvTag(pkt, (uint32_t) dts_out, flush); } void FlvMuxer::stop() { - if(_ring_reader){ + if (_ring_reader) { _ring_reader.reset(); onDetach(); } } ///////////////////////////////////////////////////////FlvRecorder///////////////////////////////////////////////////// -void FlvRecorder::startRecord(const EventPoller::Ptr &poller,const string &vhost, const string &app, const string &stream,const string &file_path) { - startRecord(poller,dynamic_pointer_cast(MediaSource::find(RTMP_SCHEMA,vhost,app,stream)),file_path); + +void FlvRecorder::startRecord(const EventPoller::Ptr &poller, const string &vhost, const string &app, const string &stream, const string &file_path) { + startRecord(poller, dynamic_pointer_cast(MediaSource::find(RTMP_SCHEMA, vhost, app, stream)), file_path); } -void FlvRecorder::startRecord(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &media, const string &file_path) { +void FlvRecorder::startRecord(const EventPoller::Ptr &poller, const RtmpMediaSource::Ptr &media, + const string &file_path) { stop(); lock_guard lck(_file_mtx); //开辟文件写缓存 - std::shared_ptr fileBuf(new char[FILE_BUF_SIZE],[](char *ptr){ - if(ptr){ - delete [] ptr; + std::shared_ptr fileBuf(new char[FILE_BUF_SIZE], [](char *ptr) { + if (ptr) { + delete[] ptr; } }); //新建文件 - _file.reset(File::create_file(file_path.data(), "wb"), [fileBuf](FILE *fp){ - if(fp){ + _file.reset(File::create_file(file_path.data(), "wb"), [fileBuf](FILE *fp) { + if (fp) { fflush(fp); fclose(fp); } }); - if (!_file){ - throw std::runtime_error( StrPrinter << "打开文件失败:" << file_path); + if (!_file) { + throw std::runtime_error(StrPrinter << "打开文件失败:" << file_path); } //设置文件写缓存 - setvbuf( _file.get(), fileBuf.get(),_IOFBF, FILE_BUF_SIZE); - start(poller,media); + setvbuf(_file.get(), fileBuf.get(), _IOFBF, FILE_BUF_SIZE); + start(poller, media); } void FlvRecorder::onWrite(const Buffer::Ptr &data, bool flush) { lock_guard lck(_file_mtx); - if(_file){ - fwrite(data->data(),data->size(),1,_file.get()); + if (_file) { + fwrite(data->data(), data->size(), 1, _file.get()); } } @@ -214,14 +192,7 @@ void FlvRecorder::onDetach() { } std::shared_ptr FlvRecorder::getSharedPtr() { - return shared_from_this(); + return shared_from_this(); } -FlvRecorder::FlvRecorder() { -} - -FlvRecorder::~FlvRecorder() { -} - - }//namespace mediakit diff --git a/src/Rtmp/FlvMuxer.h b/src/Rtmp/FlvMuxer.h index b046de84..d551e4da 100644 --- a/src/Rtmp/FlvMuxer.h +++ b/src/Rtmp/FlvMuxer.h @@ -19,11 +19,12 @@ using namespace toolkit; namespace mediakit { -class FlvMuxer{ +class FlvMuxer { public: - typedef std::shared_ptr Ptr; - FlvMuxer(); - virtual ~FlvMuxer(); + using Ptr = std::shared_ptr; + FlvMuxer() = default; + virtual ~FlvMuxer() = default; + void stop(); protected: @@ -47,9 +48,10 @@ private: class FlvRecorder : public FlvMuxer , public std::enable_shared_from_this{ public: - typedef std::shared_ptr Ptr; - FlvRecorder(); - virtual ~FlvRecorder(); + using Ptr = std::shared_ptr; + FlvRecorder() = default; + ~FlvRecorder() override = default; + void startRecord(const EventPoller::Ptr &poller, const RtmpMediaSource::Ptr &media, const string &file_path); void startRecord(const EventPoller::Ptr &poller, const string &vhost, const string &app, const string &stream, const string &file_path); @@ -63,6 +65,5 @@ private: recursive_mutex _file_mtx; }; - }//namespace mediakit #endif //ZLMEDIAKIT_FLVMUXER_H diff --git a/src/Rtmp/Rtmp.h b/src/Rtmp/Rtmp.h index 5934a3cd..3020582e 100644 --- a/src/Rtmp/Rtmp.h +++ b/src/Rtmp/Rtmp.h @@ -129,6 +129,44 @@ public: uint8_t stream_index[4]; /* Note, this is little-endian while others are BE */ }PACKED; +class FLVHeader { +public: + //FLV + char flv[3]; + //File version (for example, 0x01 for FLV version 1) + uint8_t version; +#if __BYTE_ORDER == __BIG_ENDIAN + //保留,置0 + uint8_t : 5; + //是否有音频 + uint8_t have_audio: 1; + //保留,置0 + uint8_t : 1; + //是否有视频 + uint8_t have_video: 1; +#else + //是否有视频 + uint8_t have_video: 1; + //保留,置0 + uint8_t : 1; + //是否有音频 + uint8_t have_audio: 1; + //保留,置0 + uint8_t : 5; +#endif + //The length of this header in bytes,固定为9 + uint32_t length; +} PACKED; + +class RtmpTagHeader { +public: + uint8_t type = 0; + uint8_t data_size[3] = {0}; + uint8_t timestamp[3] = {0}; + uint8_t timestamp_ex = 0; + uint8_t streamid[3] = {0}; /* Always 0. */ +} PACKED; + #if defined(_WIN32) #pragma pack(pop) #endif // defined(_WIN32)