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
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
47 #define TCURL_MAX_LENGTH 512
48 #define FLASHVER_MAX_LENGTH 64
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 {
66 URLContext* stream; ///< TCP stream used in interactions with RTMP server
67 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
68 int chunk_size; ///< size of the chunks RTMP packets are divided into
69 int is_input; ///< input/output flag
70 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
71 int live; ///< 0: recorded, -1: live, -2: both
72 char *app; ///< name of application
73 char *conn; ///< append arbitrary AMF data to the Connect message
74 ClientState state; ///< current state
75 int main_channel_id; ///< an additional channel ID which is used for some invocations
76 uint8_t* flv_data; ///< buffer with data for demuxer
77 int flv_size; ///< current buffer size
78 int flv_off; ///< number of bytes read from current buffer
79 int flv_nb_packets; ///< number of flv packets published
80 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
81 uint32_t client_report_size; ///< number of bytes after which client should report to server
82 uint32_t bytes_read; ///< number of bytes read from server
83 uint32_t last_bytes_read; ///< number of bytes read last reported to server
84 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
85 uint8_t flv_header[11]; ///< partial incoming flv packet header
86 int flv_header_bytes; ///< number of initialized bytes in flv_header
87 int nb_invokes; ///< keeps track of invoke messages
88 int create_stream_invoke; ///< invoke id for the create stream command
89 char* tcurl; ///< url of the target stream
90 char* flashver; ///< version of the flash plugin
91 char* swfurl; ///< url of the swf player
92 int server_bw; ///< server bandwidth
93 int client_buffer_time; ///< client buffer time in ms
94 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
97 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
98 /** Client key used for digest signing */
99 static const uint8_t rtmp_player_key[] = {
100 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
101 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
103 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
104 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
105 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
108 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
109 /** Key used for RTMP server digest signing */
110 static const uint8_t rtmp_server_key[] = {
111 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
112 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
113 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
115 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
116 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
117 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
120 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
125 /* The type must be B for Boolean, N for number, S for string, O for
126 * object, or Z for null. For Booleans the data must be either 0 or 1 for
127 * FALSE or TRUE, respectively. Likewise for Objects the data must be
128 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
129 * may be named, by prefixing the type with 'N' and specifying the name
130 * before the value (ie. NB:myFlag:1). This option may be used multiple times
131 * to construct arbitrary AMF sequences. */
132 if (param[0] && param[1] == ':') {
135 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
138 value = strchr(field, ':');
144 if (!field || !value)
147 ff_amf_write_field_name(p, field);
154 ff_amf_write_bool(p, value[0] != '0');
157 ff_amf_write_string(p, value);
160 ff_amf_write_number(p, strtod(value, NULL));
163 ff_amf_write_null(p);
167 ff_amf_write_object_start(p);
169 ff_amf_write_object_end(p);
179 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
180 return AVERROR(EINVAL);
184 * Generate 'connect' call and send it to the server.
186 static int gen_connect(URLContext *s, RTMPContext *rt)
192 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
198 ff_amf_write_string(&p, "connect");
199 ff_amf_write_number(&p, ++rt->nb_invokes);
200 ff_amf_write_object_start(&p);
201 ff_amf_write_field_name(&p, "app");
202 ff_amf_write_string(&p, rt->app);
205 ff_amf_write_field_name(&p, "type");
206 ff_amf_write_string(&p, "nonprivate");
208 ff_amf_write_field_name(&p, "flashVer");
209 ff_amf_write_string(&p, rt->flashver);
212 ff_amf_write_field_name(&p, "swfUrl");
213 ff_amf_write_string(&p, rt->swfurl);
216 ff_amf_write_field_name(&p, "tcUrl");
217 ff_amf_write_string(&p, rt->tcurl);
219 ff_amf_write_field_name(&p, "fpad");
220 ff_amf_write_bool(&p, 0);
221 ff_amf_write_field_name(&p, "capabilities");
222 ff_amf_write_number(&p, 15.0);
224 /* Tell the server we support all the audio codecs except
225 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
226 * which are unused in the RTMP protocol implementation. */
227 ff_amf_write_field_name(&p, "audioCodecs");
228 ff_amf_write_number(&p, 4071.0);
229 ff_amf_write_field_name(&p, "videoCodecs");
230 ff_amf_write_number(&p, 252.0);
231 ff_amf_write_field_name(&p, "videoFunction");
232 ff_amf_write_number(&p, 1.0);
234 ff_amf_write_object_end(&p);
237 char *param = rt->conn;
239 // Write arbitrary AMF data to the Connect message.
240 while (param != NULL) {
242 param += strspn(param, " ");
245 sep = strchr(param, ' ');
248 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
249 // Invalid AMF parameter.
250 ff_rtmp_packet_destroy(&pkt);
261 pkt.data_size = p - pkt.data;
263 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
265 ff_rtmp_packet_destroy(&pkt);
271 * Generate 'releaseStream' call and send it to the server. It should make
272 * the server release some channel for media streams.
274 static int gen_release_stream(URLContext *s, RTMPContext *rt)
280 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
281 0, 29 + strlen(rt->playpath))) < 0)
284 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
286 ff_amf_write_string(&p, "releaseStream");
287 ff_amf_write_number(&p, ++rt->nb_invokes);
288 ff_amf_write_null(&p);
289 ff_amf_write_string(&p, rt->playpath);
291 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
293 ff_rtmp_packet_destroy(&pkt);
299 * Generate 'FCPublish' call and send it to the server. It should make
300 * the server preapare for receiving media streams.
302 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
308 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
309 0, 25 + strlen(rt->playpath))) < 0)
312 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
314 ff_amf_write_string(&p, "FCPublish");
315 ff_amf_write_number(&p, ++rt->nb_invokes);
316 ff_amf_write_null(&p);
317 ff_amf_write_string(&p, rt->playpath);
319 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
321 ff_rtmp_packet_destroy(&pkt);
327 * Generate 'FCUnpublish' call and send it to the server. It should make
328 * the server destroy stream.
330 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
336 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
337 0, 27 + strlen(rt->playpath))) < 0)
340 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
342 ff_amf_write_string(&p, "FCUnpublish");
343 ff_amf_write_number(&p, ++rt->nb_invokes);
344 ff_amf_write_null(&p);
345 ff_amf_write_string(&p, rt->playpath);
347 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
349 ff_rtmp_packet_destroy(&pkt);
355 * Generate 'createStream' call and send it to the server. It should make
356 * the server allocate some channel for media streams.
358 static int gen_create_stream(URLContext *s, RTMPContext *rt)
364 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
366 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
371 ff_amf_write_string(&p, "createStream");
372 ff_amf_write_number(&p, ++rt->nb_invokes);
373 ff_amf_write_null(&p);
374 rt->create_stream_invoke = rt->nb_invokes;
376 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
378 ff_rtmp_packet_destroy(&pkt);
385 * Generate 'deleteStream' call and send it to the server. It should make
386 * the server remove some channel for media streams.
388 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
394 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
396 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
401 ff_amf_write_string(&p, "deleteStream");
402 ff_amf_write_number(&p, ++rt->nb_invokes);
403 ff_amf_write_null(&p);
404 ff_amf_write_number(&p, rt->main_channel_id);
406 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
408 ff_rtmp_packet_destroy(&pkt);
414 * Generate client buffer time and send it to the server.
416 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
422 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
427 bytestream_put_be16(&p, 3);
428 bytestream_put_be32(&p, rt->main_channel_id);
429 bytestream_put_be32(&p, rt->client_buffer_time);
431 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
433 ff_rtmp_packet_destroy(&pkt);
439 * Generate 'play' call and send it to the server, then ping the server
440 * to start actual playing.
442 static int gen_play(URLContext *s, RTMPContext *rt)
448 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
450 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
451 0, 29 + strlen(rt->playpath))) < 0)
454 pkt.extra = rt->main_channel_id;
457 ff_amf_write_string(&p, "play");
458 ff_amf_write_number(&p, ++rt->nb_invokes);
459 ff_amf_write_null(&p);
460 ff_amf_write_string(&p, rt->playpath);
461 ff_amf_write_number(&p, rt->live);
463 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
465 ff_rtmp_packet_destroy(&pkt);
471 * Generate 'publish' call and send it to the server.
473 static int gen_publish(URLContext *s, RTMPContext *rt)
479 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
481 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
482 0, 30 + strlen(rt->playpath))) < 0)
485 pkt.extra = rt->main_channel_id;
488 ff_amf_write_string(&p, "publish");
489 ff_amf_write_number(&p, ++rt->nb_invokes);
490 ff_amf_write_null(&p);
491 ff_amf_write_string(&p, rt->playpath);
492 ff_amf_write_string(&p, "live");
494 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
496 ff_rtmp_packet_destroy(&pkt);
502 * Generate ping reply and send it to the server.
504 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
510 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
511 ppkt->timestamp + 1, 6)) < 0)
515 bytestream_put_be16(&p, 7);
516 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
517 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
519 ff_rtmp_packet_destroy(&pkt);
525 * Generate server bandwidth message and send it to the server.
527 static int gen_server_bw(URLContext *s, RTMPContext *rt)
533 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
538 bytestream_put_be32(&p, rt->server_bw);
539 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
541 ff_rtmp_packet_destroy(&pkt);
547 * Generate check bandwidth message and send it to the server.
549 static int gen_check_bw(URLContext *s, RTMPContext *rt)
555 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
560 ff_amf_write_string(&p, "_checkbw");
561 ff_amf_write_number(&p, ++rt->nb_invokes);
562 ff_amf_write_null(&p);
564 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
566 ff_rtmp_packet_destroy(&pkt);
572 * Generate report on bytes read so far and send it to the server.
574 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
580 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
585 bytestream_put_be32(&p, rt->bytes_read);
586 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
588 ff_rtmp_packet_destroy(&pkt);
593 //TODO: Move HMAC code somewhere. Eventually.
594 #define HMAC_IPAD_VAL 0x36
595 #define HMAC_OPAD_VAL 0x5C
598 * Calculate HMAC-SHA2 digest for RTMP handshake packets.
600 * @param src input buffer
601 * @param len input buffer length (should be 1536)
602 * @param gap offset in buffer where 32 bytes should not be taken into account
603 * when calculating digest (since it will be used to store that digest)
604 * @param key digest key
605 * @param keylen digest key length
606 * @param dst buffer where calculated digest will be stored (32 bytes)
608 static int rtmp_calc_digest(const uint8_t *src, int len, int gap,
609 const uint8_t *key, int keylen, uint8_t *dst)
612 uint8_t hmac_buf[64+32] = {0};
615 sha = av_mallocz(av_sha_size);
617 return AVERROR(ENOMEM);
620 memcpy(hmac_buf, key, keylen);
622 av_sha_init(sha, 256);
623 av_sha_update(sha,key, keylen);
624 av_sha_final(sha, hmac_buf);
626 for (i = 0; i < 64; i++)
627 hmac_buf[i] ^= HMAC_IPAD_VAL;
629 av_sha_init(sha, 256);
630 av_sha_update(sha, hmac_buf, 64);
632 av_sha_update(sha, src, len);
633 } else { //skip 32 bytes used for storing digest
634 av_sha_update(sha, src, gap);
635 av_sha_update(sha, src + gap + 32, len - gap - 32);
637 av_sha_final(sha, hmac_buf + 64);
639 for (i = 0; i < 64; i++)
640 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
641 av_sha_init(sha, 256);
642 av_sha_update(sha, hmac_buf, 64+32);
643 av_sha_final(sha, dst);
651 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
652 * will be stored) into that packet.
654 * @param buf handshake data (1536 bytes)
655 * @return offset to the digest inside input data
657 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
659 int i, digest_pos = 0;
662 for (i = 8; i < 12; i++)
663 digest_pos += buf[i];
664 digest_pos = (digest_pos % 728) + 12;
666 ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
667 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
676 * Verify that the received server response has the expected digest value.
678 * @param buf handshake data received from the server (1536 bytes)
679 * @param off position to search digest offset from
680 * @return 0 if digest is valid, digest position otherwise
682 static int rtmp_validate_digest(uint8_t *buf, int off)
684 int i, digest_pos = 0;
688 for (i = 0; i < 4; i++)
689 digest_pos += buf[i + off];
690 digest_pos = (digest_pos % 728) + off + 4;
692 ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
693 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
698 if (!memcmp(digest, buf + digest_pos, 32))
704 * Perform handshake with the server by means of exchanging pseudorandom data
705 * signed with HMAC-SHA2 digest.
707 * @return 0 if handshake succeeds, negative value otherwise
709 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
712 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
713 3, // unencrypted data
714 0, 0, 0, 0, // client uptime
720 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
721 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
723 int server_pos, client_pos;
727 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
729 av_lfg_init(&rnd, 0xDEADC0DE);
730 // generate handshake packet - 1536 bytes of pseudorandom data
731 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
732 tosend[i] = av_lfg_get(&rnd) >> 24;
733 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
737 if ((ret = ffurl_write(rt->stream, tosend,
738 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
739 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
743 if ((ret = ffurl_read_complete(rt->stream, serverdata,
744 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
745 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
749 if ((ret = ffurl_read_complete(rt->stream, clientdata,
750 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
751 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
755 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
756 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
758 if (rt->is_input && serverdata[5] >= 3) {
759 server_pos = rtmp_validate_digest(serverdata + 1, 772);
764 server_pos = rtmp_validate_digest(serverdata + 1, 8);
769 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
774 ret = rtmp_calc_digest(tosend + 1 + client_pos, 32, 0, rtmp_server_key,
775 sizeof(rtmp_server_key), digest);
779 ret = rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
784 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
785 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
789 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
790 tosend[i] = av_lfg_get(&rnd) >> 24;
791 ret = rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
792 rtmp_player_key, sizeof(rtmp_player_key),
797 ret = rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
799 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
803 // write reply back to the server
804 if ((ret = ffurl_write(rt->stream, tosend,
805 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
808 if ((ret = ffurl_write(rt->stream, serverdata + 1,
809 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
817 * Parse received packet and possibly perform some action depending on
818 * the packet contents.
819 * @return 0 for no errors, negative values for serious errors which prevent
820 * further communications, positive values for uncritical errors
822 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
825 const uint8_t *data_end = pkt->data + pkt->data_size;
829 ff_rtmp_packet_dump(s, pkt);
833 case RTMP_PT_CHUNK_SIZE:
834 if (pkt->data_size != 4) {
835 av_log(s, AV_LOG_ERROR,
836 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
840 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size,
841 rt->prev_pkt[1])) < 0)
843 rt->chunk_size = AV_RB32(pkt->data);
844 if (rt->chunk_size <= 0) {
845 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
848 av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
851 t = AV_RB16(pkt->data);
853 if ((ret = gen_pong(s, rt, pkt)) < 0)
856 case RTMP_PT_CLIENT_BW:
857 if (pkt->data_size < 4) {
858 av_log(s, AV_LOG_ERROR,
859 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
863 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
864 rt->client_report_size = AV_RB32(pkt->data) >> 1;
866 case RTMP_PT_SERVER_BW:
867 rt->server_bw = AV_RB32(pkt->data);
868 if (rt->server_bw <= 0) {
869 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n", rt->server_bw);
870 return AVERROR(EINVAL);
872 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
875 //TODO: check for the messages sent for wrong state?
876 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
879 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
880 "description", tmpstr, sizeof(tmpstr)))
881 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
883 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
885 case STATE_HANDSHAKED:
887 if ((ret = gen_release_stream(s, rt)) < 0)
889 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
891 rt->state = STATE_RELEASING;
893 if ((ret = gen_server_bw(s, rt)) < 0)
895 rt->state = STATE_CONNECTING;
897 if ((ret = gen_create_stream(s, rt)) < 0)
900 case STATE_FCPUBLISH:
901 rt->state = STATE_CONNECTING;
903 case STATE_RELEASING:
904 rt->state = STATE_FCPUBLISH;
905 /* hack for Wowza Media Server, it does not send result for
906 * releaseStream and FCPublish calls */
907 if (!pkt->data[10]) {
908 int pkt_id = av_int2double(AV_RB64(pkt->data + 11));
909 if (pkt_id == rt->create_stream_invoke)
910 rt->state = STATE_CONNECTING;
912 if (rt->state != STATE_CONNECTING)
914 case STATE_CONNECTING:
915 //extract a number from the result
916 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
917 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
919 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
922 if ((ret = gen_play(s, rt)) < 0)
924 if ((ret = gen_buffer_time(s, rt)) < 0)
927 if ((ret = gen_publish(s, rt)) < 0)
930 rt->state = STATE_READY;
933 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
934 const uint8_t* ptr = pkt->data + 11;
937 for (i = 0; i < 2; i++) {
938 t = ff_amf_tag_size(ptr, data_end);
943 t = ff_amf_get_field_value(ptr, data_end,
944 "level", tmpstr, sizeof(tmpstr));
945 if (!t && !strcmp(tmpstr, "error")) {
946 if (!ff_amf_get_field_value(ptr, data_end,
947 "description", tmpstr, sizeof(tmpstr)))
948 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
951 t = ff_amf_get_field_value(ptr, data_end,
952 "code", tmpstr, sizeof(tmpstr));
953 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
954 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
955 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
956 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
957 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
958 if ((ret = gen_check_bw(s, rt)) < 0)
963 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
970 * Interact with the server by receiving and sending RTMP packets until
971 * there is some significant data (media data or expected status notification).
973 * @param s reading context
974 * @param for_header non-zero value tells function to work until it
975 * gets notification from the server that playing has been started,
976 * otherwise function will work until some media data is received (or
978 * @return 0 for successful operation, negative value in case of error
980 static int get_packet(URLContext *s, int for_header)
982 RTMPContext *rt = s->priv_data;
987 uint32_t ts, cts, pts=0;
989 if (rt->state == STATE_STOPPED)
993 RTMPPacket rpkt = { 0 };
994 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
995 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
997 return AVERROR(EAGAIN);
1002 rt->bytes_read += ret;
1003 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
1004 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
1005 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
1007 rt->last_bytes_read = rt->bytes_read;
1010 ret = rtmp_parse_result(s, rt, &rpkt);
1011 if (ret < 0) {//serious error in current packet
1012 ff_rtmp_packet_destroy(&rpkt);
1015 if (rt->state == STATE_STOPPED) {
1016 ff_rtmp_packet_destroy(&rpkt);
1019 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
1020 ff_rtmp_packet_destroy(&rpkt);
1023 if (!rpkt.data_size || !rt->is_input) {
1024 ff_rtmp_packet_destroy(&rpkt);
1027 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
1028 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
1029 ts = rpkt.timestamp;
1031 // generate packet header and put data into buffer for FLV demuxer
1033 rt->flv_size = rpkt.data_size + 15;
1034 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
1035 bytestream_put_byte(&p, rpkt.type);
1036 bytestream_put_be24(&p, rpkt.data_size);
1037 bytestream_put_be24(&p, ts);
1038 bytestream_put_byte(&p, ts >> 24);
1039 bytestream_put_be24(&p, 0);
1040 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1041 bytestream_put_be32(&p, 0);
1042 ff_rtmp_packet_destroy(&rpkt);
1044 } else if (rpkt.type == RTMP_PT_METADATA) {
1045 // we got raw FLV data, make it available for FLV demuxer
1047 rt->flv_size = rpkt.data_size;
1048 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1049 /* rewrite timestamps */
1051 ts = rpkt.timestamp;
1052 while (next - rpkt.data < rpkt.data_size - 11) {
1054 data_size = bytestream_get_be24(&next);
1056 cts = bytestream_get_be24(&next);
1057 cts |= bytestream_get_byte(&next) << 24;
1062 bytestream_put_be24(&p, ts);
1063 bytestream_put_byte(&p, ts >> 24);
1064 next += data_size + 3 + 4;
1066 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
1067 ff_rtmp_packet_destroy(&rpkt);
1070 ff_rtmp_packet_destroy(&rpkt);
1074 static int rtmp_close(URLContext *h)
1076 RTMPContext *rt = h->priv_data;
1079 if (!rt->is_input) {
1080 rt->flv_data = NULL;
1081 if (rt->out_pkt.data_size)
1082 ff_rtmp_packet_destroy(&rt->out_pkt);
1083 if (rt->state > STATE_FCPUBLISH)
1084 ret = gen_fcunpublish_stream(h, rt);
1086 if (rt->state > STATE_HANDSHAKED)
1087 ret = gen_delete_stream(h, rt);
1089 av_freep(&rt->flv_data);
1090 ffurl_close(rt->stream);
1095 * Open RTMP connection and verify that the stream can be played.
1097 * URL syntax: rtmp://server[:port][/app][/playpath]
1098 * where 'app' is first one or two directories in the path
1099 * (e.g. /ondemand/, /flash/live/, etc.)
1100 * and 'playpath' is a file name (the rest of the path,
1101 * may be prefixed with "mp4:")
1103 static int rtmp_open(URLContext *s, const char *uri, int flags)
1105 RTMPContext *rt = s->priv_data;
1106 char proto[8], hostname[256], path[1024], *fname;
1112 rt->is_input = !(flags & AVIO_FLAG_WRITE);
1114 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
1115 path, sizeof(path), s->filename);
1117 if (!strcmp(proto, "rtmpt")) {
1118 /* open the http tunneling connection */
1119 ff_url_join(buf, sizeof(buf), "rtmphttp", NULL, hostname, port, NULL);
1121 /* open the tcp connection */
1123 port = RTMP_DEFAULT_PORT;
1124 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
1127 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
1128 &s->interrupt_callback, NULL)) < 0) {
1129 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
1133 rt->state = STATE_START;
1134 if ((ret = rtmp_handshake(s, rt)) < 0)
1137 rt->chunk_size = 128;
1138 rt->state = STATE_HANDSHAKED;
1140 // Keep the application name when it has been defined by the user.
1143 rt->app = av_malloc(APP_MAX_LENGTH);
1145 ret = AVERROR(ENOMEM);
1149 //extract "app" part from path
1150 if (!strncmp(path, "/ondemand/", 10)) {
1152 memcpy(rt->app, "ondemand", 9);
1154 char *next = *path ? path + 1 : path;
1155 char *p = strchr(next, '/');
1160 // make sure we do not mismatch a playpath for an application instance
1161 char *c = strchr(p + 1, ':');
1162 fname = strchr(p + 1, '/');
1163 if (!fname || (c && c < fname)) {
1165 av_strlcpy(rt->app, path + 1, p - path);
1168 av_strlcpy(rt->app, path + 1, fname - path - 1);
1174 // The name of application has been defined by the user, override it.
1179 if (!rt->playpath) {
1180 int len = strlen(fname);
1182 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
1183 if (!rt->playpath) {
1184 ret = AVERROR(ENOMEM);
1188 if (!strchr(fname, ':') && len >= 4 &&
1189 (!strcmp(fname + len - 4, ".f4v") ||
1190 !strcmp(fname + len - 4, ".mp4"))) {
1191 memcpy(rt->playpath, "mp4:", 5);
1192 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
1193 fname[len - 4] = '\0';
1195 rt->playpath[0] = 0;
1197 strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
1201 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
1203 ret = AVERROR(ENOMEM);
1206 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
1207 port, "/%s", rt->app);
1210 if (!rt->flashver) {
1211 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
1212 if (!rt->flashver) {
1213 ret = AVERROR(ENOMEM);
1217 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
1218 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
1219 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
1221 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
1222 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
1226 rt->client_report_size = 1048576;
1228 rt->last_bytes_read = 0;
1229 rt->server_bw = 2500000;
1231 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
1232 proto, path, rt->app, rt->playpath);
1233 if ((ret = gen_connect(s, rt)) < 0)
1237 ret = get_packet(s, 1);
1238 } while (ret == EAGAIN);
1243 // generate FLV header for demuxer
1245 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1247 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
1250 rt->flv_data = NULL;
1252 rt->skip_bytes = 13;
1255 s->max_packet_size = rt->stream->max_packet_size;
1264 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
1266 RTMPContext *rt = s->priv_data;
1267 int orig_size = size;
1271 int data_left = rt->flv_size - rt->flv_off;
1273 if (data_left >= size) {
1274 memcpy(buf, rt->flv_data + rt->flv_off, size);
1275 rt->flv_off += size;
1278 if (data_left > 0) {
1279 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
1282 rt->flv_off = rt->flv_size;
1285 if ((ret = get_packet(s, 0)) < 0)
1291 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
1293 RTMPContext *rt = s->priv_data;
1294 int size_temp = size;
1295 int pktsize, pkttype;
1297 const uint8_t *buf_temp = buf;
1302 if (rt->skip_bytes) {
1303 int skip = FFMIN(rt->skip_bytes, size_temp);
1306 rt->skip_bytes -= skip;
1310 if (rt->flv_header_bytes < 11) {
1311 const uint8_t *header = rt->flv_header;
1312 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
1313 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
1314 rt->flv_header_bytes += copy;
1316 if (rt->flv_header_bytes < 11)
1319 pkttype = bytestream_get_byte(&header);
1320 pktsize = bytestream_get_be24(&header);
1321 ts = bytestream_get_be24(&header);
1322 ts |= bytestream_get_byte(&header) << 24;
1323 bytestream_get_be24(&header);
1324 rt->flv_size = pktsize;
1326 //force 12bytes header
1327 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1328 pkttype == RTMP_PT_NOTIFY) {
1329 if (pkttype == RTMP_PT_NOTIFY)
1331 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1334 //this can be a big packet, it's better to send it right here
1335 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
1336 pkttype, ts, pktsize)) < 0)
1339 rt->out_pkt.extra = rt->main_channel_id;
1340 rt->flv_data = rt->out_pkt.data;
1342 if (pkttype == RTMP_PT_NOTIFY)
1343 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1346 if (rt->flv_size - rt->flv_off > size_temp) {
1347 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1348 rt->flv_off += size_temp;
1351 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
1352 size_temp -= rt->flv_size - rt->flv_off;
1353 rt->flv_off += rt->flv_size - rt->flv_off;
1356 if (rt->flv_off == rt->flv_size) {
1359 if ((ret = ff_rtmp_packet_write(rt->stream, &rt->out_pkt,
1360 rt->chunk_size, rt->prev_pkt[1])) < 0)
1362 ff_rtmp_packet_destroy(&rt->out_pkt);
1365 rt->flv_header_bytes = 0;
1366 rt->flv_nb_packets++;
1368 } while (buf_temp - buf < size);
1370 if (rt->flv_nb_packets < rt->flush_interval)
1372 rt->flv_nb_packets = 0;
1374 /* set stream into nonblocking mode */
1375 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
1377 /* try to read one byte from the stream */
1378 ret = ffurl_read(rt->stream, &c, 1);
1380 /* switch the stream back into blocking mode */
1381 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
1383 if (ret == AVERROR(EAGAIN)) {
1384 /* no incoming data to handle */
1386 } else if (ret < 0) {
1388 } else if (ret == 1) {
1389 RTMPPacket rpkt = { 0 };
1391 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
1393 rt->prev_pkt[0], c)) <= 0)
1396 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
1399 ff_rtmp_packet_destroy(&rpkt);
1405 #define OFFSET(x) offsetof(RTMPContext, x)
1406 #define DEC AV_OPT_FLAG_DECODING_PARAM
1407 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1409 static const AVOption rtmp_options[] = {
1410 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1411 {"rtmp_buffer", "Set buffer time in milliseconds. The default is 3000.", OFFSET(client_buffer_time), AV_OPT_TYPE_INT, {3000}, 0, INT_MAX, DEC|ENC},
1412 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1413 {"rtmp_flashver", "Version of the Flash plugin used to run the SWF player.", OFFSET(flashver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1414 {"rtmp_flush_interval", "Number of packets flushed in the same request (RTMPT only).", OFFSET(flush_interval), AV_OPT_TYPE_INT, {10}, 0, INT_MAX, ENC},
1415 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
1416 {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
1417 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"},
1418 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {0}, 0, 0, DEC, "rtmp_live"},
1419 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1420 {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1421 {"rtmp_tcurl", "URL of the target stream. Defaults to rtmp://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1425 static const AVClass rtmp_class = {
1426 .class_name = "rtmp",
1427 .item_name = av_default_item_name,
1428 .option = rtmp_options,
1429 .version = LIBAVUTIL_VERSION_INT,
1432 URLProtocol ff_rtmp_protocol = {
1434 .url_open = rtmp_open,
1435 .url_read = rtmp_read,
1436 .url_write = rtmp_write,
1437 .url_close = rtmp_close,
1438 .priv_data_size = sizeof(RTMPContext),
1439 .flags = URL_PROTOCOL_FLAG_NETWORK,
1440 .priv_data_class= &rtmp_class,
1443 static const AVClass rtmpt_class = {
1444 .class_name = "rtmpt",
1445 .item_name = av_default_item_name,
1446 .option = rtmp_options,
1447 .version = LIBAVUTIL_VERSION_INT,
1450 URLProtocol ff_rtmpt_protocol = {
1452 .url_open = rtmp_open,
1453 .url_read = rtmp_read,
1454 .url_write = rtmp_write,
1455 .url_close = rtmp_close,
1456 .priv_data_size = sizeof(RTMPContext),
1457 .flags = URL_PROTOCOL_FLAG_NETWORK,
1458 .priv_data_class = &rtmpt_class,