【live555】WISInput类及其重要相关类分析
来源:互联网 发布:脑白金的网络推广案例 编辑:程序博客网 时间:2024/05/16 01:28
之前写过一篇 http://blog.csdn.net/commshare/article/details/14652363
是11月9号的,20天过去了,再看一遍,有何新的认识呢.....请看下文:
(1)WISInput作为WIS-STREAMER的最为重要的类,代表数据输入和获取。
该类处理了很多V4L2的视频输入,这里暂时不做分析。
// An interface to the WIS GO7007 capture device.// C++ header#ifndef _WIS_INPUT_HH#define _WIS_INPUT_HH#include <MediaSink.hh>//Medium的子类。class WISInput: public Medium {public: static WISInput* createNew(UsageEnvironment& env);//一帧数据的源头 FramedSource* videoSource(); FramedSource* audioSource();//私有的。private://创建的时候,由createNew来调用这个构造函数? WISInput(UsageEnvironment& env); // called only by createNew() virtual ~WISInput();//初始化,打开文件,初始化ALSA和V4L static Boolean initialize(UsageEnvironment& env); static Boolean openFiles(UsageEnvironment& env); static Boolean initALSA(UsageEnvironment& env); static Boolean initV4L(UsageEnvironment& env); //初始化视频输入设备 static void listVideoInputDevices(UsageEnvironment& env);//私有的private://友类,是啥??//打开视频文件源 friend class WISVideoOpenFileSource;//音频 friend class WISAudioOpenFileSource;//是否已经初始化了。 static Boolean fHaveInitialized;//这个是?视频文件号? static int fOurVideoFileNo;//又是一帧数据的源头,视频的?? static FramedSource* fOurVideoSource;// static int fOurAudioFileNo; static FramedSource* fOurAudioSource;};#endif
(2)这个WISInput.hh中,还有两个函数的声明,这是给sink们用的,与输出的缓冲区大小有关系:
//为RTP sink对象设置最佳的缓冲的大小的函数// Functions to set the optimal buffer size for RTP sink objects.//在每个RTPSink创建的时候被调用// These should be called before each RTPSink is created.//音视频帧的最大大小,然后给音视频帧的输出缓冲设置最大的值。#define AUDIO_MAX_FRAME_SIZE 20480#define VIDEO_MAX_FRAME_SIZE 250000inline void setAudioRTPSinkBufferSize() { OutPacketBuffer::maxSize = AUDIO_MAX_FRAME_SIZE; }inline void setVideoRTPSinkBufferSize() { OutPacketBuffer::maxSize = VIDEO_MAX_FRAME_SIZE; }
(3)
WISInput有两个友元类,
friend class WISVideoOpenFileSource;
friend class WISAudioOpenFileSource;
这俩类非常重要,随后还会分析。
这俩类需要访问WISInput的私有属性和方法有:
//私有的属性
private: static Boolean fHaveInitialized; static int fOurVideoFileNo; static FramedSource* fOurVideoSource; static int fOurAudioFileNo; static FramedSource* fOurAudioSource;
//私有的函数
private://创建的时候,由createNew来调用这个构造函数? WISInput(UsageEnvironment& env); // called only by createNew() virtual ~WISInput();//初始化,打开文件,初始化ALSA和V4L static Boolean initialize(UsageEnvironment& env); static Boolean openFiles(UsageEnvironment& env); static Boolean initALSA(UsageEnvironment& env); static Boolean initV4L(UsageEnvironment& env); //初始化视频输入设备 static void listVideoInputDevices(UsageEnvironment& env);
(4)WISInput类分析:
【1】 父类是Medium,表明WISInput类的功能将会是liveMedia的一部分,而且将作为WIS-STREAMDER中的基类存在。
////////// WISInput implementation //////////
WISInput* WISInput::createNew(UsageEnvironment& env) {
if (!fHaveInitialized) {
if (!initialize(env)) return NULL;
fHaveInitialized = True;
}
return new WISInput(env);
}
WISInput::WISInput(UsageEnvironment& env)
: Medium(env) {
}
WISInput::~WISInput() {
}
Boolean WISInput::initialize(UsageEnvironment& env) {
do {
if (!openFiles(env)) break;
if (!initALSA(env)) break;
if (!initV4L(env)) break;
return True;
} while (0);
// An error occurred
return False;
}
static void printErr(UsageEnvironment& env, char const* str = NULL) {
if (str != NULL) err(env) << str;
env << ": " << strerror(env.getErrno()) << "\n";
}
【2】 public的创建函数,欢迎大家使用她。
public:
static WISInput* createNew(UsageEnvironment& env);
【3】与俩友元有关的俩函数:
这里也是public的:难道是欢迎大家得到数据源(音频和视频的数据源是分开提供的)
//一帧数据的源头
FramedSource* videoSource();
FramedSource* audioSource();
private的:
而且是静态的啊。
static FramedSource* fOurVideoSource;
static FramedSource* fOurAudioSource;
以上俩public的函数,就是用来给外部访问这俩private的数据源(属性)用的方法。
友元是:
friend class WISVideoOpenFileSource;
friend class WISAudioOpenFileSource;
只是不理解,为啥返回的是FrameSource *类型的,这是他们的爷爷类啊。
难道是为了虚函数?,一个指向爷爷的指针,操控各个成员,得到的是爷爷类的成员实现?
FramedSource* WISInput::videoSource() { if (fOurVideoSource == NULL) { fOurVideoSource = new WISVideoOpenFileSource(envir(), *this); } return fOurVideoSource;}FramedSource* WISInput::audioSource() { if (fOurAudioSource == NULL) { fOurAudioSource = new WISAudioOpenFileSource(envir(), *this); } return fOurAudioSource;}
【4】静态函数们是类内部的功能代码:
//初始化,打开文件,初始化ALSA和V4L
static Boolean initialize(UsageEnvironment& env);
static Boolean openFiles(UsageEnvironment& env);
static Boolean initALSA(UsageEnvironment& env);
static Boolean initV4L(UsageEnvironment& env);
//初始化视频输入设备
static void listVideoInputDevices(UsageEnvironment& env);
(5)在WISInput.cpp中,有三个;类的声明和实现:
【1】
作为一个通用类,专门处理打开文件(获取一帧数据)的类WISOpenFileSource
////////// WISOpenFileSource definition ////////////文件源// A common "FramedSource" subclass, used for reading from an open file://一个通用的FrameSource 子类,用于从一个打开的文件中读取class WISOpenFileSource: public FramedSource {//保护protected: WISOpenFileSource(UsageEnvironment& env, WISInput& input, int fileNo); virtual ~WISOpenFileSource(); virtual void readFromFile() = 0;private: // redefined virtual functions: virtual void doGetNextFrame();private: static void incomingDataHandler(WISOpenFileSource* source, int mask); void incomingDataHandler1();protected: WISInput& fInput; // int fFileNo;};
注意到他的纯虚函数
virtual void readFromFile() = 0;
这个必须由子类实现,这个是获取一帧的关键函数。
2)
该类继承自FrameSource,可以参考我的http://blog.csdn.net/commshare/article/details/17072581 【live555】代表帧类型输入的媒体源的类FramedSource浅析】
因此定义了一个虚函数 doGetNextFrame(),要重新实现。
4)私有的 静态的 函数 incomingDataHandler是一个回调函数,看起来是只在WISOpenFileSource中使用的。
还有一个非staitc的函数incomingDataHandler1是实际实现incomingDataHandler的函数。
private: static void incomingDataHandler(WISOpenFileSource* source, int mask); void incomingDataHandler1();
5) 居然有一个数据域,是一个引用,指向WISInput类。
protected:
WISInput& fInput; //
int fFileNo;
6)WISOpenFileSource的实现:
////////// WISOpenFileSource implementation //////////WISOpenFileSource::WISOpenFileSource(UsageEnvironment& env, WISInput& input, int fileNo) : FramedSource(env), fInput(input), fFileNo(fileNo) {}WISOpenFileSource::~WISOpenFileSource() { envir().taskScheduler().turnOffBackgroundReadHandling(fFileNo);}void WISOpenFileSource::doGetNextFrame() { // Await the next incoming data on our FID: //在这里调用了自己实现的incomingDataHandler函数来处理。 envir().taskScheduler().turnOnBackgroundReadHandling(fFileNo, (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);}void WISOpenFileSource::incomingDataHandler(WISOpenFileSource* source, int /*mask*/) {//又做了一层封装。 source->incomingDataHandler1();}void WISOpenFileSource::incomingDataHandler1() { // Read the data from our file into the client's buffer: //调用了这个函数,读取一帧数据 readFromFile(); // Stop handling any more input, until we're ready again: envir().taskScheduler().turnOffBackgroundReadHandling(fFileNo); // Tell our client that we have new data: 这个是说有新的数据来了? afterGetting(this);}
这里,我们最关心的是doGetNextFrame的实现了,这是来自父类FramedSource的纯虚函数:
- virtual void doGetNextFrame() = 0;
- // called by getNextFrame()
子类WISOpenFileSource必须实现:
看上去是在调用一个static的函数?
void WISOpenFileSource::doGetNextFrame() {
// Await the next incoming data on our FID:
//在这里调用了自己实现的incomingDataHandler函数来处理。
envir().taskScheduler().turnOnBackgroundReadHandling(fFileNo,
(TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this);
}
这个数据处理是一个static的函数incomingDataHandler,实际调用的是一个非static的incomingDataHandler1:
void WISOpenFileSource
::incomingDataHandler(WISOpenFileSource* source, int /*mask*/) {
//又做了一层封装。
source->incomingDataHandler1();
}
/***********incomingDataHandler1()的实现*****************/
void WISOpenFileSource::incomingDataHandler1() {
// Read the data from our file into the client's buffer:
//调用了这个函数,读取一帧数据
readFromFile();
// Stop handling any more input, until we're ready again:
envir().taskScheduler().turnOffBackgroundReadHandling(fFileNo);
// Tell our client that we have new data: 这个是说有新的数据来了?
afterGetting(this);
}
这个afterGetting函数,看起来是是使用的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); }}
看起来需要执行一个以函数指针提供的函数啊:
- private:
- afterGettingFunc* fAfterGettingFunc; //处理获取到一帧之后的事儿?
可这个函数指针,又是在哪里的呢??
【2】WISOpenFileSource 有两个子类,分别处理音频和视频的打开。
他们主要是根据要求,实现WISOpenFileSource的纯虚函数readFromFIle()。
视频:
////////// WISVideoOpenFileSource definition //////////class WISVideoOpenFileSource: public WISOpenFileSource {public: WISVideoOpenFileSource(UsageEnvironment& env, WISInput& input); virtual ~WISVideoOpenFileSource();protected: // redefined virtual functions: virtual void readFromFile();};
音频:
////////// WISAudioOpenFileSource definition //////////class WISAudioOpenFileSource: public WISOpenFileSource {public: WISAudioOpenFileSource(UsageEnvironment& env, WISInput& input); virtual ~WISAudioOpenFileSource();protected: // redefined virtual functions: virtual void readFromFile();};
实际读取一帧数据的活,就是由这俩子类所实现的父类WISOpenFileSource的纯虚函数readFromFile做的。
1)读取一帧视频
void WISVideoOpenFileSource::readFromFile() { // Retrieve a filled video buffer from the kernel: unsigned i; struct v4l2_buffer buf; if (capture_start) { capture_start = 0; for (i = 0; i < MAX_BUFFERS; ++i) { memset(&buf, 0, sizeof buf); buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (ioctl(fFileNo, VIDIOC_QBUF, &buf) < 0) { printErr(envir(), "VIDIOC_QBUF"); return; } } // Start capturing: i = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fFileNo, VIDIOC_STREAMON, &i) < 0) { printErr(envir(), "VIDIOC_STREAMON"); return; } } memset(&buf, 0, sizeof buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (ioctl(fFileNo, VIDIOC_DQBUF, &buf) < 0) { printErr(envir(), "VIDIOC_DQBUF"); return; } // 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); // Send the buffer back to the kernel to be filled in again: if (ioctl(fFileNo, VIDIOC_QBUF, &buf) < 0) { printErr(envir(), "VIDIOC_QBUF"); return; }}
2)读取一帧音频
void WISAudioOpenFileSource::readFromFile() { // Read available audio data: int timeinc; int ret = read(fInput.fOurAudioFileNo, fTo, fMaxSize); if (ret < 0) ret = 0; fFrameSize = (unsigned)ret; gettimeofday(&fPresentationTime, NULL); /* PR#2665 fix from Robin * Assuming audio format = AFMT_S16_LE * Get the current time * Substract the time increment of the audio oss buffer, which is equal to * buffer_size / channel_number / sample_rate / sample_size ==> 400+ millisec */ timeinc = fFrameSize * 1000 / audioNumChannels / (audioSamplingFrequency/1000) / 2; while (fPresentationTime.tv_usec < timeinc) { fPresentationTime.tv_sec -= 1; timeinc -= 1000000; } fPresentationTime.tv_usec -= timeinc;}
因此,核心的重要的需要修改的功能就在于如何去实现这俩函数。
- 【live555】WISInput类及其重要相关类分析
- 【live555】WISInput类分析
- 【live555】MediaSink类分析
- live555 类图结构分析
- 和数据分析相关的重要Python类库介绍
- (重要)live555开源工程 相关资料
- Live555 分析(一):类介绍
- C#:类及其相关
- MonoBehaviour继承类及其重要方法
- live555相关
- 类Rectangle及其相关操作
- live555 分析
- live555 分析
- Live555类结构
- live555-基础类
- Live555学习基础类
- 二、Live555 基础类
- live555类关系图
- MFC中使用正则表达式
- scalar and list context in Perl
- linux中select()函数分析
- Java基础知识学习三 (String类型,字符串处理)
- ubuntu1204常用快捷键
- 【live555】WISInput类及其重要相关类分析
- usaco_3.2.2
- cocos2d-x按钮回调方法的参数
- android中的侧滑效果
- ubuntu12.04下redis安装/配置
- pthread_create()之前的基本设置
- linux字符设备驱动
- html常用特殊字符(备用)
- java中如何实现swap(int a,int b)