【live555】MediaSink类分析

来源:互联网 发布:godaddy域名优惠 编辑:程序博客网 时间:2024/06/05 08:53

MediaSink是Medium的子类。

是所有sink类的基类。


(一)MediaSink 

1. 需要他的子类实现:

(1)停止播放  stopPlaying()。(虚函数)。

在MediaSink的虚函数中,会调用这个函数,停止播放。


(2)继续播放  continuePlaying()(纯虚函数)。 

(3) 这个函数仅仅支持FramedSource类型的输入源。  (虚函数)

  virtual Boolean sourceIsCompatibleWithUs(MediaSource& source);
      // called by startPlaying()


(4)         (虚函数),如果子类直接继承的话,就是false。

  // Test for specific types of sink:     

  virtual Boolean isRTPSink() const;

(5)   虚函数,如果子类直接继承的话就是ture。

  // redefined virtual functions:
  virtual Boolean isSink() const;




2. 需要子类继承  

开始播放    startPlaying 函数。

 Boolean startPlaying(MediaSource& source, 
       afterPlayingFunc* afterFunc,
       void* afterClientData);

处理的参数是 MediaSource 类型的。

处理完数据之后,要用传入的afterPlayingFunc 函数处理afterClientData 数据。


这俩都是作为private的变量存在这个类中的:

  // The following fields are used when we're being played:
  afterPlayingFunc* fAfterFunc; //一个函数
  void* fAfterClientData;


startPlaying会调用另外两个protect的虚函数:

sourceIsCompatibleWithUs 和 continuePlaying() 


MediaSink的构造函数和析构函数是protect的:

  MediaSink(UsageEnvironment& env); // abstract base class
  virtual ~MediaSink();




3. MediaSink有一个static的方法:

  static void onSourceClosure(void* clientData); // can be used in "getNextFrame()" calls

这个 静态的方法,是被getNextFrame调用 的。


同时,还有一个非static的同名重载方法:
  void onSourceClosure();

注释说,这个函数是被continuePlaying 这个唯一的虚函数调用的,用来当检测到正在播放的source已经关闭的时候,调用。
      // should be called (on ourselves) by continuePlaying() when it
      // discovers that the source we're playing from has closed.

根据实现,可以看出:

静态的方法实际是在调用非静态的方法,并且,静态方法的所谓的参数clientData是一个MediaSInk类型的对象。

void MediaSink::onSourceClosure(void* clientData) {  MediaSink* sink = (MediaSink*)clientData;  sink->onSourceClosure();}


那这个非静态的,实际执行关闭输入源的方法,是怎么做的呢?

【1】 取消所有的等待任务。

【2】输入源域设置为NULL

【3】执行函数指针 (这个是关键过程)

  if (fAfterFunc != NULL) {    (*fAfterFunc)(fAfterClientData);  }


void MediaSink::onSourceClosure() {  // Cancel any pending tasks:  envir().taskScheduler().unscheduleDelayedTask(nextTask());  fSource = NULL; // indicates that we can be played again  if (fAfterFunc != NULL) {    (*fAfterFunc)(fAfterClientData);  }}




(2)记录着FramedSource类型的输入源。

  FramedSource* fSource;

输入源是public的。

也有一个public的方法,来返回这个输入源。

  FramedSource* source() const {return fSource;}

在构造函数中,输入源会默认置为NULL。


======


class MediaSink: public Medium {
public:
  static Boolean lookupByName(UsageEnvironment& env, char const* sinkName,
     MediaSink*& resultSink);


  typedef void (afterPlayingFunc)(void* clientData); //一个函数指针类型
  Boolean startPlaying(MediaSource& source, 
      afterPlayingFunc* afterFunc,
      void* afterClientData);
  virtual void stopPlaying();


  // Test for specific types of sink:
  virtual Boolean isRTPSink() const;


  FramedSource
* source() const {return fSource;}


protected:
  MediaSink(UsageEnvironment& env); // abstract base class
  virtual ~MediaSink();


  virtual Boolean sourceIsCompatibleWithUs(MediaSource& source);
      // called by startPlaying()
  virtual Boolean continuePlaying() = 0;
      // called by startPlaying()


  static void onSourceClosure(void* clientData); // can be used in "getNextFrame()" calls
  void onSourceClosure();
      // should be called (on ourselves) by continuePlaying() when it
      // discovers that the source we're playing from has closed.


  FramedSource* fSource;


private:

  // redefined virtual functions:
  virtual Boolean isSink() const;


private:
  // The following fields are used when we're being played:
  afterPlayingFunc* fAfterFunc; //一个函数
  void* fAfterClientData;

};



class MediaSink: public Medium {public:  static Boolean lookupByName(UsageEnvironment& env, char const* sinkName,     MediaSink*& resultSink);  typedef void (afterPlayingFunc)(void* clientData); //一个函数指针类型  Boolean startPlaying(MediaSource& source,       afterPlayingFunc* afterFunc,      void* afterClientData);  virtual void stopPlaying();  // Test for specific types of sink:  virtual Boolean isRTPSink() const;  FramedSource* source() const {return fSource;}protected:  MediaSink(UsageEnvironment& env); // abstract base class  virtual ~MediaSink();  virtual Boolean sourceIsCompatibleWithUs(MediaSource& source);      // called by startPlaying()  virtual Boolean continuePlaying() = 0;      // called by startPlaying()  static void onSourceClosure(void* clientData); // can be used in "getNextFrame()" calls  void onSourceClosure();      // should be called (on ourselves) by continuePlaying() when it      // discovers that the source we're playing from has closed.  FramedSource* fSource;private:  // redefined virtual functions:  virtual Boolean isSink() const;private:  // The following fields are used when we're being played:  afterPlayingFunc* fAfterFunc; //一个函数  void* fAfterClientData;};


====

===========================

(二)MediaSink的实现:


1 。 可以看到,sourceIsCompatibleWithUs 是检查是不是FramedSourc类型的源。


Boolean MediaSink::sourceIsCompatibleWithUs(MediaSource& source) {
  // We currently support only framed sources.
  return source.isFramedSource();  //是不是FramedSource
}


2.   当开始播放之后,记录在MediaSink中的FramedSource是被赋值的。

动用了强制类型转换,将MediaSource变为FrameSource。

fSource = (FramedSource*)&source;

也就是说fSource 非空。


同时, 这俩非常重要的私有属性,也要被赋值。

  fAfterFunc = afterFunc;  fAfterClientData = afterClientData;

可以看到,实际执行功能的方法是,唯一的纯虚函数

 continuePlaying();


Boolean MediaSink::startPlaying(MediaSource& source,afterPlayingFunc* afterFunc,void* afterClientData) {  // Make sure we're not already being played:  if (fSource != NULL) {    envir().setResultMsg("This sink is already being played");    return False;  }  // Make sure our source is compatible:  if (!sourceIsCompatibleWithUs(source)) {    envir().setResultMsg("MediaSink::startPlaying(): source is not compatible!");    return False;  }  fSource = (FramedSource*)&source;  fAfterFunc = afterFunc;  fAfterClientData = afterClientData;  return continuePlaying();}


3. 停止播放

(1)可以推测出,

获取每一帧,是由FramedSource的对象来控制的,比如说停止获取帧,就是调用 stopGettingFrames();

  // First, tell the source that we're no longer interested:  if (fSource != NULL) fSource->stopGettingFrames();


(2)MediaSink 会要求调度器停止调度其余的等待的任务。


  // Cancel any pending tasks:  envir().taskScheduler().unscheduleDelayedTask(nextTask());


(3)某个source可以再次被播放???

把fSource置为NULL,我觉得只能是让一个sink自由吧,不能改变source吧。

  fSource = NULL; // indicates that we can be played again  fAfterFunc = NULL;



4. 关闭输入源。

参见(一)3.




////////// MediaSink //////////MediaSink::MediaSink(UsageEnvironment& env)  : Medium(env), fSource(NULL) {}MediaSink::~MediaSink() {  stopPlaying();}Boolean MediaSink::isSink() const {  return True;}Boolean MediaSink::lookupByName(UsageEnvironment& env, char const* sinkName,MediaSink*& resultSink) {  resultSink = NULL; // unless we succeed  Medium* medium;  if (!Medium::lookupByName(env, sinkName, medium)) return False;  if (!medium->isSink()) {    env.setResultMsg(sinkName, " is not a media sink");    return False;  }  resultSink = (MediaSink*)medium;  return True;}Boolean MediaSink::sourceIsCompatibleWithUs(MediaSource& source) {  // We currently support only framed sources.  return source.isFramedSource();  //是不是FramedSource}Boolean MediaSink::startPlaying(MediaSource& source,afterPlayingFunc* afterFunc,void* afterClientData) {  // Make sure we're not already being played:  if (fSource != NULL) {    envir().setResultMsg("This sink is already being played");    return False;  }  // Make sure our source is compatible:  if (!sourceIsCompatibleWithUs(source)) {    envir().setResultMsg("MediaSink::startPlaying(): source is not compatible!");    return False;  }  fSource = (FramedSource*)&source;  fAfterFunc = afterFunc;  fAfterClientData = afterClientData;  return continuePlaying();}void MediaSink::stopPlaying() {  // First, tell the source that we're no longer interested:  if (fSource != NULL) fSource->stopGettingFrames();  // Cancel any pending tasks:  envir().taskScheduler().unscheduleDelayedTask(nextTask());  fSource = NULL; // indicates that we can be played again  fAfterFunc = NULL;}void MediaSink::onSourceClosure(void* clientData) {  MediaSink* sink = (MediaSink*)clientData;  sink->onSourceClosure();}void MediaSink::onSourceClosure() {  // Cancel any pending tasks:  envir().taskScheduler().unscheduleDelayedTask(nextTask());  fSource = NULL; // indicates that we can be played again  if (fAfterFunc != NULL) {    (*fAfterFunc)(fAfterClientData);  }}Boolean MediaSink::isRTPSink() const {  return False; // default implementation}void MediaSink::stopPlaying() {  // First, tell the source that we're no longer interested:  if (fSource != NULL) fSource->stopGettingFrames();  // Cancel any pending tasks:  envir().taskScheduler().unscheduleDelayedTask(nextTask());  fSource = NULL; // indicates that we can be played again  fAfterFunc = NULL;}



(三)总结一下

(1)作为所有sink基类的MediaSink ,其父类是livemedia库的基类Medium。

(2)MediaSink类的主要功能是 开始播放、停止播放,这俩是MediaSink的使命。

(3)开始播放的实际执行者叫做”继续播放“,这是一个必须由子类实现的纯虚函数。

(4)停止播放时要调用FramedSource的”停止获取帧“函数。

(5)关闭输入源这个功能

       【1】静态方法:好像是一种响应,是被"getNextFrame()" 所调用的。(这个 "getNextFrame()" 是来自哪里的???)

       【2】实际要调用一个非静态的方法,该方法的核心过程是 

  if (fAfterFunc != NULL) {    (*fAfterFunc)(fAfterClientData);  }
  这俩都是指针吧,是在”开始播放“方法中传递进来的。

 


看起来牵扯到了很多,source 、 sink  都有涉及,sink主要是跟source打交道的啊???!!!肿么没见session呢?

0 0
原创粉丝点击