2 * RTMP network protocol
3 * Copyright (c) 2009 Kostya Shishkov
5 * This file is part of Libav.
7 * Libav 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 * Libav 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 Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/lfg.h"
30 #include "libavutil/sha.h"
41 /* we can't use av_log() with URLContext yet... */
45 #define LOG_CONTEXT NULL
50 /** RTMP protocol handler state */
52 STATE_START, ///< client has not done anything yet
53 STATE_HANDSHAKED, ///< client has performed handshake
54 STATE_RELEASING, ///< client releasing stream before publish it (for output)
55 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
56 STATE_CONNECTING, ///< client connected to server successfully
57 STATE_READY, ///< client has sent all needed commands and waits for server reply
58 STATE_PLAYING, ///< client has started receiving multimedia data from server
59 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
60 STATE_STOPPED, ///< the broadcast has been stopped
63 /** protocol handler context */
64 typedef struct RTMPContext {
65 URLContext* stream; ///< TCP stream used in interactions with RTMP server
66 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
67 int chunk_size; ///< size of the chunks RTMP packets are divided into
68 int is_input; ///< input/output flag
69 char playpath[256]; ///< path to filename to play (with possible "mp4:" prefix)
70 char app[128]; ///< application
71 ClientState state; ///< current state
72 int main_channel_id; ///< an additional channel ID which is used for some invocations
73 uint8_t* flv_data; ///< buffer with data for demuxer
74 int flv_size; ///< current buffer size
75 int flv_off; ///< number of bytes read from current buffer
76 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
77 uint32_t client_report_size; ///< number of bytes after which client should report to server
78 uint32_t bytes_read; ///< number of bytes read from server
79 uint32_t last_bytes_read; ///< number of bytes read last reported to server
82 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
83 /** Client key used for digest signing */
84 static const uint8_t rtmp_player_key[] = {
85 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
86 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', '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
93 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
94 /** Key used for RTMP server digest signing */
95 static const uint8_t rtmp_server_key[] = {
96 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
97 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
98 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
100 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
101 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
102 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
106 * Generate 'connect' call and send it to the server.
108 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto,
109 const char *host, int port)
115 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096);
118 ff_url_join(tcurl, sizeof(tcurl), proto, NULL, host, port, "/%s", rt->app);
119 ff_amf_write_string(&p, "connect");
120 ff_amf_write_number(&p, 1.0);
121 ff_amf_write_object_start(&p);
122 ff_amf_write_field_name(&p, "app");
123 ff_amf_write_string(&p, rt->app);
126 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1,
127 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
129 snprintf(ver, sizeof(ver), "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
130 ff_amf_write_field_name(&p, "type");
131 ff_amf_write_string(&p, "nonprivate");
133 ff_amf_write_field_name(&p, "flashVer");
134 ff_amf_write_string(&p, ver);
135 ff_amf_write_field_name(&p, "tcUrl");
136 ff_amf_write_string(&p, tcurl);
138 ff_amf_write_field_name(&p, "fpad");
139 ff_amf_write_bool(&p, 0);
140 ff_amf_write_field_name(&p, "capabilities");
141 ff_amf_write_number(&p, 15.0);
142 ff_amf_write_field_name(&p, "audioCodecs");
143 ff_amf_write_number(&p, 1639.0);
144 ff_amf_write_field_name(&p, "videoCodecs");
145 ff_amf_write_number(&p, 252.0);
146 ff_amf_write_field_name(&p, "videoFunction");
147 ff_amf_write_number(&p, 1.0);
149 ff_amf_write_object_end(&p);
151 pkt.data_size = p - pkt.data;
153 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
154 ff_rtmp_packet_destroy(&pkt);
158 * Generate 'releaseStream' call and send it to the server. It should make
159 * the server release some channel for media streams.
161 static void gen_release_stream(URLContext *s, RTMPContext *rt)
166 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
167 29 + strlen(rt->playpath));
169 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Releasing stream...\n");
171 ff_amf_write_string(&p, "releaseStream");
172 ff_amf_write_number(&p, 2.0);
173 ff_amf_write_null(&p);
174 ff_amf_write_string(&p, rt->playpath);
176 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
177 ff_rtmp_packet_destroy(&pkt);
181 * Generate 'FCPublish' call and send it to the server. It should make
182 * the server preapare for receiving media streams.
184 static void gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
189 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
190 25 + strlen(rt->playpath));
192 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "FCPublish stream...\n");
194 ff_amf_write_string(&p, "FCPublish");
195 ff_amf_write_number(&p, 3.0);
196 ff_amf_write_null(&p);
197 ff_amf_write_string(&p, rt->playpath);
199 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
200 ff_rtmp_packet_destroy(&pkt);
204 * Generate 'FCUnpublish' call and send it to the server. It should make
205 * the server destroy stream.
207 static void gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
212 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
213 27 + strlen(rt->playpath));
215 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "UnPublishing stream...\n");
217 ff_amf_write_string(&p, "FCUnpublish");
218 ff_amf_write_number(&p, 5.0);
219 ff_amf_write_null(&p);
220 ff_amf_write_string(&p, rt->playpath);
222 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
223 ff_rtmp_packet_destroy(&pkt);
227 * Generate 'createStream' call and send it to the server. It should make
228 * the server allocate some channel for media streams.
230 static void gen_create_stream(URLContext *s, RTMPContext *rt)
235 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Creating stream...\n");
236 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 25);
239 ff_amf_write_string(&p, "createStream");
240 ff_amf_write_number(&p, rt->is_input ? 3.0 : 4.0);
241 ff_amf_write_null(&p);
243 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
244 ff_rtmp_packet_destroy(&pkt);
249 * Generate 'deleteStream' call and send it to the server. It should make
250 * the server remove some channel for media streams.
252 static void gen_delete_stream(URLContext *s, RTMPContext *rt)
257 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Deleting stream...\n");
258 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 34);
261 ff_amf_write_string(&p, "deleteStream");
262 ff_amf_write_number(&p, 0.0);
263 ff_amf_write_null(&p);
264 ff_amf_write_number(&p, rt->main_channel_id);
266 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
267 ff_rtmp_packet_destroy(&pkt);
271 * Generate 'play' call and send it to the server, then ping the server
272 * to start actual playing.
274 static void gen_play(URLContext *s, RTMPContext *rt)
279 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
280 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0,
281 20 + strlen(rt->playpath));
282 pkt.extra = rt->main_channel_id;
285 ff_amf_write_string(&p, "play");
286 ff_amf_write_number(&p, 0.0);
287 ff_amf_write_null(&p);
288 ff_amf_write_string(&p, rt->playpath);
290 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
291 ff_rtmp_packet_destroy(&pkt);
293 // set client buffer time disguised in ping packet
294 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
297 bytestream_put_be16(&p, 3);
298 bytestream_put_be32(&p, 1);
299 bytestream_put_be32(&p, 256); //TODO: what is a good value here?
301 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
302 ff_rtmp_packet_destroy(&pkt);
306 * Generate 'publish' call and send it to the server.
308 static void gen_publish(URLContext *s, RTMPContext *rt)
313 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
314 ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE, 0,
315 30 + strlen(rt->playpath));
316 pkt.extra = rt->main_channel_id;
319 ff_amf_write_string(&p, "publish");
320 ff_amf_write_number(&p, 0.0);
321 ff_amf_write_null(&p);
322 ff_amf_write_string(&p, rt->playpath);
323 ff_amf_write_string(&p, "live");
325 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
326 ff_rtmp_packet_destroy(&pkt);
330 * Generate ping reply and send it to the server.
332 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
337 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6);
339 bytestream_put_be16(&p, 7);
340 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
341 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
342 ff_rtmp_packet_destroy(&pkt);
346 * Generate report on bytes read so far and send it to the server.
348 static void gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
353 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ, ts, 4);
355 bytestream_put_be32(&p, rt->bytes_read);
356 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
357 ff_rtmp_packet_destroy(&pkt);
360 //TODO: Move HMAC code somewhere. Eventually.
361 #define HMAC_IPAD_VAL 0x36
362 #define HMAC_OPAD_VAL 0x5C
365 * Calculate HMAC-SHA2 digest for RTMP handshake packets.
367 * @param src input buffer
368 * @param len input buffer length (should be 1536)
369 * @param gap offset in buffer where 32 bytes should not be taken into account
370 * when calculating digest (since it will be used to store that digest)
371 * @param key digest key
372 * @param keylen digest key length
373 * @param dst buffer where calculated digest will be stored (32 bytes)
375 static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
376 const uint8_t *key, int keylen, uint8_t *dst)
379 uint8_t hmac_buf[64+32] = {0};
382 sha = av_mallocz(av_sha_size);
385 memcpy(hmac_buf, key, keylen);
387 av_sha_init(sha, 256);
388 av_sha_update(sha,key, keylen);
389 av_sha_final(sha, hmac_buf);
391 for (i = 0; i < 64; i++)
392 hmac_buf[i] ^= HMAC_IPAD_VAL;
394 av_sha_init(sha, 256);
395 av_sha_update(sha, hmac_buf, 64);
397 av_sha_update(sha, src, len);
398 } else { //skip 32 bytes used for storing digest
399 av_sha_update(sha, src, gap);
400 av_sha_update(sha, src + gap + 32, len - gap - 32);
402 av_sha_final(sha, hmac_buf + 64);
404 for (i = 0; i < 64; i++)
405 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
406 av_sha_init(sha, 256);
407 av_sha_update(sha, hmac_buf, 64+32);
408 av_sha_final(sha, dst);
414 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
415 * will be stored) into that packet.
417 * @param buf handshake data (1536 bytes)
418 * @return offset to the digest inside input data
420 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
422 int i, digest_pos = 0;
424 for (i = 8; i < 12; i++)
425 digest_pos += buf[i];
426 digest_pos = (digest_pos % 728) + 12;
428 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
429 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
435 * Verify that the received server response has the expected digest value.
437 * @param buf handshake data received from the server (1536 bytes)
438 * @param off position to search digest offset from
439 * @return 0 if digest is valid, digest position otherwise
441 static int rtmp_validate_digest(uint8_t *buf, int off)
443 int i, digest_pos = 0;
446 for (i = 0; i < 4; i++)
447 digest_pos += buf[i + off];
448 digest_pos = (digest_pos % 728) + off + 4;
450 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
451 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
453 if (!memcmp(digest, buf + digest_pos, 32))
459 * Perform handshake with the server by means of exchanging pseudorandom data
460 * signed with HMAC-SHA2 digest.
462 * @return 0 if handshake succeeds, negative value otherwise
464 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
467 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
468 3, // unencrypted data
469 0, 0, 0, 0, // client uptime
475 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
476 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
478 int server_pos, client_pos;
481 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Handshaking...\n");
483 av_lfg_init(&rnd, 0xDEADC0DE);
484 // generate handshake packet - 1536 bytes of pseudorandom data
485 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
486 tosend[i] = av_lfg_get(&rnd) >> 24;
487 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
489 ffurl_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
490 i = ffurl_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
491 if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
492 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
495 i = ffurl_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
496 if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
497 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
501 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
502 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
504 if (rt->is_input && serverdata[5] >= 3) {
505 server_pos = rtmp_validate_digest(serverdata + 1, 772);
507 server_pos = rtmp_validate_digest(serverdata + 1, 8);
509 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server response validating failed\n");
514 rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
515 rtmp_server_key, sizeof(rtmp_server_key),
517 rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
520 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
521 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Signature mismatch\n");
525 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
526 tosend[i] = av_lfg_get(&rnd) >> 24;
527 rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
528 rtmp_player_key, sizeof(rtmp_player_key),
530 rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
532 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
534 // write reply back to the server
535 ffurl_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
537 ffurl_write(rt->stream, serverdata+1, RTMP_HANDSHAKE_PACKET_SIZE);
544 * Parse received packet and possibly perform some action depending on
545 * the packet contents.
546 * @return 0 for no errors, negative values for serious errors which prevent
547 * further communications, positive values for uncritical errors
549 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
552 const uint8_t *data_end = pkt->data + pkt->data_size;
555 ff_rtmp_packet_dump(LOG_CONTEXT, pkt);
559 case RTMP_PT_CHUNK_SIZE:
560 if (pkt->data_size != 4) {
561 av_log(LOG_CONTEXT, AV_LOG_ERROR,
562 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
566 ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size, rt->prev_pkt[1]);
567 rt->chunk_size = AV_RB32(pkt->data);
568 if (rt->chunk_size <= 0) {
569 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
572 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
575 t = AV_RB16(pkt->data);
577 gen_pong(s, rt, pkt);
579 case RTMP_PT_CLIENT_BW:
580 if (pkt->data_size < 4) {
581 av_log(LOG_CONTEXT, AV_LOG_ERROR,
582 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
586 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
587 rt->client_report_size = AV_RB32(pkt->data) >> 1;
590 //TODO: check for the messages sent for wrong state?
591 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
594 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
595 "description", tmpstr, sizeof(tmpstr)))
596 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
598 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
600 case STATE_HANDSHAKED:
602 gen_release_stream(s, rt);
603 gen_fcpublish_stream(s, rt);
604 rt->state = STATE_RELEASING;
606 rt->state = STATE_CONNECTING;
608 gen_create_stream(s, rt);
610 case STATE_FCPUBLISH:
611 rt->state = STATE_CONNECTING;
613 case STATE_RELEASING:
614 rt->state = STATE_FCPUBLISH;
615 /* hack for Wowza Media Server, it does not send result for
616 * releaseStream and FCPublish calls */
617 if (!pkt->data[10]) {
618 int pkt_id = (int) av_int2dbl(AV_RB64(pkt->data + 11));
620 rt->state = STATE_CONNECTING;
622 if (rt->state != STATE_CONNECTING)
624 case STATE_CONNECTING:
625 //extract a number from the result
626 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
627 av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n");
629 rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
636 rt->state = STATE_READY;
639 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
640 const uint8_t* ptr = pkt->data + 11;
643 for (i = 0; i < 2; i++) {
644 t = ff_amf_tag_size(ptr, data_end);
649 t = ff_amf_get_field_value(ptr, data_end,
650 "level", tmpstr, sizeof(tmpstr));
651 if (!t && !strcmp(tmpstr, "error")) {
652 if (!ff_amf_get_field_value(ptr, data_end,
653 "description", tmpstr, sizeof(tmpstr)))
654 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
657 t = ff_amf_get_field_value(ptr, data_end,
658 "code", tmpstr, sizeof(tmpstr));
659 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
660 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
661 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
662 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
670 * Interact with the server by receiving and sending RTMP packets until
671 * there is some significant data (media data or expected status notification).
673 * @param s reading context
674 * @param for_header non-zero value tells function to work until it
675 * gets notification from the server that playing has been started,
676 * otherwise function will work until some media data is received (or
678 * @return 0 for successful operation, negative value in case of error
680 static int get_packet(URLContext *s, int for_header)
682 RTMPContext *rt = s->priv_data;
687 uint32_t ts, cts, pts=0;
689 if (rt->state == STATE_STOPPED)
694 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
695 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
697 return AVERROR(EAGAIN);
702 rt->bytes_read += ret;
703 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
704 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending bytes read report\n");
705 gen_bytes_read(s, rt, rpkt.timestamp + 1);
706 rt->last_bytes_read = rt->bytes_read;
709 ret = rtmp_parse_result(s, rt, &rpkt);
710 if (ret < 0) {//serious error in current packet
711 ff_rtmp_packet_destroy(&rpkt);
714 if (rt->state == STATE_STOPPED) {
715 ff_rtmp_packet_destroy(&rpkt);
718 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
719 ff_rtmp_packet_destroy(&rpkt);
722 if (!rpkt.data_size || !rt->is_input) {
723 ff_rtmp_packet_destroy(&rpkt);
726 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
727 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
730 // generate packet header and put data into buffer for FLV demuxer
732 rt->flv_size = rpkt.data_size + 15;
733 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
734 bytestream_put_byte(&p, rpkt.type);
735 bytestream_put_be24(&p, rpkt.data_size);
736 bytestream_put_be24(&p, ts);
737 bytestream_put_byte(&p, ts >> 24);
738 bytestream_put_be24(&p, 0);
739 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
740 bytestream_put_be32(&p, 0);
741 ff_rtmp_packet_destroy(&rpkt);
743 } else if (rpkt.type == RTMP_PT_METADATA) {
744 // we got raw FLV data, make it available for FLV demuxer
746 rt->flv_size = rpkt.data_size;
747 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
748 /* rewrite timestamps */
751 while (next - rpkt.data < rpkt.data_size - 11) {
753 data_size = bytestream_get_be24(&next);
755 cts = bytestream_get_be24(&next);
756 cts |= bytestream_get_byte(&next) << 24;
761 bytestream_put_be24(&p, ts);
762 bytestream_put_byte(&p, ts >> 24);
763 next += data_size + 3 + 4;
765 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
766 ff_rtmp_packet_destroy(&rpkt);
769 ff_rtmp_packet_destroy(&rpkt);
774 static int rtmp_close(URLContext *h)
776 RTMPContext *rt = h->priv_data;
780 if (rt->out_pkt.data_size)
781 ff_rtmp_packet_destroy(&rt->out_pkt);
782 if (rt->state > STATE_FCPUBLISH)
783 gen_fcunpublish_stream(h, rt);
785 if (rt->state > STATE_HANDSHAKED)
786 gen_delete_stream(h, rt);
788 av_freep(&rt->flv_data);
789 ffurl_close(rt->stream);
795 * Open RTMP connection and verify that the stream can be played.
797 * URL syntax: rtmp://server[:port][/app][/playpath]
798 * where 'app' is first one or two directories in the path
799 * (e.g. /ondemand/, /flash/live/, etc.)
800 * and 'playpath' is a file name (the rest of the path,
801 * may be prefixed with "mp4:")
803 static int rtmp_open(URLContext *s, const char *uri, int flags)
806 char proto[8], hostname[256], path[1024], *fname;
811 rt = av_mallocz(sizeof(RTMPContext));
813 return AVERROR(ENOMEM);
815 rt->is_input = !(flags & URL_WRONLY);
817 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
818 path, sizeof(path), s->filename);
821 port = RTMP_DEFAULT_PORT;
822 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
824 if (ffurl_open(&rt->stream, buf, URL_RDWR) < 0) {
825 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot open connection %s\n", buf);
829 rt->state = STATE_START;
830 if (rtmp_handshake(s, rt))
833 rt->chunk_size = 128;
834 rt->state = STATE_HANDSHAKED;
835 //extract "app" part from path
836 if (!strncmp(path, "/ondemand/", 10)) {
838 memcpy(rt->app, "ondemand", 9);
840 char *p = strchr(path + 1, '/');
845 char *c = strchr(p + 1, ':');
846 fname = strchr(p + 1, '/');
847 if (!fname || c < fname) {
849 av_strlcpy(rt->app, path + 1, p - path);
852 av_strlcpy(rt->app, path + 1, fname - path - 1);
856 if (!strchr(fname, ':') &&
857 (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
858 !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
859 memcpy(rt->playpath, "mp4:", 5);
863 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
865 rt->client_report_size = 1048576;
867 rt->last_bytes_read = 0;
869 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
870 proto, path, rt->app, rt->playpath);
871 gen_connect(s, rt, proto, hostname, port);
874 ret = get_packet(s, 1);
875 } while (ret == EAGAIN);
880 // generate FLV header for demuxer
882 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
884 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
891 s->max_packet_size = url_get_max_packet_size(rt->stream);
900 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
902 RTMPContext *rt = s->priv_data;
903 int orig_size = size;
907 int data_left = rt->flv_size - rt->flv_off;
909 if (data_left >= size) {
910 memcpy(buf, rt->flv_data + rt->flv_off, size);
915 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
918 rt->flv_off = rt->flv_size;
921 if ((ret = get_packet(s, 0)) < 0)
927 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
929 RTMPContext *rt = s->priv_data;
930 int size_temp = size;
931 int pktsize, pkttype;
933 const uint8_t *buf_temp = buf;
936 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "FLV packet too small %d\n", size);
943 if (buf_temp[0] == 'F' && buf_temp[1] == 'L' && buf_temp[2] == 'V') {
948 pkttype = bytestream_get_byte(&buf_temp);
949 pktsize = bytestream_get_be24(&buf_temp);
950 ts = bytestream_get_be24(&buf_temp);
951 ts |= bytestream_get_byte(&buf_temp) << 24;
952 bytestream_get_be24(&buf_temp);
954 rt->flv_size = pktsize;
956 //force 12bytes header
957 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
958 pkttype == RTMP_PT_NOTIFY) {
959 if (pkttype == RTMP_PT_NOTIFY)
961 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
964 //this can be a big packet, it's better to send it right here
965 ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL, pkttype, ts, pktsize);
966 rt->out_pkt.extra = rt->main_channel_id;
967 rt->flv_data = rt->out_pkt.data;
969 if (pkttype == RTMP_PT_NOTIFY)
970 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
973 if (rt->flv_size - rt->flv_off > size_temp) {
974 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
975 rt->flv_off += size_temp;
977 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
978 rt->flv_off += rt->flv_size - rt->flv_off;
981 if (rt->flv_off == rt->flv_size) {
982 bytestream_get_be32(&buf_temp);
984 ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]);
985 ff_rtmp_packet_destroy(&rt->out_pkt);
989 } while (buf_temp - buf < size_temp);
993 URLProtocol ff_rtmp_protocol = {