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/intfloat.h"
30 #include "libavutil/lfg.h"
31 #include "libavutil/opt.h"
32 #include "libavutil/sha.h"
45 #define APP_MAX_LENGTH 128
46 #define PLAYPATH_MAX_LENGTH 256
48 /** RTMP protocol handler state */
50 STATE_START, ///< client has not done anything yet
51 STATE_HANDSHAKED, ///< client has performed handshake
52 STATE_RELEASING, ///< client releasing stream before publish it (for output)
53 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
54 STATE_CONNECTING, ///< client connected to server successfully
55 STATE_READY, ///< client has sent all needed commands and waits for server reply
56 STATE_PLAYING, ///< client has started receiving multimedia data from server
57 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
58 STATE_STOPPED, ///< the broadcast has been stopped
61 /** protocol handler context */
62 typedef struct RTMPContext {
64 URLContext* stream; ///< TCP stream used in interactions with RTMP server
65 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
66 int chunk_size; ///< size of the chunks RTMP packets are divided into
67 int is_input; ///< input/output flag
68 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
69 char *app; ///< name of application
70 ClientState state; ///< current state
71 int main_channel_id; ///< an additional channel ID which is used for some invocations
72 uint8_t* flv_data; ///< buffer with data for demuxer
73 int flv_size; ///< current buffer size
74 int flv_off; ///< number of bytes read from current buffer
75 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
76 uint32_t client_report_size; ///< number of bytes after which client should report to server
77 uint32_t bytes_read; ///< number of bytes read from server
78 uint32_t last_bytes_read; ///< number of bytes read last reported to server
79 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
80 uint8_t flv_header[11]; ///< partial incoming flv packet header
81 int flv_header_bytes; ///< number of initialized bytes in flv_header
82 int nb_invokes; ///< keeps track of invoke messages
83 int create_stream_invoke; ///< invoke id for the create stream command
86 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
87 /** Client key used for digest signing */
88 static const uint8_t rtmp_player_key[] = {
89 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
90 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
92 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
93 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
94 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
97 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
98 /** Key used for RTMP server digest signing */
99 static const uint8_t rtmp_server_key[] = {
100 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
101 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
102 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
104 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
105 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
106 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
110 * Generate 'connect' call and send it to the server.
112 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto,
113 const char *host, int port)
119 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096);
122 ff_url_join(tcurl, sizeof(tcurl), proto, NULL, host, port, "/%s", rt->app);
123 ff_amf_write_string(&p, "connect");
124 ff_amf_write_number(&p, ++rt->nb_invokes);
125 ff_amf_write_object_start(&p);
126 ff_amf_write_field_name(&p, "app");
127 ff_amf_write_string(&p, rt->app);
130 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1,
131 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
133 snprintf(ver, sizeof(ver), "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
134 ff_amf_write_field_name(&p, "type");
135 ff_amf_write_string(&p, "nonprivate");
137 ff_amf_write_field_name(&p, "flashVer");
138 ff_amf_write_string(&p, ver);
139 ff_amf_write_field_name(&p, "tcUrl");
140 ff_amf_write_string(&p, tcurl);
142 ff_amf_write_field_name(&p, "fpad");
143 ff_amf_write_bool(&p, 0);
144 ff_amf_write_field_name(&p, "capabilities");
145 ff_amf_write_number(&p, 15.0);
147 /* Tell the server we support all the audio codecs except
148 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
149 * which are unused in the RTMP protocol implementation. */
150 ff_amf_write_field_name(&p, "audioCodecs");
151 ff_amf_write_number(&p, 4071.0);
152 ff_amf_write_field_name(&p, "videoCodecs");
153 ff_amf_write_number(&p, 252.0);
154 ff_amf_write_field_name(&p, "videoFunction");
155 ff_amf_write_number(&p, 1.0);
157 ff_amf_write_object_end(&p);
159 pkt.data_size = p - pkt.data;
161 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
162 ff_rtmp_packet_destroy(&pkt);
166 * Generate 'releaseStream' call and send it to the server. It should make
167 * the server release some channel for media streams.
169 static void gen_release_stream(URLContext *s, RTMPContext *rt)
174 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
175 29 + strlen(rt->playpath));
177 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
179 ff_amf_write_string(&p, "releaseStream");
180 ff_amf_write_number(&p, ++rt->nb_invokes);
181 ff_amf_write_null(&p);
182 ff_amf_write_string(&p, rt->playpath);
184 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
185 ff_rtmp_packet_destroy(&pkt);
189 * Generate 'FCPublish' call and send it to the server. It should make
190 * the server preapare for receiving media streams.
192 static void gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
197 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
198 25 + strlen(rt->playpath));
200 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
202 ff_amf_write_string(&p, "FCPublish");
203 ff_amf_write_number(&p, ++rt->nb_invokes);
204 ff_amf_write_null(&p);
205 ff_amf_write_string(&p, rt->playpath);
207 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
208 ff_rtmp_packet_destroy(&pkt);
212 * Generate 'FCUnpublish' call and send it to the server. It should make
213 * the server destroy stream.
215 static void gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
220 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0,
221 27 + strlen(rt->playpath));
223 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
225 ff_amf_write_string(&p, "FCUnpublish");
226 ff_amf_write_number(&p, ++rt->nb_invokes);
227 ff_amf_write_null(&p);
228 ff_amf_write_string(&p, rt->playpath);
230 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
231 ff_rtmp_packet_destroy(&pkt);
235 * Generate 'createStream' call and send it to the server. It should make
236 * the server allocate some channel for media streams.
238 static void gen_create_stream(URLContext *s, RTMPContext *rt)
243 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
244 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 25);
247 ff_amf_write_string(&p, "createStream");
248 ff_amf_write_number(&p, ++rt->nb_invokes);
249 ff_amf_write_null(&p);
250 rt->create_stream_invoke = rt->nb_invokes;
252 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
253 ff_rtmp_packet_destroy(&pkt);
258 * Generate 'deleteStream' call and send it to the server. It should make
259 * the server remove some channel for media streams.
261 static void gen_delete_stream(URLContext *s, RTMPContext *rt)
266 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
267 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 34);
270 ff_amf_write_string(&p, "deleteStream");
271 ff_amf_write_number(&p, ++rt->nb_invokes);
272 ff_amf_write_null(&p);
273 ff_amf_write_number(&p, rt->main_channel_id);
275 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
276 ff_rtmp_packet_destroy(&pkt);
280 * Generate 'play' call and send it to the server, then ping the server
281 * to start actual playing.
283 static void gen_play(URLContext *s, RTMPContext *rt)
288 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
289 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0,
290 20 + strlen(rt->playpath));
291 pkt.extra = rt->main_channel_id;
294 ff_amf_write_string(&p, "play");
295 ff_amf_write_number(&p, ++rt->nb_invokes);
296 ff_amf_write_null(&p);
297 ff_amf_write_string(&p, rt->playpath);
299 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
300 ff_rtmp_packet_destroy(&pkt);
302 // set client buffer time disguised in ping packet
303 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
306 bytestream_put_be16(&p, 3);
307 bytestream_put_be32(&p, 1);
308 bytestream_put_be32(&p, 256); //TODO: what is a good value here?
310 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
311 ff_rtmp_packet_destroy(&pkt);
315 * Generate 'publish' call and send it to the server.
317 static void gen_publish(URLContext *s, RTMPContext *rt)
322 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
323 ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE, 0,
324 30 + strlen(rt->playpath));
325 pkt.extra = rt->main_channel_id;
328 ff_amf_write_string(&p, "publish");
329 ff_amf_write_number(&p, ++rt->nb_invokes);
330 ff_amf_write_null(&p);
331 ff_amf_write_string(&p, rt->playpath);
332 ff_amf_write_string(&p, "live");
334 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
335 ff_rtmp_packet_destroy(&pkt);
339 * Generate ping reply and send it to the server.
341 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
346 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6);
348 bytestream_put_be16(&p, 7);
349 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
350 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
351 ff_rtmp_packet_destroy(&pkt);
355 * Generate server bandwidth message and send it to the server.
357 static void gen_server_bw(URLContext *s, RTMPContext *rt)
362 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW, 0, 4);
364 bytestream_put_be32(&p, 2500000);
365 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
366 ff_rtmp_packet_destroy(&pkt);
370 * Generate report on bytes read so far and send it to the server.
372 static void gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
377 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ, ts, 4);
379 bytestream_put_be32(&p, rt->bytes_read);
380 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
381 ff_rtmp_packet_destroy(&pkt);
384 //TODO: Move HMAC code somewhere. Eventually.
385 #define HMAC_IPAD_VAL 0x36
386 #define HMAC_OPAD_VAL 0x5C
389 * Calculate HMAC-SHA2 digest for RTMP handshake packets.
391 * @param src input buffer
392 * @param len input buffer length (should be 1536)
393 * @param gap offset in buffer where 32 bytes should not be taken into account
394 * when calculating digest (since it will be used to store that digest)
395 * @param key digest key
396 * @param keylen digest key length
397 * @param dst buffer where calculated digest will be stored (32 bytes)
399 static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
400 const uint8_t *key, int keylen, uint8_t *dst)
403 uint8_t hmac_buf[64+32] = {0};
406 sha = av_mallocz(av_sha_size);
409 memcpy(hmac_buf, key, keylen);
411 av_sha_init(sha, 256);
412 av_sha_update(sha,key, keylen);
413 av_sha_final(sha, hmac_buf);
415 for (i = 0; i < 64; i++)
416 hmac_buf[i] ^= HMAC_IPAD_VAL;
418 av_sha_init(sha, 256);
419 av_sha_update(sha, hmac_buf, 64);
421 av_sha_update(sha, src, len);
422 } else { //skip 32 bytes used for storing digest
423 av_sha_update(sha, src, gap);
424 av_sha_update(sha, src + gap + 32, len - gap - 32);
426 av_sha_final(sha, hmac_buf + 64);
428 for (i = 0; i < 64; i++)
429 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
430 av_sha_init(sha, 256);
431 av_sha_update(sha, hmac_buf, 64+32);
432 av_sha_final(sha, dst);
438 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
439 * will be stored) into that packet.
441 * @param buf handshake data (1536 bytes)
442 * @return offset to the digest inside input data
444 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
446 int i, digest_pos = 0;
448 for (i = 8; i < 12; i++)
449 digest_pos += buf[i];
450 digest_pos = (digest_pos % 728) + 12;
452 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
453 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
459 * Verify that the received server response has the expected digest value.
461 * @param buf handshake data received from the server (1536 bytes)
462 * @param off position to search digest offset from
463 * @return 0 if digest is valid, digest position otherwise
465 static int rtmp_validate_digest(uint8_t *buf, int off)
467 int i, digest_pos = 0;
470 for (i = 0; i < 4; i++)
471 digest_pos += buf[i + off];
472 digest_pos = (digest_pos % 728) + off + 4;
474 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
475 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
477 if (!memcmp(digest, buf + digest_pos, 32))
483 * Perform handshake with the server by means of exchanging pseudorandom data
484 * signed with HMAC-SHA2 digest.
486 * @return 0 if handshake succeeds, negative value otherwise
488 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
491 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
492 3, // unencrypted data
493 0, 0, 0, 0, // client uptime
499 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
500 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
502 int server_pos, client_pos;
505 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
507 av_lfg_init(&rnd, 0xDEADC0DE);
508 // generate handshake packet - 1536 bytes of pseudorandom data
509 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
510 tosend[i] = av_lfg_get(&rnd) >> 24;
511 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
513 ffurl_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
514 i = ffurl_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
515 if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
516 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
519 i = ffurl_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
520 if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
521 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
525 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
526 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
528 if (rt->is_input && serverdata[5] >= 3) {
529 server_pos = rtmp_validate_digest(serverdata + 1, 772);
531 server_pos = rtmp_validate_digest(serverdata + 1, 8);
533 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
538 rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
539 rtmp_server_key, sizeof(rtmp_server_key),
541 rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
544 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
545 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
549 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
550 tosend[i] = av_lfg_get(&rnd) >> 24;
551 rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
552 rtmp_player_key, sizeof(rtmp_player_key),
554 rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
556 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
558 // write reply back to the server
559 ffurl_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
561 ffurl_write(rt->stream, serverdata+1, RTMP_HANDSHAKE_PACKET_SIZE);
568 * Parse received packet and possibly perform some action depending on
569 * the packet contents.
570 * @return 0 for no errors, negative values for serious errors which prevent
571 * further communications, positive values for uncritical errors
573 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
576 const uint8_t *data_end = pkt->data + pkt->data_size;
579 ff_rtmp_packet_dump(s, pkt);
583 case RTMP_PT_CHUNK_SIZE:
584 if (pkt->data_size != 4) {
585 av_log(s, AV_LOG_ERROR,
586 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
590 ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size, rt->prev_pkt[1]);
591 rt->chunk_size = AV_RB32(pkt->data);
592 if (rt->chunk_size <= 0) {
593 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
596 av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
599 t = AV_RB16(pkt->data);
601 gen_pong(s, rt, pkt);
603 case RTMP_PT_CLIENT_BW:
604 if (pkt->data_size < 4) {
605 av_log(s, AV_LOG_ERROR,
606 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
610 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
611 rt->client_report_size = AV_RB32(pkt->data) >> 1;
614 //TODO: check for the messages sent for wrong state?
615 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
618 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
619 "description", tmpstr, sizeof(tmpstr)))
620 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
622 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
624 case STATE_HANDSHAKED:
626 gen_release_stream(s, rt);
627 gen_fcpublish_stream(s, rt);
628 rt->state = STATE_RELEASING;
630 gen_server_bw(s, rt);
631 rt->state = STATE_CONNECTING;
633 gen_create_stream(s, rt);
635 case STATE_FCPUBLISH:
636 rt->state = STATE_CONNECTING;
638 case STATE_RELEASING:
639 rt->state = STATE_FCPUBLISH;
640 /* hack for Wowza Media Server, it does not send result for
641 * releaseStream and FCPublish calls */
642 if (!pkt->data[10]) {
643 int pkt_id = av_int2double(AV_RB64(pkt->data + 11));
644 if (pkt_id == rt->create_stream_invoke)
645 rt->state = STATE_CONNECTING;
647 if (rt->state != STATE_CONNECTING)
649 case STATE_CONNECTING:
650 //extract a number from the result
651 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
652 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
654 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
661 rt->state = STATE_READY;
664 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
665 const uint8_t* ptr = pkt->data + 11;
668 for (i = 0; i < 2; i++) {
669 t = ff_amf_tag_size(ptr, data_end);
674 t = ff_amf_get_field_value(ptr, data_end,
675 "level", tmpstr, sizeof(tmpstr));
676 if (!t && !strcmp(tmpstr, "error")) {
677 if (!ff_amf_get_field_value(ptr, data_end,
678 "description", tmpstr, sizeof(tmpstr)))
679 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
682 t = ff_amf_get_field_value(ptr, data_end,
683 "code", tmpstr, sizeof(tmpstr));
684 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
685 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
686 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
687 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
695 * Interact with the server by receiving and sending RTMP packets until
696 * there is some significant data (media data or expected status notification).
698 * @param s reading context
699 * @param for_header non-zero value tells function to work until it
700 * gets notification from the server that playing has been started,
701 * otherwise function will work until some media data is received (or
703 * @return 0 for successful operation, negative value in case of error
705 static int get_packet(URLContext *s, int for_header)
707 RTMPContext *rt = s->priv_data;
712 uint32_t ts, cts, pts=0;
714 if (rt->state == STATE_STOPPED)
718 RTMPPacket rpkt = { 0 };
719 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
720 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
722 return AVERROR(EAGAIN);
727 rt->bytes_read += ret;
728 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
729 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
730 gen_bytes_read(s, rt, rpkt.timestamp + 1);
731 rt->last_bytes_read = rt->bytes_read;
734 ret = rtmp_parse_result(s, rt, &rpkt);
735 if (ret < 0) {//serious error in current packet
736 ff_rtmp_packet_destroy(&rpkt);
739 if (rt->state == STATE_STOPPED) {
740 ff_rtmp_packet_destroy(&rpkt);
743 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
744 ff_rtmp_packet_destroy(&rpkt);
747 if (!rpkt.data_size || !rt->is_input) {
748 ff_rtmp_packet_destroy(&rpkt);
751 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
752 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
755 // generate packet header and put data into buffer for FLV demuxer
757 rt->flv_size = rpkt.data_size + 15;
758 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
759 bytestream_put_byte(&p, rpkt.type);
760 bytestream_put_be24(&p, rpkt.data_size);
761 bytestream_put_be24(&p, ts);
762 bytestream_put_byte(&p, ts >> 24);
763 bytestream_put_be24(&p, 0);
764 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
765 bytestream_put_be32(&p, 0);
766 ff_rtmp_packet_destroy(&rpkt);
768 } else if (rpkt.type == RTMP_PT_METADATA) {
769 // we got raw FLV data, make it available for FLV demuxer
771 rt->flv_size = rpkt.data_size;
772 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
773 /* rewrite timestamps */
776 while (next - rpkt.data < rpkt.data_size - 11) {
778 data_size = bytestream_get_be24(&next);
780 cts = bytestream_get_be24(&next);
781 cts |= bytestream_get_byte(&next) << 24;
786 bytestream_put_be24(&p, ts);
787 bytestream_put_byte(&p, ts >> 24);
788 next += data_size + 3 + 4;
790 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
791 ff_rtmp_packet_destroy(&rpkt);
794 ff_rtmp_packet_destroy(&rpkt);
798 static int rtmp_close(URLContext *h)
800 RTMPContext *rt = h->priv_data;
804 if (rt->out_pkt.data_size)
805 ff_rtmp_packet_destroy(&rt->out_pkt);
806 if (rt->state > STATE_FCPUBLISH)
807 gen_fcunpublish_stream(h, rt);
809 if (rt->state > STATE_HANDSHAKED)
810 gen_delete_stream(h, rt);
812 av_freep(&rt->flv_data);
813 ffurl_close(rt->stream);
818 * Open RTMP connection and verify that the stream can be played.
820 * URL syntax: rtmp://server[:port][/app][/playpath]
821 * where 'app' is first one or two directories in the path
822 * (e.g. /ondemand/, /flash/live/, etc.)
823 * and 'playpath' is a file name (the rest of the path,
824 * may be prefixed with "mp4:")
826 static int rtmp_open(URLContext *s, const char *uri, int flags)
828 RTMPContext *rt = s->priv_data;
829 char proto[8], hostname[256], path[1024], *fname;
835 rt->is_input = !(flags & AVIO_FLAG_WRITE);
837 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
838 path, sizeof(path), s->filename);
841 port = RTMP_DEFAULT_PORT;
842 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
844 if (ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
845 &s->interrupt_callback, NULL) < 0) {
846 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
850 rt->state = STATE_START;
851 if (rtmp_handshake(s, rt))
854 rt->chunk_size = 128;
855 rt->state = STATE_HANDSHAKED;
857 // Keep the application name when it has been defined by the user.
860 rt->app = av_malloc(APP_MAX_LENGTH);
863 return AVERROR(ENOMEM);
866 //extract "app" part from path
867 if (!strncmp(path, "/ondemand/", 10)) {
869 memcpy(rt->app, "ondemand", 9);
871 char *p = strchr(path + 1, '/');
876 char *c = strchr(p + 1, ':');
877 fname = strchr(p + 1, '/');
878 if (!fname || c < fname) {
880 av_strlcpy(rt->app, path + 1, p - path);
883 av_strlcpy(rt->app, path + 1, fname - path - 1);
889 // The name of application has been defined by the user, override it.
895 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
898 return AVERROR(ENOMEM);
901 if (!strchr(fname, ':') &&
902 (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
903 !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
904 memcpy(rt->playpath, "mp4:", 5);
908 strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
911 rt->client_report_size = 1048576;
913 rt->last_bytes_read = 0;
915 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
916 proto, path, rt->app, rt->playpath);
917 gen_connect(s, rt, proto, hostname, port);
920 ret = get_packet(s, 1);
921 } while (ret == EAGAIN);
926 // generate FLV header for demuxer
928 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
930 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
938 s->max_packet_size = rt->stream->max_packet_size;
947 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
949 RTMPContext *rt = s->priv_data;
950 int orig_size = size;
954 int data_left = rt->flv_size - rt->flv_off;
956 if (data_left >= size) {
957 memcpy(buf, rt->flv_data + rt->flv_off, size);
962 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
965 rt->flv_off = rt->flv_size;
968 if ((ret = get_packet(s, 0)) < 0)
974 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
976 RTMPContext *rt = s->priv_data;
977 int size_temp = size;
978 int pktsize, pkttype;
980 const uint8_t *buf_temp = buf;
983 if (rt->skip_bytes) {
984 int skip = FFMIN(rt->skip_bytes, size_temp);
987 rt->skip_bytes -= skip;
991 if (rt->flv_header_bytes < 11) {
992 const uint8_t *header = rt->flv_header;
993 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
994 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
995 rt->flv_header_bytes += copy;
997 if (rt->flv_header_bytes < 11)
1000 pkttype = bytestream_get_byte(&header);
1001 pktsize = bytestream_get_be24(&header);
1002 ts = bytestream_get_be24(&header);
1003 ts |= bytestream_get_byte(&header) << 24;
1004 bytestream_get_be24(&header);
1005 rt->flv_size = pktsize;
1007 //force 12bytes header
1008 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1009 pkttype == RTMP_PT_NOTIFY) {
1010 if (pkttype == RTMP_PT_NOTIFY)
1012 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1015 //this can be a big packet, it's better to send it right here
1016 ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL, pkttype, ts, pktsize);
1017 rt->out_pkt.extra = rt->main_channel_id;
1018 rt->flv_data = rt->out_pkt.data;
1020 if (pkttype == RTMP_PT_NOTIFY)
1021 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1024 if (rt->flv_size - rt->flv_off > size_temp) {
1025 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1026 rt->flv_off += size_temp;
1029 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
1030 size_temp -= rt->flv_size - rt->flv_off;
1031 rt->flv_off += rt->flv_size - rt->flv_off;
1034 if (rt->flv_off == rt->flv_size) {
1037 ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]);
1038 ff_rtmp_packet_destroy(&rt->out_pkt);
1041 rt->flv_header_bytes = 0;
1043 } while (buf_temp - buf < size);
1047 #define OFFSET(x) offsetof(RTMPContext, x)
1048 #define DEC AV_OPT_FLAG_DECODING_PARAM
1049 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1051 static const AVOption rtmp_options[] = {
1052 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1053 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1057 static const AVClass rtmp_class = {
1058 .class_name = "rtmp",
1059 .item_name = av_default_item_name,
1060 .option = rtmp_options,
1061 .version = LIBAVUTIL_VERSION_INT,
1064 URLProtocol ff_rtmp_protocol = {
1066 .url_open = rtmp_open,
1067 .url_read = rtmp_read,
1068 .url_write = rtmp_write,
1069 .url_close = rtmp_close,
1070 .priv_data_size = sizeof(RTMPContext),
1071 .flags = URL_PROTOCOL_FLAG_NETWORK,
1072 .priv_data_class= &rtmp_class,