Pipeline是媒体处理的核心流程逻辑。

Pipeline里面定义了两个主要的概念:Service和Handler。

Service负责处理那些不仅要看当前数据包,还要分析之前的数据包的那些业务,比如丢包重传;Handler处理当前的数据包的情形,比如生成填充字节。

在Pipeline里面,Handler和Service是配合起来一起工作的,他们通过一套框架将之关联起来。

先看看使用上:

void MediaStream::initializePipeline() {handler_manager_ = std::make_shared<HandlerManager>(shared_from_this());pipeline_->addService(shared_from_this());pipeline_->addService(handler_manager_);pipeline_->addService(rtcp_processor_);pipeline_->addService(stats_);pipeline_->addService(quality_manager_);pipeline_->addService(packet_buffer_);pipeline_->addFront(std::make_shared<PacketReader>(this));pipeline_->addFront(std::make_shared<RtcpProcessorHandler>());pipeline_->addFront(std::make_shared<FecReceiverHandler>());pipeline_->addFront(std::make_shared<LayerBitrateCalculationHandler>());pipeline_->addFront(std::make_shared<QualityFilterHandler>());pipeline_->addFront(std::make_shared<IncomingStatsHandler>());pipeline_->addFront(std::make_shared<RtpTrackMuteHandler>());pipeline_->addFront(std::make_shared<RtpSlideShowHandler>());pipeline_->addFront(std::make_shared<RtpPaddingGeneratorHandler>());pipeline_->addFront(std::make_shared<PliPacerHandler>());pipeline_->addFront(std::make_shared<BandwidthEstimationHandler>());pipeline_->addFront(std::make_shared<RtpPaddingRemovalHandler>());pipeline_->addFront(std::make_shared<RtcpFeedbackGenerationHandler>());pipeline_->addFront(std::make_shared<RtpRetransmissionHandler>());pipeline_->addFront(std::make_shared<SRPacketHandler>());pipeline_->addFront(std::make_shared<SenderBandwidthEstimationHandler>());pipeline_->addFront(std::make_shared<LayerDetectorHandler>());pipeline_->addFront(std::make_shared<OutgoingStatsHandler>());pipeline_->addFront(std::make_shared<PacketCodecParser>());pipeline_->addFront(std::make_shared<PacketWriter>(this));pipeline_->finalize();pipeline_initialized_ = true;
}

在初始化时,pipeline调用了addService和addFront接口,将Service和Handler添加到pipeline中去。在初始化里面,我们可以看到其支持了哪些处理。

在实际使用中,接收到的数据,调用pipeline的read接口,就完成了解析为裸数据的事儿;调用write接口,就完成了fec等处理数据的事儿。

pipeline的数据,read的源需要是srtp解密后的数据,处理后为rtp裸数据;write的源为rtp裸数据,处理后的数据经过srtp加密输出到网络。(网络使用的是DtlsTransport接口对接的)

这些功能先不去管它,这里先弄清楚他们的架构和工作方式。

阅读这块儿的代码真是不容易,使用了很多模板类,为了方便理解,菜鸟哥根据代码,把所有的模板类替换为了实际的基类,来进行理解。

先看看pipeline的Service部分的继承体系以及数据结构:

再结合PipelineBase的addService实现,看一下Service是干啥用的

template <class S>
void PipelineBase::addService(std::shared_ptr<S> service) {typedef typename ServiceContextType<S>::type Context;service_ctxs_.push_back(std::make_shared<Context>(shared_from_this(), std::move(service)));
}

template <class Service>
struct ServiceContextType {typedef ServiceContextImpl<Service> type;
};

addService其实就是传递一个Service的子类对象,这个子类对象是用来给Context的构造函数传递参数的;Context就是ServiceContextImpl,也就是说addService里面的参数,就是为了创建一个ServiceContextImpl对象,这个对象创建出来以后,被存储在pipelinebase的service_ctxs_成员中。在addService接口中,还将pipeline自身,作为参数,传递给了ServiceContextImpl。通过代码看看这些参数怎么用

  explicit ServiceContextImpl(std::weak_ptr<PipelineBase> pipeline,std::weak_ptr<S> service) {this->impl_ = this;this->initialize(pipeline, std::move(service));}void initialize(std::weak_ptr<PipelineBase> pipeline,std::weak_ptr<S> service) {pipeline_weak_ = pipeline;pipeline_raw_ = pipeline.lock().get();service_ = std::move(service);}

std::weak_ptr<S> getService() {
       return service_;
    }

ServiceContextImpl在构造时存储了PipelineBase和Service,这样外面再使用时,可以通过getService来获取到Service的实例。

这个获取操作很重要,看一下pipeline的notifyUpdate方法,看实际的处理handler(RtcpProcessorHandler)

void RtcpProcessorHandler::notifyUpdate() {auto pipeline = getContext()->getPipelineShared();if (pipeline && !stream_) {stream_ = pipeline->getService<MediaStream>().get();processor_ = pipeline->getService<RtcpProcessor>();stats_ = pipeline->getService<Stats>();}
}

这个地方好神奇,通过调用getService方法,模板传递不同的类型,则能够获取到不同的对象实例。看一下getService方法

template <class S>
std::shared_ptr<S> PipelineBase::getService() {auto ctx = getServiceContext<S>();return ctx ? ctx->getService().lock() : std::shared_ptr<S>();
}template <class S>
typename ServiceContextType<S>::type* PipelineBase::getServiceContext() {for (auto pipeline_service_ctx : service_ctxs_) {auto ctx = dynamic_cast<typename ServiceContextType<S>::type*>(pipeline_service_ctx.get());if (ctx) {return ctx;}}return nullptr;
}

在getServiceContext方法里面,遍历了pipeline的service_ctxs_,并对每一个ctx进行dynamic_cast转换,能够成功,就返回,不能成功就继续。这个地方真是灵活使用,奇思妙想。

到这里,就形成了一个共享的方式,所有的handler,都可以获得到所有的service的子类实例,在实现过程中就极大的提升了灵活性,每个service独立做自己的事儿,并且由handler直接进行数据驱动,简直太符合这个媒体处理的需要了。

总结:Service的核心意义是共享,即每个handler都可以通过类型来获取到所有的Service子类实例,进行使用,而不必要为每个Handler定义不同的接口来传递Service对象。Service也为了多个Handler公用数据而提供服务。

转载于:https://www.cnblogs.com/limedia/p/licode_erizo_pipeline_service.html

licode学习之erizo篇--Pipeline_service相关推荐

  1. licode学习之编译篇--3

    上一篇中,提示找不到NICE库,先看看CMakList里面吧 [root@localhost erizo]# pwd /home/test/licode-master/erizo [root@loca ...

  2. licode 学习总结

    licode 学习总结 参考: licode编译以及源码分析:https://www.cnblogs.com/limedia/category/1350712.html Licode-基于webrtc ...

  3. 深度学习——数据预处理篇

    深度学习--数据预处理篇 文章目录 深度学习--数据预处理篇 一.前言 二.常用的数据预处理方法 零均值化(中心化) 数据归一化(normalization) 主成分分析(PCA.Principal ...

  4. [BTS]BizTalk学习之Functoid篇(ID Cross-References)

    早在三周前,就已经收集了所有有关Cross-Reference Functoid的资源,虽然现在看来,它并不是很难,但想真正的应用它,还是需要花费一些心思的研究一下,不过,托了三周时间,还是写完了. ...

  5. RabbitMQ学习总结 第一篇:理论篇

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  6. redis 3.0 cluster 集群 学习之路篇 [3]

    周氏一族,整理技术文档,给下一代留点教程...... redis 3.0 cluster 安装篇,请看 http://zhoushouby.blog.51cto.com/9150272/1560400 ...

  7. ASP.NET MVC学习之路由篇(2)

    ASP.NET MVC学习之路由篇(2) 原文:ASP.NET MVC学习之路由篇(2) 继ASP.NET MVC学习之路由篇(1)后继续学习. 7.解决与物理路径的冲突 当发送一个请求至ASP.NE ...

  8. python学习历程-安装篇(一)

    python学习历程-安装篇 之前工作中数据量很少,每天也就是用excel发一下报表,函数已经足够应付工作内容,但心里一直渴望学习更深层次一点的数据分析(崇拜那些技术大神),网上看了很多有关数据分析挖 ...

  9. [mmu/cache]-ARM MMU的学习笔记-一篇就够了

    ★★★ 个人博客导读首页-点击此处 ★★★ . 说明: 在默认情况下,本文讲述的都是ARMV8-aarch64架构,linux kernel 64位 . 相关文章 1.ARM cache的学习笔记-一 ...

最新文章

  1. IDEA直接跳转到方法的实现类快捷键
  2. diagram怎么记忆_UML20以上14图的解释、分类记忆方法及类之间6种关系
  3. 修改mysql数据引擎的方法- 提高数据库性能
  4. 三年Java,真的卷不动了……
  5. 深入探索 IBM 数据分析和预测软件 - PASW Modeler
  6. ubuntu 11.10 使用 emacs-23.4 开发 erlang 整理之 安装distel
  7. XML的概述,.Dom4解析和SAX解析
  8. LeetCode—Python版数组简单题(一)
  9. apt安装openjdk8
  10. Oracle表字段的增加、删除、修改和重命名
  11. 中国农药中间体行业发展前景预测与投资规划建议报告2021-2027年版
  12. moodle 中文文件名无法打开和下载问题
  13. 消费者运营咨询顾问认证
  14. 微信开放平台应用申请
  15. 美丽中国 纪录片 高频词 GRE 托福词汇
  16. 如何正确薅华为云的羊毛
  17. 一卡通(M1卡)破解过程记录——理论篇
  18. [收藏]家用三线插座(220V单相)正确接线方法
  19. 12 搜索之DSL--基础查询
  20. css盒模型(css盒模型包括)

热门文章

  1. jdk,Eclipse,SWTDesigner安装【原创】
  2. uboot的readme导读(转)
  3. 「软件测试」刚从腾讯面试出来,留下了这些面试笔记
  4. java tts引擎_让Java说话-用Java实现语音引擎
  5. 走进markdown
  6. http mjpeg 图像读取
  7. u-boot移植随笔:u-boot的内存分布图
  8. 点击图片旋转180_一起来点亮斗门!请你旋转手机屏幕90横屏并点击图片!
  9. 【Spring] Spring boot 报错 Unable to start ServletWebServerApplicationContext due to missing ServletWe
  10. Spring : @Value注解