From Gnash Project Wiki
This document is based mostly on my own reverse engineering of the RTMP protocol and AMF format. tcpdump and ethereal are your friend. Some additional info that got me started was from the Red5 project. Red5 is the only other open source Flash server. So some details are still vague, but as the implementation appears to work, we'll figure out what they are later.
The Real Time Messaging Protocol was created by MacroMedia (now Adobe) for delivering Flash objects and video over a network connection. Currently the only servers which support this format are the MacroMedia Media sever, and the Open Source Red5 project.
This is a simple protocol, optimized for poor bandwidth connections. It can support up to 64 concurrent streams over the same network connection. Part of each AMF packet header contains the index number of the stream. A single RTMP message can contain multiple AMF packets.
An RTMP connection uses Tcp/ip port 1935. It is also possible to tunnel RTMP over an HTTP connection using port 80. Each AMF packet is 128 bytes long except for streaming audio, which has 64 byte packets.
The basics of the RTMP protocol are as follows. All communications are initiated by the client.
The client starts the RTMP connection by sending a single byte with a value of 0x3. This byte is followed by a data block of 1536 bytes. The format if this data block is unknown, but it appears to not be actually used by the protocol except as a handshake.
The server receives this packet, stores the 1536 byte data block, and then send a single byte with the value of 0x3, followed by two 1536 data blocks. The second data block is the full contents of the original data block as sent by the client.
The client receives the 1536 byte data block, and if they match, the connection is established. After the handshake process is done, there are three other messages that the client sends to the sever to start the data flowing.
The first AMF packet sent to the server contains the connect packet. This doesn't appear to do much but notify the server the client is happy with the handshake, and ready to start reading packets.
The second packet is the NetConnection object from the client. This ActionScript class is used by the Flash movie to create the network connection to the server.
The third packet is the NetStream object from the client. This is the ActionScript class used to specify the file to be streamed by the server.
The RTMP packet for our example looks like this:
- software/gnash/tests/1153948634.flv0008flashVer02000cLNX 6,0,82,0 0006
We'll take this apart in a bit, but you can see how all three AMF packets are in the same message. The message is received in several 128 byte blocks, with the last one being less than that. The total size of the RTMP message is in the header, so the reader can tell if the entire message was read or not.
The RTMP header is first, followed by the connect message as an ASCII string as the message body. The following AMF packet is the NetConnection one, which specifies that this is coming from a Flash application. This also contains the file path the server can use to find the file to stream. This is then followed by the version number, which I assume is the version of the Flash player, so the server knows what it is talking to.
The third packet is the one from NetStream, which specifies the URL used for the movie, followed by the user name for a semblance of security.
For the next level of detail, we'll explain the format of AMF. AMF is used by the RTMP protocol to transfer data. Each Flash object is encapsulated in an AMF packet, including streaming audio or video.
The first byte of the RTMP header determines two things about the rest of the message. The first 2 bits of this byte signify the total size of the RTMP header. The RTMP header is of a variable size, so this is important.
- This specifies the header contains 12 bytes, including this one.
- This specifies the header contains 8 bytes, including this one.
- This specifies the header contains 4 bytes, including this one.
- This specifies the header contains 1 byte, so this is the complete header.
The other 6 bits in this byte represent the AMF index. As a single RTMP connection can support multiple data streams, this signifies which stream this packet is for. Once an AMF object is fully received by the client, the AMF index may be reused.
For messages with headers of at least 4 bytes, the next 3 bytes are used by audio and video data packets, but at this time the meaning of this field is unknown.
For messages with a 8 byte or larger header, the next 3 bytes determine the size of the RTMP message being transmitted. Messages with a 1 byte or 4 byte header use a standard size, 128 bytes for video, and 64 bytes for audio. If the header size is a 1 or 4 byte one, then the body size is the same as the previous message's body size.
For messages with an 8 byte or larger header, the next byte is the type of the AMF object.
- This specifies the content type of the RTMP packet is the number of bytes read. This is used to start the RTMP connection.
- This specifies the content type of the RTMP message is a ping packet.
- This specifies the content type of the RTMP message is server response of some type.
- This specifies the content type of the RTMP packet is client request of some type.
- This specifies the content type of the RTMP packet is an audio message.
- This specifies the content type of the RTMP message is a video packet.
- This specifies the content type of the RTMP message is notify.
- This specifies the content type of the RTMP message is shared object.
- This specifies the content type of the RTMP message is remote procedure call. This invokes the method of a Flash class remotely.
There are two sets of data types to consider. One set is used by the to specify the content type of the AMF object, the other is an ActionScript data type tag used to denote which type of object is being transferred.
The values of the initial type byte are:
- This specifies the data in the AMF packet is a numeric value. All numeric values in Flash are 64 bit, big-endian.
- This specifies the data in the AMF packet is a boolean value.
- This specifies the data in the AMF packet is an ASCII string.
- This specifies the data in the AMF packet is a Flash object. The Flash object data type field further along in the message specifies which type of ActionScript object it is.
- This specifies the data in the AMF packet is a Flash movie, ie. another Flash movie.
- This specifies the data in the AMF packet is a NULL value. NULL is often used as the return code from calling Flash functions.
- This specifies the data in the AMF packet is a undefined. This is also used as the return code from calling Flash functions.
- This specifies the data in the AMF packet is a reference.
- This specifies the data in the AMF packet is a ECMA array.
- This specifies the data in the AMF packet is the end of an object definition. As an object is transmitted with multiple AMF packets, this lets the server know when the end of the object is reached.
- This specifies the data in the AMF packet is a Strict array.
- This specifies the data in the AMF packet is a date.
- This specifies the data in the AMF packet is a multi-byte string. Multi-byte strings are used for international language support to represent non ASCII fonts.
- This specifies the data in the AMF packet is a an unsupported feature.
- This specifies the data in the AMF packet is a record set.
- This specifies the data in the AMF packet is a AML object. XML objects are then parsed by the XML ActionScript class.
- This specifies the data in the AMF packet is a typed object.
For messages with a 12 byte header, the last 4 bytes are the routing of the message. If the destination is the server, this value is the NetStream object source. If the destination is the client, this is the NetStream object for this RTMP message. A value of 0x00000000 appears to be reserved for the NetConnection object.
Multiple AMF streams can be contained in a single RTMP messages, so it's important to check the index of each AMF packet.
An example RTMP header might look like this. (spaces added between fields for clarity) All the numbers are in hex.
- 03 000019 0000c9 14 000000000
- The first two bits of this byte are the size of the header, which in this example is 00, for a 12 byte header. The next 6 bits is the AMF stream index number, which in this example is 0x3.
- These 3 bytes are a timestamp relative to the timestamp of the previous packet header (from the same channel or kind, please check: FLV chunks timestamps seem to be absolute). When the timestamp is greater than 0xffffff, this field is set to 0xffffff and the value in 32 bits big endian is append to the header and to the following one byte compressed headers for the same channel (so then, they are 5 bytes long).
- Since this example has a 12 byte header, this is the size of the RTMP message, in this case 201 bytes.
- This is the content type of the RTMP message, which in this case is to invoke a remote function call. (which we later see is the connect function).
- The source is the NetConnection object used to start this connection.
Here is an example stream from a session with Justin.TV, decoding using diagram_rtmp.py (to be released soon)
RTMP Status Codes
RTMP supports a large list of status codes. A result message is sent by the server to the client to notify the client of the status of the request. I've extracted a few typical result messages and decoded them on the RTMP Messages Decoded page.
The AMF format is used in the LocalConnection, SharedObject, NetConnection, and NetStream ActionScript classes. This is a means of binary data interchange between Flash movies, or between a Flash player and a Flash server.
Like the RTMP messages, an AMF packet header can be of a variable size. The size is either the same as the initial header of the RTMP message, or a 1 byte header, which is commonly used for streaming audio or video data.
There is more detailed information on the AMF object format at this link.
Other sources of information on RTMP can be found here: