www.pudn.com > vls-0.5.6.rar > streamer.sgml
The TsStreamer The Streamer, part of that we called the "consumer thread", takes the data from the SyncFifo, makes some timing synchro and sends it to the output. Refer to to see the position of TsStreamer between other parts of vls. The TsStreamer is declared and implemented in server/tsstreamer.* . The main purpose of TsStreamer is to deal with timing management, especially with Program Clock References. What's a PCR ? Program Clock Reference are 33 bits time values, which are in the adaptation_field of a TS packet header (see 13818-1 specifications). There are not in each TS packet, the specs say that there should be at least one PCR every 0.1 second. The PCR located at a given byte i is the time at which the byte i has to be processed (sent in the case of a streamer). Obviously, there can not be a PCR for each byte of a TS stream, so we make a linear calculation between two PCRs to send the data regularly along the time. So, the bitrate between two PCR shall be constant. PCR graph That is why PCR are the core of streaming : they say when datas have to be sent over the network. In the case of file stored on and hard disk, this System Layer (TS in our case) provide timing information. That is why, for the moment, it is not possible to stream any file format. For example, in the case of mpeg4, most files does not contain streaming time stamps since they don't have a system layer. It would be possible to re-generate them knowing the frame-rate, and going deeper in the stream layer to get each frame, remixing the data and sending the at the right date. Using or not PCRs First of all, the streamer can (or not) take into account PCRs. This is specified when instanciating a new TsStreaming : the constructor has a field bool m_bUsePcr :C_TsStreamer(handle hLog, C_Broadcast* pBroadcast, C_NetList* pTsProvider, C_SyncFifo* pBuffer, C_EventHandler* pEventHandler, bool m_bOwnProvider, bool m_bUsePcr); In the case of a stored stream (file or Dvd), the use of PCR is essential since we do not have any other timing info. That's why, in modules/localinput/localinput.cpp , C_TsStreamer is instantiated with :C_TsStreamer* pStreamer = new C_TsStreamer(m_hLog, pBroadcast, pTsProvider, pBuffer, m_pEventHandler, true, true); Don't forget that the localinput input deals with Dvd and files, and - like other input modules - spawns all the streaming chain. In the case of satellite or live-video encoding, the data comes at the correct rate (since it is live and supposed to be well broadcasted...). So the TsStreamer doesn't need to handle the PCRs, it just transmits the packets as they come. That's why the value m_bUsePcr is set tofalse .How vls handles PCRs We said before that between two PCRs, a streamer should make a linear interpolation. However, as the streamer does not contain any buffer, it is not possible to know what the next PCR will be, so it is impossible to calculate the interpolated date at which a byte has to be sent. Extrapolation Instead, vls uses extrapolation : when the PCR(j) is received, the slope and offset are updated to correspond to the segment [i,j]. This is done in modules/server/tsstreamer.cpp :inline void C_TsStreamer::AdjustClock(C_TsPacket* pPacket) { (...) m_dSlope = ((double)iPCRTime - m_iLastTime) / (s64)m_uiByteRead; (...) m_iLastTime = iPCRTime; (...) Then, when holding the data D, the streamer computes the linear extrapolation of the sending date Streaming(Data) using the previous values m_dSlope andm_iLastTime of segment [i,j] :inline void C_TsStreamer::WaitSendDate() { s64 iSendDate = m_iLastTime + m_iDeltaClock + (s64)m_dSlope*m_uiByteRead; (...) } Of course, this method is not exactly accurate, since just before k, extrapolated_date(k) and PCR(k) do not match : there is a tiny jitter. However, extrapolation avoids an extra buffer, and the jitter may be negligible in regards to the amount of data transmited. At last, one must be aware that PCR are expressed in a 27 MHz clock, so when mixing PCR and system clock (in seconds or milliseconds), conversions have to be done. The TsStreamer itself The main job is made in void C_TsStreamer::DoWork() . First, a packet is taken from the SyncFifo :C_TsPacket* pPacket = m_pBuffer->Pop(); TsStreamer After all the timing calculations described before, each TS packet is sent to the output : Output->Send(pPacket, (...) );