【live555】代表帧类型输入的媒体源的类FramedSource浅析

原创 2013年12月02日 14:55:26


======FramedSource类===============

个人理解,对于按照一帧一帧的输入给rtsp服务器的媒体源,应该继承FramedSource类。

当然,看起来FramedSource比较通用吧,还有专门的“帧源”的类,比如在MediaSource中,

就有几种不同的视频帧的源/jpeg源/音频源,FramedSource仅仅是其中之一。


MediaSource知道眼下自己支持这么几种源(她的子类了吧):

  // Test for specific types of source:
  virtual Boolean isFramedSource() const; //帧
  virtual Boolean isRTPSource() const;  //RTP
  virtual Boolean isMPEG1or2VideoStreamFramer() const;  //mpeg1和mpeg2 视频流帧
  virtual Boolean isMPEG4VideoStreamFramer() const;  //mpeg4视频流帧
  virtual Boolean isH264VideoStreamFramer() const;  //h264视频流帧
  virtual Boolean isDVVideoStreamFramer() const;   //DV视频流
  virtual Boolean isJPEGVideoSource() const;  //JPEG视频
  virtual Boolean isAMRAudioSource() const;  //AMR音频


=======

FramedSource类:

// "liveMedia"
// Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
// Framed Sources
// C++ header

#ifndef _FRAMED_SOURCE_HH
#define _FRAMED_SOURCE_HH

#ifndef _NET_COMMON_H
#include "NetCommon.h"
#endif
#ifndef _MEDIA_SOURCE_HH
#include "MediaSource.hh"
#endif

class FramedSource: public MediaSource {
public:
  static Boolean lookupByName(UsageEnvironment& env, char const* sourceName,
			      FramedSource*& resultSource);

  typedef void (afterGettingFunc)(void* clientData, unsigned frameSize,
				  unsigned numTruncatedBytes,
				  struct timeval presentationTime,
				  unsigned durationInMicroseconds);
  typedef void (onCloseFunc)(void* clientData);
  void getNextFrame(unsigned char* to, unsigned maxSize,
		    afterGettingFunc* afterGettingFunc,
		    void* afterGettingClientData,
		    onCloseFunc* onCloseFunc,
		    void* onCloseClientData);

  static void handleClosure(void* clientData);
      // This should be called (on ourself) if the source is discovered
      // to be closed (i.e., no longer readable)

  void stopGettingFrames();

  virtual unsigned maxFrameSize() const;
      // size of the largest possible frame that we may serve, or 0
      // if no such maximum is known (default)

  virtual void doGetNextFrame() = 0;
      // called by getNextFrame()

  Boolean isCurrentlyAwaitingData() const {return fIsCurrentlyAwaitingData;}

  static void afterGetting(FramedSource* source);
      // doGetNextFrame() should arrange for this to be called after the
      // frame has been read (*iff* it is read successfully)

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

  virtual void doStopGettingFrames();

protected:
  // The following variables are typically accessed/set by doGetNextFrame()
  unsigned char* fTo; // in
  unsigned fMaxSize; // in
  unsigned fFrameSize; // out
  unsigned fNumTruncatedBytes; // out
  struct timeval fPresentationTime; // out
  unsigned fDurationInMicroseconds; // out

private:
  // redefined virtual functions:
  virtual Boolean isFramedSource() const;

private:
  afterGettingFunc* fAfterGettingFunc;   //处理获取到一帧之后的事儿?
  void* fAfterGettingClientData;   
  onCloseFunc* fOnCloseFunc;  //响应关闭
  void* fOnCloseClientData;

  Boolean fIsCurrentlyAwaitingData;
};

#endif


=====--1

定义两个函数指针,专门用来处理特定的行为:

  typedef void (afterGettingFunc)(void* clientData, unsigned frameSize,
 unsigned numTruncatedBytes,
 struct timeval presentationTime,
 unsigned durationInMicroseconds);
  typedef void (onCloseFunc)(void* clientData);

是不是有很多种 处理方法,而且可以让其他人的代码来注册给live555使用?


调用他们的函数:

//当一帧被成功读取,之后,应该做的事儿。

  static void afterGetting(FramedSource* source);
      // doGetNextFrame() should arrange for this to be called after the
      // frame has been read
(*iff* it is read successfully)


//当发现数据源已经关闭,这个函数要被调用来处理关闭。

  static void handleClosure(void* clientData);
      // This should be called (on ourself) if the source is discovered
      // to be closed (i.e., no longer readable)


========2 定义了一个纯虚函数

这个必须要由子类实现。

 virtual void doGetNextFrame() = 0;

      // called by getNextFrame()

他的调用者是 :



  void getNextFrame(unsigned char* to, unsigned maxSize,
    afterGettingFunc* afterGettingFunc,
    void* afterGettingClientData,
    onCloseFunc* onCloseFunc,
    void* onCloseClientData);

=========MediaSource============BEGIN========


FramedSource类继承自MediaSource,我想,MediaSource应该就是所有媒体源的基类了吧。

当然,liveMedia文件下的各位类,都是继承自Medium这个基类的。


这个“媒体源”的基类,除了辨别是哪几种源,其他的主要的成员函数有:

=====

  static Boolean lookupByName(UsageEnvironment& env, char const* sourceName,
     MediaSource*& resultSource);
  virtual void getAttributes() const;
      // attributes are returned in "env's" 'result message'



  // The MIME type of this source:
  virtual char const* MIMEtype() const;   //源的MIME类型。


protected:
  MediaSource(UsageEnvironment& env); // abstract base class 抽象基类
  virtual ~MediaSource();


private:
  // redefined virtual functions:
  virtual Boolean isSource() const;  //是不是一个源


看了之后,感觉MediaSource果然是足够基础的源。



===MediaSource 类:

// "liveMedia"
// Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
// Media Sources
// C++ header

#ifndef _MEDIA_SOURCE_HH
#define _MEDIA_SOURCE_HH

#ifndef _MEDIA_HH
#include "Media.hh"
#endif

class MediaSource: public Medium {
public:
  static Boolean lookupByName(UsageEnvironment& env, char const* sourceName,
			      MediaSource*& resultSource);
  virtual void getAttributes() const;
      // attributes are returned in "env's" 'result message'

  // The MIME type of this source:
  virtual char const* MIMEtype() const;

  // Test for specific types of source:  //特定类型的源的测试,可以知道是那种源么?
  virtual Boolean isFramedSource() const;
  virtual Boolean isRTPSource() const;
  virtual Boolean isMPEG1or2VideoStreamFramer() const;
  virtual Boolean isMPEG4VideoStreamFramer() const;
  virtual Boolean isH264VideoStreamFramer() const;
  virtual Boolean isDVVideoStreamFramer() const;
  virtual Boolean isJPEGVideoSource() const;
  virtual Boolean isAMRAudioSource() const;

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

private:
  // redefined virtual functions:
  virtual Boolean isSource() const;  //在这个类里头,重新实现了的来自父类的虚函数
};

#endif


=============MediaSource============END==========

看下实现:

MediaSource类的实现:


// "liveMedia"
// Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
// Media Sources
// Implementation


#include "MediaSource.hh"


////////// MediaSource //////////


MediaSource::MediaSource(UsageEnvironment& env)
: Medium(env) { //这是初始化父类的构造函数吧

}


MediaSource::~MediaSource() {
}

//默认是源
Boolean MediaSource::isSource() const {
  return True;
}

//默认的MIME类型。
char const* MediaSource::MIMEtype() const {
  return "application/OCTET-STREAM"; // default type
}


/*下面的默认全都不是*/
Boolean MediaSource::isFramedSource() const {
  return False; // default implementation
}
Boolean MediaSource::isRTPSource() const {
  return False; // default implementation
}
Boolean MediaSource::isMPEG1or2VideoStreamFramer() const {
  return False; // default implementation
}
Boolean MediaSource::isMPEG4VideoStreamFramer() const {
  return False; // default implementation
}
Boolean MediaSource::isH264VideoStreamFramer() const {
  return False; // default implementation
}
Boolean MediaSource::isDVVideoStreamFramer() const {
  return False; // default implementation
}
Boolean MediaSource::isJPEGVideoSource() const {
  return False; // default implementation
}
Boolean MediaSource::isAMRAudioSource() const {
  return False; // default implementation
}


Boolean MediaSource::lookupByName(UsageEnvironment& env,
 char const* sourceName,
 MediaSource*& resultSource) {
  resultSource = NULL; // unless we succeed


  Medium* medium;
  if (!Medium::lookupByName(env, sourceName, medium)) return False;


  if (!medium->isSource()) {
    env.setResultMsg(sourceName, " is not a media source");
    return False;
  }


  resultSource = (MediaSource*)medium;
  return True;
}


void MediaSource::getAttributes() const {
  // Default implementation
  envir().setResultMsg("");
}


================FramedSource类的实现=============

// "liveMedia"
// Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
// Framed Sources
// Implementation


#include "FramedSource.hh"
#include <stdlib.h>


////////// FramedSource //////////

//构造函数中,设置初始值。
FramedSource::FramedSource(UsageEnvironment& env)
  : MediaSource(env),
    fAfterGettingFunc(NULL), fAfterGettingClientData(NULL),
    fOnCloseFunc(NULL), fOnCloseClientData(NULL),
    fIsCurrentlyAwaitingData(False) {
  fPresentationTime.tv_sec = fPresentationTime.tv_usec = 0; // initially
}


FramedSource::~FramedSource() {
}


Boolean FramedSource::isFramedSource() const {
  return True;
}


Boolean FramedSource::lookupByName(UsageEnvironment& env, char const* sourceName,
  FramedSource*& resultSource) {
  resultSource = NULL; // unless we succeed


  MediaSource* source;
  if (!MediaSource::lookupByName(env, sourceName, source)) return False;


  if (!source->isFramedSource()) {
    env.setResultMsg(sourceName, " is not a framed source");
    return False;
  }


  resultSource = (FramedSource*)source;
  return True;
}


void FramedSource::getNextFrame(unsigned char* to, unsigned maxSize,
afterGettingFunc* afterGettingFunc,
void* afterGettingClientData,
onCloseFunc* onCloseFunc,
void* onCloseClientData) {
  // Make sure we're not already being read:
  if (fIsCurrentlyAwaitingData) {
    envir() << "FramedSource[" << this << "]::getNextFrame(): attempting to read more than once at the same time!\n";
    envir().internalError();
  }


  fTo = to;
  fMaxSize = maxSize;
  fNumTruncatedBytes = 0; // by default; could be changed by doGetNextFrame()
  fDurationInMicroseconds = 0; // by default; could be changed by doGetNextFrame()
  fAfterGettingFunc = afterGettingFunc;
  fAfterGettingClientData = afterGettingClientData;
  fOnCloseFunc = onCloseFunc;
  fOnCloseClientData = onCloseClientData;
  fIsCurrentlyAwaitingData = True;


  doGetNextFrame();  //这是一个纯虚函数。FramedSource中声明的。必须由子类实现
}


void FramedSource::afterGetting(FramedSource* source) {
  source->fIsCurrentlyAwaitingData = False;
      // indicates that we can be read again
      // Note that this needs to be done here, in case the "fAfterFunc"
      // called below tries to read another frame (which it usually will)


  if (source->fAfterGettingFunc != NULL) {
    (*(source->fAfterGettingFunc))(source->fAfterGettingClientData,
  source->fFrameSize, source->fNumTruncatedBytes,
  source->fPresentationTime,
  source->fDurationInMicroseconds);
  }
}


void FramedSource::handleClosure(void* clientData) {
  FramedSource* source = (FramedSource*)clientData;
  source->fIsCurrentlyAwaitingData = False; // because we got a close instead
  if (source->fOnCloseFunc != NULL) {
    (*(source->fOnCloseFunc))(source->fOnCloseClientData);
  }
}

/**停止获取帧*/
void FramedSource::stopGettingFrames() { //停止读取帧。
  fIsCurrentlyAwaitingData = False; // indicates that we can be read again
  fAfterGettingFunc = NULL;
  fOnCloseFunc = NULL;


  // Perform any specialized action now:
  doStopGettingFrames();
}


void FramedSource::doStopGettingFrames() {
  // Default implementation: Do nothing except cancel any pending 'delivery' task:
  envir().taskScheduler().unscheduleDelayedTask(nextTask());
  // Subclasses may wish to redefine this function.
}


unsigned FramedSource::maxFrameSize() const {
  // By default, this source has no maximum frame size.
  return 0;
}
  void getNextFrame(unsigned char* to, unsigned maxSize,
    afterGettingFunc* afterGettingFunc,
    void* afterGettingClientData,
    onCloseFunc* onCloseFunc,
    void* onCloseClientData);

==============之前说过了,doGetNextFrame()是一个纯虚函数,需要子类实现,
WISOpenFileSource就是FramedSource的一个子类:
class WISOpenFileSource: public FramedSource {

他声明了一个虚函数doGetNextFrame():

private: // redefined virtual functions:
  virtual void doGetNextFrame();


并且实现了它:
void WISOpenFileSource::doGetNextFrame() {
  // Await the next incoming data on our FID:
  envir().taskScheduler().turnOnBackgroundReadHandling(fFileNo,
	       (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
}

参考WISInput.cpp

==============FramedSource类的这个几个值,也必须被子类的函数填充。至少他们是典型的应该被填充的值。

protected:
  // The following variables are typically accessed/set by doGetNextFrame()
  unsigned char* fTo; // in
  unsigned fMaxSize; // in
  unsigned fFrameSize; // out
  unsigned fNumTruncatedBytes; // out
  struct timeval fPresentationTime; // out
  unsigned fDurationInMicroseconds; // out

看他们是如何被填充的:
这是来自void WISVideoOpenFileSource::readFromFile() 的代码,
他填充了这几个值中的部分(fNumTruncatedBytes,fMaxSize、fMaxSize、fPresentationTime、fTo),也说明了不一定要被doGetNextFrame()填充,其他函数也可以:

  // Note the timestamp and size:
  fPresentationTime = buf.timestamp;
  fFrameSize = buf.bytesused;
  if (fFrameSize > fMaxSize) {
    fNumTruncatedBytes = fFrameSize - fMaxSize;
    fFrameSize = fMaxSize;
  } else {
    fNumTruncatedBytes = 0;
  }


  // Copy to the desired place:
  memmove(fTo, buffers[buf.index].addr, fFrameSize);


live555学习-FramedSource详解

FramedSource讲解 FramedSource是一个抽象类,继承自mediaSource

live555学习-FramedSource详解

FramedSource讲解 FramedSource是一个抽象类,继承自mediaSource继承自medium,里面有纯虚函数virtual void doGetNextFrame() = ...

live555直播(准备2)-重写doGetNextFrame()和doEventLoop()

#include "live555/liveMedia.hh" #include "live555/BasicUsageEnvironment.hh" #include "live555/Framed...

live555从RTSP服务器读取数据到使用接收到的数据流程分析

本文在linux环境下编译live555工程,并用cgdb调试工具对live555工程中的testProgs目录下的openRTSP的执行过程进行了跟踪分析,直到将从socket端读取视频数据并保存为...
  • c_m_deng
  • c_m_deng
  • 2013年01月09日 17:30
  • 10986

live555从RTSP服务器读取数据到使用接收到的数据流程分析

本文在linux环境下编译live555工程,并用cgdb调试工具对live555工程中的testProgs目录下的openRTSP的执行过程进行了跟踪分析,直到将从socket端读取视频数据并保存为...

流媒体学习笔记2(live555中的Session)

毕业课题打算从最原始的地方做起。好吧,那就从live555采集转发本地摄像头视频开始吧。首先从源码开始吧,今天看了点liveMedia中的session,这里做个总结。 整个源码中的继承顺序为H264...

【live555】Medium的子类们的静态方法lookupByName的实现

liveMedia的基类Medium,有一个非常重要的静态方法: staitc Boolean lookupByName(UsageEnvrionment &env,char const * medi...

浅析live555媒体库之实现实时码流预览

live555实时码流预览的相关实现操作。

浅析live555媒体库之自己实现文件流的读写

博客前面两篇基本介绍了live555的一些入门知识以及大致的工作流程框架。下面就是代码的实现,如果通过自己实现的子类是实现文件流的播放。 主要实现两个子类即可:FramedSource 和 FileS...

【流媒体学习】live555学习(二):基础类

参考 http://blog.csdn.net/niu_gao/article/details/6906163    讲几个重要的基础类: BasicUsageEnvironment和Usa...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【live555】代表帧类型输入的媒体源的类FramedSource浅析
举报原因:
原因补充:

(最多只允许输入30个字)