整理MediaSink

This commit is contained in:
xiongziliang 2019-12-03 12:32:57 +08:00
parent c1ab73f758
commit c55f26fba7
19 changed files with 243 additions and 167 deletions

View File

@ -111,21 +111,16 @@ void MediaSink::inputFrame(const Frame::Ptr &frame) {
} }
} }
bool MediaSink::isAllTrackReady() const { vector<Track::Ptr> MediaSink::getTracks(bool trackReady) const{
return _allTrackReady; vector<Track::Ptr> ret;
}
Track::Ptr MediaSink::getTrack(TrackType type,bool trackReady) const {
lock_guard<recursive_mutex> lck(_mtx); lock_guard<recursive_mutex> lck(_mtx);
for (auto &pr : _track_map){ for (auto &pr : _track_map){
if(pr.second->getTrackType() == type){ if(trackReady && !pr.second->ready()){
if(!trackReady){ continue;
return pr.second;
} }
return pr.second->ready() ? pr.second : nullptr; ret.emplace_back(pr.second);
} }
} return std::move(ret);
return nullptr;
} }

View File

@ -38,11 +38,29 @@ using namespace toolkit;
namespace mediakit{ namespace mediakit{
class MediaSinkInterface : public FrameWriterInterface {
public:
MediaSinkInterface(){};
virtual ~MediaSinkInterface(){};
/**
* trackTrack的clone方法
* sps pps这些信息 Delegate相关关系
* @param track
*/
virtual void addTrack(const Track::Ptr & track) = 0;
/**
* track
*/
virtual void resetTracks() = 0;
};
/** /**
* Track ready()true也就是就绪后再通知派生类进行下一步的操作 * Track ready()true也就是就绪后再通知派生类进行下一步的操作
* Frame前由Track截取处理下便sps pps aa_cfg * Frame前由Track截取处理下便sps pps aa_cfg
*/ */
class MediaSink : public FrameWriterInterface , public std::enable_shared_from_this<MediaSink>{ class MediaSink : public MediaSinkInterface , public TrackSource , public std::enable_shared_from_this<MediaSink>{
public: public:
typedef std::shared_ptr<MediaSink> Ptr; typedef std::shared_ptr<MediaSink> Ptr;
MediaSink(){} MediaSink(){}
@ -59,26 +77,18 @@ public:
* sps pps这些信息 Delegate相关关系 * sps pps这些信息 Delegate相关关系
* @param track * @param track
*/ */
virtual void addTrack(const Track::Ptr & track); void addTrack(const Track::Ptr & track) override;
/** /**
* track * track
*/ */
virtual void resetTracks(); void resetTracks() override;
/** /**
* Track是否都准备好了 * Track
* @return
*/
bool isAllTrackReady() const;
/**
* Track
* @param type track类型
* @param trackReady Track * @param trackReady Track
* @return
*/ */
Track::Ptr getTrack(TrackType type,bool trackReady = true) const; vector<Track::Ptr> getTracks(bool trackReady = true) const override ;
protected: protected:
/** /**
* track已经准备好ready()true * track已经准备好ready()true

View File

@ -92,7 +92,7 @@ public:
string _param_strs; string _param_strs;
}; };
class MediaSource: public enable_shared_from_this<MediaSource> { class MediaSource: public TrackSource, public enable_shared_from_this<MediaSource> {
public: public:
typedef std::shared_ptr<MediaSource> Ptr; typedef std::shared_ptr<MediaSource> Ptr;
typedef unordered_map<string, weak_ptr<MediaSource> > StreamMap; typedef unordered_map<string, weak_ptr<MediaSource> > StreamMap;
@ -191,14 +191,6 @@ public:
} }
virtual int readerCount() = 0; virtual int readerCount() = 0;
/**
* track
* @return
*/
virtual vector<Track::Ptr> getTracks(bool trackReady) const{
return vector<Track::Ptr>(0);
}
protected: protected:
void regist() ; void regist() ;
bool unregist() ; bool unregist() ;

View File

@ -31,7 +31,7 @@
#include "Rtmp/RtmpMediaSourceMuxer.h" #include "Rtmp/RtmpMediaSourceMuxer.h"
#include "MediaFile/MediaRecorder.h" #include "MediaFile/MediaRecorder.h"
class MultiMediaSourceMuxer : public FrameWriterInterface{ class MultiMediaSourceMuxer : public MediaSink{
public: public:
typedef std::shared_ptr<MultiMediaSourceMuxer> Ptr; typedef std::shared_ptr<MultiMediaSourceMuxer> Ptr;
@ -54,25 +54,10 @@ public:
} }
virtual ~MultiMediaSourceMuxer(){} virtual ~MultiMediaSourceMuxer(){}
/**
*
* @param track
*/
void addTrack(const Track::Ptr & track) {
if(_rtmp){
_rtmp->addTrack(track);
}
if(_rtsp){
_rtsp->addTrack(track);
}
_record->addTrack(track);
}
/** /**
* *
*/ */
void resetTracks() { void resetTracks() override{
if(_rtmp){ if(_rtmp){
_rtmp->resetTracks(); _rtmp->resetTracks();
} }
@ -82,20 +67,6 @@ public:
_record->resetTracks(); _record->resetTracks();
} }
/**
* rtmp
* @param frame
*/
void inputFrame(const Frame::Ptr &frame) override {
if(_rtmp) {
_rtmp->inputFrame(frame);
}
if(_rtsp) {
_rtsp->inputFrame(frame);
}
_record->inputFrame(frame);
}
/** /**
* *
* @param listener * @param listener
@ -122,6 +93,47 @@ public:
_rtsp->setTimeStamp(stamp); _rtsp->setTimeStamp(stamp);
} }
} }
protected:
/**
*
* @param track
*/
void onTrackReady(const Track::Ptr & track) override {
if(_rtmp){
_rtmp->addTrack(track);
}
if(_rtsp){
_rtsp->addTrack(track);
}
_record->addTrack(track);
}
/**
* rtmp
* @param frame
*/
void onTrackFrame(const Frame::Ptr &frame) override {
if(_rtmp) {
_rtmp->inputFrame(frame);
}
if(_rtsp) {
_rtsp->inputFrame(frame);
}
_record->inputFrame(frame);
}
/**
* Track都准备就绪
*/
void onAllTrackReady() override{
if(_rtmp) {
_rtmp->onAllTrackReady();
}
if(_rtsp) {
_rtsp->onAllTrackReady();
}
}
private: private:
RtmpMediaSourceMuxer::Ptr _rtmp; RtmpMediaSourceMuxer::Ptr _rtmp;
RtspMediaSourceMuxer::Ptr _rtsp; RtspMediaSourceMuxer::Ptr _rtsp;

View File

@ -50,7 +50,7 @@ typedef enum {
TrackVideo = 0, TrackVideo = 0,
TrackAudio, TrackAudio,
TrackTitle, TrackTitle,
TrackMax = 0x7FFF TrackMax = 3
} TrackType; } TrackType;
/** /**

View File

@ -131,6 +131,37 @@ public:
}; };
class TrackSource{
public:
TrackSource(){}
virtual ~TrackSource(){}
/**
* Track
* @param trackReady Track
* @return
*/
virtual vector<Track::Ptr> getTracks(bool trackReady = true) const {
return vector<Track::Ptr>();
}
/**
* Track
* @param type track类型
* @param trackReady Track
* @return
*/
Track::Ptr getTrack(TrackType type , bool trackReady = true) const {
auto tracks = getTracks(trackReady);
for(auto &track : tracks){
if(track->getTrackType() == type){
return track;
}
}
return nullptr;
}
};
}//namespace mediakit }//namespace mediakit
#endif //ZLMEDIAKIT_TRACK_H #endif //ZLMEDIAKIT_TRACK_H

View File

@ -67,8 +67,12 @@ void MP4MuxerBase::init(int flags) {
} }
/////////////////////////////////// ///////////////////////////////////
void MP4Muxer::resetTracks() {
_codec_to_trackid.clear();
_started = false;
}
void MP4Muxer::onTrackFrame(const Frame::Ptr &frame) { void MP4Muxer::inputFrame(const Frame::Ptr &frame) {
if(frame->configFrame()){ if(frame->configFrame()){
//忽略配置帧 //忽略配置帧
return; return;
@ -117,7 +121,7 @@ void MP4Muxer::onTrackFrame(const Frame::Ptr &frame) {
with_nalu_size); with_nalu_size);
} }
void MP4Muxer::onTrackReady(const Track::Ptr &track) { void MP4Muxer::addTrack(const Track::Ptr &track) {
switch (track->getCodecId()) { switch (track->getCodecId()) {
case CodecAAC: { case CodecAAC: {
auto aac_track = dynamic_pointer_cast<AACTrack>(track); auto aac_track = dynamic_pointer_cast<AACTrack>(track);
@ -210,7 +214,12 @@ void MP4Muxer::onTrackReady(const Track::Ptr &track) {
} }
} }
MP4MuxerFile::MP4MuxerFile(const char *file) { MP4MuxerFile::MP4MuxerFile(const char *file){
_file_name = file;
openFile(file);
}
void MP4MuxerFile::openFile(const char *file) {
//创建文件 //创建文件
auto fp = File::createfile_file(file,"wb+"); auto fp = File::createfile_file(file,"wb+");
if(!fp){ if(!fp){
@ -237,7 +246,6 @@ MP4MuxerFile::MP4MuxerFile(const char *file) {
}); });
GET_CONFIG(bool, mp4FastStart, Record::kFastStart); GET_CONFIG(bool, mp4FastStart, Record::kFastStart);
init(mp4FastStart ? MOV_FLAG_FASTSTART : 0); init(mp4FastStart ? MOV_FLAG_FASTSTART : 0);
} }
@ -264,6 +272,12 @@ uint64_t MP4MuxerFile::onTell() {
return ftell64(_file.get()); return ftell64(_file.get());
} }
void MP4MuxerFile::resetTracks(){
MP4Muxer::resetTracks();
openFile(_file_name.data());
}
}//namespace mediakit }//namespace mediakit
#endif//#ifdef ENABLE_MP4RECORD #endif//#ifdef ENABLE_MP4RECORD

View File

@ -57,23 +57,24 @@ protected:
std::shared_ptr<mov_writer_t> _mov_writter; std::shared_ptr<mov_writer_t> _mov_writter;
}; };
class MP4Muxer : public MediaSink , public MP4MuxerBase{ class MP4Muxer : public MediaSinkInterface , public MP4MuxerBase{
public: public:
MP4Muxer() = default; MP4Muxer() = default;
~MP4Muxer() override = default; ~MP4Muxer() override = default;
protected:
/**
* track已经准备好ready()true
* sps pps等相关信息了
* @param track
*/
void onTrackReady(const Track::Ptr & track) override;
/** /**
* Track输出frameonAllTrackReady触发后才会调用此方法 * ready状态的track
* @param frame
*/ */
void onTrackFrame(const Frame::Ptr &frame) override; void addTrack(const Track::Ptr & track) override;
/**
*
*/
void inputFrame(const Frame::Ptr &frame) override;
/**
* track
*/
void resetTracks() override ;
private: private:
struct track_info{ struct track_info{
int track_id = -1; int track_id = -1;
@ -89,13 +90,16 @@ public:
typedef std::shared_ptr<MP4MuxerFile> Ptr; typedef std::shared_ptr<MP4MuxerFile> Ptr;
MP4MuxerFile(const char *file); MP4MuxerFile(const char *file);
~MP4MuxerFile(); ~MP4MuxerFile();
void resetTracks() override ;
protected: protected:
int onRead(void* data, uint64_t bytes) override; int onRead(void* data, uint64_t bytes) override;
int onWrite(const void* data, uint64_t bytes) override; int onWrite(const void* data, uint64_t bytes) override;
int onSeek( uint64_t offset) override; int onSeek( uint64_t offset) override;
uint64_t onTell() override ; uint64_t onTell() override ;
void openFile(const char *file);
private: private:
std::shared_ptr<FILE> _file; std::shared_ptr<FILE> _file;
string _file_name;
}; };
}//namespace mediakit }//namespace mediakit

View File

@ -128,7 +128,7 @@ void MP4Recorder::closeFile() {
} }
} }
void MP4Recorder::onTrackFrame(const Frame::Ptr &frame) { void MP4Recorder::inputFrame(const Frame::Ptr &frame) {
GET_CONFIG(uint32_t,recordSec,Record::kFileSecond); GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
if(!_muxer || ((_createFileTicker.elapsedTime() > recordSec * 1000) && if(!_muxer || ((_createFileTicker.elapsedTime() > recordSec * 1000) &&
(!_haveVideo || (_haveVideo && frame->keyFrame()))) ){ (!_haveVideo || (_haveVideo && frame->keyFrame()))) ){
@ -145,7 +145,7 @@ void MP4Recorder::onTrackFrame(const Frame::Ptr &frame) {
} }
} }
void MP4Recorder::onTrackReady(const Track::Ptr & track){ void MP4Recorder::addTrack(const Track::Ptr & track){
//保存所有的track为创建MP4MuxerFile做准备 //保存所有的track为创建MP4MuxerFile做准备
_tracks.emplace_back(track); _tracks.emplace_back(track);
if(track->getTrackType() == TrackVideo){ if(track->getTrackType() == TrackVideo){
@ -158,7 +158,6 @@ void MP4Recorder::resetTracks() {
_tracks.clear(); _tracks.clear();
_haveVideo = false; _haveVideo = false;
_createFileTicker.resetTime(); _createFileTicker.resetTime();
MediaSink::resetTracks();
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -55,7 +55,7 @@ public:
string strStreamId;//流ID string strStreamId;//流ID
string strVhost;//vhost string strVhost;//vhost
}; };
class MP4Recorder : public MediaSink{ class MP4Recorder : public MediaSinkInterface{
public: public:
typedef std::shared_ptr<MP4Recorder> Ptr; typedef std::shared_ptr<MP4Recorder> Ptr;
MP4Recorder(const string &strPath, MP4Recorder(const string &strPath,
@ -68,19 +68,16 @@ public:
* Track * Track
*/ */
void resetTracks() override; void resetTracks() override;
private:
/**
* Track输出frameonAllTrackReady触发后才会调用此方法
* @param frame
*/
void onTrackFrame(const Frame::Ptr &frame) override ;
/** /**
* track已经准备好ready()true * frame
* sps pps等相关信息了
* @param track
*/ */
void onTrackReady(const Track::Ptr & track) override; void inputFrame(const Frame::Ptr &frame) override;
/**
* ready状态的track
*/
void addTrack(const Track::Ptr & track) override;
private: private:
void createFile(); void createFile();
void closeFile(); void closeFile();

View File

@ -37,7 +37,7 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
class MediaRecorder : public MediaSink{ class MediaRecorder : public MediaSinkInterface{
public: public:
typedef std::shared_ptr<MediaRecorder> Ptr; typedef std::shared_ptr<MediaRecorder> Ptr;
MediaRecorder(const string &strVhost, MediaRecorder(const string &strVhost,

View File

@ -38,7 +38,7 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
class TsMuxer : public MediaSink { class TsMuxer : public MediaSinkInterface {
public: public:
TsMuxer(); TsMuxer();
virtual ~TsMuxer(); virtual ~TsMuxer();

View File

@ -41,7 +41,7 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
class DemuxerBase { class DemuxerBase : public TrackSource{
public: public:
typedef std::shared_ptr<DemuxerBase> Ptr; typedef std::shared_ptr<DemuxerBase> Ptr;
@ -57,29 +57,6 @@ public:
* @return * @return
*/ */
virtual bool isInited(int analysisMs) { return true; } virtual bool isInited(int analysisMs) { return true; }
/**
* Track
* @param trackReady Track
* @return
*/
virtual vector<Track::Ptr> getTracks(bool trackReady = true) const { return vector<Track::Ptr>();}
/**
* Track
* @param type track类型
* @param trackReady Track
* @return
*/
virtual Track::Ptr getTrack(TrackType type , bool trackReady = true) const {
auto tracks = getTracks(trackReady);
for(auto &track : tracks){
if(track->getTrackType() == type){
return track;
}
}
return nullptr;
}
}; };
@ -274,14 +251,14 @@ public:
bool isInited(int analysisMs) override; bool isInited(int analysisMs) override;
/** /**
* TrackisInited()true时调用 * Track
* @return * @return Track
*/ */
vector<Track::Ptr> getTracks(bool trackReady = true) const override; vector<Track::Ptr> getTracks(bool trackReady = true) const override;
/** /**
* *
* @return * @return ,
*/ */
float getDuration() const override; float getDuration() const override;
protected: protected:

View File

@ -48,11 +48,12 @@ public:
void setListener(const std::weak_ptr<MediaSourceEvent> &listener){ void setListener(const std::weak_ptr<MediaSourceEvent> &listener){
_mediaSouce->setListener(listener); _mediaSouce->setListener(listener);
} }
int readerCount() const{ int readerCount() const{
return _mediaSouce->readerCount(); return _mediaSouce->readerCount();
} }
private:
void onAllTrackReady() override { void onAllTrackReady(){
_mediaSouce->onGetMetaData(getMetadata()); _mediaSouce->onGetMetaData(getMetadata());
} }
private: private:

View File

@ -38,13 +38,7 @@ RtmpMuxer::RtmpMuxer(const TitleMeta::Ptr &title) {
_rtmpRing = std::make_shared<RtmpRingInterface::RingType>(); _rtmpRing = std::make_shared<RtmpRingInterface::RingType>();
} }
void RtmpMuxer::onTrackReady(const Track::Ptr &track) { void RtmpMuxer::addTrack(const Track::Ptr &track) {
//生成rtmp编码器
//克隆该Track防止循环引用
auto encoder = Factory::getRtmpCodecByTrack(track->clone());
if (!encoder) {
return;
}
//根据track生产metadata //根据track生产metadata
Metadata::Ptr metadata; Metadata::Ptr metadata;
switch (track->getTrackType()){ switch (track->getTrackType()){
@ -57,26 +51,34 @@ void RtmpMuxer::onTrackReady(const Track::Ptr &track) {
} }
break; break;
default: default:
return;; return;
} }
auto &encoder = _encoder[track->getTrackType()];
//生成rtmp编码器,克隆该Track防止循环引用
encoder = Factory::getRtmpCodecByTrack(track->clone());
if (!encoder) {
return;
}
//设置rtmp输出环形缓存
encoder->setRtmpRing(_rtmpRing);
//添加其metadata //添加其metadata
metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value){ metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value){
_metadata.set(key,value); _metadata.set(key,value);
}); });
//设置Track的代理这样输入frame至Track时最终数据将输出到RtmpEncoder中
track->addDelegate(encoder);
//Rtmp编码器共用同一个环形缓存
encoder->setRtmpRing(_rtmpRing);
} }
void RtmpMuxer::inputFrame(const Frame::Ptr &frame) {
auto &encoder = _encoder[frame->getTrackType()];
if(encoder){
encoder->inputFrame(frame);
}
}
const AMFValue &RtmpMuxer::getMetadata() const { const AMFValue &RtmpMuxer::getMetadata() const {
if(!isAllTrackReady()){
//尚未就绪
static AMFValue s_amf;
return s_amf;
}
return _metadata; return _metadata;
} }
@ -84,4 +86,12 @@ RtmpRingInterface::RingType::Ptr RtmpMuxer::getRtmpRing() const {
return _rtmpRing; return _rtmpRing;
} }
void RtmpMuxer::resetTracks() {
_metadata.clear();
for(auto &encoder : _encoder){
encoder = nullptr;
}
}
}/* namespace mediakit */ }/* namespace mediakit */

View File

@ -34,7 +34,7 @@
namespace mediakit{ namespace mediakit{
class RtmpMuxer : public MediaSink{ class RtmpMuxer : public MediaSinkInterface{
public: public:
typedef std::shared_ptr<RtmpMuxer> Ptr; typedef std::shared_ptr<RtmpMuxer> Ptr;
@ -55,16 +55,26 @@ public:
* @return * @return
*/ */
RtmpRingInterface::RingType::Ptr getRtmpRing() const; RtmpRingInterface::RingType::Ptr getRtmpRing() const;
protected:
/** /**
* track已经准备好ready()true * ready状态的track
* sps pps等相关信息了
* @param track
*/ */
void onTrackReady(const Track::Ptr & track) override ; void addTrack(const Track::Ptr & track) override;
/**
*
* @param frame
*/
void inputFrame(const Frame::Ptr &frame) override;
/**
* track
*/
void resetTracks() override ;
private: private:
RtmpRingInterface::RingType::Ptr _rtmpRing; RtmpRingInterface::RingType::Ptr _rtmpRing;
AMFValue _metadata; AMFValue _metadata;
RtmpCodec::Ptr _encoder[TrackMax];
}; };

View File

@ -48,14 +48,16 @@ public:
void setListener(const std::weak_ptr<MediaSourceEvent> &listener){ void setListener(const std::weak_ptr<MediaSourceEvent> &listener){
_mediaSouce->setListener(listener); _mediaSouce->setListener(listener);
} }
int readerCount() const{ int readerCount() const{
return _mediaSouce->readerCount(); return _mediaSouce->readerCount();
} }
void setTimeStamp(uint32_t stamp){ void setTimeStamp(uint32_t stamp){
_mediaSouce->setTimeStamp(stamp); _mediaSouce->setTimeStamp(stamp);
} }
private:
void onAllTrackReady() override { void onAllTrackReady(){
_mediaSouce->onGetSDP(getSdp()); _mediaSouce->onGetSDP(getSdp());
} }
private: private:

View File

@ -38,29 +38,34 @@ RtspMuxer::RtspMuxer(const TitleSdp::Ptr &title){
_rtpRing = std::make_shared<RtpRingInterface::RingType>(); _rtpRing = std::make_shared<RtpRingInterface::RingType>();
} }
void RtspMuxer::onTrackReady(const Track::Ptr &track) { void RtspMuxer::addTrack(const Track::Ptr &track) {
//根据track生成sdp //根据track生成sdp
Sdp::Ptr sdp = track->getSdp(); Sdp::Ptr sdp = track->getSdp();
if (!sdp) { if (!sdp) {
return; return;
} }
auto encoder = Factory::getRtpEncoderBySdp(sdp);
auto &encoder = _encoder[track->getTrackType()];
encoder = Factory::getRtpEncoderBySdp(sdp);
if (!encoder) { if (!encoder) {
return; return;
} }
//设置rtp输出环形缓存
encoder->setRtpRing(_rtpRing);
//添加其sdp //添加其sdp
_sdp.append(sdp->getSdp()); _sdp.append(sdp->getSdp());
//设置Track的代理这样输入frame至Track时最终数据将输出到RtpEncoder中 }
track->addDelegate(encoder);
//rtp编码器共用同一个环形缓存 void RtspMuxer::inputFrame(const Frame::Ptr &frame) {
encoder->setRtpRing(_rtpRing); auto &encoder = _encoder[frame->getTrackType()];
if(encoder){
encoder->inputFrame(frame);
}
} }
string RtspMuxer::getSdp() { string RtspMuxer::getSdp() {
if(!isAllTrackReady()){
//尚未就绪
return "";
}
return _sdp; return _sdp;
} }
@ -68,5 +73,12 @@ RtpRingInterface::RingType::Ptr RtspMuxer::getRtpRing() const {
return _rtpRing; return _rtpRing;
} }
void RtspMuxer::resetTracks() {
_sdp.clear();
for(auto &encoder : _encoder){
encoder = nullptr;
}
}
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -35,7 +35,7 @@ namespace mediakit{
/** /**
* rtsp生成器 * rtsp生成器
*/ */
class RtspMuxer : public MediaSink{ class RtspMuxer : public MediaSinkInterface{
public: public:
typedef std::shared_ptr<RtspMuxer> Ptr; typedef std::shared_ptr<RtspMuxer> Ptr;
@ -57,16 +57,26 @@ public:
* @return * @return
*/ */
RtpRingInterface::RingType::Ptr getRtpRing() const; RtpRingInterface::RingType::Ptr getRtpRing() const;
protected:
/** /**
* track已经准备好ready()true * ready状态的track
* sps pps等相关信息了
* @param track
*/ */
void onTrackReady(const Track::Ptr & track) override ; void addTrack(const Track::Ptr & track) override;
/**
*
* @param frame
*/
void inputFrame(const Frame::Ptr &frame) override;
/**
* track
*/
void resetTracks() override ;
private: private:
RtpRingInterface::RingType::Ptr _rtpRing;
string _sdp; string _sdp;
RtpCodec::Ptr _encoder[TrackMax];
RtpRingInterface::RingType::Ptr _rtpRing;
}; };