上文我们已经讲过了,客户端的DESCRIBE命令,接下来,我们继续讲一下剩下的RTSP命令。
发送SETUP命令,就是告诉服务器我们已经准备好了,可以建立连接进行数据传输了。之后,客户端通过之前设置好的RTP/RTCP端口去取流,进行数据的保存或播放,专业点叫做FileSink。
void createPeriodicOutputFiles() {
// Create a filename suffix that notes the time interval that's being recorded:
char periodicFileNameSuffix[100];
snprintf(periodicFileNameSuffix, sizeof periodicFileNameSuffix, "-%05d-%05d",
fileOutputSecondsSoFar, fileOutputSecondsSoFar + fileOutputInterval);
createOutputFiles(periodicFileNameSuffix);
//按持续时间进行切片
// Schedule an event for writing the next output file:
periodicFileOutputTask
= env->taskScheduler().scheduleDelayedTask(fileOutputInterval*1000000,
(TaskFunc*)periodicFileOutputTimerHandler,
(void*)NULL);
}
void createOutputFiles(char const* periodicFilenameSuffix) {
char outFileName[1000];
//这边表示创建文件
if (outputQuickTimeFile || outputAVIFile) {
if (periodicFilenameSuffix[0] == '\0') {
// Normally (unless the '-P <interval-in-seconds>' option was given) we output to 'stdout':
sprintf(outFileName, "stdout");
} else {
// Otherwise output to a type-specific file name, containing "periodicFilenameSuffix":
char const* prefix = fileNamePrefix[0] == '\0' ? "output" : fileNamePrefix;
snprintf(outFileName, sizeof outFileName, "%s%s.%s", prefix, periodicFilenameSuffix,
outputAVIFile ? "avi" : generateMP4Format ? "mp4" : "mov");
}
//封装为MP4文件
if (outputQuickTimeFile) {
qtOut = QuickTimeFileSink::createNew(*env, *session, outFileName,
fileSinkBufferSize,
movieWidth, movieHeight,
movieFPS,
packetLossCompensate,
syncStreams,
generateHintTracks,
generateMP4Format);
if (qtOut == NULL) {
*env << "Failed to create a \"QuickTimeFileSink\" for outputting to \""
<< outFileName << "\": " << env->getResultMsg() << "\n";
shutdown();
} else {
*env << "Outputting to the file: \"" << outFileName << "\"\n";
}
//开始数据传输,启动取流处理流程
qtOut->startPlaying(sessionAfterPlaying, NULL);
} else { // outputAVIFile
aviOut = AVIFileSink::createNew(*env, *session, outFileName,
fileSinkBufferSize,
movieWidth, movieHeight,
movieFPS,
packetLossCompensate);
if (aviOut == NULL) {
*env << "Failed to create an \"AVIFileSink\" for outputting to \""
<< outFileName << "\": " << env->getResultMsg() << "\n";
shutdown();
} else {
*env << "Outputting to the file: \"" << outFileName << "\"\n";
}
aviOut->startPlaying(sessionAfterPlaying, NULL);
}
}
}
FileSink已经创建好了,下面就是直接发送PLAY命令,通知服务器进行数据传输了。
//发送PLAY命令,一个是相对时间,一个是绝对时间
void startPlayingSession(MediaSession* session, double start, double end, float scale, RTSPClient::responseHandler* afterFunc) {
ourRTSPClient->sendPlayCommand(*session, afterFunc, start, end, scale, ourAuthenticator);
}
void startPlayingSession(MediaSession* session, char const* absStartTime, char const* absEndTime, float scale, RTSPClient::responseHandler* afterFunc) {
ourRTSPClient->sendPlayCommand(*session, afterFunc, absStartTime, absEndTime, scale, ourAuthenticator);
}
之后,客户端源源不断的接收服务器发送来的RTP数据包,并进行数据处理,最后收到服务器一个BYE的RTP包后,整个流程就结束了。