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不拉流,播放放。