Hey Ryo,<br><br>First of all, thanks for submitting a patch and for your kind words about Red5.<br><br>We have a dedicated mailing list for Red5 here: <a onclick="return top.js.OpenExtLink(window,event,this)" href="http://osflash.org/mailman/listinfo/osflash_osflash.org" target="_blank">
http://osflash.org/mailman/listinfo/red5_osflash.org</a> Please sign up for that and send future Red5 emails there. This list that you sent to is for general Open Source Flash topics.<br><br>As for the patch, could you open a ticket on Jira (
<a href="http://jira.red5.org">http://jira.red5.org</a>) and submit it through there? This way it won't get lost.<br><br>Thanks again!<br><br>-Chris<br><br><div><span class="gmail_quote">On 9/10/07, <b class="gmail_sendername">
Ryo Neyama</b> <<a href="mailto:neyama@utagoe.com">neyama@utagoe.com</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi,<br><br>I'm a user of Red5. Thank you very much for providing the great open<br>source software.<br><br>I'm using org.red5.server.stream.ClientBroadcastStream to record video<br>stream into flv files.<br><br>I expected that calling ClientBroadcastStream#saveAs(name, isAppend)
<br>multiple times allows me to change the file without any<br>frame-overwrapping and any frame-loss.<br><br>However, current SVN trunk and v0.6.2 do not behave as I expected. By<br>calling saveAs() twice (with different file names), two files are
<br>created and both files just keep growing.<br><br>Calling stopRecording() before second saveAs() works. However, some<br>flames seem to be lost. This seems to be due to unsubscribing from<br>the pipe by stopRecording() and skipping some frames before the next
<br>keyframe.<br><br>Subscribing new FileConsumer followed by unsubscribing the original<br>FileConsumer results in overwrapping some frames among files.<br><br>After some trial and error, I made some changes in the following
<br>source code in SVN trunk so that I can change files without any<br>frame-overwrapping and any frame-loss. The new code with my patch<br>changes files at the next keyframe.<br><br> org.red5.server.stream.ClientBroadcastStream
<br> org.red5.server.stream.consumer.FileConsumer<br><br>I think this patch might be useful for other users too. So, I'm<br>wondering if this patch could be incorporated into the main stream of<br>Red5. Any comments and helps will be appreciated.
<br><br>Best regards,<br>-----------------------------------------<br>Ryo Neyama<br> Utagoe Inc.<br> email: <a href="mailto:neyama@utagoe.com">neyama@utagoe.com</a><br> Tel: 03-3461-1118 / Fax: 03-3461-1119<br><br> <a href="http://www.utagoe.com/">
http://www.utagoe.com/</a><br> <a href="http://channel.is/">http://channel.is/</a><br>-----------------------------------------<br><br>Index: C:/work/WorkingDraft/eclipse-ws/red5_server/src/org/red5/server/stream/consumer/FileConsumer.java
<br>===================================================================<br>--- C:/work/WorkingDraft/eclipse-ws/red5_server/src/org/red5/server/stream/consumer/FileConsumer.java (revision 2305)<br>+++ C:/work/WorkingDraft/eclipse-ws/red5_server/src/org/red5/server/stream/consumer/FileConsumer.java (working copy)
<br>@@ -44,6 +44,8 @@<br> import org.red5.server.messaging.OOBControlMessage;<br> import org.red5.server.messaging.PipeConnectionEvent;<br> import org.red5.server.net.rtmp.event.IRTMPEvent;<br>+import org.red5.server.net.rtmp.event.VideoData
;<br>+import org.red5.server.net.rtmp.event.VideoData.FrameType;<br> import org.red5.server.net.rtmp.message.Constants;<br> import org.red5.server.stream.IStreamData;<br> import org.red5.server.stream.message.RTMPMessage;
<br>@@ -87,6 +89,10 @@<br> * Start timestamp<br> */<br> private int startTimestamp;<br>+ /**<br>+ * Next file<br>+ */<br>+ private File nextFile;<br><br> /**<br> * Creates file consumer
<br>@@ -96,10 +102,21 @@<br> public FileConsumer(IScope scope, File file) {<br> this.scope = scope;<br> this.file = file;<br>+ this.nextFile = null;<br> offset = 0;
<br> lastTimestamp = 0;<br> startTimestamp = -1;<br> }<br>+<br>+ /**<br>+ * Changes file<br>+ * @param file<br>+ */<br>+ public synchronized void changeFile(File file) {
<br>+ if (!file.equals(this.file)) {<br>+ this.nextFile = file;<br>+ }<br>+ }<br><br> /**<br> * Push message through pipe<br>@@ -119,11 +136,21 @@<br> if (!(message instanceof RTMPMessage)) {
<br> return;<br> }<br>- if (writer == null) {<br>- init();<br>- }<br> RTMPMessage rtmpMsg = (RTMPMessage) message;<br>
final IRTMPEvent msg = rtmpMsg.getBody();<br>+ synchronized (this) {<br>+ if (writer == null) {<br>+ init();<br>+ } else if (nextFile != null && msg instanceof VideoData && ((VideoData) msg).getFrameType() ==
FrameType.KEYFRAME) {<br>+ this.file = this.nextFile;<br>+ this.nextFile = null;<br>+ this.writer = null;<br>+ offset = 0;
<br>+ lastTimestamp = 0;<br>+ startTimestamp = -1;<br>+ init();<br>+ }<br>+ }<br> if (startTimestamp == -1) {
<br> startTimestamp = msg.getTimestamp();<br> }<br>Index: C:/work/WorkingDraft/eclipse-ws/red5_server/src/org/red5/server/stream/ClientBroadcastStream.java<br>===================================================================
<br>--- C:/work/WorkingDraft/eclipse-ws/red5_server/src/org/red5/server/stream/ClientBroadcastStream.java (revision 2305)<br>+++ C:/work/WorkingDraft/eclipse-ws/red5_server/src/org/red5/server/stream/ClientBroadcastStream.java (working copy)
<br>@@ -569,15 +569,20 @@<br> if (log.isDebugEnabled()) {<br> log.debug("Recording file: " + file.getCanonicalPath());<br> }<br>- recordingFile = new FileConsumer(scope, file);
<br>- Map<Object, Object> paramMap = new HashMap<Object, Object>();<br>- if (isAppend) {<br>- paramMap.put("mode", "append");<br>+ if (recordingFile == null) {
<br>+ recordingFile = new FileConsumer(scope, file);<br>+ Map<Object, Object> paramMap = new HashMap<Object, Object>();<br>+ if (isAppend) {<br>
+ paramMap.put("mode", "append");<br>+ } else {<br>+ paramMap.put("mode", "record");<br>+ }
<br>+ recordPipe.subscribe(recordingFile, paramMap);<br>+ recording = true;<br> } else {<br>- paramMap.put("mode", "record");
<br>+ recordingFile.changeFile(file);<br>+ recordingFilename = filename;<br> }<br>- recordPipe.subscribe(recordingFile, paramMap);<br>- recording = true;
<br> recordingFilename = filename;<br> }<br><br><br>_______________________________________________<br>osflash mailing list<br><a href="mailto:osflash@osflash.org">osflash@osflash.org</a><br><a href="http://osflash.org/mailman/listinfo/osflash_osflash.org">
http://osflash.org/mailman/listinfo/osflash_osflash.org</a><br><br></blockquote></div><br>