Update 2009-04-04: I’ve released an open source project that you can use to download RTMP video streams in a much simpler way. You can find it here: http://flazr.com
Red5 is an open source Flash server written in Java. It does not include a standalone client yet but I was able to write a Java program that uses Red5 to connect to an RTMP video stream and record / save it to a file. Code is provided below and also some tips on how to get the details required to download flash videos that you come across on the internet.
Here’s the code of “MyRtmpClient.java”, you are free to use and modify this in any way you want.
import java.io.File;
import org.apache.mina.common.ByteBuffer;
import org.red5.io.IStreamableFile;
import org.red5.io.ITag;
import org.red5.io.ITagWriter;
import org.red5.io.flv.impl.FLVService;
import org.red5.io.flv.impl.Tag;
import org.red5.io.utils.ObjectMap;
import org.red5.server.api.event.IEvent;
import org.red5.server.api.event.IEventDispatcher;
import org.red5.server.api.service.IPendingServiceCall;
import org.red5.server.api.service.IPendingServiceCallback;
import org.red5.server.net.rtmp.Channel;
import org.red5.server.net.rtmp.RTMPClient;
import org.red5.server.net.rtmp.RTMPConnection;
import org.red5.server.net.rtmp.codec.RTMP;
import org.red5.server.net.rtmp.event.AudioData;
import org.red5.server.net.rtmp.event.IRTMPEvent;
import org.red5.server.net.rtmp.event.Notify;
import org.red5.server.net.rtmp.event.VideoData;
import org.red5.server.net.rtmp.message.Header;
import org.red5.server.net.rtmp.status.StatusCodes;
import org.red5.server.stream.AbstractClientStream;
import org.red5.server.stream.IStreamData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyRtmpClient extends RTMPClient {
private static final Logger logger = LoggerFactory.getLogger(MyRtmpClient.class);
private String saveAsFileName = "test.flv";
public static void main(String[] args) {
String host = "localhost";
String app = "oflaDemo";
final String name = "IronMan.flv";
int port = 1935;
final int duration = 10000; // milliseconds, -2 means until end of stream
final MyRtmpClient client = new MyRtmpClient();
logger.debug("connecting, host: " + host + ", app: " + app + ", port: " + port);
IPendingServiceCallback callback = new IPendingServiceCallback() {
public void resultReceived(IPendingServiceCall call) {
logger.debug("service call result: " + call);
if ("connect".equals(call.getServiceMethodName())) {
client.createStream(this);
} else if ("createStream".equals(call.getServiceMethodName())) {
Integer streamId = (Integer) call.getResult();
logger.debug("createStream result stream id: " + streamId);
logger.debug("playing video by name: " + name);
client.play(streamId, name, 0, duration);
}
}
};
client.connect(host, port, app, callback);
}
private RTMPConnection conn;
private ITagWriter writer;
private int videoTs;
private int audioTs;
@Override
public void connectionOpened(RTMPConnection conn, RTMP state) {
logger.debug("connection opened");
super.connectionOpened(conn, state);
this.conn = conn;
init();
}
@Override
public void connectionClosed(RTMPConnection conn, RTMP state) {
logger.debug("connection closed");
super.connectionClosed(conn, state);
if (writer != null) {
writer.close();
writer = null;
}
System.exit(0);
}
@Override
public void createStream(IPendingServiceCallback callback) {
logger.debug("create stream");
IPendingServiceCallback wrapper = new CreateStreamCallBack(callback);
invoke("createStream", null, wrapper);
}
@Override
protected void onInvoke(RTMPConnection conn, Channel channel, Header header, Notify notify, RTMP rtmp) {
super.onInvoke(conn, channel, header, notify, rtmp);
ObjectMap<String, String> map = (ObjectMap) notify.getCall().getArguments()[0];
String code = map.get("code");
if (StatusCodes.NS_PLAY_STOP.equals(code)) {
logger.debug("onInvoke, code == NetStream.Play.Stop, disconnecting");
disconnect();
}
}
private void init() {
File file = new File(saveAsFileName);
FLVService flvService = new FLVService();
flvService.setGenerateMetadata(true);
try {
IStreamableFile flv = flvService.getStreamableFile(file);
writer = flv.getWriter();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private class CreateStreamCallBack implements IPendingServiceCallback {
private IPendingServiceCallback wrapped;
public CreateStreamCallBack(IPendingServiceCallback wrapped) {
this.wrapped = wrapped;
}
public void resultReceived(IPendingServiceCall call) {
Integer streamIdInt = (Integer) call.getResult();
if (conn != null && streamIdInt != null) {
MyNetStream stream = new MyNetStream();
stream.setConnection(conn);
stream.setStreamId(streamIdInt.intValue());
conn.addClientStream(stream);
}
wrapped.resultReceived(call);
}
}
private class MyNetStream extends AbstractClientStream implements IEventDispatcher {
public void close() { }
public void start() { }
public void stop() { }
public void dispatchEvent(IEvent event) {
if (!(event instanceof IRTMPEvent)) {
logger.debug("skipping non rtmp event: " + event);
return;
}
IRTMPEvent rtmpEvent = (IRTMPEvent) event;
if (logger.isDebugEnabled()) {
logger.debug("rtmp event: " + rtmpEvent.getHeader() + ", "
+ rtmpEvent.getClass().getSimpleName());
}
if (!(rtmpEvent instanceof IStreamData)) {
logger.debug("skipping non stream data");
return;
}
if (rtmpEvent.getHeader().getSize() == 0) {
logger.debug("skipping event where size == 0");
return;
}
ITag tag = new Tag();
tag.setDataType(rtmpEvent.getDataType());
if (rtmpEvent instanceof VideoData) {
videoTs += rtmpEvent.getTimestamp();
tag.setTimestamp(videoTs);
} else if (rtmpEvent instanceof AudioData) {
audioTs += rtmpEvent.getTimestamp();
tag.setTimestamp(audioTs);
}
ByteBuffer data = ((IStreamData) rtmpEvent).getData().asReadOnlyBuffer();
tag.setBodySize(data.limit());
tag.setBody(data);
try {
writer.writeTag(tag);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
To compile and run the code you need the following libraries:
commons-collections-3.2.jar jcl104-over-slf4j-1.4.3.jar logback-classic-0.9.8.jar logback-core-0.9.8.jar mina-core-1.1.6.jar red5.jar slf4j-api-1.4.3.jar spring-beans-2.0.8.jar spring-context-2.0.8.jar spring-core-2.0.8.jar
We need the latest Red5 JAR built from version control (not the latest official release) and I have uploaded these files here: red5-rtmp-client-libszip.pdf – just rename the file to end with “.zip” after downloading.
The code shown is hard-coded to connect to “localhost”, app name “oflaDemo” and stream name “IronMan.flv” which can be tested on the official Red5 server distribution which you can download and run. When it comes to downloading flash streams from the internet, WireShark can be used to sniff out the values you need.
Let’s take this site for example: http://videolectures.net/ Start a WireShark capture session before clicking on a video on the site to play it. Let WireShark grab all the information exchanged between your PC and the remote flash server and you can stop the capture once the video begins to play, we are only interested in what goes on during the connection handshake. I will use this video as an example: http://videolectures.net/ff06_chomsky_szmp/ [update Jun-2008: looks like they changed this particular video to Windows media instead of Flash, so try other videos or other sites]
In WireShark you can filter for protocol “rtmpt” and the first few entries would be handshake or “invoke” operations. Examining the “Handshake part 3″ we can easily get the value of the required “app” property. Below we can see it is “video/2006/other/ff06/chomsky_noam”:

For the host name, the IP address should do fine for most sites, but we can easily figure out the host name of the stream server from what appears after “rtmp://”. Note that WireShark allows you to search the text contents of captured packets. Here below we can see that the host name is “velblod.videolectures.net”:

And finally when the “play” command is issued – we need the value of the stream name. Below we see it is “chomsky_noam_01″:

So with the right values of hostname, app and stream name set – you can run the program and download the stream to your local drive for offline viewing. To download the whole stream – just change the duration to ‘-2′ as hinted in the source code comment. There are many free Flash players available you can use to play downloaded content such as FLV Player.
Do let me know if this works for you and if you find any additional parameters that need to be passed for other sites.





Hi,
Thanks for a great tutorial! I was just looking do find a way to record an RTMP stream.
Unfortunately, I can’t download anything from SouthparkStudios.com, which was what I wanted to do. If I put in:
String ep = “0404″;
int part = 1;
String host = “76.9.18.94″;
String app = “ondemand?_fcs_vhost=cp40493.edgefcs.net”;
final String name = “flv:comedystor/_!/com/sp/acts/Season04/E_” + ep + “/compressed/flv/” + ep + “_” + part + “_DI_640×480_500kbps”;
it downloads 868.9 KB and then there’s an exception, and it stops working:
…
15:11:11.518 [AnonymousIoService-15] DEBUG org.red5.server.net.rtmp.RTMPClient – onInvoke:Invoke: Service: null Method: onStatus Num Params: 10: {clientid=f55Qgqdo, level=status, details=comedystor/_!/com/sp/acts/Season04/E_0404/compressed/flv/0404_1_DI_640×480_500kbps, reason=, description=Stopped playing comedystor/_!/com/sp/acts/Season04/E_0404/compressed/flv/0404_1_DI_640×480_500kbps., code=NetStream.Play.Stop}
15:11:11.518 [AnonymousIoService-15] ERROR o.r.server.net.rtmp.BaseRTMPHandler – Exception
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at org.red5.server.net.rtmp.RTMPClient.onInvoke(RTMPClient.java:381)
at MyRtmpClient.onInvoke(MyRtmpClient.java:122)
at org.red5.server.net.rtmp.BaseRTMPHandler.messageReceived(BaseRTMPHandler.java:143)
at org.red5.server.net.rtmp.RTMPMinaIoHandler.messageReceived(RTMPMinaIoHandler.java:119)
at org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.messageReceived(AbstractIoFilterChain.java:570)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.LoggingFilter.messageReceived(LoggingFilter.java:89)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.executor.ExecutorFilter.processEvent(ExecutorFilter.java:220)
at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:264)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
at java.lang.Thread.run(Thread.java:619)
15:11:11.519 [AnonymousIoService-15] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [/76.9.18.94:1935] SENT: org.red5.server.net.rtmp.message.Packet@1e2befa
15:11:11.519 [AnonymousIoService-15] DEBUG o.r.s.net.rtmp.RTMPMinaIoHandler – messageSent
…
Well, in any case, my Flash player is now working properly again, so I can just go to the website and watch it from there ;)
Comment by Bob — April 28, 2008 @ 12:19 am
@Bob
Did you change the value of duration from 10000 to -2 ? See the comment in the source code.
Comment by Peter Thomas — April 28, 2008 @ 9:38 am
Oh wow. I’m such a complete idiot.
I remember seeing that, and I even thought I changed it… I can’t believe I went through all the trouble trying it on different computers.
Thank you!
Comment by Bob — April 30, 2008 @ 1:46 am
Nice post, Explained very well.
Comment by Sunil — May 10, 2008 @ 8:07 pm
I’m new in this and am trying to figure out if I could make this work with live streams. Any tips?
Comment by yenn — May 14, 2008 @ 11:01 am
@yenn
Never tried, what I would do is use Wireshark to look at the handshake for a live stream to see if there is something else going on. You may then need to dig deeper into the internals of the RTMPClient java code – for e.g. in case the “play” command takes slightly different arguments for a live stream. BTW the RTMP protocol was very recently opened-up by Adobe so you should be able to look at that as well. I am not working on this for the time being you would probably get more tips from the Red5 mailing list. Do post back here if you have any success.
Comment by Peter Thomas — May 14, 2008 @ 12:21 pm
I am tyring to connect from java to Flash Media Server using this class, but it is not connecting error. When I change host from remote IP to local IP, it is not giving error.
Here is error, I am getting:
15:07:26.234 [AnonymousIoService-3] DEBUG o.r.s.net.rtmp.RTMPMinaIoHandler – messageSent
15:07:26.234 [AnonymousIoService-3] DEBUG o.r.server.net.rtmp.BaseRTMPHandler – Message sent
15:07:26.234 [AnonymousIoService-3] DEBUG abc.MyRtmpClient – connection opened
15:07:26.234 [AnonymousIoService-3] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [/172.29.9.99:1935] WRITE: org.red5.server.net.rtmp.message.Packet@1d1acd3
15:07:26.265 [AnonymousIoService-3] DEBUG o.r.s.n.r.codec.RTMPProtocolEncoder – This is a pending call, send request
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – serialize
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – write basic
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – serialize
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – write basic
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – serialize
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – writeComplex
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – writeListType
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – writeArrayType
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – writeXMLType
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – serialize
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – write basic
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – serialize
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – write basic
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – serialize
15:07:26.265 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – write basic
15:07:26.265 [AnonymousIoService-3] DEBUG o.r.s.n.r.codec.RTMPProtocolEncoder – Writing params
15:07:26.296 [AnonymousIoService-3] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [/172.29.9.99:1935] SENT: org.red5.server.net.rtmp.message.Packet@1d1acd3
15:07:26.296 [AnonymousIoService-3] DEBUG o.r.s.net.rtmp.RTMPMinaIoHandler – messageSent
15:07:26.296 [AnonymousIoService-3] DEBUG o.r.server.net.rtmp.BaseRTMPHandler – Message sent
15:07:26.296 [AnonymousIoService-3] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [/172.29.9.99:1935] CLOSED
15:07:26.296 [AnonymousIoService-3] DEBUG abc.MyRtmpClient – connection closed
15:07:26.296 [AnonymousIoService-3] DEBUG org.red5.server.BaseConnection – Close, not connected nothing to do.
15:07:26.359 [AnonymousIoService-3] DEBUG org.red5.server.jmx.JMXAgent – leaving unregisterMBean…
Comment by Narender Poonia — May 14, 2008 @ 2:40 pm
@Narender: I can’t tell from this. Maybe the port is wrong.
Sometimes it needs more work. For example on one particular site I tried, there was a security feature where an initial HTTP request would return a security ticket or token and this token had to be passed as a querystring parameter to the “play” invoke for things to work. You may need to do some digging with Wireshark, but if you have time it is fun.
Comment by Peter Thomas — May 14, 2008 @ 8:17 pm
I got it working with live streams now, looks like i missed something simple…
Yup, the play takes different arguments for live streams, so I had to pass -2 for the start instead of 0.
client.play(streamId, name, -2, duration);
Thanks~
Comment by yenn — May 15, 2008 @ 9:10 am
@yenn: Great! Thanks for the update.
Comment by Peter Thomas — May 15, 2008 @ 11:27 am
I doesnt work for me wih live streams even with the
client.play(streamId, name, -2, duration);
argument. It gets stuck on this:
[edit: shifted long stack trace to here: http://pastebin.com/f7ab285f ]
You say adobe has opened-up RTMP protocol very recently, where can I find the spec?? I cant find it on the abode website or anywhere else.
Thanks.
Comment by Christian — May 16, 2008 @ 1:01 am
@Christian: If you look at line 97 of the stack trace the server has responded with this error: “Connection failed: Application folder ([install-location]/applications/) is missing.”
I was able to find the FLV spec here: http://www.adobe.com/devnet/flv/
The Adobe announcement I am referring to is here:
http://ajaxian.com/archives/adobe-lifts-swfflv-restrictions-and-creates-open-screen-project
I thought I saw somewhere that RTMP was opened up as well but can’t find it.
Comment by Peter Thomas — May 16, 2008 @ 5:18 pm
Hi!
I used the following param values for MyRmtpClient:
String host = “flashstreaming.prosieben.de”;
String app = “ondemand?_fcs_vhost=flashstreaming.prosieben.de”;
final String name = “prosieben-de/kino_dvd/bbtv/BBTV_Folge_5″;
It downloads the file correctly, but if I only want to download the first 10 Seconds I get an error and the main routine still runs, without stopping or exiting. I tried to embed the origigal red5 sources and compile them, but then the play method for RTMPClient is missing.
Do you know how I can make the Java main stop, without throwing this exception?
02:50:12.750 [AnonymousIoService-1] ERROR o.r.server.net.rtmp.BaseRTMPHandler – Exception
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at org.red5.server.net.rtmp.RTMPClient.onInvoke(RTMPClient.java:381)
at MyRtmpClient.onInvoke(MyRtmpClient.java:123)
at org.red5.server.net.rtmp.BaseRTMPHandler.messageReceived(BaseRTMPHandler.java:143)
at org.red5.server.net.rtmp.RTMPMinaIoHandler.messageReceived(RTMPMinaIoHandler.java:119)
at org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.messageReceived(AbstractIoFilterChain.java:570)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.LoggingFilter.messageReceived(LoggingFilter.java:89)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.executor.ExecutorFilter.processEvent(ExecutorFilter.java:220)
at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:264)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
at java.lang.Thread.run(Unknown Source)
02:50:12.750 [AnonymousIoService-1] DEBUG o.a.m.filter.executor.ExecutorFilter – Exiting since queue is empty for flashstreaming.prosieben.de/84.53.177.148:1935
Comment by Kostas — May 17, 2008 @ 5:56 am
@Kostas: Yes you can do some better checking in the onInvoke method (after the call to super) like this:
if (call.getServiceMethodName().equals("onStatus")) { ObjectMap<String, String> map = (ObjectMap) call.getArguments()[0]; String code = map.get("code"); if (StatusCodes.NS_PLAY_STOP.equals(code)) { logger.debug("onStatus code == NetStream.Play.Stop, disconnecting"); disconnect(); } }Comment by Peter Thomas — May 17, 2008 @ 9:36 am
Hi,
Is it possible to do an incremental save? For example, I downloaded, the first 10 mins of a video and then my internet connection broke.. How do I restart the download from the point I got disconnected? And also, how do I merge the two files together?
Thanks,
Jack
Comment by Jack — May 20, 2008 @ 7:06 pm
@Jack: haven’t tried but I’m guessing passing the start time in milliseconds instead of 0 in the ‘play’ method (where someone above found -2 works for live streams) – should do the trick.
For merging, from what I’ve seen in Red5 it should be easy to write a program to do it e.g. there is a class you could look at called FLVReader. I’m not really working on this now and you should be able to get more help from the Red5 mailing list.
Comment by Peter Thomas — May 20, 2008 @ 7:29 pm
Thanks Thomas — I will check that out. Now, sometimes after like half an hour of download, the program freezes.. It doesn’t download anything anymore but wouldn’t exit also. I have attached some debug messages. Please let me know if you can figure out something..
09:43:00.750 [AnonymousIoService-10] DEBUG o.r.server.net.rtmp.BaseRTMPHandler -
Stream Id: ChannelId: 2, Timer: 0 (absolute), Size: 6, DateType: 4, StreamId: 0
09:43:00.750 [AnonymousIoService-10] DEBUG o.r.server.net.rtmp.BaseRTMPHandler -
Channel: org.red5.server.net.rtmp.Channel@df503
09:43:00.750 [AnonymousIoService-10] DEBUG org.red5.server.net.rtmp.RTMPClient -
onPing
09:43:00.750 [AnonymousIoService-10] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [v
elblod.videolectures.net/193.2.4.161:1935] WRITE: org.red5.server.net.rtmp.messa
ge.Packet@9f25c5
09:43:00.750 [AnonymousIoService-10] DEBUG o.a.m.filter.executor.ExecutorFilter
- Exiting since queue is empty for velblod.videolectures.net/193.2.4.161:1935
09:43:00.750 [SocketConnectorIoProcessor-0.0] DEBUG o.a.m.filter.executor.Execut
orFilter – Launching thread for velblod.videolectures.net/193.2.4.161:1935
09:43:00.750 [AnonymousIoService-11] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [v
elblod.videolectures.net/193.2.4.161:1935] SENT: org.red5.server.net.rtmp.messag
e.Packet@9f25c5
09:43:00.750 [AnonymousIoService-11] DEBUG o.r.s.net.rtmp.RTMPMinaIoHandler – me
ssageSent
09:43:00.750 [AnonymousIoService-11] DEBUG o.r.server.net.rtmp.BaseRTMPHandler -
Message sent
09:43:00.750 [AnonymousIoService-11] DEBUG o.a.m.filter.executor.ExecutorFilter
- Exiting since queue is empty for velblod.videolectures.net/193.2.4.161:1935
Comment by Jack — May 21, 2008 @ 9:19 am
I tried changing values for live stream capture like it has been said here (-2 and so), but without any success. I was doing it from the FMS I made publishing. What should I put in the variable app, and what in the variable name in case of rtmp://host/mystr/live?
Has anybody succeed capturing live stream?
Comment by Bojan — May 23, 2008 @ 8:14 am
@Peter: Thanks for your response
Here is my problem:
I have a java code for capturing screen, which I need to communicate with “Flash media server” application to broadcast that captured image.
I am able to connect to Red5 server and broadcast image.
I am able to connect from Flex to Flash Media server application. But I want to connect to “Flash Media Server” from java code using RTMPClient class, which I am not able to make connection presently.
Your help will be highly appreciated.
Thanks!
Comment by Narender Poonia — May 26, 2008 @ 4:40 pm
I’m wondering if anybody could offer compilation tips… I seem to have trouble getting javac to recognize the jar files. (My experience with java is minimal…)
Comment by Graham — June 29, 2008 @ 5:39 am
I’m with Graham. I’ve got the parameters from Wireshark and am trying to compile, but I’m getting “cannot find symbol” and “does not exist” errors (because I’m supposed to put the libraries somewhere other than java’s lib directory?) This is a cool project that I’d really like to understand. Thanks.
Comment by Brad — June 29, 2008 @ 5:48 am
@Graham, @Brad:
Yes, the post assumes that you have a working knowledge of Java. But try the following steps:
1) Download NetBeans from here, you need only the one that says “Java SE”, around 31 MB.
2) Install and start NetBeans, create a new Java Project of type “Java Application”, name it “test”, also uncheck the “Create Main Class” option.
3) Set up the libraries: after downloading and getting the bunch of *.jar files, place them in a folder (typically called “lib” within the newly created project folder “test”).
4) In the projects explorer, right click on the “Libraries” node and “Add JAR/Folder”. Browse to where the JAR files are and you can multi-select all of them.
5) Right click on “Source Packages” and select New –> Java Class, provide the name as “MyRtmpClient”.
6) Cut and paste the code from the blog post completely replacing whatever was in the editor window for “MyRtmpClient.java”. There should not be any errors. After pasting, you can optionally select all, right click and “Format” so that the code indents better.
7) Make the modifications needed as described in the blog post and the comments. Now you can go to the toolbar menu: Run –> Run File –> Run “MyRtmpClient.java” and things should work. You should see logs in the output window.
All the best!
Comment by Peter Thomas — June 29, 2008 @ 12:17 pm
Thanks for the response, Peter. I was trying to do this from the commandline, but given that I’m still having no luck, I’ll try what you said.
Comment by Brad — June 29, 2008 @ 1:02 pm
I am also wondering about capturing a live stream. I got the impression I just needed to change to client.play((streamId, name, -2, duration), but I find that I am still recording the IronMan.flv when I try this.
Comment by David — July 10, 2008 @ 1:57 am
@David – you do have to change lines 37 – 39 also to suit your requirement.
Comment by Peter Thomas — July 10, 2008 @ 2:25 pm
If I am broadcasting on my local machine using the SimpleBroadcaster that comes with Red5 then that takes care of lines 37 and 38. As far as line 39 I don’t have a clue what it should be for recording a live stream.
Comment by David — July 10, 2008 @ 2:42 pm
Ok I get it. Honestly I don’t have a clue either. I vaguely remember that Red5 has a built in feature to record live streams – on the server.
Hope one of the earlier commenters can come to your help. Maybe you can consider turning to the Red5 mailing list for help as well.
Comment by Peter Thomas — July 10, 2008 @ 6:18 pm
Hi Peter,
Really appreciate for your work. I am a newbie to red5, your java client indeed help me understand red5 a lot.
I am asked to develop a similar client and now I have some questions after trying/testing your java client.
I’ve downloaded and installed both red5 (build from latest trunk) and flash media development server 3(free version of fms). My problem is, I can get the client connected to the red5 and downloaded a city_of_ember.flv correctly. However, when I connected to flash media development server the download can not start. the log is as follow:
(last few line)
11:50:13.799 [AnonymousIoService-4] DEBUG o.r.s.n.r.codec.RTMPProtocolEncoder – Writing params
11:50:13.830 [AnonymousIoService-4] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [/144.214.37.244:1935] SENT: org.red5.server.net.rtmp.message.Packet@21b6d
11:50:13.830 [AnonymousIoService-4] DEBUG o.r.s.net.rtmp.RTMPMinaIoHandler – messageSent
11:50:13.830 [AnonymousIoService-4] DEBUG o.r.server.net.rtmp.BaseRTMPHandler – Message sent
11:50:13.830 [AnonymousIoService-4] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [/144.214.37.244:1935] CLOSED
11:50:13.830 [AnonymousIoService-4] DEBUG org.po.MyRtmpClient – connection closed
11:50:13.830 [AnonymousIoService-4] DEBUG org.red5.server.BaseConnection – Close, not connected nothing to do.
11:50:13.987 [AnonymousIoService-4] DEBUG org.red5.server.jmx.JMXAgent – leaving unregisterMBean…
I attached the flash media development server to the internet @ 144.214.37.244. you may test it with following settings:
host = “144.214.37.244″;
app = “vod”;
name = “sample.flv”;
port = 1935;
many thanks!
Comment by posco — July 17, 2008 @ 8:56 am
Hi Peter, any updates for the above problem.
Even I am facing a similar issue
Comment by Ciddu — July 26, 2008 @ 2:18 pm
Did somebody get it to work with livestreams? client.play(streamId, name, -2, duration); doesn’t work for me either.
Comment by Dennis — August 19, 2008 @ 4:26 pm
Hey, im German
I tried to download streams from adobe flash player 9 but “Wireshark” dont found any rtmp links, can anyone tell me how it’s work?
Comment by Erich Klassen — October 7, 2008 @ 7:50 pm
…
16:44:17.765 [AnonymousIoService-3] DEBUG org.red5.io.object.Serializer – write basic
16:44:17.765 [AnonymousIoService-3] DEBUG o.r.s.n.r.codec.RTMPProtocolEncoder – Writing params
16:44:17.781 [AnonymousIoService-3] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [/195.27.154.133:1935] SENT: org.red5.server.net.rtmp.message.Packet@c9ba38
16:44:17.781 [AnonymousIoService-3] DEBUG o.r.s.net.rtmp.RTMPMinaIoHandler – messageSent
16:44:17.781 [AnonymousIoService-3] DEBUG o.r.server.net.rtmp.BaseRTMPHandler – Message sent
16:44:17.781 [AnonymousIoService-3] DEBUG o.a.m.filter.executor.ExecutorFilter – Exiting since queue is empty for /195.27.154.133:1935
16:44:17.875 [SocketConnectorIoProcessor-0.0] DEBUG o.a.m.filter.executor.ExecutorFilter – Launching thread for /195.27.154.133:1935
16:44:17.875 [AnonymousIoService-4] INFO o.r.s.net.rtmp.RTMPMinaIoHandler – [/195.27.154.133:1935] CLOSED
16:44:17.875 [AnonymousIoService-4] DEBUG org.red5.server.BaseConnection – Close, not connected nothing to do.
16:44:17.921 [AnonymousIoService-4] DEBUG org.red5.server.jmx.JMXAgent – leaving unregisterMBean…
I try to download stream, but at result get only 13 bytes with header. No calls for “play” method.
With oflaDemo all works fine.
Please, help :(
Comment by Li — November 7, 2008 @ 8:08 pm
Hi,
I’ve been trying to make it work live streams but so far i m not successful.
I have following configuration.
host is “172.30.0.6″
applicaation is “oflaDemo”
stream is “abc”
and port is 1935
When I specify the above configuration in the application as follows:
String host = “172.30.0.6″;
String app = “oflaDemo”;
final String name = “abc”;
int port = 1935;
it does not work saying stream not found.
could any body give me a clue what am i missing.
Regards.
Atif Ali Bhatti.
Comment by Atif Ali Bhatti — November 18, 2008 @ 1:15 pm
Hi,
with version 0.7, for playback works:
client.play(streamId, name, -2000, -2000);
But the question for thomas is: where is the src code for that Red5 build that u’v uploaded? May u specify the svn link for that Red5 build…
Many thanks!
Bye
Comment by GerardoL — January 10, 2009 @ 3:47 am
@GerardoL – I just checked my archived workspace and the SVN link appears to be:
http://svn1.cvsdude.com/osflash/red5/java/server/trunk
You may need to figure out the correct revision if needed – based on the date of this blog post etc.
Comment by Peter Thomas — January 10, 2009 @ 10:45 am
How can I display debug messages that are recorded with logger.debug()?
I tried downloading a video from videolectures.net and MyRtmpClient starts but does not do anything afterwards.
(FLV file is not created, but no error messages either)
Comment by CaptSolo — January 18, 2009 @ 5:07 am
My mistake, log messages are appearing, but there is just a single message “connecting” and nothing else.
Could you please give me a hint of what’s wrong?
Comment by CaptSolo — January 18, 2009 @ 5:17 am
@CaptSolo
For the logging, just create a file called logback.xml and put it into the classpath (placing it in the “src” folder should be fine) – with the following contents, change DEBUG to INFO, WARN etc till you are satisfied.
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>[%t] %p [%c] - %m%n</pattern> </layout> </appender> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <File>log.log</File> <Append>false</Append> <Encoding>UTF-8</Encoding> <BufferedIO>false</BufferedIO> <ImmediateFlush>true</ImmediateFlush> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern> %date [%thread] %-5level %logger{35} - %msg%n </Pattern> </layout> </appender> <logger name="MyRtmpClient"> <level value="DEBUG"/> </logger> <logger name="org.red5"> <level value="DEBUG"/> </logger> <root> <level value="DEBUG"/> <appender-ref ref="stdout"/> <appender-ref ref="FILE"/> </root> </configuration>Comment by Peter Thomas — January 18, 2009 @ 9:52 pm
@Peter – thanks, logging gives much more detail now. :)
I got further but am still getting exceptions. Plus I don’t know if those are due to me having messed up the Java environment or is it caused by the source RTMP stream doing something unexpected.
Could you please tell me if the following code (http://pastebin.com/m49daaad9) works for you?
Comment by CaptSolo — January 19, 2009 @ 3:39 am
I had a quick look at the code, looks okay to me. Here are a couple of links that may be relevant:
http://blogs.adobe.com/ktowes/2008/09/encryption_and_streaming_media.html
http://www.adobe.com/devnet/flashmediaserver/articles/protecting_video_fms.pdf
Comment by Peter Thomas — January 19, 2009 @ 7:52 am
I am comiling MyRTMPClient code on eclipse, its generates class, but when I run it, it gives me these kind of error, What need to be done to fix this.
java.lang.UnsupportedClassVersionError: Bad version number in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
Exception in thread “main”
Comment by Tarun Kumar — February 5, 2009 @ 10:56 am
@Tarun that usually happens when you compile with a higher version of Java and try to run using a lower version (e.g. JDK 1.5 vs JRE 1.4), please check.
Comment by Peter Thomas — February 5, 2009 @ 11:39 am
Thanks Peter, I compiled this code on JDK 1.6, now it got compiled but it is not storing stream to flv file.
it does proper hand shake
and suddenly stops
[AnonymousIoService-2] DEBUG [org.red5.server.net.rtmp.RTMPMinaIoHandler] – messageSent
[AnonymousIoService-2] DEBUG [org.red5.server.net.rtmp.BaseRTMPHandler] – Message sent
[AnonymousIoService-2] DEBUG [MyRtmpClient] – connection opened
[AnonymousIoService-2] DEBUG [org.red5.server.net.rtmp.RTMPClient] – connectionOpened
[AnonymousIoService-2] INFO [org.red5.server.net.rtmp.RTMPMinaIoHandler] – [stockuncle-lx.eglbp.corp.yahoo.com/10.66.74.61:1935] WRITE: org.red5.server.net.rtmp.message.Packet@145f0e3
[AnonymousIoService-2] DEBUG [org.red5.server.net.rtmp.codec.RTMPProtocolEncoder] – This is a pending call, send request
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – writeComplex
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – writeListType
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – writeArrayType
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – writeXMLType
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – serialize
[AnonymousIoService-2] DEBUG [org.red5.io.object.Serializer] – write basic
[AnonymousIoService-2] DEBUG [org.red5.server.net.rtmp.codec.RTMPProtocolEncoder] – Writing params
[AnonymousIoService-2] INFO [org.red5.server.net.rtmp.RTMPMinaIoHandler] – [stockuncle-lx.eglbp.corp.yahoo.com/10.66.74.61:1935] SENT: org.red5.server.net.rtmp.message.Packet@145f0e3
[AnonymousIoService-2] DEBUG [org.red5.server.net.rtmp.RTMPMinaIoHandler] – messageSent
[AnonymousIoService-2] DEBUG [org.red5.server.net.rtmp.BaseRTMPHandler] – Message sent
[AnonymousIoService-2] INFO [org.red5.server.net.rtmp.RTMPMinaIoHandler] – [stockuncle-lx.eglbp.corp.yahoo.com/10.66.74.61:1935] CLOSED
[AnonymousIoService-2] DEBUG [MyRtmpClient] – connection closed
[AnonymousIoService-2] DEBUG [org.red5.server.BaseConnection] – Close, not connected nothing to do.
[AnonymousIoService-2] DEBUG [org.red5.server.jmx.JMXAgent] – leaving unregisterMBean…
is there any other version available for this fix?
Comment by Tarun Kumar — February 10, 2009 @ 4:53 pm
continuing the above in lol.log file it show like that
2009-02-10 03:25:23,911 [AnonymousIoService-1] DEBUG o.r.s.net.rtmp.RTMPMinaIoHandler – messageSent
2009-02-10 03:25:23,911 [AnonymousIoService-1] DEBUG o.r.server.net.rtmp.BaseRTMPHandler – Message sent
2009-02-10 03:25:23,911 [AnonymousIoService-1] DEBUG o.a.m.f.executor.ExecutorFilter – Exiting since queue is empty for stockuncle-lx.eglbp.corp.yahoo.com/10.66.74.61:1935
2009-02-10 03:25:23,928 [SocketConnectorIoProcessor-0.0] DEBUG o.r.s.n.r.codec.RTMPProtocolDecoder – Handshake init too small, buffering. remaining: 1024
2009-02-10 03:25:23,930 [SocketConnectorIoProcessor-0.0] DEBUG o.a.m.f.executor.ExecutorFilter – Launching thread for stockuncle-lx.eglbp.corp.yahoo.com/10.66.74.61:1935
Comment by Tarun Kumar — February 10, 2009 @ 5:19 pm
I’m receving this error.
WARN o.r.s.n.r.codec.RTMPProtocolDecoder – Closing connection because decoding failed
I take it this is because any content worth copying is now encrypted? So much for downloading the latest season of..
Comment by Matt — February 16, 2009 @ 11:55 am
Yes Matt, you can see my comment at #40
Comment by Peter Thomas — February 16, 2009 @ 12:12 pm
Hello. If my understanding is correct this code when compiled is able to hook onto an RTMP live broadcasted stream? E.g. if I have simpleBroadcaster setup for live streaming then I can execute this app and point/hook it onto the live broadcast and in turn this will record it to file?
Thank you.
Comment by Keith — February 19, 2009 @ 3:34 pm
@Keith, yes this should work in theory – as you can see from previous comments, people have had mixed results.
Comment by Peter Thomas — February 19, 2009 @ 5:48 pm
Hello Peter,
I’ve tried your steps in your comment #22 but with no success.
I always got 77 errors both with NetBeans and command-line.
All the errors similar to this:
My Documents\NetBeansProjects\test\src\MyRtmpClient.java:3: package org.apache.mina.common does not exist
import org.apache.mina.common.ByteBuffer;
What can be the problem?
I’ve placed the jar files to My Documents\NetBeansProjects\test\lib and added it to the Libraries in NetBean.
I have jdk1.6.0_12 and jre1.6.0_07.
Thanks for your reply
Comment by Destone — March 4, 2009 @ 3:09 pm
@Destone – I suggest you get someone who knows Java to look at your setup. Sounds like the libraries have not been added to the project (maybe you added it to NetBeans global?). Otherwise I can’t make out what the problem is.
Comment by Peter Thomas — March 4, 2009 @ 8:47 pm
[...] source. Judging by the number of hits I keep getting on this blog entry I made previously on “how to download RTMP streams with Red5” – there appears to be a lot of demand for [...]
Pingback by Announcing Flazr - download RTMP (Flash video) streams « Incremental Operations — April 5, 2009 @ 6:17 am
hello,
I can’t get it work with this :
http://www.oc-tv.net/sonic-youth,concert-live.htm
it seems that it is encrypted and I can’t get handshake informations with wireshark right. What do you think?
thanks,
tom
Comment by Tom — May 18, 2009 @ 11:41 pm
Hi Peter,
Thanks for the Rtmp client. Is it possible that since this was written last year, the Red5 server has changed significantly enough that this is no longer working? I’m connecting to a pretty plain Red5 app that’s streaming my webcam stream and it gets stuck looping on this same log message over and over:
2009-07-21 10:41:46,417 [NioProcessor-1] DEBUG o.r.server.net.rtmp.BaseRTMPHandler – Message sent
2009-07-21 10:41:48,416 [NioProcessor-1] DEBUG o.a.m.f.codec.ProtocolCodecFilter – Processing a MESSAGE_RECEIVED for session 1
2009-07-21 10:41:48,416 [NioProcessor-1] DEBUG o.r.s.n.r.codec.RTMPProtocolDecoder – Start: 0
2009-07-21 10:41:48,416 [NioProcessor-1] INFO o.a.m.filter.logging.LoggingFilter – RECEIVED: org.red5.server.net.rtmp.message.Packet@32c26ede
2009-07-21 10:41:48,416 [NioProcessor-1] DEBUG o.r.server.net.rtmp.BaseRTMPHandler – Message received, header: ChannelId: 2, Timer: 0 (relative), Size: 6, DataType: 4, StreamId: 0
2009-07-21 10:41:48,416 [NioProcessor-1] DEBUG o.r.s.n.rtmp.BaseRTMPClientHandler – onPing
2009-07-21 10:41:48,417 [NioProcessor-1] INFO o.a.m.filter.logging.LoggingFilter – SENT: org.red5.server.net.rtmp.message.Packet@7afccada
2009-07-21 10:41:48,417 [NioProcessor-1] DEBUG o.r.s.net.rtmp.RTMPMinaIoHandler – messageSent
2009-07-21 10:41:48,417 [NioProcessor-1] DEBUG o.r.server.net.rtmp.BaseRTMPHandler – Message sent
Any ideas?
Thanks!
Dave
Comment by Dave Feltenberger — July 21, 2009 @ 7:42 pm
@Dave yes indeed could be out of date. But have you tried Flazr yet!? http://flazr.com
Comment by Peter Thomas — July 21, 2009 @ 7:49 pm