<br><br><div><span class="gmail_quote">On 7/31/05, <b class="gmail_sendername">Ross Finlayson</b> &lt;<a href="mailto:finlayson@live.com">finlayson@live.com</a>&gt; wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
At 08:43 PM 7/30/2005, you wrote:<br>&gt;Hello, all<br>&gt;I've read the FAQ about synchronization. It says that the parameter<br>&gt;presentationTime passed to afterGetFrame() can be used to synchronize,<br><br>Yes, but note that this FAQ applies to *receiving* RTP streams (
i.e.,<br>over a network).&nbsp;&nbsp;I.e., it applies to subclasses of &quot;RTPSource&quot;.<br><br>&gt;&nbsp;&nbsp;but I can't figure out how to use the parameter. I even can't<br>&gt; understand the exact mean of the parameter. Is it the same as the
<br>&gt; MediaSource::fPresentationTime exactly? In other words, if in my<br>&gt; MultiFramedMediaSource::doGetNextFrame() implementation, I set<br>&gt; fPresentationTime={1000,1000} for one particular frame, the<br>&gt; receiver should get a presentationTime={1000,1000} for this frame
<br>&gt; when call afterGettingFrame, shouldn't it?<br><br>It's not clear from your description exactly what you are using your<br>&quot;MultiFramedMediaSource&quot; for.&nbsp;&nbsp;But, if you are using it as a source<br>for an outgoing RTP stream (
i.e., feeding it into a &quot;RTPSink&quot;), then<br>your presentation times should be aligned with real, 'wallclock'<br>time.&nbsp;&nbsp;I.e., the first time you generate &quot;fPresentationTime&quot; in your<br>source object, you should do so using the value obtained by calling
<br>&quot;gettimeofday()&quot;.&nbsp;&nbsp;Plus, of course, you must have a &quot;RTCPInstance&quot; -<br>at both the sender and receiver - for synchronization to work.</blockquote><div><br>
Yes, I use FramedSource as the source for SimpleRTPSink<br>
my implementation is:<br>
<br>
class BufferedFramedSource: public FramedSource{<br>
public:<br>
&nbsp;&nbsp;&nbsp; BufferedFramedSource(UsageEnvironment &amp; env,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const std::string &amp; type);<br>
&nbsp;&nbsp;&nbsp; virtual ~BufferedFramedSource();<br>
private:<br>
&nbsp;&nbsp;&nbsp; void doGetNextFrame();<br>
<br>
&nbsp;&nbsp;&nbsp; std::string category;<br>
};<br>
<br>
<br>
BufferedFramedSource::BufferedFramedSource(UsageEnvironment &amp; env, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
const std::string &amp; type)<br>
&nbsp;&nbsp;&nbsp;&nbsp; :FramedSource(env), fInBuffer(ib), category(type)<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gettimeofday(&amp;fPresentationTime, NULL);<br>
&nbsp;&nbsp;&nbsp; };<br>
BufferedFramedSource::~BufferedFramedSource()<br>
{<br>
}<br>
<br>
void BufferedFramedSource::doGetNextFrame()<br>
{<br>
&nbsp;&nbsp;&nbsp; unsigned frameSize = 1024;<br>
&nbsp;&nbsp;&nbsp; if(fMaxSize &lt; frameSize){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fNumTruncatedBytes = frameSize - fMaxSize;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fFrameSize = fMaxSize;<br>
&nbsp;&nbsp;&nbsp; }else{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fNumTruncatedBytes = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fFrameSize = frameSize;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; fPresentationTime.tv_sec += 10;<br>
<br>
&nbsp;&nbsp;&nbsp; //fill the buffer with the discription of fPresentationTime<br>
&nbsp;&nbsp;&nbsp; std::stringstream ss(std::stringstream::out);<br>
&nbsp;&nbsp;&nbsp; ss &lt;&lt; category <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt;&quot; presentation time : &quot;&lt;&lt; fPresentationTime.tv_sec &lt;&lt;&quot;s, &quot;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; fPresentationTime.tv_usec &lt;&lt; &quot;microseconds&quot;;<br>
&nbsp;&nbsp;&nbsp; memcpy(fTo, ss.str().c_str(), fFrameSize);<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; fDurationInMicroseconds = 1000;<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; nextTask() = envir().taskScheduler().scheduleDelayedTask(0,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(TaskFunc*)afterGetting, this);<br>
}<br>
<br>
On the client peer, I use SimpleRTPSource to receive the stream, and try to print the presentation asocciated with the frame.<br>
<br>
class BufferedSink: public MediaSink{<br>
public:<br>
&nbsp;&nbsp;&nbsp; BufferedSink(UsageEnvironment &amp;env, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ofstream &amp; file,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned maxSize=1024);<br>
&nbsp;&nbsp;&nbsp; ~BufferedSink();<br>
protected:<br>
&nbsp;&nbsp;&nbsp; static void &nbsp;&nbsp;&nbsp; afterGettingFrame(void *clientData, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned frameSize, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned numTruncatedBytes, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
struct timeval presentationTime, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned durationInMicroseconds);<br>
<br>
&nbsp;&nbsp;&nbsp; virtual Boolean continuePlaying();<br>
private:<br>
&nbsp;&nbsp;&nbsp; virtual void &nbsp;&nbsp;&nbsp; afterGettingFrame1 (unsigned frameSize, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
struct timeval presentationTime,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned durationInMicroseconds);<br>
&nbsp;&nbsp;&nbsp; unsigned char *fBuffer;<br>
&nbsp;&nbsp;&nbsp; ofstream &amp; ofile;<br>
};<br>
<br>
<br>
<br>
BufferedSink::BufferedSink(UsageEnvironment &amp;env, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ofstream &amp; file,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned maxSize):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MediaSink(env), fBufferSize(maxSize),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ofile(file)<br>
{<br>
&nbsp;&nbsp;&nbsp; fBuffer = new unsigned char[maxSize];<br>
}<br>
<br>
BufferedSink::~BufferedSink()<br>
{<br>
&nbsp;&nbsp;&nbsp; delete []fBuffer;<br>
}<br>
&nbsp;&nbsp;&nbsp; <br>
void <br>
BufferedSink::afterGettingFrame(void* clientData, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned frameSize,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned numTruncatedBytes,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
struct timeval presentationTime,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned durationInMicroseconds) <br>
{<br>
&nbsp; BufferedSink* sink = (BufferedSink*)clientData;<br>
&nbsp; sink-&gt;afterGettingFrame1(frameSize, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
presentationTime, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
durationInMicroseconds);<br>
}<br>
<br>
<br>
void BufferedSink::afterGettingFrame1(unsigned frameSize,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; struct timeval presentationTime, <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned durationInMicroseconds) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ofile &lt;&lt; &quot;presentationTime: &quot; &lt;&lt; presentationTime.tv_sec &lt;&lt; &quot;s,&quot;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; presentationTime.tv_usec &lt;&lt; &quot;micros, &quot;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;&lt;&quot;durationInMicroseconds: &quot;&lt;&lt; durationInMicroseconds <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;&lt;&quot;, size: &quot; &lt;&lt;frameSize &lt;&lt; &quot; bytes&quot; &lt;&lt; endl;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ofile &lt;&lt; &quot;Content of
the buffer is:\n&quot; &lt;&lt; fBuffer &lt;&lt; endl &lt;&lt; endl;<br>
&nbsp;&nbsp; if(presentationTime.tv_sec == 0 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; presentationTime.tv_usec == 0){<br>
&nbsp;&nbsp;&nbsp; // The output file has closed.&nbsp; Handle this the same way as if the<br>
&nbsp;&nbsp;&nbsp; // input source had closed:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout&lt;&lt; &quot;End of the stream...&quot;;<br>
&nbsp;&nbsp;&nbsp; onSourceClosure(this);<br>
<br>
&nbsp;&nbsp;&nbsp; stopPlaying();<br>
&nbsp;&nbsp;&nbsp; return;<br>
&nbsp; }<br>
&nbsp; // Then try getting the next frame:<br>
&nbsp; continuePlaying();<br>
}<br>
<br>
Boolean<br>
BufferedSink::continuePlaying()<br>
{<br>
&nbsp; if (fSource == NULL) return False;<br>
<br>
&nbsp; fSource-&gt;getNextFrame(fBuffer, fBufferSize,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; afterGettingFrame, this,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; onSourceClosure, this);<br>
<br>
&nbsp; return True;<br>
}<br>
<br>
I also created a RTPCPInstance for the stream. What I got from the output of the client is:<br>
<br>
presentationTime: 1122790619s,599583micros, durationInMicroseconds: 0, size: 1024 bytes<br>
Content of the buffer is:<br>
video presentation time : 1123141214s, 536290microseconds<br>
<br>
presentationTime: 1122790629s,599583micros, durationInMicroseconds: 0, size: 1024 bytes<br>
Content of the buffer is:<br>
video presentation time : 1123141224s, 536290microseconds<br>
<br>
Apparently, the received presentationTime is not the same as the sending presentationTime. What's wrong with my codes?<br>
<br>
</div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&gt;Another attribute of MediaSource I don't understand is<br>&gt;fDurationInMicroseconds. In the above example, I set it to 10000 in
<br>&gt;MultiFramedMediaSource::doGetNextFrame, but I always get a 0 for<br>&gt;durantiontimeInMicroseconds in afterGetttingFrame(), why?<br><br>&quot;duration in microseconds&quot; - unlike &quot;presentation time&quot; - is not a
<br>parameter that gets passed within RTP (i.e., from sender to<br>receiver).&nbsp;&nbsp;Instead, it is a parameter that is used only internally<br>within a chain of &quot;Media&quot; objects.&nbsp;&nbsp;In particular, for data sources<br>that feed into a &quot;MultiFramedRTPSink&quot; (subclass), &quot;duration in
<br>microseconds&quot; tells the &quot;MultiFramedRTPSink&quot; how long to delay<br>between sending each outgoing RTP packet.</blockquote><div><br>
That is to say the durationTime from RTPSource is useless? <br>
</div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">To understand how the &quot;<a href="http://LIVE.COM">LIVE.COM</a> Streaming Media&quot; code works, I
<br>suggest that you start by examing the code for the existing demo<br>applications (&quot;testProgs&quot;), before trying to modify this to develop<br>your own code.</blockquote><div><br>
I have read testMP3Streamer and testMP3Receiver. but synchronization is not involved in them.<br>
Thanks!<br>
</div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">_______________________________________________<br>live-devel mailing list<br><a href="mailto:live-devel@lists.live.com">
live-devel@lists.live.com</a><br><a href="http://lists.live.com/mailman/listinfo/live-devel">http://lists.live.com/mailman/listinfo/live-devel</a><br></blockquote></div><br><br clear="all"><br>-- <br>Best regards<br><br>Shixin Zeng