国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

live555學習筆記10-h264 RTP傳輸詳解(2)

2019-11-08 18:27:08
字體:
來源:轉載
供稿:網友

十 h264 RTP傳輸詳解(2)

上一章并沒有把打開文件分析文件的代碼找到,因為發現它隱藏得比較深,而且H264的Source又有多個,形成了連環計。所以此章中就將文件處理與H264的Source們并在一起分析吧。從哪里開始呢?從source開始吧!為什么要從它開始呢?我就想從這里開始,行了吧?

[cpp] view plain copyFramedSource* 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,顯然這是一個從文件按字節讀取數據的source,沒什么可細說的。但是,打開文件,讀寫文件操作的確就在其中。最終來處理h264文件,分析其格式,解析出幀或nal的應是這個source: H264VideoStreamFramer。打開文件的地方找到了,但分析文件的代碼才是更有價值的。那我們只能來看H264VideoStreamFramer。H264VideoStreamFramer繼承自MPEGVideoStreamFramer,MPEGVideoStreamFramer繼承自FramedFilter,FramedFilter繼承自FramedSource。啊,中間又冒出個Filter??吹剿?,是不是聯想到了DirectShow的filter?或者說photoshop中的filter?它們的意義應該都差不多吧?即插入到source和render(sink)之間的處理媒體數據的東東?如果這樣理解,還是更接近于photoshop中的概念。唉,說實話,我估計自己說的也不全對,反正就這樣認識吧,謬不了一千里。既然我們這樣認識了,那么我們就有理由相信可能會出現多個filter們一個連一個,然后高唱:手牽著腳腳牽著手一起向前走...H264VideoStreamFramer繼承自MPEGVideoStreamFramer,MPEGVideoStreamFramer比較簡單,它只是把一些工作交給了MPEGVideoStreamParser(又出來個parser,這可是個新東西哦,先不要管它吧),重點來看一下。構造函數:[cpp] view plain copyH264VideoStreamFramer::H264VideoStreamFramer(UsageEnvironment& env,          FramedSource* inputSource,          Boolean createParser,          Boolean includeStartCodeInOutput)          : MPEGVideoStreamFramer(env, inputSource),                  fIncludeStartCodeInOutput(includeStartCodeInOutput),                  fLastSeenSPS(NULL),                  fLastSeenSPSSize(0),                  fLastSeenPPS(NULL),                  fLastSeenPPSSize(0)  {      fParser = createParser ?              new H264VideoStreamParser(this, inputSource,                      includeStartCodeInOutput) : NULL;      fNextPResentationTime = fPresentationTimeBase;      fFrameRate = 25.0; // We assume a frame rate of 25 fps,           //unless we learn otherwise (from parsing a Sequence Parameter Set NAL unit)  }  由于createParser肯定為真,所以主要內容是創建了H264VideoStreamParser對象(先不管這個parser)。其它的函數就沒什么可看的了,都集中在所保存的PPS與SPS上。看來分析工作移到了H264VideoStreamParser,Parser嘛,就是分析器。分析器的基類是StreamParser。StreamParser做了不少的工作,那我們就先搞明白StreamParser做了哪些工作吧,并且可能為繼承者提供什么樣的調用框架呢?.....我看完了,呵呵。直接說分析結果吧:StreamParser的主要工作是實現了對數據以位為單位進行訪問。因為在處理媒體格式時,按位分析是很常見的情況。這兩個函數skipBits(unsigned numBits)和unsigned getBits(unsigned numBits)很明顯是基于位的操作。unsigned char* fBank[2]這個變量中的兩個緩沖區被輪換使用。這個類中保存了一個Source,理所當然地它應該保存ByteStreamFileSource的實例,而不是FramedFilter的。那些getBytes()或getBits()最終會導致讀文件的操作。從文件讀取一次數據后,StreamParser::afterGettingBytes1()被調用,StreamParser::afterGettingBytes1()中做一點簡單的工作后便調用fClientContinueFunc這個回調函數。fClientContinueFunc可能指向Frame的函數體也可能是指向RtpSink的函數體--因為Framer完全可以把RtpSink的函數體傳給Parser。至于到底指向哪個,只能在進一步分析之后才得知。

下面再來分析StreamParser的兒子:MPEGVideoStreamParser。

[cpp] view plain copyMPEGVideoStreamParser::MPEGVideoStreamParser(          MPEGVideoStreamFramer* usingSource,          FramedSource* inputSource)          : StreamParser(inputSource,              FramedSource::handleClosure,               usingSource,              &MPEGVideoStreamFramer::continueReadProcessing,              usingSource),              fUsingSource(usingSource)  {  }  

MPEGVideoStreamParser的構造函數中有很多有意思的東西。首先參數usingSource是什么意思?表示正在使用這個Parser的Source? inputSource 很明確,就是能獲取數據的source,也就是 ByteStreamFileSource。而且很明顯的,StreamParser中保存的source是ByteStreamFileSource。從傳入給StreamParser的回調函數以及它們的參數可以看出,這些回調函數全是指向的StreamParser的子類的函數(為啥不用虛函數的方式?哦,回調函數全是靜態函數,不能成為虛函數)。這說明在每讀一次數據后,MPEGVideoStreamFramer::continueReadProcessing()被調用,在其中對幀進行界定和分析,完成后再調用RTPSink的相應函數,RTPSink中對幀進行打包和發送(還記得嗎,不記得了請回頭看以前的章節)。MPEGVideoStreamParser的fTo是RTPSink傳入的緩沖指針,其saveByte(),save4Bytes()是把數據從StreamParser的緩沖把數據復制到fTo中,是給繼承類使用的。saveToNextCode()是復制數據直到遇到一個同步字節串(比如h264中分隔nal的那一陀東東,當然此處的跟h264還不一樣),也是給繼承類使用的。純虛函數parse()很明顯是留繼承類去寫幀分析代碼的地方。registerReadInterest()被調用者用來告訴MPEGVideoStreamParser其接收幀的緩沖地址與容量。現在應該來分析一下MPEGVideoStreamFramer,以明確MPEGVideoStreamFramer與MPEGVideoStreamParser是怎樣配合的。MPEGVideoStreamFramer中用到Parser的重要的函數只有兩個,一是:

[cpp] view plain copyvoid MPEGVideoStreamFramer::doGetNextFrame()  {      fParser->registerReadInterest(fTo, fMaxSize);      continueReadProcessing();  }  

很簡單,只是告訴了Parser保存幀的緩沖和緩沖的大小,然后執行continueReadProcessing(),那么來看一下continueReadProcessing():

[cpp] view plain copyvoid MPEGVideoStreamFramer::continueReadProcessing()  {      unsigned acquiredFrameSize = fParser->parse();      if (acquiredFrameSize > 0) {          // We were able to acquire a frame from the input.          // It has already been copied to the reader's space.          fFrameSize = acquiredFrameSize;          fNumTruncatedBytes = fParser->numTruncatedBytes();            // "fPresentationTime" should have already been computed.            // Compute "fDurationInMicroseconds" now:          fDurationInMicroseconds =                  (fFrameRate == 0.0 || ((int) fPictureCount) < 0) ?                          0 : (unsigned) ((fPictureCount * 1000000) / fFrameRate);          fPictureCount = 0;            // Call our own 'after getting' function.  Because we're not a 'leaf'          // source, we can call this directly, without risking infinite recursion.          afterGetting(this);      } else {          // We were unable to parse a complete frame from the input, because:          // - we had to read more data from the source stream, or          // - the source stream has ended.      }  }  先利用Parser進行分析(應該是解析出一幀吧?),分析完成后,幀數據已到了MPEGVideoStreamFramer的緩沖fTo中。計算出幀的持續時間后,調用FrameSource的afterGetting(),最終會調用RTPSink的函數??吹竭@里,可以總結一下,其實看來看去,Parser直正被外部使用的函數幾乎只有一個:parse()。下面可以看H264VideoStreamParser了。其實也很簡單,多了一些用于分析h264格式的函數,當然是非公開的,只供自己使用的。在哪里使用呢?當然是在parser()中使用。至于H264VideoStreamFramer前面已經說過了,沒什么太多的東西,所以就不看了??偨Y起來也就是這樣:RTPSink向H264VideoStreamFramer要下一幀(其實h264中肯定不是一幀了,而是一個NAL Unit),H264VideoStreamFramer告訴H264VideoStreamParser輸出緩沖和容內的字節數,然后調用H264VideoStreamParser的parser()函數,parser()中調用ByteStreamFileSource從文件中讀取數據,直到parser()獲得完整的一幀,parser()返回,H264VideoStreamFramer進行一些自己的處理后把這一幀返回給了RTPSink(當然是以回調函數的方式返回)。還有一個東西,H264FUAFragmenter,被H264VideoRTPSink所使用,繼承自FramedFilter。它最初在RTPSink開始播放后創建,如下:

[cpp] view plain copyBoolean H264VideoRTPSink::continuePlaying()  {      // First, check whether we have a 'fragmenter' class set up yet.      // If not, create it now:      if (fOurFragmenter == NULL) {          fOurFragmenter = new H264FUAFragmenter(envir(), fsource,                  OutPacketBuffer::maxSize,                  ourMaxPacketSize() - 12/*RTP hdr size*/);          fSource = fOurFragmenter;      }        // Then call the parent class's implementation:      return MultiFramedRTPSink::continuePlaying();  }  并且它取代了H264VideoStreamFramer成為直接與RTPSink發生關系的source.如此一來,RTPSink要獲取幀時,都是從它獲取的.看它最主要的一個函數吧:

[cpp] view plain copyvoid H264FUAFragmenter::doGetNextFrame()  {      if (fNumValidDataBytes == 1) {          // We have no NAL unit data currently in the buffer.  Read a new one:          fInputSource->getNextFrame(&fInputBuffer[1], fInputBufferSize - 1,                  afterGettingFrame, this, FramedSource::handleClosure, this);      } else {          // We have NAL unit data in the buffer.  There are three cases to consider:          // 1. There is a new NAL unit in the buffer, and it's small enough to deliver          //    to the RTP sink (as is).          // 2. There is a new NAL unit in the buffer, but it's too large to deliver to          //    the RTP sink in its entirety.  Deliver the first fragment of this data,          //    as a FU-A packet, with one extra preceding header byte.          // 3. There is a NAL unit in the buffer, and we've already delivered some          //    fragment(s) of this.  Deliver the next fragment of this data,          //    as a FU-A packet, with two extra preceding header bytes.            if (fMaxSize < fMaxOutputPacketSize) { // shouldn't happen              envir() << "H264FUAFragmenter::doGetNextFrame(): fMaxSize ("                      << fMaxSize << ") is smaller than expected/n";          } else {              fMaxSize = fMaxOutputPacketSize;          }            fLastFragmentCompletedNALUnit = True; // by default          if (fCurDataOffset == 1) { // case 1 or 2              if (fNumValidDataBytes - 1 <= fMaxSize) { // case 1                  memmove(fTo, &fInputBuffer[1], fNumValidDataBytes - 1);                  fFrameSize = fNumValidDataBytes - 1;                  fCurDataOffset = fNumValidDataBytes;              } else { // case 2                  // We need to send the NAL unit data as FU-A packets.  Deliver the first                  // packet now.  Note that we add FU indicator and FU header bytes to the front                  // of the packet (reusing the existing NAL header byte for the FU header).                  fInputBuffer[0] = (fInputBuffer[1] & 0xE0) | 28; // FU indicator                  fInputBuffer[1] = 0x80 | (fInputBuffer[1] & 0x1F); // FU header (with S bit)                  memmove(fTo, fInputBuffer, fMaxSize);                  fFrameSize = fMaxSize;                  fCurDataOffset += fMaxSize - 1;                  fLastFragmentCompletedNALUnit = False;              }          } else { // case 3              // We are sending this NAL unit data as FU-A packets.  We've already sent the              // first packet (fragment).  Now, send the next fragment.  Note that we add              // FU indicator and FU header bytes to the front.  (We reuse these bytes that              // we already sent for the first fragment, but clear the S bit, and add the E              // bit if this is the last fragment.)              fInputBuffer[fCurDataOffset - 2] = fInputBuffer[0]; // FU indicator              fInputBuffer[fCurDataOffset - 1] = fInputBuffer[1] & ~0x80; // FU header (no S bit)              unsigned numBytesToSend = 2 + fNumValidDataBytes - fCurDataOffset;              if (numBytesToSend > fMaxSize) {                  // We can't send all of the remaining data this time:                  numBytesToSend = fMaxSize;                  fLastFragmentCompletedNALUnit = False;              } else {                  // This is the last fragment:                  fInputBuffer[fCurDataOffset - 1] |= 0x40; // set the E bit in the FU header                  fNumTruncatedBytes = fSaveNumTruncatedBytes;              }              memmove(fTo, &fInputBuffer[fCurDataOffset - 2], numBytesToSend);              fFrameSize = numBytesToSend;              fCurDataOffset += numBytesToSend - 2;          }            if (fCurDataOffset >= fNumValidDataBytes) {              // We're done with this data.  Reset the pointers for receiving new data:              fNumValidDataBytes = fCurDataOffset = 1;          }            // Complete delivery to the client:          FramedSource::afterGetting(this);      }  }  

如果輸入緩沖中沒有數據,調用fInputSource->getNextFrame(),fInputSource是H264VideoStreamFramer,H264VideoStreamFramer的getNextFrame()會調用H264VideoStreamParser的parser(),parser()又調用ByteStreamFileSource獲取數據,然后分析,parser()完成后會調用:

[cpp] view plain copyvoid H264FUAFragmenter::afterGettingFrame1(          unsigned frameSize,          unsigned numTruncatedBytes,          struct timeval presentationTime,          unsigned durationInMicroseconds)  {      fNumValidDataBytes += frameSize;      fSaveNumTruncatedBytes = numTruncatedBytes;      fPresentationTime = presentationTime;      fDurationInMicroseconds = durationInMicroseconds;        // Deliver data to the client:      doGetNextFrame();  }  然后又調用回H264FUAFragmenter::doGetNextFrame(),此時輸入緩沖中有數據了,H264FUAFragmenter就進行分析處理.H264FUAFragmenter又對數據做了什么呢?


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 溧阳市| 田林县| 洪湖市| 吴川市| 哈密市| 庄河市| 辽中县| 那坡县| 嵊州市| 北京市| 寻乌县| 隆德县| 乡宁县| 沁水县| 红桥区| 玉龙| 苏尼特左旗| 连江县| 炎陵县| 平原县| 图们市| 土默特左旗| 即墨市| 多伦县| 儋州市| 扎赉特旗| 遵义市| 大余县| 大冶市| 临江市| 景洪市| 科技| 绥江县| 明光市| 呼玛县| 托克逊县| 独山县| 保德县| 成武县| 龙门县| 长子县|