<chapter><title>The TsStreamer</title>


<para>

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 <xref linkend="l-arch" endterm="t-arch"> to see the position of
TsStreamer between other parts of vls.
</para>

<para>
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.
</para>

<sect1><title>What's a PCR ?</title>

<para> 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.

</para>

<para>
<mediaobject>
   <imageobject>
    <imagedata fileref="pcr.eps" format="EPS" scalefit="1" scale="30">
  </imageobject>
 <imageobject>
    <imagedata fileref="pcr.jpg" format="JPG">
  </imageobject>
 <textobject>
    <phrase>PCR graph</phrase>
  </textobject>
</mediaobject>
</para>

<para>
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.
</para>
</sect1>

<sect1><title>Using or not PCRs</title>

<para> 
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 <function>bool m_bUsePcr</function> :
</para>

<programlisting>
  C_TsStreamer(handle hLog, C_Broadcast* pBroadcast,
               C_NetList* pTsProvider, C_SyncFifo* pBuffer,
               C_EventHandler* pEventHandler,
               bool m_bOwnProvider, bool m_bUsePcr);
</programlisting>

<para>
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
<filename>modules/localinput/localinput.cpp</filename>, C_TsStreamer is
instantiated with :
</para>

<programlisting>
C_TsStreamer* pStreamer = new C_TsStreamer(m_hLog, pBroadcast,
                                             pTsProvider, pBuffer,
                                             m_pEventHandler, true, true);
</programlisting>

<para>
Don't forget that the localinput input deals with Dvd and files, and -
like other input modules - spawns all the streaming chain.
</para>

<para>
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
<function>m_bUsePcr</function> is set to <emphasis>false</emphasis>.
</para>
</sect1>

<sect1><title>How vls handles PCRs</title>
<para>
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.
</para>

<para>
<mediaobject>
  <imageobject>
   <imagedata fileref="extrapolation.eps" format="EPS" scalefit="1" scale="30">
   </imageobject>
    <imageobject>
    <imagedata fileref="extrapolation.jpg" format="JPG">
  </imageobject>
<textobject>
    <phrase>Extrapolation</phrase>
  </textobject>
</mediaobject>
</para>

<para>
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 <filename>modules/server/tsstreamer.cpp</filename> :
</para>

<programlisting>
inline void C_TsStreamer::AdjustClock(C_TsPacket* pPacket)
{
(...)
  m_dSlope = ((double)iPCRTime - m_iLastTime) / (s64)m_uiByteRead;
(...)
  m_iLastTime = iPCRTime;
(...)
</programlisting>

<para>
Then, when holding the data D, the streamer computes the
linear extrapolation of the sending date Streaming(Data)
using the previous values <function>m_dSlope</function> and
<function>m_iLastTime</function> of segment [i,j] :
</para>

<programlisting>
inline void C_TsStreamer::WaitSendDate()
{
  s64 iSendDate = m_iLastTime + m_iDeltaClock + (s64)m_dSlope*m_uiByteRead;
  (...)
}
</programlisting>

<para>
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.
</para>

<para>
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.
</para>
</sect1>


<sect1><title>The TsStreamer itself</title>
<para>
The main job is made in <function>void C_TsStreamer::DoWork()</function>.

First, a packet is taken from the SyncFifo :

<programlisting>
C_TsPacket* pPacket = m_pBuffer->Pop();
</programlisting>
</para>

<para>
<mediaobject>
  <imageobject>
   <imagedata fileref="tsstreamer.eps" format="EPS" scalefit="1" scale="60">
  </imageobject>
  <imageobject>
<imagedata fileref="tsstreamer.jpg" format="JPG">
  </imageobject>
<textobject>
    <phrase>TsStreamer</phrase>
  </textobject>
</mediaobject>
</para>

<para>
After all the timing calculations described before, each TS packet is sent to the output :
<programlisting>
Output->Send(pPacket, (...) );
</programlisting>
</para>

