随笔-104  评论-133  文章-4  trackbacks-0
  2019年10月29日
     摘要: 转自:https://blog.csdn.net/A771642/article/details/70284335Settings主界面加载时序图(1)先看一下主界面布局主界面对象介绍:(1)主界面(除了Suggestion,condition)其他对象都在List<DashBoardCagtory> Categories里面(2) Categories 有 4个对象。4个DashBo...  阅读全文
posted @ 2019-10-29 17:34 lfc 阅读(11) | 评论 (0)编辑 收藏
  2019年7月31日
     摘要: 引言主要目的是为了搞清楚众多的socket正文1、RTSPClient::sendDescribeCommandCode highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->Code highlighting produced by Actipro CodeHigh...  阅读全文
posted @ 2019-07-31 13:41 lfc 阅读(33) | 评论 (0)编辑 收藏
  2019年7月30日
     摘要: 八 RTSPClient分析 有RTSPServer,当然就要有RTSPClient。 如果按照Server端的架构,想一下Client端各部分的组成可能是这样: 因为要连接RTSP server,所以RTSPClient要有TCP socket。当获取到server端的DESCRIBE后,应建立一个对应于ServerMediaSession的ClientMediaSession。对应每...  阅读全文
posted @ 2019-07-30 14:33 lfc 阅读(41) | 评论 (0)编辑 收藏
  2018年12月12日
一、windows下编译

   不推荐,主要是编译太慢。

二、linux下编译
      请参考:https://blog.csdn.net/u010311952/article/details/80658999
     
      我使用的ffmpeg版本是3.2.4,系统ubuntu 14.04,配置命令如下:
./configure --disable-static --enable-shared --enable-cross-compile --cross-prefix=i686-w64-mingw32- --target-os=mingw32 --arch=x86 --enable-gpl --enable-version3 --enable-runtime-cpudetect --prefix=/home/lfc/ffmpeg-win32/out --disable-avdevice --disable-avfilter
注:编译成static库也试过,make install时候提示莫名错误,而且vc下使用还得依赖一些gcc、mingw的库,所以放弃了。

后记
      如果只需要使用ffmpeg,而不需要在上面增加自己的东西的话,可以直接使用别人编译好的:
      https://ffmpeg.zeranoe.com/builds
posted @ 2018-12-12 13:06 lfc 阅读(44) | 评论 (0)编辑 收藏
  2018年6月1日
这段时间断断续续的在搞Onvif server,走了不少弯路,跌跌撞撞走过来,现在对接onvif test tool和海康NVR都成功了,顺便做一下记录,也供其他刚入门的朋友参考。
1、gsoap工具
其实这真的就是个工具,用于从onvif的描述文件(*wsdl等)生成框架代码(c/c++),把繁琐的xml描述变成结构体,把服务变成api调用,并提供一些封装好的工具soap_xxx。
有人喜欢这种工具(像我),也有人对它深恶痛之(主要还是因为编译出来的可执行文件大吧)。群上有高手是通过抓IPC的包,然后自己写简单的网络通信程序来发送抓包内容来实现的,简单粗暴,不过本人不喜欢这种方式,我更偏向于用gsoap工具,虽然刚开始会被它自动生成的结构体搞混,可是仔细对照协议或抓包数据来看,脉络还是很清晰的,而且这样的代码不容易犯错,更方便维护。
至于如何用gsop生产框架代码,网上有很多介绍,我自己也曾经生成过,不过后面是直接用别人生产好的^_^
2、哪些API需要实现?
我用onvif test tool调试的话,只需要实现下面几个API即可:
1)__wsdd__Probe
2)__tds__GetDeviceInformation
3)__tds__GetCapabilities
4)__tds__GetServices
5)__trt__GetProfiles
6)__trt__GetStreamUri
这么多API要实现,对于初学者来说是一件很困难的事,要是有类似live555这种开源工程供参考就好了。遗憾的是没有,幸好网上零零散散的有几个人分享的源码(最后我会列出来),虽然不尽完善,有的还有bug,不过刚好足够开个头。
后面要接海康NVR,发现又得多实现几个API(有的还没参考代码):
1)__tds__GetSystemDateAndTime
2)__tds__SetSystemDateAndTime
3)__tds__GetNetworkInterfaces
4)__trt__GetVideoEncoderConfiguration
5)__trt__GetVideoEncoderConfigurationOptions
3、总结:
Onvif其实有点像我们产品的参数配置协议(不够要复杂多了),一路开发过来,感觉有以下几点体会:
1)像我做onvif server端,手上要准备好一个IPC,电脑要装好onvif test tool工具,高手还会用Wireshark工具(我曾经用过,不够觉得没有onvif test tool工具好用)
2)gsoap里面的结构体,很多成员都需要调用soap_malloc申请的,注意申请后养成memset的好习惯,否则可能会碰到怪问题(我曾经在Ubuntu下测试都是好好的,交叉编译到arm上就出问题)
3)可以先在Ubuntu下测试,测试好了再移植到arm上
4)填写结构体成员时,一定要小心、小心、小心(重要的事说三遍),onvif不是什么高深的东西,但绝对是繁琐,需要耐心的东西。
4、干货
说了那么多虚的,来得实际的。下面是我开发过程中参考过的资料:
https://blog.csdn.net/ghostyu/article/details/8208428
https://blog.csdn.net/max_min_go/article/details/17964643
http://www.itnotepad.cn/Home/Article/num/31.html
https://wenku.baidu.com/view/510b1105a58da0116d174906.html
https://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl
上面都是我认为比较好的开发onvif server端的帖子,不过再好的帖子都比不上源码:
1)个人觉得框架写得比较好的,我也是基于他这个框架来完善的
http://www.pudn.com/Download/item/id/2481300.html
2)实现了比较多API的参考代码(从源码上看跟上面的某个贴有对应关系的)
http://www.pudn.com/Download/item/id/2836334.html
posted @ 2018-06-01 18:23 lfc 阅读(519) | 评论 (0)编辑 收藏
  2018年1月9日


起因: 不小新把记录了公司服务器IP,账号,密码的文件提交到了git
方法:

    git reset --hard <commit_id>

    git push origin HEAD --force



其他:

    根据–soft –mixed –hard,会对working tree和index和HEAD进行重置:
    git reset –mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和index信息
    git reset –soft:回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可
    git reset –hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容


    HEAD 最近一个提交
    HEAD^ 上一次
    <commit_id> 每次commit的SHA1值. 可以用git log 看到,也可以在页面上commit标签页里找到.

commit合并:
http://www.douban.com/note/318248317/
posted @ 2018-01-09 10:51 lfc 阅读(51) | 评论 (0)编辑 收藏
  2017年2月10日
参考以下帖子:
http://blog.csdn.net/vblittleboy/article/details/20121341

作了一下改动,修正了bug,提高适用性:
#include <stdlib.h>
#include 
<stdio.h>
#include 
<string.h>
#include 
<math.h>
 
#include 
<libavutil/opt.h>
#include 
<libavutil/mathematics.h>
#include 
<libavformat/avformat.h>
 
FILE 
* fp_in = NULL;
FILE 
* fp_out = NULL;
 
static 
int frame_count;
 
int main(int argc, char **argv)
{
    
int ret;
    AVCodec 
*audio_codec;
    AVCodecContext 
*c;
    AVFrame 
*frame;
    AVPacket pkt 
= { 0 }; // data and size must be 0;
    
int got_output;
 
    
/* Initialize libavcodec, and register all codecs and formats. */
    av_register_all();
    avcodec_register_all();
    
//avdevice_register_all();
 
    audio_codec 
= avcodec_find_encoder(AV_CODEC_ID_AAC);
    c 
= avcodec_alloc_context3(audio_codec);
//    c->strict_std_compliance =FF_COMPLIANCE_EXPERIMENTAL;   
    c
->codec_id = AV_CODEC_ID_AAC;
    c
->sample_fmt = AV_SAMPLE_FMT_S16;
    c
->sample_rate = 44100;
    c
->channels = 2;
    c
->channel_layout = AV_CH_LAYOUT_STEREO;
    c
->bit_rate = 64000;
 
    
/* open the codec */
    ret 
= avcodec_open2(c, audio_codec, NULL);
    
if (ret < 0) {
        fprintf(stderr, 
"Could not open video codec: %s\n", av_err2str(ret));
        
exit(1);
    }
 
    
/* allocate and init a re-usable frame */
#
if 0
    frame 
= avcodec_alloc_frame();
#
else
    frame 
= av_frame_alloc();
#endif
    
if (!frame) {
        fprintf(stderr, 
"Could not allocate video frame\n");
        
exit(1);
    }
 
 
    frame
->nb_samples = c->frame_size;
    frame
->format = c->sample_fmt;
    frame
->channels = c->channels;
    frame
->channel_layout = c->channel_layout;
#
if 0
    frame
->linesize[0= 4096;
    frame
->extended_data = frame->data[0= av_malloc((size_t)frame->linesize[0]);
#
else
    ret 
= av_frame_get_buffer(frame, 0);
    
if (ret < 0) {
        fprintf(stderr, 
"Could not allocate an audio frame.\n");
        
exit(1);
    }
    printf(
"----nb_samples= %d, linesize= %d\n", frame->nb_samples, frame->linesize[0]);
#endif

    av_init_packet(
&pkt);

    fp_in 
= fopen("in.wav","rb");
    fp_out
= fopen("out.aac","wb");
 
    
//printf("frame->nb_samples = %d\n",frame->nb_samples);
     
    
while(1)
    {
        frame_count
++;
        bzero(frame
->data[0],frame->linesize[0]);
        ret 
= fread(frame->data[0],frame->linesize[0],1,fp_in);
        
if(ret <= 0)
        {
            printf(
"read over !\n");
            break;
        }
        ret 
= avcodec_encode_audio2(c, &pkt, frame, &got_output);
        
if (ret < 0) {
            fprintf(stderr, 
"Error encoding audio frame: %s\n", av_err2str(ret));
            
exit(1);
        }
     
        
if(got_output > 0)
        {
            
//printf("pkt.size = %d\n",pkt.size);
            fwrite(pkt.data,pkt.size,
1,fp_out);
            av_free_packet(
&pkt);
        }
 
        #
if 0
        
if(frame_count > 10)
        {
            printf(
"break @@@@@@@@@@@@\n");
            break;
        }
        #endif
    }
 
    avcodec_close(c);
    av_free(c);
#
if 0
    avcodec_free_frame(
&frame);
#
else
    av_frame_free(
&frame);
#endif
    fclose(fp_in);
    fclose(fp_out);
 
    return 
0;
}

另外,建议看一下ffmpeg自带的例程,很有参考价值(特别是需要用到重采样功能):
doc/examples/transcode_aac.c

注:
    aac编码用到了libfdk_aac库,详细请参考:
http://trac.ffmpeg.org/wiki/Encode/AAC
posted @ 2017-02-10 11:24 lfc 阅读(513) | 评论 (0)编辑 收藏
  2017年2月8日
     摘要: 基础搞明白了,那么live555的RTSP服务器,又是如何创建、启动,如何和Source和Sink建立联系的呢?主程序中会调用类似下面的代码,创建RTSP服务器:Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->  // C...  阅读全文
posted @ 2017-02-08 16:47 lfc 阅读(264) | 评论 (0)编辑 收藏
  2017年1月20日
以下只作为个人总结,只作记录用,如果想系统的分析live555,建议阅读以下帖子,或阅读源码:
http://blog.csdn.net/niu_gao/article/details/6906055

一、概念
live555类似于Gstreamer和DirectShow架构,分Source、Filter、Sink的概念,例如,测试程序testOnDemandRTSPServer中,流化H264的pipeline如下(通过H264VideoFileServerMediaSubsession自动构建):

【Source】
ByteStreamFileSource->H264or5VideoStreamParser(MPEGVideoStreamParser)->H264VideoStreamFramer(H264or5VideoStreamFramer)

直接与Sink打交道的是H264VideoStreamFramer(通过H264VideoFileServerMediaSubsession的createNewStreamSource),其它Parser、FileSource是H264VideoStreamFramer自动构建(按需要)

【Sink】
H264or5Fragmenter->H264VideoRTPSink(H264or5VideoRTPSink)->VideoRTPSink->MultiFramedRTPSink

H264or5Fragmenter与上面的H264or5VideoStreamFramer打交道,获取Source的Frame数据后分段成RTP包输出。

二、数据流动
1、先来看数据的输入
1)首先,Sink下会创建缓冲,用于存放从Source获取的数据,存放缓冲的指针就是大家比较熟悉的fTo,Sink通过一系列的类,把指针传递下去,具体是:
H264or5Fragmenter->MPEGVideoStreamFramer->MPEGVideoStreamParser

最终从Sink传递到Parser中,相关的代码片段是:
H264or5Fragmenter::H264or5Fragmenter
{
fInputBuffer 
= new unsignedchar[fInputBufferSize];
}

void H264or5Fragmenter::doGetNextFrame()
{
fInputSource
->getNextFrame(&fInputBuffer[1], fInputBufferSize - 1,  
afterGettingFrame, this,
FramedSource::handleClosure, this);
}

MPEGVideoStreamFramer::doGetNextFrame()
{
  fParser
->registerReadInterest(fTo, fMaxSize);
  continueReadProcessing();
}

void MPEGVideoStreamParser::registerReadInterest(unsigned char
* to,
                         unsigned maxSize) {
  fStartOfFrame 
= fTo = fSavedTo = to
  fLimit 
= to + maxSize;
  fNumTruncatedBytes 
= fSavedNumTruncatedBytes = 0;
}

2)或许你注意到,fTo还没传递到最终的Source(ByteStreamFileSource),那是因为ByteStreamFileSource是由Parser来访问的,而Parser本身会建立Buffer用于存储从ByteStreamFileSource读取的数据,再把分析出来的NAL写入fTo(来自Sink),所以你就可以理解为什么fTo只到达了Parser,而不到达ByteStreamFileSource了吧。

相关代码如下:
StreamParser::StreamParser
{
  fBank[
0= new unsigned char[BANK_SIZE];
  fBank[
1= new unsigned char[BANK_SIZE];
}

StreamParser::ensureValidBytes1
{
  unsigned maxNumBytesToRead 
= BANK_SIZE - fTotNumValidBytes; 
  fInputSource
->getNextFrame(&curBank()[fTotNumValidBytes], 
                 maxNumBytesToRead,
                 afterGettingBytes, this,
                 onInputClosure, this);
}

unsigned H264or5VideoStreamParser::parse()
{
saveXBytes(Y);
}

class MPEGVideoStreamParser: 
public StreamParser 
{
  
// Record "byte" in the current output frame:
  void saveByte(u_int8_t 
byte) {
    
if (fTo >= fLimit) { // there's no space left
      ++fNumTruncatedBytes;
      return;
    }

    
*fTo++ = byte;
  }
}

2、再来看数据的输出
1)上面输入的数据最终去到H264or5Fragmenter,这里说明一下:
H264or5Fragmenter还是FrameSource(在H264or5VideoRTSPSink.cpp内定义),用于连接H264VideoRTSPSink和H264VideoStreamFramer;H264or5Fragmenter的doGetNextFrame实现,会把从Source获取到的数据,按照RTP协议的要求进行分段,保存到Sink的fOutBuf中。

具体代码如下:
MultiFramedRTPSink::MultiFramedRTPSink(UsageEnvironment& env,
                       Groupsock
* rtpGS,
                       unsigned char rtpPayloadType,
                       unsigned rtpTimestampFrequency,
                       char 
const* rtpPayloadFormatName,
                       unsigned numChannels)
  : RTPSink(env, rtpGS, rtpPayloadType, rtpTimestampFrequency,
        rtpPayloadFormatName, numChannels),
    fOutBuf(
NULL), fCurFragmentationOffset(0), fPreviousFrameEndedFragmentation(False),
    fOnSendErrorFunc(
NULL), fOnSendErrorData(NULL) {
  setPacketSizes((RTP_PAYLOAD_PREFERRED_SIZE), (RTP_PAYLOAD_MAX_SIZE)); 
//sihid
}

void MultiFramedRTPSink::setPacketSizes(unsigned preferredPacketSize,
                    unsigned maxPacketSize) {
  
if (preferredPacketSize > maxPacketSize || preferredPacketSize == 0) return;
      
// sanity check

  delete fOutBuf;
  fOutBuf 
= new OutPacketBuffer(preferredPacketSize, maxPacketSize);
  fOurMaxPacketSize 
= maxPacketSize; // save value, in case subclasses need it
}

Boolean MultiFramedRTPSink::continuePlaying() {
  
// Send the first packet.
  
// (This will also schedule any future sends.)
  buildAndSendPacket(
True);
  return 
True;
}

void MultiFramedRTPSink::buildAndSendPacket(
Boolean isFirstPacket) {
..
  packFrame();
}

void MultiFramedRTPSink::packFrame() {
  
// Get the next frame.
..
    
// Normal case: we need to read a new frame from the source
    
if (fSource == NULL) return;
    fSource
->getNextFrame(fOutBuf->curPtr(), fOutBuf->totalBytesAvailable(),
              afterGettingFrame, this, ourHandleClosure, this);
}
void H264or5Fragmenter::doGetNextFrame() {
  
if (fNumValidDataBytes == 1) {
    
// We have no NAL unit data currently in the buffer.  Read a new one:
    fInputSource
->getNextFrame(&fInputBuffer[1], fInputBufferSize - 1,  //Sink调用Source的getNextFrame获取数据
                   afterGettingFrame, this,
                   FramedSource::handleClosure, this);
  } 
else {
..
memmove(fTo, 
&fInputBuffer[1], fNumValidDataBytes - 1);
..
memmove(fTo, fInputBuffer, fMaxSize);
..
memmove(fTo, 
&fInputBuffer[fCurDataOffset-numExtraHeaderBytes], numBytesToSend);
..
}

看到了吧,数据的输入操作,其实是由Sink(MultiFramedRTPSink)发起的,当Sink需要获取数据时,通过调用Source的getNextFrame操作(具体由Source的doGetNextFrame操作来实现),经过一系列的类操作(Source->Filter->Sink),获取到Sink想要的数据。

2)到目前为止,终于可以构建出完整的Pipeline了:ByteStreamFileSource->H264or5VideoStreamParser(MPEGVideoStreamParser)->H264VideoStreamFramer(H264or5VideoStreamFramer)->H264or5Fragmenter->H264VideoRTPSink(H264or5VideoRTPSink)->VideoRTPSink->MultiFramedRTPSink

三、设计思想

1、对于Buffer
上面的Pipeline中,有几处Buffer,对于实时性要求比较高的应用,有必要理清buffer的数量和控制buffer的大小
1)StreamParser会产生buffer,大小是BANK_SIZE(150000),那是因为StreamParser的前端是无格式的ByteStream,后面是完整的一帧数据(NAL),需要通过Parser来处理;
2)H264or5Fragmenter会产生buffer,用于StreamParser存放分析之后的数据(NAL),并生成后端RTPSink需要的RTP包;
3)MultiFramedRTPSink会产生buffer,用于Fragmenter存放分段之后的数据(RTP),以供RTSP服务器使用;

2、对于fTo
fTo,顾名思义,就是To的buffer指针,也就是后端提供的buffer指针;那fTo是在什么时候赋值的呢,答案在这里:

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//把Sink的bufer赋给Source的fTo sihid
  fMaxSize 
= maxSize; //设置FrameSource的MaxSize sihid
  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();
}

另外,MPEGVideoStreamFramer还会通过其它方式传递fTo给MPEGVideoStreamParser:

MPEGVideoStreamFramer::doGetNextFrame()
{
  fParser->registerReadInterest(fTo, fMaxSize);
  continueReadProcessing();
}


void MPEGVideoStreamParser::registerReadInterest(unsigned char* to,unsigned maxSize) {
  fStartOfFrame = fTo = fSavedTo = to;
  fLimit = to + maxSize;
  fNumTruncatedBytes = fSavedNumTruncatedBytes = 0;
}

原因是MPEGVideoStreamParser(StreamParser)不是FrameSource,所以只能提供另外的API来获取fTo
当Sink需要数据时,会调用Source的getNextFrame方法,同时把自身的buffer通过参数(to)传递给Source,保存在Source的fTo中。

3、对于fSource
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();
}

Sink的fSource,在startPlaying中被设置为createNewStreamSource返回的H264VideoStreamFramer。

随后在continuePlaying(H264or5VideoRTPSink实现)方法中被修改为H264or5Fragmenter,同时通过reassignInputSource函数记录H264VideoStreamFramer到H264or5Fragmenter的fInputSource成员,这样Sink和H264VideoStreamFramer之间隔着H264or5Fragmenter(如其名,顾问)。

Boolean H264or5VideoRTPSink::continuePlaying() {
  
// First, check whether we have a 'fragmenter' class set up yet.
  // If not, create it now:
  
if (fOurFragmenter == NULL) {
    fOurFragmenter 
= new H264or5Fragmenter(fHNumber, envir(), fSource, OutPacketBuffer::maxSize, ourMaxPacketSize() - 12/*RTP hdr size*/);
  } 
else {
    fOurFragmenter
->reassignInputSource(fSource); 
  }
  fSource 
= fOurFragmenter; 

  
// Then call the parent class's implementation:  return MultiFramedRTPSink::continuePlaying();
}

class FramedFilter: public FramedSource {
public:
  FramedSource* inputSource() const { return fInputSource; }
  void reassignInputSource(FramedSource* newInputSource) { fInputSource = newInputSource; }
  // Call before destruction if you want to prevent the destructor from closing the input source
  void detachInputSource();
protected:
  FramedFilter(UsageEnvironment& env, FramedSource* inputSource);
     // abstract base class
  virtual ~FramedFilter();
protected:
  // Redefined virtual functions (with default 'null' implementations):
  virtual char const* MIMEtype() const;
  virtual void getAttributes() const;
  virtual void doStopGettingFrames();
protected:
  FramedSource* fInputSource; //输入文件对应的Source
};

为什么要这么做?因为RTPSink需要的数据,需要在H264VideoStreamFramer输出数据的基础上,通过H264or5Fragmenter封装成RTP包,所以多出了H264or5Fragmenter这个东西(类似于前面的H264or5VideoStreamParser)。

4、对于fInputSource

class FramedFilter下定义,被H264or5VideoStreamFramer和H264or5Fragmenter所继承。可是,fInputSource在这两个类下,指向的内容是不同的。
1)H264or5VideoStreamFramer下指向ByteStreamFileSource,具体见以下代码:
FramedSource* H264VideoFileServerMediaSubsession::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) {
  estBitrate 
= 500// kbps, estimate

  
// Create the video source:
  
ByteStreamFileSource* fileSource = ByteStreamFileSource::createNew(envir(), fFileName);
  
if (fileSource == NULL) return NULL;
  fFileSize 
= fileSource->fileSize();

  
// Create a framer for the Video Elementary Stream:
  return H264VideoStreamFramer::createNew(envir(), 
fileSource); //把ByteStreamFileSource记录到H264VideoStreamFramer的fInputSource

}

H264or5VideoStreamFramer
::H264or5VideoStreamFramer(
int hNumber, UsageEnvironment& env, FramedSource* inputSource,
               
Boolean createParser, Boolean includeStartCodeInOutput)
  : MPEGVideoStreamFramer(env, inputSource),
    fHNumber(hNumber),
    fLastSeenVPS(
NULL), fLastSeenVPSSize(0),
    fLastSeenSPS(
NULL), fLastSeenSPSSize(0),
    fLastSeenPPS(
NULL), fLastSeenPPSSize(0) {
.
}

MPEGVideoStreamFramer::MPEGVideoStreamFramer(UsageEnvironment& env,
                         FramedSource
* inputSource)
  : FramedFilter(env, inputSource),
    fFrameRate(
0.0/* until we learn otherwise */,
    fParser(
NULL) {
  reset();
}

2)H264or5Fragmenter下指向H264VideoStreamFramer,具体见以下代码:
Boolean H264or5VideoRTPSink::continuePlaying() {
  
// First, check whether we have a 'fragmenter' class set up yet.
  // If not, create it now:
  
if (fOurFragmenter == NULL) {
    fOurFragmenter 
= new H264or5Fragmenter(fHNumber, envir(), fSource, OutPacketBuffer::maxSize,    //OutPacketBuffer::maxSize决定了fInputBufferSize. sihid
                       ourMaxPacketSize() 
- 12/*RTP hdr size*/);
  } 
else {
    fOurFragmenter
->reassignInputSource(fSource); //把fSource(对应H264VideoStreamFramer)保存到fOurFragmenter(对应H264or5Fragmenter)的fInputSource
  }
  fSource 
= fOurFragmenter;

  
// Then call the parent class's implementation:
  return MultiFramedRTPSink::continuePlaying();
}
posted @ 2017-01-20 12:15 lfc 阅读(899) | 评论 (0)编辑 收藏
仅列出标题  下一页