发生时间 在处理Describe 请求
在处理describe 请求的时候 DynamicRTSPServer::lookupServerMediaSession ,rtsp服务器会查找SDP信息并且创建,包括查找track1和track2 的信息即 音频视频轨道信息
live555 处理 请求消息 二 “DESCRIBE 分析了为什么会处理 lookupServerMediaSession 函数
具体的判断 视频轨道 track1 和音频轨道 track2过程如下:
简单跟一下,就是代码回调的过程
解析文件 获取track1 track2
ByteStreamFileSource 读取文件内容
void ByteStreamFileSource::doReadFromFile() {
//...
fMaxSize = (unsigned)fNumBytesToStream;
fFrameSize = fread(fTo, 1, fMaxSize, fFid);
//..
}
ByteStreamFileSource 负责读取文件的内容 ,最后读取的fMaxSize 个字节,保存在指针变量fTo指向的内存中,默认fMaxSize = 15000,所以内存中有15000个字节
根据 流程图中,首先需要在MatroskaFileParser::parseTrack()读取音视频轨道信息
Boolean MatroskaFileParser::parseTrack() {
// Read and process each Matroska header, until we get to the end of the Track:
while (fCurOffsetInFile < fLimitOffsetInFile) {
while (!parseEBMLIdAndSize(id, size)) {} //从内存中读取信息 音视频框架EBML
switch (id.val()) {
case MATROSKA_ID_TRACK_ENTRY: { // 'Track Entry' header: enter this
// Create a new "MatroskaTrack" object for this entry:
if (track != NULL && track->trackNumber == 0) delete track;
track = new MatroskaTrack;
break;
}
case MATROSKA_ID_TRACK_NUMBER: {
unsigned trackNumber;
if (parseEBMLVal_unsigned(size, trackNumber)) {
if (track != NULL && trackNumber != 0) {
track->trackNumber = trackNumber;
fOurFile.addTrack(track, trackNumber);
}
}
break;
}
case: ....
case:....
}
return True; // we're done parsing track entries
}
parseEBMLIdAndSize 读取数据过程如下
所以将读出的15000个字节其中第一个字节保存在num.data[i] 然后计算出id.val()
当MATROSKA_ID_TRACK_NUMBER == id.val() 就把track1 track2的信息用
fOurFile.addTrack(track, trackNumber)保存
因为 while 循环,而id.val() 不断的计算,会轮询case 情况
u_int64_t EBMLNumber::val() const {
u_int64_t result = 0;
for (unsigned i = 0; i < len; ++i) {
result = result*256 + data[i];
}
return result;
}
所以case MATROSKA_ID_TRACK_ENTRY 执行完后执行 case MATROSKA_ID_TRACK_NUMBER
然后执行后面的case 有关track其他的信息
trackType = audio video subtitle? 以及 重要的信息 mimeType = video/H264 和 A_AAC
为了验证如何创建 track1 和track2 的,我加了log,就可以知道如何执行代码
id.val() = MATROSKA_ID_TRACK_ENTRY
id.val() = MATROSKA_ID_TRACK_NUMBER
trackNumber = 1
id.val() = MATROSKA_ID_TRACK_TYPE
id.val() = MATROSKA_ID_CODEC
id.val() = MATROSKA_ID_LANGUAGE
id.val() = MATROSKA_ID_VIDEO
id.val() = MATROSKA_ID_PIXEL_WIDTH
id.val() = MATROSKA_ID_PIXEL_HEIGHT
id.val() = MATROSKA_ID_DISPLAY_WIDTH
id.val() = MATROSKA_ID_DISPLAY_HEIGHT
id.val() = MATROSKA_ID_CODEC_PRIVATE
id.val() = MATROSKA_ID_DEFAULT_DURATION
id.val() = MATROSKA_ID_TRACK_ENTRY
id.val() = MATROSKA_ID_TRACK_NUMBER
trackNumber = 2
id.val() = MATROSKA_ID_TRACK_TYPE
id.val() = MATROSKA_ID_CODEC
id.val() = MATROSKA_ID_CODEC_PRIVATE
id.val() = MATROSKA_ID_DEFAULT_DURATION
id.val() = MATROSKA_ID_AUDIO
id.val() = MATROSKA_ID_SAMPLING_FREQUENCY
id.val() = MATROSKA_ID_CHANNELS
这样track1 和track2信息保存在fTrackTable 中
//保存轨道信息
void MatroskaFile::addTrack(MatroskaTrack* newTrack, unsigned trackNumber) {
fTrackTable->add(newTrack, trackNumber);
}
//查找轨道信息
MatroskaTrack* MatroskaFile::lookup(unsigned trackNumber) const {
return fTrackTable->lookup(trackNumber);
}
解析完成后,就开始回调函数,在回调中会取出fTrackTable 轨道信息
void MatroskaFileParser::continueParsing() {
if (fInputSource != NULL) {
if (fInputSource->isCurrentlyAwaitingData()) return;
if (!parse()) {
return;
}
}
// We successfully parsed the file. Call our 'done' function now:
if (fOnEndFunc != NULL) (*fOnEndFunc)(fOnEndClientData);
}
MatroskaFile::handleEndOfTrackHeaderParsing() 会取出轨道信息,最后
在 MatroskaFileServerDemux::newServerMediaSubsession 创建轨道,因为 DynamicRTSPServer while 循环创建所有track,最后加入subseesion中
while ((smss = creationState.demux->newServerMediaSubsession()) != NULL) {
sms->addSubsession(smss);
}
果然看完协议后,就知道 session用来干嘛的,track1 track2 获取过程解析完毕,也顺便知道如何读取*.mkv 文件