<div style="line-height:1.7;color:#000000;font-size:14px;font-family:arial">At 2011-10-14 12:34:56,"Ross Finlayson" <finlayson@live555.com> wrote:<br> <blockquote id="isReplyContent" style="padding-left: 1ex; margin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(204, 204, 204);"><div>No, unfortunately there's no general 'frame duplicator' mechanism in our library.</div><br><div><br><blockquote type="cite"><div>Now, I known I can use a FileSink for save the media data to file. <br><br>RTPSource -> FileSink<br><br>But, how to send to the live player simultaneously? Should I make a Filter class, so the chain becomes:<br><br>RTPSource -> Filter -> RTPSink(to player)<br></div></blockquote><div><br></div>Yes, the simplest thing to do here would be to write your own filter class (a subclass of "FramedFilter") that copies input frames to the output, but also writes them to a file.  The "writing to a file" would be done directly (i.e., using "fwrite()"), rather than using a "FileSink").</div><div><br></div><div><br><blockquote type="cite"><div>If I should do so, how about send to 2 and more live player</div></blockquote><div><br></div></div>The simplest way to do this is just to use multicast.  I.e., send the frames out just once (using a single "RTPSink" object, but do so using an IP multicast address).  (E.g., our "testRelay" demo application does something like this.)<br><br><div apple-content-edited="true">
<span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Helvetica; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; "><span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Helvetica; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; ">Ross Finlayson<br>Live Networks, Inc.<br><a href="http://www.live555.com/">http://www.live555.com/</a></span></span>
</div>
</blockquote><br>Thank you for your reply!<br><br>I just wrote a simple Filter class:<br>===========================================================<br>H264VideoFilter::H264VideoFilter(UsageEnvironment& env,<br>        H264VideoRTPSource* source, char* saveToFileName) :<br>    FramedSource(env) {<br>    this->source = source;<br>    this->saveToFileName = saveToFileName;<br><br>    fileToSave = fopen(saveToFileName, "rw");<br>}<br><br>H264VideoFilter::~H264VideoFilter() {<br>    if (fileToSave != NULL) {<br>        fclose(fileToSave);<br>    }<br>}<br><br>void H264VideoFilter::onCloseCallback(void *clientData) {<br>    H264VideoFilter* filter = (H264VideoFilter*) clientData;<br><br>    if (filter->fileToSave != NULL) {<br>        fclose(filter->fileToSave);<br>        filter->fileToSave = NULL;<br>    }<br>}<br><br>void H264VideoFilter::afterGettingCallback(void *clientData,<br>        unsigned frameSize, unsigned numTruncatedBytes,<br>        struct timeval presentationTime, unsigned durationInMicroseconds) {<br><br>    H264VideoFilter* source = (H264VideoFilter*) clientData;<br>   /* save the frame to file */<br>    fwrite((void*)source->fTo, (size_t)frameSize, 1, source->fileToSave);<br><br>    FramedSource::afterGetting(source);<br>}<br><br>void H264VideoFilter::doGetNextFrame() {<br>    source->getNextFrame(fTo, fMaxSize, &afterGettingCallback, this,<br>            &onCloseCallback, this);<br>}<br>===========================================================<br>Now, I can use this filter as the source of my custom subsession object, then pass True as reuseFirstSource argument of the subsession constructor, so I can just use one filter to serve multiple remote player, right?<br><br></div>