2 * RTMP network protocol
3 * Copyright (c) 2009 Kostya Shishkov
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * @file libavformat/rtmpproto.c
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/lfg.h"
30 #include "libavutil/sha.h"
39 /* we can't use av_log() with URLContext yet... */
40 #if LIBAVFORMAT_VERSION_MAJOR < 53
41 #define LOG_CONTEXT NULL
46 /** RTMP protocol handler state */
48 STATE_START, ///< client has not done anything yet
49 STATE_HANDSHAKED, ///< client has performed handshake
50 STATE_CONNECTING, ///< client connected to server successfully
51 STATE_READY, ///< client has sent all needed commands and waits for server reply
52 STATE_PLAYING, ///< client has started receiving multimedia data from server
55 /** protocol handler context */
56 typedef struct RTMPContext {
57 URLContext* stream; ///< TCP stream used in interactions with RTMP server
58 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
59 int chunk_size; ///< size of the chunks RTMP packets are divided into
60 char playpath[256]; ///< path to filename to play (with possible "mp4:" prefix)
61 ClientState state; ///< current state
62 int main_channel_id; ///< an additional channel ID which is used for some invocations
63 uint8_t* flv_data; ///< buffer with data for demuxer
64 int flv_size; ///< current buffer size
65 int flv_off; ///< number of bytes read from current buffer
66 uint32_t video_ts; ///< current video timestamp in milliseconds
67 uint32_t audio_ts; ///< current audio timestamp in milliseconds
70 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
71 /** Client key used for digest signing */
72 static const uint8_t rtmp_player_key[] = {
73 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
74 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
76 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
77 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
78 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
81 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
82 /** Key used for RTMP server digest signing */
83 static const uint8_t rtmp_server_key[] = {
84 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
85 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
86 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
88 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
89 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
90 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
94 * Generates 'connect' call and sends it to the server.
96 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto,
97 const char *host, int port, const char *app)
103 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0, 4096);
106 snprintf(tcurl, sizeof(tcurl), "%s://%s:%d/%s", proto, host, port, app);
107 ff_amf_write_string(&p, "connect");
108 ff_amf_write_number(&p, 1.0);
109 ff_amf_write_object_start(&p);
110 ff_amf_write_field_name(&p, "app");
111 ff_amf_write_string(&p, app);
113 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1,
114 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
115 ff_amf_write_field_name(&p, "flashVer");
116 ff_amf_write_string(&p, ver);
117 ff_amf_write_field_name(&p, "tcUrl");
118 ff_amf_write_string(&p, tcurl);
119 ff_amf_write_field_name(&p, "fpad");
120 ff_amf_write_bool(&p, 0);
121 ff_amf_write_field_name(&p, "capabilities");
122 ff_amf_write_number(&p, 15.0);
123 ff_amf_write_field_name(&p, "audioCodecs");
124 ff_amf_write_number(&p, 1639.0);
125 ff_amf_write_field_name(&p, "videoCodecs");
126 ff_amf_write_number(&p, 252.0);
127 ff_amf_write_field_name(&p, "videoFunction");
128 ff_amf_write_number(&p, 1.0);
129 ff_amf_write_object_end(&p);
131 pkt.data_size = p - pkt.data;
133 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
137 * Generates 'createStream' call and sends it to the server. It should make
138 * the server allocate some channel for media streams.
140 static void gen_create_stream(URLContext *s, RTMPContext *rt)
145 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Creating stream...\n");
146 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0, 25);
149 ff_amf_write_string(&p, "createStream");
150 ff_amf_write_number(&p, 3.0);
151 ff_amf_write_null(&p);
153 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
154 ff_rtmp_packet_destroy(&pkt);
158 * Generates 'play' call and sends it to the server, then pings the server
159 * to start actual playing.
161 static void gen_play(URLContext *s, RTMPContext *rt)
166 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
167 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0,
168 20 + strlen(rt->playpath));
169 pkt.extra = rt->main_channel_id;
172 ff_amf_write_string(&p, "play");
173 ff_amf_write_number(&p, 0.0);
174 ff_amf_write_null(&p);
175 ff_amf_write_string(&p, rt->playpath);
177 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
178 ff_rtmp_packet_destroy(&pkt);
180 // set client buffer time disguised in ping packet
181 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
184 bytestream_put_be16(&p, 3);
185 bytestream_put_be32(&p, 1);
186 bytestream_put_be32(&p, 256); //TODO: what is a good value here?
188 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
189 ff_rtmp_packet_destroy(&pkt);
193 * Generates ping reply and sends it to the server.
195 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
200 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6);
202 bytestream_put_be16(&p, 7);
203 bytestream_put_be32(&p, AV_RB32(ppkt->data+2) + 1);
204 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
205 ff_rtmp_packet_destroy(&pkt);
208 //TODO: Move HMAC code somewhere. Eventually.
209 #define HMAC_IPAD_VAL 0x36
210 #define HMAC_OPAD_VAL 0x5C
213 * Calculates HMAC-SHA2 digest for RTMP handshake packets.
215 * @param src input buffer
216 * @param len input buffer length (should be 1536)
217 * @param gap offset in buffer where 32 bytes should not be taken into account
218 * when calculating digest (since it will be used to store that digest)
219 * @param key digest key
220 * @param keylen digest key length
221 * @param dst buffer where calculated digest will be stored (32 bytes)
223 static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
224 const uint8_t *key, int keylen, uint8_t *dst)
227 uint8_t hmac_buf[64+32] = {0};
230 sha = av_mallocz(av_sha_size);
233 memcpy(hmac_buf, key, keylen);
235 av_sha_init(sha, 256);
236 av_sha_update(sha,key, keylen);
237 av_sha_final(sha, hmac_buf);
239 for (i = 0; i < 64; i++)
240 hmac_buf[i] ^= HMAC_IPAD_VAL;
242 av_sha_init(sha, 256);
243 av_sha_update(sha, hmac_buf, 64);
245 av_sha_update(sha, src, len);
246 } else { //skip 32 bytes used for storing digest
247 av_sha_update(sha, src, gap);
248 av_sha_update(sha, src + gap + 32, len - gap - 32);
250 av_sha_final(sha, hmac_buf + 64);
252 for (i = 0; i < 64; i++)
253 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
254 av_sha_init(sha, 256);
255 av_sha_update(sha, hmac_buf, 64+32);
256 av_sha_final(sha, dst);
262 * Puts HMAC-SHA2 digest of packet data (except for the bytes where this digest
263 * will be stored) into that packet.
265 * @param buf handshake data (1536 bytes)
266 * @return offset to the digest inside input data
268 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
270 int i, digest_pos = 0;
272 for (i = 8; i < 12; i++)
273 digest_pos += buf[i];
274 digest_pos = (digest_pos % 728) + 12;
276 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
277 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
283 * Verifies that the received server response has the expected digest value.
285 * @param buf handshake data received from the server (1536 bytes)
286 * @param off position to search digest offset from
287 * @return 0 if digest is valid, digest position otherwise
289 static int rtmp_validate_digest(uint8_t *buf, int off)
291 int i, digest_pos = 0;
294 for (i = 0; i < 4; i++)
295 digest_pos += buf[i + off];
296 digest_pos = (digest_pos % 728) + off + 4;
298 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
299 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
301 if (!memcmp(digest, buf + digest_pos, 32))
307 * Performs handshake with the server by means of exchanging pseudorandom data
308 * signed with HMAC-SHA2 digest.
310 * @return 0 if handshake succeeds, negative value otherwise
312 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
315 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
316 3, // unencrypted data
317 0, 0, 0, 0, // client uptime
323 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
324 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
326 int server_pos, client_pos;
329 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Handshaking...\n");
331 av_lfg_init(&rnd, 0xDEADC0DE);
332 // generate handshake packet - 1536 bytes of pseudorandom data
333 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
334 tosend[i] = av_lfg_get(&rnd) >> 24;
335 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
337 url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
338 i = url_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
339 if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
340 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
343 i = url_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
344 if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
345 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
349 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
350 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
352 server_pos = rtmp_validate_digest(serverdata + 1, 772);
354 server_pos = rtmp_validate_digest(serverdata + 1, 8);
356 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server response validating failed\n");
361 rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
362 rtmp_server_key, sizeof(rtmp_server_key),
364 rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
367 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
368 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Signature mismatch\n");
372 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
373 tosend[i] = av_lfg_get(&rnd) >> 24;
374 rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
375 rtmp_player_key, sizeof(rtmp_player_key),
377 rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
379 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
381 // write reply back to the server
382 url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
387 * Parses received packet and may perform some action depending on
388 * the packet contents.
389 * @return 0 for no errors, negative values for serious errors which prevent
390 * further communications, positive values for uncritical errors
392 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
395 const uint8_t *data_end = pkt->data + pkt->data_size;
398 case RTMP_PT_CHUNK_SIZE:
399 if (pkt->data_size != 4) {
400 av_log(LOG_CONTEXT, AV_LOG_ERROR,
401 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
404 rt->chunk_size = AV_RB32(pkt->data);
405 if (rt->chunk_size <= 0) {
406 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
409 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
412 t = AV_RB16(pkt->data);
414 gen_pong(s, rt, pkt);
417 //TODO: check for the messages sent for wrong state?
418 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
421 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
422 "description", tmpstr, sizeof(tmpstr)))
423 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
425 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
427 case STATE_HANDSHAKED:
428 gen_create_stream(s, rt);
429 rt->state = STATE_CONNECTING;
431 case STATE_CONNECTING:
432 //extract a number from the result
433 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
434 av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n");
436 rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
439 rt->state = STATE_READY;
442 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
443 const uint8_t* ptr = pkt->data + 11;
447 for (i = 0; i < 2; i++) {
448 t = ff_amf_tag_size(ptr, data_end);
453 t = ff_amf_get_field_value(ptr, data_end,
454 "level", tmpstr, sizeof(tmpstr));
455 if (!t && !strcmp(tmpstr, "error")) {
456 if (!ff_amf_get_field_value(ptr, data_end,
457 "description", tmpstr, sizeof(tmpstr)))
458 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
461 t = ff_amf_get_field_value(ptr, data_end,
462 "code", tmpstr, sizeof(tmpstr));
463 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) {
464 rt->state = STATE_PLAYING;
474 * Interacts with the server by receiving and sending RTMP packets until
475 * there is some significant data (media data or expected status notification).
477 * @param s reading context
478 * @param for_header non-zero value tells function to work until it gets notification from the server that playing has been started, otherwise function will work until some media data is received (or an error happens)
479 * @return 0 for successful operation, negative value in case of error
481 static int get_packet(URLContext *s, int for_header)
483 RTMPContext *rt = s->priv_data;
488 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
489 rt->chunk_size, rt->prev_pkt[0])) != 0) {
491 return AVERROR(EAGAIN);
497 ret = rtmp_parse_result(s, rt, &rpkt);
498 if (ret < 0) {//serious error in current packet
499 ff_rtmp_packet_destroy(&rpkt);
502 if (for_header && rt->state == STATE_PLAYING) {
503 ff_rtmp_packet_destroy(&rpkt);
506 if (!rpkt.data_size) {
507 ff_rtmp_packet_destroy(&rpkt);
510 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
511 rpkt.type == RTMP_PT_NOTIFY) {
513 uint32_t ts = rpkt.timestamp;
515 if (rpkt.type == RTMP_PT_VIDEO) {
516 rt->video_ts += rpkt.timestamp;
518 } else if (rpkt.type == RTMP_PT_AUDIO) {
519 rt->audio_ts += rpkt.timestamp;
522 // generate packet header and put data into buffer for FLV demuxer
524 rt->flv_size = rpkt.data_size + 15;
525 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
526 bytestream_put_byte(&p, rpkt.type);
527 bytestream_put_be24(&p, rpkt.data_size);
528 bytestream_put_be24(&p, ts);
529 bytestream_put_byte(&p, ts >> 24);
530 bytestream_put_be24(&p, 0);
531 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
532 bytestream_put_be32(&p, 0);
533 ff_rtmp_packet_destroy(&rpkt);
535 } else if (rpkt.type == RTMP_PT_METADATA) {
536 // we got raw FLV data, make it available for FLV demuxer
538 rt->flv_size = rpkt.data_size;
539 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
540 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
541 ff_rtmp_packet_destroy(&rpkt);
544 ff_rtmp_packet_destroy(&rpkt);
549 static int rtmp_close(URLContext *h)
551 RTMPContext *rt = h->priv_data;
553 av_freep(&rt->flv_data);
554 url_close(rt->stream);
560 * Opens RTMP connection and verifies that the stream can be played.
562 * URL syntax: rtmp://server[:port][/app][/playpath]
563 * where 'app' is first one or two directories in the path
564 * (e.g. /ondemand/, /flash/live/, etc.)
565 * and 'playpath' is a file name (the rest of the path,
566 * may be prefixed with "mp4:")
568 static int rtmp_open(URLContext *s, const char *uri, int flags)
571 char proto[8], hostname[256], path[1024], app[128], *fname;
576 is_input = !(flags & URL_WRONLY);
578 rt = av_mallocz(sizeof(RTMPContext));
580 return AVERROR(ENOMEM);
583 url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
584 path, sizeof(path), s->filename);
587 port = RTMP_DEFAULT_PORT;
588 snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
590 if (url_open(&rt->stream, buf, URL_RDWR) < 0)
594 av_log(LOG_CONTEXT, AV_LOG_ERROR, "RTMP output is not supported yet.\n");
597 rt->state = STATE_START;
598 if (rtmp_handshake(s, rt))
601 rt->chunk_size = 128;
602 rt->state = STATE_HANDSHAKED;
603 //extract "app" part from path
604 if (!strncmp(path, "/ondemand/", 10)) {
606 memcpy(app, "ondemand", 9);
608 char *p = strchr(path + 1, '/');
613 char *c = strchr(p + 1, ':');
614 fname = strchr(p + 1, '/');
615 if (!fname || c < fname) {
617 av_strlcpy(app, path + 1, p - path);
620 av_strlcpy(app, path + 1, fname - path - 1);
624 if (!strchr(fname, ':') &&
625 (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
626 !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
627 memcpy(rt->playpath, "mp4:", 5);
631 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
633 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
634 proto, path, app, rt->playpath);
635 gen_connect(s, rt, proto, hostname, port, app);
638 ret = get_packet(s, 1);
639 } while (ret == EAGAIN);
642 // generate FLV header for demuxer
644 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
646 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
649 s->max_packet_size = url_get_max_packet_size(rt->stream);
658 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
660 RTMPContext *rt = s->priv_data;
661 int orig_size = size;
665 int data_left = rt->flv_size - rt->flv_off;
667 if (data_left >= size) {
668 memcpy(buf, rt->flv_data + rt->flv_off, size);
673 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
676 rt->flv_off = rt->flv_size;
678 if ((ret = get_packet(s, 0)) < 0)
684 static int rtmp_write(URLContext *h, uint8_t *buf, int size)
689 URLProtocol rtmp_protocol = {