live555源码分析
1.针对官方测试程序live/testProgs/testOnDemandRTSPServer.cpp进行部分分析。
- live/testProgs/testOnDemandRTSPServer.cpp main函数中创建服务端,并根据提供的文件名创建相应的类。
// A H.264 video elementary stream:
//创建h264RTSP服务端,播放的视频是out.h264
{
char const* streamName = "h264ESVideoTest";
char const* inputFileName = "out.h264";//xzm0114
ServerMediaSession* sms
= ServerMediaSession::createNew(*env, streamName, streamName,
descriptionString);
sms->addSubsession(H264VideoFileServerMediaSubsession
::createNew(*env, inputFileName, reuseFirstSource));//根据文件名创建新的H264VideoFileServerMediaSubsession
rtspServer->addServerMediaSession(sms);
announceStream(rtspServer, sms, streamName, inputFileName);
}
- 进一步查看 live/liveMedia/H264VideoFileServerMediaSubsession.cpp
H264VideoFileServerMediaSubsession*
H264VideoFileServerMediaSubsession::createNew(UsageEnvironment& env,
char const* fileName,
Boolean reuseFirstSource) {
return new H264VideoFileServerMediaSubsession(env, fileName, reuseFirstSource);
}
H264VideoFileServerMediaSubsession::H264VideoFileServerMediaSubsession(UsageEnvironment& env,
char const* fileName, Boolean reuseFirstSource)
: FileServerMediaSubsession(env, fileName, reuseFirstSource),
fAuxSDPLine(NULL), fDoneFlag(0), fDummyRTPSink(NULL) {
}
- 下一步live/liveMedia/FileServerMediaSubsession.cpp
FileServerMediaSubsession
::FileServerMediaSubsession(UsageEnvironment& env, char const* fileName,
Boolean reuseFirstSource)
: OnDemandServerMediaSubsession(env, reuseFirstSource),
fFileSize(0) {
//头文件中定义 char const* fFileName; 子类可以通过继承得到文件名
fFileName = strDup(fileName);
}
FileServerMediaSubsession::~FileServerMediaSubsession() {
delete[] (char*)fFileName;
}
- 回到live/liveMedia/H264VideoFileServerMediaSubsession.cpp中
//createNewStreamSource 为虚函数 父类中进行使用
FramedSource* H264VideoFileServerMediaSubsession::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) {
estBitrate = 500; // kbps, estimate
// Create the video source:
//xzm0114 通过继承得到的fFilename 创建ByteStreamFileSource
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);
}
- 这里重点看一下继承关系:
- 类 H264VideoFileServerMediaSubsession:公共 FileServerMediaSubsession
- 类 FileServerMediaSubsession:公共 OnDemandServerMediaSubsession
- 打开live/liveMedia/OnDemandServerMediaSubsession.cpp查看调用createNewStreamSource的地方,一共有两处。
OnDemandServerMediaSubsession::sdpLines() {
if (fSDPLines == NULL) {
// We need to construct a set of SDP lines that describe this
// subsession (as a unicast stream). To do so, we first create
// dummy (unused) source and "RTPSink" objects,
// whose parameters we use for the SDP lines:
unsigned estBitrate;
//调用子类实现的createNewStreamSource
/* 头文件中定义虚函数
protected: // new virtual functions, defined by all subclasses
virtual FramedSource* createNewStreamSource(unsigned clientSessionId,
unsigned& estBitrate) = 0;
*/
FramedSource* inputSource = createNewStreamSource(0, estBitrate);
printf("=====xzm %s:%d:%s=======nn",__FILE__, __LINE__, __func__); //xzm0114
if (inputSource == NULL) return NULL; // file not found
struct in_addr dummyAddr;
dummyAddr.s_addr = 0;
Groupsock* dummyGroupsock = createGroupsock(dummyAddr, 0);
unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic
RTPSink* dummyRTPSink = createNewRTPSink(dummyGroupsock, rtpPayloadType, inputSource);
if (dummyRTPSink != NULL && dummyRTPSink->estimatedBitrate() > 0) estBitrate = dummyRTPSink->estimatedBitrate();
setSDPLinesFromRTPSink(dummyRTPSink, inputSource, estBitrate);
Medium::close(dummyRTPSink);
delete dummyGroupsock;
closeStreamSource(inputSource);
printf("=====xzm %s:%d:%s=======nn",__FILE__, __LINE__, __func__); //xzm0114
}
return fSDPLines;
}
//void OnDemandServerMediaSubsession::getStreamParameters函数中
FramedSource* mediaSource
= createNewStreamSource(clientSessionId, streamBitrate);
// Create 'groupsock' and 'sink' objects for the destination,
// using previously unused server port numbers:
- 重点讲一下文件打开和关闭的接口函数
- live/liveMedia/InputFile.cpp中 实现了OpenInputFile和CloseInputFile,并在live/liveMedia/ByteStreamFileSource.cpp中调用
FILE* OpenInputFile(UsageEnvironment& env, char const* fileName) {
FILE* fid;
// Check for a special case file name: "stdin"
if (strcmp(fileName, "stdin") == 0) {
fid = stdin;
#if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE)
_setmode(_fileno(stdin), _O_BINARY); // convert to binary mode
#endif
} else {
fid = fopen(fileName, "rb");
if (fid == NULL) {
env.setResultMsg("unable to open file "",fileName, """);
}
printf("nnnnn======xzm Open file:%s========nnnnnn", fileName); //xzm0113
}
return fid;
}
void CloseInputFile(FILE* fid) {
// Don't close 'stdin', in case we want to use it again later.
if (fid != NULL && fid != stdin) fclose(fid);
printf("nnnnn======xzm Close file ========nnnnnn");//xzm0113
}
- 打开live/liveMedia/ByteStreamFileSource.cpp,函数根据不同的文件类型使用fread或者read,对于管道而言,函数会使用read进行读取。
void ByteStreamFileSource::doReadFromFile() {
// Try to read as many bytes as will fit in the buffer provided (or "fPreferredFrameSize" if less)
if (fLimitNumBytesToStream && fNumBytesToStream < (u_int64_t)fMaxSize) {
fMaxSize = (unsigned)fNumBytesToStream;
}
if (fPreferredFrameSize > 0 && fPreferredFrameSize < fMaxSize) {
fMaxSize = fPreferredFrameSize;
}
#ifdef READ_FROM_FILES_SYNCHRONOUSLY
fFrameSize = fread(fTo, 1, fMaxSize, fFid);
#else
//xzm0113
if (fFidIsSeekable) {
printf("======Use fread=======nn");//xzm0113
fFrameSize = fread(fTo, 1, fMaxSize, fFid);
} else {
// For non-seekable files (e.g., pipes), call "read()" rather than "fread()", to ensure that the read doesn't block:
fFrameSize = read(fileno(fFid), fTo, fMaxSize);
printf("======Use read,fFrameSize:%d ,fMaxSize:%d =======nn", fFrameSize, fMaxSize);//xzm0113
}
#endif
if (fFrameSize == 0) {
handleClosure();
return;
}
fNumBytesToStream -= fFrameSize;
// Set the 'presentation time':
if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) {
if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
// This is the first frame, so use the current time:
gettimeofday(&fPresentationTime, NULL);
} else {
// Increment by the play time of the previous data:
unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;
fPresentationTime.tv_sec += uSeconds/1000000;
fPresentationTime.tv_usec = uSeconds%1000000;
}
// Remember the play time of this data:
fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize;
fDurationInMicroseconds = fLastPlayTime;
} else {
// We don't know a specific play time duration for this data,
// so just record the current time as being the 'presentation time':
gettimeofday(&fPresentationTime, NULL);
}
// Inform the reader that he has data:
#ifdef READ_FROM_FILES_SYNCHRONOUSLY
// To avoid possible infinite recursion, we need to return to the event loop to do this:
nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
(TaskFunc*)FramedSource::afterGetting, this);
#else
// Because the file read was done from the event loop, we can call the
// 'after getting' function directly, without risk of infinite recursion:
FramedSource::afterGetting(this);
#endif
}
- 注:源头修改了一些定义的值,是为了避免单帧过大导致无法读取,具体有
// live/liveMedia/StreamParser.cpp
// #define BANK_SIZE 150000
#define BANK_SIZE 3000000 //xzm0113
OutPacketBuffer::maxSize = 500000;//1229xzm live555初始化时执行
live555源码分析
1.针对官方测试程序live/testProgs/testOnDemandRTSPServer.cpp进行部分分析。
- live/testProgs/testOnDemandRTSPServer.cpp main函数中创建服务端,并根据提供的文件名创建相应的类。
// A H.264 video elementary stream:
//创建h264RTSP服务端,播放的视频是out.h264
{
char const* streamName = "h264ESVideoTest";
char const* inputFileName = "out.h264";//xzm0114
ServerMediaSession* sms
= ServerMediaSession::createNew(*env, streamName, streamName,
descriptionString);
sms->addSubsession(H264VideoFileServerMediaSubsession
::createNew(*env, inputFileName, reuseFirstSource));//根据文件名创建新的H264VideoFileServerMediaSubsession
rtspServer->addServerMediaSession(sms);
announceStream(rtspServer, sms, streamName, inputFileName);
}
- 进一步查看 live/liveMedia/H264VideoFileServerMediaSubsession.cpp
H264VideoFileServerMediaSubsession*
H264VideoFileServerMediaSubsession::createNew(UsageEnvironment& env,
char const* fileName,
Boolean reuseFirstSource) {
return new H264VideoFileServerMediaSubsession(env, fileName, reuseFirstSource);
}
H264VideoFileServerMediaSubsession::H264VideoFileServerMediaSubsession(UsageEnvironment& env,
char const* fileName, Boolean reuseFirstSource)
: FileServerMediaSubsession(env, fileName, reuseFirstSource),
fAuxSDPLine(NULL), fDoneFlag(0), fDummyRTPSink(NULL) {
}
- 下一步live/liveMedia/FileServerMediaSubsession.cpp
FileServerMediaSubsession
::FileServerMediaSubsession(UsageEnvironment& env, char const* fileName,
Boolean reuseFirstSource)
: OnDemandServerMediaSubsession(env, reuseFirstSource),
fFileSize(0) {
//头文件中定义 char const* fFileName; 子类可以通过继承得到文件名
fFileName = strDup(fileName);
}
FileServerMediaSubsession::~FileServerMediaSubsession() {
delete[] (char*)fFileName;
}
- 回到live/liveMedia/H264VideoFileServerMediaSubsession.cpp中
//createNewStreamSource 为虚函数 父类中进行使用
FramedSource* H264VideoFileServerMediaSubsession::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) {
estBitrate = 500; // kbps, estimate
// Create the video source:
//xzm0114 通过继承得到的fFilename 创建ByteStreamFileSource
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);
}
- 这里重点看一下继承关系:
- 类 H264VideoFileServerMediaSubsession:公共 FileServerMediaSubsession
- 类 FileServerMediaSubsession:公共 OnDemandServerMediaSubsession
- 打开live/liveMedia/OnDemandServerMediaSubsession.cpp查看调用createNewStreamSource的地方,一共有两处。
OnDemandServerMediaSubsession::sdpLines() {
if (fSDPLines == NULL) {
// We need to construct a set of SDP lines that describe this
// subsession (as a unicast stream). To do so, we first create
// dummy (unused) source and "RTPSink" objects,
// whose parameters we use for the SDP lines:
unsigned estBitrate;
//调用子类实现的createNewStreamSource
/* 头文件中定义虚函数
protected: // new virtual functions, defined by all subclasses
virtual FramedSource* createNewStreamSource(unsigned clientSessionId,
unsigned& estBitrate) = 0;
*/
FramedSource* inputSource = createNewStreamSource(0, estBitrate);
printf("=====xzm %s:%d:%s=======nn",__FILE__, __LINE__, __func__); //xzm0114
if (inputSource == NULL) return NULL; // file not found
struct in_addr dummyAddr;
dummyAddr.s_addr = 0;
Groupsock* dummyGroupsock = createGroupsock(dummyAddr, 0);
unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic
RTPSink* dummyRTPSink = createNewRTPSink(dummyGroupsock, rtpPayloadType, inputSource);
if (dummyRTPSink != NULL && dummyRTPSink->estimatedBitrate() > 0) estBitrate = dummyRTPSink->estimatedBitrate();
setSDPLinesFromRTPSink(dummyRTPSink, inputSource, estBitrate);
Medium::close(dummyRTPSink);
delete dummyGroupsock;
closeStreamSource(inputSource);
printf("=====xzm %s:%d:%s=======nn",__FILE__, __LINE__, __func__); //xzm0114
}
return fSDPLines;
}
//void OnDemandServerMediaSubsession::getStreamParameters函数中
FramedSource* mediaSource
= createNewStreamSource(clientSessionId, streamBitrate);
// Create 'groupsock' and 'sink' objects for the destination,
// using previously unused server port numbers:
- 重点讲一下文件打开和关闭的接口函数
- live/liveMedia/InputFile.cpp中 实现了OpenInputFile和CloseInputFile,并在live/liveMedia/ByteStreamFileSource.cpp中调用
FILE* OpenInputFile(UsageEnvironment& env, char const* fileName) {
FILE* fid;
// Check for a special case file name: "stdin"
if (strcmp(fileName, "stdin") == 0) {
fid = stdin;
#if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE)
_setmode(_fileno(stdin), _O_BINARY); // convert to binary mode
#endif
} else {
fid = fopen(fileName, "rb");
if (fid == NULL) {
env.setResultMsg("unable to open file "",fileName, """);
}
printf("nnnnn======xzm Open file:%s========nnnnnn", fileName); //xzm0113
}
return fid;
}
void CloseInputFile(FILE* fid) {
// Don't close 'stdin', in case we want to use it again later.
if (fid != NULL && fid != stdin) fclose(fid);
printf("nnnnn======xzm Close file ========nnnnnn");//xzm0113
}
- 打开live/liveMedia/ByteStreamFileSource.cpp,函数根据不同的文件类型使用fread或者read,对于管道而言,函数会使用read进行读取。
void ByteStreamFileSource::doReadFromFile() {
// Try to read as many bytes as will fit in the buffer provided (or "fPreferredFrameSize" if less)
if (fLimitNumBytesToStream && fNumBytesToStream < (u_int64_t)fMaxSize) {
fMaxSize = (unsigned)fNumBytesToStream;
}
if (fPreferredFrameSize > 0 && fPreferredFrameSize < fMaxSize) {
fMaxSize = fPreferredFrameSize;
}
#ifdef READ_FROM_FILES_SYNCHRONOUSLY
fFrameSize = fread(fTo, 1, fMaxSize, fFid);
#else
//xzm0113
if (fFidIsSeekable) {
printf("======Use fread=======nn");//xzm0113
fFrameSize = fread(fTo, 1, fMaxSize, fFid);
} else {
// For non-seekable files (e.g., pipes), call "read()" rather than "fread()", to ensure that the read doesn't block:
fFrameSize = read(fileno(fFid), fTo, fMaxSize);
printf("======Use read,fFrameSize:%d ,fMaxSize:%d =======nn", fFrameSize, fMaxSize);//xzm0113
}
#endif
if (fFrameSize == 0) {
handleClosure();
return;
}
fNumBytesToStream -= fFrameSize;
// Set the 'presentation time':
if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) {
if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
// This is the first frame, so use the current time:
gettimeofday(&fPresentationTime, NULL);
} else {
// Increment by the play time of the previous data:
unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;
fPresentationTime.tv_sec += uSeconds/1000000;
fPresentationTime.tv_usec = uSeconds%1000000;
}
// Remember the play time of this data:
fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize;
fDurationInMicroseconds = fLastPlayTime;
} else {
// We don't know a specific play time duration for this data,
// so just record the current time as being the 'presentation time':
gettimeofday(&fPresentationTime, NULL);
}
// Inform the reader that he has data:
#ifdef READ_FROM_FILES_SYNCHRONOUSLY
// To avoid possible infinite recursion, we need to return to the event loop to do this:
nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
(TaskFunc*)FramedSource::afterGetting, this);
#else
// Because the file read was done from the event loop, we can call the
// 'after getting' function directly, without risk of infinite recursion:
FramedSource::afterGetting(this);
#endif
}
- 注:源头修改了一些定义的值,是为了避免单帧过大导致无法读取,具体有
// live/liveMedia/StreamParser.cpp
// #define BANK_SIZE 150000
#define BANK_SIZE 3000000 //xzm0113
OutPacketBuffer::maxSize = 500000;//1229xzm live555初始化时执行
举报