查阅网上各种资料,发现live555作为服务器实现h264码流的rtsp传输的例子很多,但关于live555实现ts流的rtsp传输的资料很少。由于项目需要,我的客户端只能实现rtsp的TS流解码,故只能自己摸索。

  以下参考h264相关资料和自己理解进行编写,不当之处请理解。本工程以ts文件为数据源,通过live555服务器推送ts流,从而实现rtsp传输。

1.概述

  liveMedia 库中有一系列类,基类是Medium,这些类针对不同的流媒体类型和编码。 其中的StreamFrame类文件(如MPEG4VideoStreamFramer)为流传输关键。

 

重要概念:

StreamFrame类:该类继承FramedSource基类,实现数据流的控制和传输。

StreamFrame(ByteStreamLiveSource) -->FramedFilter--> FramedSource----> MediaSource

   FramedSource 派继承MediaSource父类,一帧码流的实现。

 注意:unsigned char* fTo; 为指向发送的码流的指针,采集到视频数据后填充到该指针中即可实现码流的传输。针对TS流,必选保证每次放入fTO的数据个数为188的整数倍。

为何?因为188为TS流每帧数据的个数,如果放置个数不对,不够188的结尾帧会被舍弃,而从新放置在fto中的数据开头不是以0x47开始的,就出现了循环解析错误,于是大量马赛克就产生了。

主要步骤:1.定义自己的StreamFramer类,实现getNextFrame重写。

getNextFrame函数来自live\liveMedia\FramedSource文件


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();
}



其中最后的doGetNextFrame(); 是一个虚函数,具体各种编码模式,我们可以根据自己的码流类型定义一个派生自FramedSource的类(本工程ByteStreamLiveSource类), 重新再定义doGetNextFrame如何获得下一帧的码流,在自己重定义的doGetNextFrame() 中将fTo指向要发送的缓存即可。这样我们就实现了流的传输而非文件传输。

本工程中doGetNextFrame()代码如下:

void ByteStreamLiveSource::doGetNextFrame() 
{
	
	printf("doGetNextFrame=%d\n",fMaxSize);
    if( filesize(fp) >  fMaxSize)
	{
     printf("doGetNextFrame111\n");
  //    fFrameSize = fread(fTo,1,fMaxSize,fp); 
	  fFrameSize = fread(fTo,1,188,fp); 	//取数值去TS流每帧整数倍(*n),否则容易丢包或解包错误
	   for(int i=0;i<10;i++)
           {
        printf("%x ",fTo[i]);
         }
	   printf("\n"); 
	}
    else
    {
		 printf("doGetNextFrame222\n");
        fFrameSize = fread(fTo,1,filesize(fp),fp);
        fseek(fp, 0, SEEK_SET);
			
	for(int i=0;i<10;i++)
           {
        printf("%x ",fTo[i]);
         }
	   printf("\n"); 
    }
    //fFrameSize = fMaxSize;
    nextTask() = envir().taskScheduler().scheduleDelayedTask( 0,
        (TaskFunc*)FramedSource::afterGetting, this);
    return;


}



2.实现fTO与会话连接,自定义ServerMediaSubsession

定义ServerMediaSubsession类H264LiveVideoServerMediaSubssion,该类由ServerMediaSubsession 派生而来。该类中有私有函数virtual FramedSource* createNewStreamSource,在该函数中进行重新定义即可实现。

ByteStreamLiveSource*
ByteStreamLiveSource::createNew(UsageEnvironment& env, 
                char const* fileName,
				unsigned preferredFrameSize,
				unsigned playTimePerFrame)
{
  
    printf("\nByteStreamLiveSource::createNew\n");	  
 
    ByteStreamLiveSource* newSource = new ByteStreamLiveSource(env, fileName, preferredFrameSize, playTimePerFrame);
 
    return newSource;
	}



主要最后返回的ByteStreamLiveSource 继承自FramedSource,定义了从文件获取source的方法,从而将ServerMedia 与source联系起来。

代码为vs2008工程,采用VLC测试,测试结果如下图所示


android TS流读取 ts流 rtsp_TS流