RTP Timestamp to presentationTime (live555)

RTSP流中實(shí)際傳輸音頻或視頻數(shù)據(jù)為一個(gè)個(gè)RTP包购对,每個(gè)RTP包的Header的第5個(gè)到第8個(gè)字節(jié)為RTP Timestamp(時(shí)間戳),是個(gè)32bit的整數(shù)。

RTP Header

而live555中類似H264or5VideoFileSink::afterGettingFrame(接收每幀數(shù)據(jù))函數(shù)中:

void H264or5VideoFileSink::afterGettingFrame(unsigned frameSize, 
                                             unsigned numTruncatedBytes, 
                                             struct timeval presentationTime) 
{
    ...
}

實(shí)際接收到的時(shí)間戳為 struct timeval presentationTime,
其中:

struct timeval {
        long    tv_sec;         /* seconds */
        long    tv_usec;        /* and microseconds */
};

舉例示意如下:

轉(zhuǎn)換前:
rtpTimestamp:439803124

轉(zhuǎn)換后:
presentationTime.tv_sec: 1482476415
presentationTime.tv_usec:183008 

在live555中,兩者是如何實(shí)現(xiàn)轉(zhuǎn)換的呢?

liveMedia\RTPSource.cppRTPReceptionStats::noteIncomingPacket函數(shù)中實(shí)現(xiàn)這一轉(zhuǎn)換屑柔。

RTPReceptionStats::noteIncomingPacket
void RTPReceptionStats::noteIncomingPacket(u_int16_t seqNum, 
                                           u_int32_t rtpTimestamp,
                                           unsigned timestampFrequency,
                                           Boolean useForJitterCalculation,
                                           struct timeval& resultPresentationTime,
                                           Boolean& resultHasBeenSyncedUsingRTCP,
                                           unsigned packetSize) 
{
    ...

    // Record the inter-packet delay
    struct timeval timeNow;
    gettimeofday(&timeNow, NULL);

    ...

    fLastPacketReceptionTime = timeNow;

    ... 

    // Return the 'presentation time' that corresponds to "rtpTimestamp":
    if (fSyncTime.tv_sec == 0 && fSyncTime.tv_usec == 0) 
    {
        // 第一個(gè)時(shí)間戳
        // 用當(dāng)前系統(tǒng)時(shí)間作為同步時(shí)刻
        // 后續(xù)將會(huì)根據(jù)接收到的RTCP SRs進(jìn)行校正.
        fSyncTimestamp = rtpTimestamp;
        fSyncTime      = timeNow;
    }

    int timestampDiff = rtpTimestamp - fSyncTimestamp;

    // Note: This works even if the timestamp wraps around
    // (as long as "int" is 32 bits)

    // Divide this by the timestamp frequency to get real time:
    double timeDiff = timestampDiff/(double)timestampFrequency;

    // Add this to the 'sync time' to get our result:
    unsigned const million = 1000000;
    unsigned seconds, uSeconds;

    if (timeDiff >= 0.0) 
    {
        // 核心算法
        seconds  = fSyncTime.tv_sec  + (unsigned)(timeDiff);
        uSeconds = fSyncTime.tv_usec + (unsigned)((timeDiff - (unsigned)timeDiff)*million);

        if (uSeconds >= million) 
        {
            uSeconds -= million;
            ++seconds;
        }
    } 
    else 
    {
        timeDiff = -timeDiff;
        seconds  = fSyncTime.tv_sec  - (unsigned)(timeDiff);
        uSeconds = fSyncTime.tv_usec - (unsigned)((timeDiff - (unsigned)timeDiff)*million);
        if ((int)uSeconds < 0) 
        {
            uSeconds += million;
            --seconds;
        }
    }

    resultPresentationTime.tv_sec  = seconds;
    resultPresentationTime.tv_usec = uSeconds;
    resultHasBeenSyncedUsingRTCP   = fHasBeenSynchronized;

    // Save these as the new synchronization timestamp & time:
    fSyncTimestamp = rtpTimestamp;
    fSyncTime      = resultPresentationTime;

    fPreviousPacketRTPTimestamp = rtpTimestamp;
}

輸入rtpTimestamp等,輸出struct timeval& resultPresentationTime珍剑。

RTPReceptionStats::noteIncomingPacket() 的調(diào)用堆棧
     RTPReceptionStats::noteIncomingPacket()  
    RTPReceptionStatsDB::noteIncomingPacket()  
    MultiFramedRTPSource::networkReadHandler1()  
    MultiFramedRTPSource::networkReadHandler()  
    SocketDescriptor::tcpReadHandler1(int mask, bool callAgain)  
    SocketDescriptor::tcpReadHandler()  
    BasicTaskScheduler::SingleStep(unsigned int maxDelayTime) 
    BasicTaskScheduler0::doEventLoop(volatile char * watchVariable)  
MultiFramedRTPSource
MultiFramedRTPSource
class FramedSource: public MediaSource {
  ...
  struct timeval fPresentationTime; // out
  ...
};

class RTPSource: public FramedSource {
  ...
}

class MultiFramedRTPSource: public RTPSource {

  ...
  static void networkReadHandler(MultiFramedRTPSource* source, int /*mask*/);
  void networkReadHandler1();
};

class BufferedPacket {
  ...
  struct timeval fPresentationTime; // corresponding to "fRTPTimestamp"
  ...
};

MultiFramedRTPSource::networkReadHandler1()
void MultiFramedRTPSource::networkReadHandler1() {
    BufferedPacket* bPacket = fPacketReadInProgress;
    if (bPacket == NULL) {
        // Normal case: Get a free BufferedPacket descriptor to hold the new network packet:
        bPacket = fReorderingBuffer->getFreePacket(this);
    }

    ...

    struct timeval presentationTime; // computed by:
    Boolean hasBeenSyncedUsingRTCP; // computed by:

        // 此函數(shù)中調(diào)用RTPReceptionStats::noteIncomingPacket()
        // 生成的時(shí)間保存在presentationTime
        receptionStatsDB().noteIncomingPacket(rtpSSRC, 
                                              rtpSeqNo, 
                                              rtpTimestamp,
                                              timestampFrequency(),
                                              usableInJitterCalculation, 
                                              presentationTime,
                                              hasBeenSyncedUsingRTCP, bPacket->dataSize());

    // Fill in the rest of the packet descriptor, and store it:
    struct timeval timeNow;
    gettimeofday(&timeNow, NULL);

    // 將presentationTime保存在BufferedPacket的fPresentationTime中
    bPacket->assignMiscParams(rtpSeqNo, 
                              rtpTimestamp, 
                              presentationTime,
                              hasBeenSyncedUsingRTCP, 
                              rtpMarkerBit,
                              timeNow);

    ...
    
    // doGetNextFrame1中調(diào)用BufferedPacket::use將保存在BufferedPacket中的fPresentationTime
    // 賦值給FramedSource的fPresentationTime
    doGetNextFrame1();
    // If we didn't get proper data this time, we'll get another chance
}
  • S1: RTPReceptionStats::noteIncomingPacket()
    獲取resultPresentationTime掸宛。

  • S2: BufferedPacket::assignMiscParams()
    resultPresentationTime賦值給BufferedPacketfPresentationTime

void BufferedPacket::assignMiscParams(unsigned short rtpSeqNo, 
                                      unsigned rtpTimestamp,
                                      struct timeval presentationTime,
                                      Boolean hasBeenSyncedUsingRTCP, 
                                      Boolean rtpMarkerBit,
                                      struct timeval timeReceived) 
{
    fRTPSeqNo               = rtpSeqNo;
    fRTPTimestamp           = rtpTimestamp;
    fPresentationTime       = presentationTime;
    fHasBeenSyncedUsingRTCP = hasBeenSyncedUsingRTCP;
    fRTPMarkerBit           = rtpMarkerBit;
    fTimeReceived           = timeReceived;
}
  • S3: doGetNextFrame1()
    將保存在BufferedPacket中的fPresentationTime賦值給FramedSourcefPresentationTime招拙。
void MultiFramedRTPSource::doGetNextFrame1() 
{
    while (fNeedDelivery) 
    {
        // If we already have packet data available, then deliver it now.
        Boolean packetLossPrecededThis;
        BufferedPacket* nextPacket
            = fReorderingBuffer->getNextCompletedPacket(packetLossPrecededThis);

        if (nextPacket == NULL) break;

        ...

        // The packet is usable. Deliver all or part of it to our caller:
        unsigned frameSize;
        nextPacket->use(fTo, 
                        fMaxSize, 
                        frameSize, 
                        fNumTruncatedBytes,
                        fCurPacketRTPSeqNum, 
                        fCurPacketRTPTimestamp,
                        fPresentationTime,  // 時(shí)間戳
                        fCurPacketHasBeenSynchronizedUsingRTCP,
                        fCurPacketMarkerBit);
        ...
     }
}
void BufferedPacket::use(unsigned char* to, 
                         unsigned toSize,
                         unsigned& bytesUsed, 
                         unsigned& bytesTruncated,
                         unsigned short& rtpSeqNo, 
                         unsigned& rtpTimestamp,
                         struct timeval& presentationTime, // out
                         Boolean& hasBeenSyncedUsingRTCP,
                         Boolean& rtpMarkerBit) 
{
        ...
        rtpTimestamp = fRTPTimestamp;
        presentationTime = fPresentationTime; // 賦值
        ...
}
H264or5VideoFileSink::afterGettingFrame調(diào)用堆棧
H264or5VideoFileSink::afterGettingFrame(unsigned int frameSize, unsigned int numTruncatedBytes, timeval presentationTime) 
FileSink::afterGettingFrame(void * clientData, unsigned int frameSize, unsigned int numTruncatedBytes, timeval presentationTime, unsigned int __formal)  
FramedSource::afterGetting(FramedSource * source)  
MultiFramedRTPSource::doGetNextFrame1()  
MultiFramedRTPSource::networkReadHandler1() 
MultiFramedRTPSource::networkReadHandler(MultiFramedRTPSource * source, int __formal)  
SocketDescriptor::tcpReadHandler1(int mask) 
SocketDescriptor::tcpReadHandler(SocketDescriptor * socketDescriptor, int mask)  
BasicTaskScheduler::SingleStep(unsigned int maxDelayTime)  
BasicTaskScheduler0::doEventLoop(volatile char * watchVariable)  
FramedSource::afterGetting()

此函數(shù)中將FramedSourcefPresentationTime傳給FileSink::afterGettingFrame唧瘾。
將Source(生產(chǎn)者)的視音頻數(shù)據(jù)的buffer、數(shù)據(jù)大小别凤、時(shí)間戳等傳給Sink(消費(fèi)者)饰序。

void FramedSource::afterGetting(FramedSource* source) {
  source->fIsCurrentlyAwaitingData = False;
      // indicates that we can be read again
      // Note that this needs to be done here, in case the "fAfterFunc"
      // called below tries to read another frame (which it usually will)

  // source->fPresentationTime即是FramedSource的fPresentationTime
  // fPresentationTime由此傳入 

  if (source->fAfterGettingFunc != NULL) {
    (*(source->fAfterGettingFunc))(source->fAfterGettingClientData,
                   source->fFrameSize, source->fNumTruncatedBytes,
                   source->fPresentationTime, 
                   source->fDurationInMicroseconds);
  }
}
FileSink::afterGettingFrame()
void FileSink::afterGettingFrame(void* clientData, 
                                 unsigned frameSize,
                                 unsigned numTruncatedBytes,
                                 struct timeval presentationTime,
                                 unsigned /*durationInMicroseconds*/) 
{
        FileSink* sink = (FileSink*)clientData;

        sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市规哪,隨后出現(xiàn)的幾起案子求豫,更是在濱河造成了極大的恐慌,老刑警劉巖诉稍,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝠嘉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡杯巨,警方通過(guò)查閱死者的電腦和手機(jī)蚤告,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)服爷,“玉大人杜恰,你說(shuō)我怎么就攤上這事∪栽矗” “怎么了心褐?”我有些...
    開(kāi)封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)镜会。 經(jīng)常有香客問(wèn)我檬寂,道長(zhǎng),這世上最難降的妖魔是什么戳表? 我笑而不...
    開(kāi)封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任桶至,我火速辦了婚禮,結(jié)果婚禮上匾旭,老公的妹妹穿的比我還像新娘镣屹。我一直安慰自己,他們只是感情好价涝,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布女蜈。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伪窖。 梳的紋絲不亂的頭發(fā)上逸寓,一...
    開(kāi)封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音覆山,去河邊找鬼竹伸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛簇宽,可吹牛的內(nèi)容都是我干的勋篓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼魏割,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼譬嚣!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起钞它,我...
    開(kāi)封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拜银,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后遭垛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體盐股,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年耻卡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牲尺。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卵酪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谤碳,到底是詐尸還是另有隱情溃卡,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布蜒简,位于F島的核電站瘸羡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏搓茬。R本人自食惡果不足惜犹赖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卷仑。 院中可真熱鬧峻村,春花似錦、人聲如沸锡凝。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至张肾,卻和暖如春芭析,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吞瞪。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工馁启, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尸饺。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓进统,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親浪听。 傳聞我的和親對(duì)象是個(gè)殘疾皇子螟碎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容