jonathan
beluch

 

Posted on January 19, 2011.

This post will outline a quick and easy method for gathering info about an RTMP stream. The goal is to gather the proper parameters to enable playback of the RTMP stream in XBMC.

This tutorial will utilize two command lines tools that should be available in most package managers.

  1. tcpdump - A network capture tool
  2. rtmpdump - An RTMP streaming media client. We will be using this to verify our RTMP parameters.

To gather the required RTMP parameters, we are going to capture the network traffic between our local machine and the RTMP server while playing a target video in a browser.

Overview

The RTMP protocol is owned by Adobe and used for streaming media. You typically encounter this technology on a website that uses a flash player. The binary swf file that your browser downloads contains all the information needed to connect directly to the RTMP server.

If you have an SWF decompiler, you can decompile the swf and look through the source for the proper parameters. However, I think it is both easier and faster to sniff the actual network traffic being used by flash. Since flash makes the connections to the RTMP server outside of your browser, we cannot simply use google chrome developer tools or something of that nature. We need to capture packets from the OS.

RTMP Parameters

There are lots of possible RTMP connection parameters that can be set to play a given video. We will be trying to find the minimum needed to successfully play a video. We are going to be interested in:

  • app
  • tcUrl
  • playpath

For a complete list, check out the RTMP specification (pdf) or the man page for rtmpdump.

Capturing the Stream

For our example, we are going to use http://mitworld.mit.edu. They have plenty of awesome videos, and it’s also the website I used while learning this myself.

Setting up the capture

First we’ll need to figure out the hostname of the RTMP server. If you navigate to a video page, you can search through the source for ‘host:’. Or easier yet, curl -s "http://mitworld.mit.edu/video/867" | grep "host:".

We’re going to add this hostname as a filter to our network capture. We don’t necessarily need to, but packet captures can grow very large depending on what else is running on the machine. Your best bet is to filter the traffic as much as possible.

tcpdump

Here is our tcpdump command, which we can kick off.

$ tcpdump -w mitworld.cap -s 0 -i wlan0 host cp58255.edgefcs.net
  • -w mitworld.cap - Write raw packets to a capture file.
  • -s 0 - Grab up 65,535 bytes from each packet. On some versions of tcpdump, the default is too small to grab the entire packet.
  • -i wlan0 - The network interface to listen on, in my case my wireless card.
  • host cp58255.edgefcs.net - Only match packets which are to/from a given host.

After kicking it off (you might need root privileges) you should see output similar to the following:

tcpdump: listening on wlan0, link-type EN10MB (Ethernet), capture size 65535 bytes

Now, visit the video page again. The parameters we are interested in will be sent once we click play, so it’s only necessary to run the capture for a second or so. Once the movie begins playing, you can halt the capture with Ctrl + C.

When you halt the capture, you should see some output telling you how many packets were capture.

Searching the packet capture

RTMP encodes objects using the binary AMF protocol. There are two versions of AMF, AMF0 (pdf) and AMF3 (pdf). If you’d like to read more about the protocol, the open-source project gnash has some good stuff in their wiki, however it’s not necessary for this exercise.

There are 2 RTMP command we are interested in, connect and play.

Finding connect parameters

We are going to output our packet capture with ASCII characters (-X) and then grep for our matching packets. You might need to mess with the numbers for grep specifying -Before context lines and -After context lines to grep.

$ tcpdump -X -r mitworld.cap | grep -B 5 -A 20 connect
    0x00b0:  9b56 a0c1 9ee8 2764 dc3e 2e4b b188 350b  .V....'d.>.K..5.
    0x00c0:  802b 7d88 0d16 003d 44e7 e13d 04e9 a031  .+}....=D..=...1
    0x00d0:  c16f 8c41 363c a31b 3769 3ea6 9d4e 7b81  .o.A6<..7i>..N{.
    0x00e0:  a655 0567 f4b5 96ba 1a99 e29e 28d6 f7d0  .U.g........(...
    0x00f0:  eb92 3ef8 0300 0001 0001 8d14 0000 0000  ..>.............
    0x0100:  0200 0763 6f6e 6e65 6374 003f f000 0000  ...connect.?....
    0x0110:  0000 0003 0003 6170 7002 0027 6f6e 6465  ......app..'onde
    0x0120:  6d61 6e64 3f5f 6663 735f 7668 6f73 743d  mand?_fcs_vhost=
    0x0130:  6370 3538 3235 352e 6564 6765 6663 732e  cp58255.edgefcs.
    0x0140:  6e65 7400 0866 6c61 7368 5665 7202 000d  net..flashVer...
    0x0150:  4c4e 5820 3130 2c30 2c34 352c 3200 0673  LNX.10,0,45,2..s
    0x0160:  7766 5572 6c02 002d 6874 7470 3a2f 2f6d  wfUrl..-http://m
    0x0170:  6974 776f 726c 642e 6d69 742e 6564 752f  itworld.mit.edu/
    0x0180:  c366 6c61 7368 2f70 6c61 7965 722f 4d61  .flash/player/Ma
    0x0190:  696e 2e73 7766 0005 7463 5572 6c02 0040  in.swf..tcUrl..@
    0x01a0:  7274 6d70 3a2f 2f38 302e 3135 342e 3131  rtmp://80.154.11
    0x01b0:  382e 3232 3a34 3433 2f6f 6e64 656d 616e  8.22:443/ondeman
    0x01c0:  643f 5f66 6373 5f76 686f 7374 3d63 7035  d?_fcs_vhost=cp5
    0x01d0:  3832 3535 2e65 6467 6566 6373 2e6e 6574  8255.edgefcs.net
    0x01e0:  0004 6670 6164 0100 000c 6361 7061 6269  ..fpad....capabi
    0x01f0:  6c69 7469 6573 0040 2e00 0000 0000 0000  lities.@........
    0x0200:  0bc3 6175 6469 6f43 6f64 6563 7300 40a8  ..audioCodecs.@.
    0x0210:  ee00 0000 0000 000b 7669 6465 6f43 6f64  ........videoCod
    0x0220:  6563 7300 406f 8000 0000 0000 000d 7669  ecs.@o........vi
    0x0230:  6465 6f46 756e 6374 696f 6e00 3ff0 0000  deoFunction.?...
    0x0240:  0000 0000 0007 7061 6765 5572 6c02 0021  ......pageUrl..!
    0x0250:  6874 7470 3a2f 2f6d 6974 776f 726c 642e  http://mitworld.
    0x0260:  6d69 742e 6564 752f 7669 6465 6f2f 3836  mit.edu/video/86
    0x0270:  3700 0e6f 626a 6563 7445 6e63 6f64 696e  7..objectEncodin
    0x0280:  6700 c300 0000 0000 0000 0000 0009 0100  g...............
  • string-object-marker - A single byte of 02.
  • unsigned 16-bit integer in big endian (network) byte order - Specifies the length of the string to follow
  • the actual string

You can probably determine the proper string values by simply scanning the ascii column, however I’ve highlighted specific bytes and strings in the output so you can see how the AMF protocol is structured.

From the above packet, we can gather the following parameters:

  • app - ondemand?_fcs_vhost=cp58255.edgefcs.net
  • swfUrl - http://mitworld.mit.edu/.flash/player/Main.swf
  • tcUrl - rtmp://80.154.118.22:443/ondemand?_fcs_vhost=cp58255.edgefcs.net
  • pageUrl - http://mitworld.mit.edu/video/867

Finding play parameters

Now let’s do the same command as above, but for ‘play’ this time.

$ tcpdump -X -r mitworld.cap | grep -B 5 -A 20 play
    0x0000:  4500 0093 f495 4000 4006 a321 c0a8 0228  E.....@.@..!...(
    0x0010:  188f c74e 80ff 078f 931b 8661 1f34 958d  ...N.......a.4..
    0x0020:  8018 ffff 76b3 0000 0101 080a 0008 8921  ....v..........!
    0x0030:  0ef1 08da 0800 101f 0000 5314 0100 0000  ..........S.....
    0x0040:  0200 0470 6c61 7900 0000 0000 0000 0000  ...play.........
    0x0050:  0502 0036 616d 7073 666c 6173 682f 6d69  ...6ampsflash/mi
    0x0060:  7477 2d30 3132 3532 2d74 7261 6e73 706f  tw-01252-transpo
    0x0070:  7274 2d6c 6f67 6769 6e67 2d73 6172 6d61  rt-logging-sarma
    0x0080:  2d33 306e 6f76 3230 3130 0000 0000 0000  -30nov2010......
    0x0090:  0000 00                                  ...

From this packet, which is sending the play command, we can extract our playpath.

  • playpath - ampsflash/mitw-01252-transport-logging-sarma-30nov2010

Testing the captured RTMP parameters

Now we’re going to use the rtmpdump tool to verify our connection parameters are correct. We’re going to redirect the video to /dev/null since we don’t actually want to download it.

$ rtmpdump -r "rtmp://cp58255.edgefcs.net/ondemand?_fcs_vhost=cp58255.edgefcs.net" \
--tcUrl "rtmp://80.154.118.22:443/ondemand?_fcs_vhost=cp58255.edgefcs.net" \
--playpath "ampsflash/mitw-01252-transport-logging-sarma-30nov2010" > /dev/null

You can experiment here and try dropping off some of the parameters to see which ones aren’t required. If the video connection works you will see a progress meter. If you have an issues, you will see an error in the output.

Playing an RTMP video in XBMC

I found some helpful forum posts and a trac ticket with documentation on playing RTMP streams.

import xbmc, xbmcgui

app = 'ondemand?_fcs_vhost=cp58255.edgefcs.net'
swfurl = 'http://mitworld.mit.edu/.flash/player/Main.swf'
rtmpurl = 'rtmp://80.154.118.22:443/ondemand?_fcs_vhost=cp58255.edgefcs.net'
pageurl = 'http://mitworld.mit.edu/video/867'
playpath = 'ampsflash/mitw-01252-transport-logging-sarma-30nov2010'

li = xbmc.ListItem('RTMP Stream')
li.setProperty('PlayPath', playpath)
li.setProperty('SWFPlayer', swfurl)
li.setProperty('PageURL', pageurl)
xbmc.Player(xbmc.PLAYER_CORE_DVDPLAYER).play(rtmpurl, li)