ZLMediaKit接收ffmpeg rtmp推流
目录
一 关键类
二 推流缓冲
webrtc拉流篇,可参考
https://mp.csdn.net/mp_blog/creation/editor/122743325
RTMP采用的封装格式是FLV。所以在指定输出流媒体的时候须要指定其封装格式为“flv”。同理,其余流媒体协议也须要指定其封装格式。例如采用UDP推送流媒体的时候,能够指定其封装格式为“mpegts”。
一 关键类
环形缓冲,聚合了_RingStorage template<typename T> class RingBuffer : public enable_shared_from_this<RingBuffer<T> > { public: typedef std::shared_ptr<RingBuffer> Ptr; typedef _RingReader<T> RingReader; typedef _RingStorage<T> RingStorage; typedef _RingReaderDispatcher<T> RingReaderDispatcher; typedef function<void(int size)> onReaderChanged; RingBuffer(int max_size = 1024, const onReaderChanged &cb = nullptr) { _on_reader_changed = cb; _storage = std::make_shared<RingStorage>(max_size); } ~RingBuffer() {} void write(T in, bool is_key = true) { if (_delegate) { _delegate->onWrite(std::move(in), is_key); return; } LOCK_GUARD(_mtx_map); for (auto &pr : _dispatcher_map) { auto &second = pr.second; //切换线程后触发onRead事件 pr.first->async([second, in, is_key]() { second->write(std::move(const_cast<T &>(in)), is_key); }, false); } _storage->write(std::move(in), is_key); } int readerCount() { return _total_count; } void clearCache(){ LOCK_GUARD(_mtx_map); _storage->clearCache(); for (auto &pr : _dispatcher_map) { auto &second = pr.second; //切换线程后清空缓存 pr.first->async([second]() { second->clearCache(); }, false); } } private: struct HashOfPtr { std::size_t operator()(const EventPoller::Ptr &key) const { return (std::size_t) key.get(); } }; private: mutex _mtx_map; atomic_int _total_count {0}; typename RingStorage::Ptr _storage; typename RingDelegate<T>::Ptr _delegate; onReaderChanged _on_reader_changed; unordered_map<EventPoller::Ptr, typename RingReaderDispatcher::Ptr, HashOfPtr> _dispatcher_map; }; |
存放ffmpeg rtmp推流,demuxer,解码,重新编码后的rtppacket数据 template<typename T> class _RingStorage { public: typedef std::shared_ptr<_RingStorage> Ptr; _RingStorage(int max_size) { //gop缓存个数不能小于32 if(max_size < RING_MIN_SIZE){ max_size = RING_MIN_SIZE; } _max_size = max_size; } ~_RingStorage() {} /** * 写入环形缓存数据 * @param in 数据 * @param is_key 是否为关键帧 * @return 是否触发重置环形缓存大小 */ void write(T in, bool is_key = true) { if (is_key) { //遇到I帧,那么移除老数据 _size = 0; _have_idr = true; _data_cache.clear(); } if (!_have_idr) { //缓存中没有关键帧,那么gop缓存无效 return; } _data_cache.emplace_back(std::make_pair(is_key, std::move(in))); if (++_size > _max_size) { //GOP缓存溢出,清空关老数据 _size = 0; _have_idr = false; _data_cache.clear(); } } Ptr clone() const { Ptr ret(new _RingStorage()); ret->_size = _size; ret->_have_idr = _have_idr; ret->_max_size = _max_size; ret->_data_cache = _data_cache; return ret; } const List<pair<bool, T> > &getCache() const { return _data_cache; } void clearCache(){ _size = 0; _data_cache.clear(); } private: _RingStorage() = default; private: bool _have_idr = false; int _size = 0; int _max_size; List<pair<bool, T> > _data_cache; }; |
webrtc从此处reader template<typename T> class _RingReader { public: typedef std::shared_ptr<_RingReader> Ptr; friend class _RingReaderDispatcher<T>; _RingReader(const std::shared_ptr<_RingStorage<T> > &storage, bool use_cache) { _storage = storage; _use_cache = use_cache; } ~_RingReader() {} void setReadCB(const function<void(const T &)> &cb) { if (!cb) { _read_cb = [](const T &) {}; } else { _read_cb = cb; flushGop(); } } void setDetachCB(const function<void()> &cb) { if (!cb) { _detach_cb = []() {}; } else { _detach_cb = cb; } } private: void onRead(const T &data, bool is_key) { _read_cb(data); } void onDetach() const { _detach_cb(); } void flushGop() { if (!_use_cache) { return; } _storage->getCache().for_each([&](const pair<bool, T> &pr) { onRead(pr.second, pr.first); }); } private: bool _use_cache; shared_ptr<_RingStorage<T> > _storage; function<void(void)> _detach_cb = []() {}; function<void(const T &)> _read_cb = [](const T &) {}; }; |
二 推流缓冲
void EventPoller::runLoop(bool blocked,bool regist_self)
bool Socket::attachEvent(const SockFD::Ptr &sock, bool is_udp) /lambda表达式
ssize_t Socket::onRead(const SockFD::Ptr &sock, bool is_udp) noexcept
void TcpServer::onAcceptConnection(const Socket::Ptr &sock) /lambda表达式
void RtmpSession::onRecv(const Buffer::Ptr &buf)
void RtmpProtocol::onParseRtmp(const char *data, size_t size)
void HttpRequestSplitter::input(const char *data,size_t len)
const char *RtmpProtocol::onSearchPacketTail(const char *data,size_t len)
const char* RtmpProtocol::handle_C2(const char *data, size_t len)
const char* RtmpProtocol::handle_rtmp(const char *data, size_t len)
void RtmpProtocol::handle_chunk(RtmpPacket::Ptr packet)
void RtmpSession::onRtmpChunk(RtmpPacket::Ptr packet)
void onWrite(RtmpPacket::Ptr pkt, bool = true) override
void RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt)
void H264RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt)
inline void H264RtmpDecoder::onGetH264(const char* data, size_t len, uint32_t dts, uint32_t pts)
bool FrameDispatcher :: inputFrame(const Frame::Ptr &frame) override
bool H264Track::inputFrame(const Frame::Ptr &frame)
bool H264Track::inputFrame_l(const Frame::Ptr &frame)
bool FrameWriterInterfaceHelper::inputFrame(const Frame::Ptr &frame) override
bool MediaSink::addTrack(const Track::Ptr &track_in)/lambda表达式
bool MultiMediaSourceMuxer::onTrackFrame(const Frame::Ptr &frame_in)
bool RtspMediaSourceMuxer::inputFrame(const Frame::Ptr &frame) override
bool RtspMuxer::inputFrame(const Frame::Ptr &frame)
bool H264RtpEncoder::inputFrame(const Frame::Ptr &frame)
bool H264RtpEncoder::inputFrame_l(const Frame::Ptr &frame, bool is_mark)
void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint32_t pts, bool is_mark, bool gop_pos)
void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint32_t pts, bool is_mark, bool gop_pos)
bool RtpRing::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos)
void RingBuffer::write(T in, bool is_key = true)
ringbuffer超过maxsize 512之后,推流数据未被拉流的话,会清空。推流和拉流过程是独立进行,比如只ffmepg推流,webrtc不拉流,播放放。
ZLMediaKit接收ffmpeg rtmp推流相关推荐
- ffmpeg+rtmp推流/拉流(十)
一.搭建rtmp服务器 1.下载nginx https://github.com/nginx/nginx/archive/release-1.19.6.zip2.下载nginx-rtmp-module ...
- ffmpeg rtmp推流
本文实现ffmpeg本地文件rtmp推流 ffmpeg本地文件推流主要流程 ffmpeg视频格式转换示例 #include <iostream>extern "C" { ...
- 音视频开发---ffmpeg rtmp推流
目录 推流介绍 FFmpeg推流 推流器函数流程图 代码 遗留问题 参考 推流介绍 推流是将输入视频数据推送至流媒体服务器, 输入视频数据可以是本地视频文件(avi,mp4,flv......),也可 ...
- ffmpeg rtmp推流代码示例
rtmp推流,得有rtmp服务器,可以参考这篇博客搭建rtmp服务器 ===>>>ubuntu搭建rtmp服务器,如果自己有rtmp服务器,可以不用看. rtmp推流需要用flv格 ...
- ffmpeg rtmp 推流错误WriteN, RTMP send error 10053 10038
利用ffmepg推264流到rtmp服务端出现错误WriteN, RTMP send error 10053,具体如下图所示. 图1推流到rtmp服务错误 原因是视频流缺少SPS,PPS信息,加上这两 ...
- LiveNVR视频平台接收无人机等移动终端RTMP推流后转成GB28181协议输出级联到GB28181视频平台的操作说明...
1.需求介绍 目前很多移动终端设备(如无人机等)只支持RTMP推流输出,不支持GB28181协议.但是又有需要通过GB28181协议接入到视频平台的需求.比如有些大疆无人机产品不能直接注册国标平台,只 ...
- python利用ffmpeg进行rtmp推流直播
思路: opencv读取视频 -> 将视频分割为帧 -> 将每一帧进行需求加工后 -> 将此帧写入pipe管道 -> 利用ffmpeg进行推流直播 pipe管道: 啥是pipe ...
- 【音视频】利用ffmpeg实现:音视频的提取,rtmp推流等
目录 可列出电脑的设备 音频+桌面视频,存mp4 录声音 推流到服务器 音频+桌面视频,推流到服务器 音频+笔记本摄像头,推流到服务器 音频+笔记本摄像头,推流到服务器:通过wvp-pro代+AAC ...
- 最简单的基于FFmpeg的推流器(以推送RTMP为例)
===================================================== 最简单的基于FFmpeg的推流器系列文章列表: <最简单的基于FFmpeg的推流器(以 ...
最新文章
- 什么是REST?以及RESTful
- Apache与Tomcat联系及区别
- golang reflect Pointer 获取 传入的interface信息
- MFC之ComboBox控件用法
- 科普 | 5G基站功耗,到底有多可怕?
- Android -- 带你从源码角度领悟Dagger2入门到放弃(一)
- 电脑模拟器哪个好_电脑系统杀毒软件哪个好测评
- php 事件调度,MySQL的事件调度器使用介绍
- 整理LVS架构压力测试工作
- 修改删除idea快捷键
- CentOS7 安装 7-zip 压缩工具
- CKEDITOR富文本编辑器+AJAX+JQUERY+ListView综合应用
- 计算机日期的格式怎么写,在excel表格中怎么把日期格式改成文本格式(excle表格中改变日期格式)...
- thinkphp5 自定义分页样式
- 给你一个完整的社群鸭介绍
- IPQ8072A 如何通过AT指令跟SDX55交互
- 最新史上最大数据泄露,名为“Collection #1”的7.73亿数据!
- 系统重启后mipi屏幕黑屏的问题
- pq下垂控制单相逆变器matlab仿真,学习下垂控制的逆变器并联原理,如何实现仿真P1?-控制器/处理器-与非网...
- 深度学习在工业界的应用案例(二)