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 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
80 uint32_t client_report_size; ///< number of bytes after which client should report to server
81 uint32_t bytes_read; ///< number of bytes read from server
82 uint32_t last_bytes_read; ///< number of bytes read last reported to server
83 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
84 uint8_t flv_header[11]; ///< partial incoming flv packet header
85 int flv_header_bytes; ///< number of initialized bytes in flv_header
86 int nb_invokes; ///< keeps track of invoke messages
87 int create_stream_invoke; ///< invoke id for the create stream command
88 char* tcurl; ///< url of the target stream
89 char* flashver; ///< version of the flash plugin
90 char* swfurl; ///< url of the swf player
91 int server_bw; ///< server bandwidth
92 int client_buffer_time; ///< client buffer time in ms
95 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
96 /** Client key used for digest signing */
97 static const uint8_t rtmp_player_key[] = {
98 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
99 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
101 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
102 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
103 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
106 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
107 /** Key used for RTMP server digest signing */
108 static const uint8_t rtmp_server_key[] = {
109 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
110 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
111 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
113 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
114 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
115 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
118 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
123 /* The type must be B for Boolean, N for number, S for string, O for
124 * object, or Z for null. For Booleans the data must be either 0 or 1 for
125 * FALSE or TRUE, respectively. Likewise for Objects the data must be
126 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
127 * may be named, by prefixing the type with 'N' and specifying the name
128 * before the value (ie. NB:myFlag:1). This option may be used multiple times
129 * to construct arbitrary AMF sequences. */
130 if (param[0] && param[1] == ':') {
133 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
136 value = strchr(field, ':');
142 if (!field || !value)
145 ff_amf_write_field_name(p, field);
152 ff_amf_write_bool(p, value[0] != '0');
155 ff_amf_write_string(p, value);
158 ff_amf_write_number(p, strtod(value, NULL));
161 ff_amf_write_null(p);
165 ff_amf_write_object_start(p);
167 ff_amf_write_object_end(p);
177 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
178 return AVERROR(EINVAL);
182 * Generate 'connect' call and send it to the server.
184 static int gen_connect(URLContext *s, RTMPContext *rt)
190 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
196 ff_amf_write_string(&p, "connect");
197 ff_amf_write_number(&p, ++rt->nb_invokes);
198 ff_amf_write_object_start(&p);
199 ff_amf_write_field_name(&p, "app");
200 ff_amf_write_string(&p, rt->app);
203 ff_amf_write_field_name(&p, "type");
204 ff_amf_write_string(&p, "nonprivate");
206 ff_amf_write_field_name(&p, "flashVer");
207 ff_amf_write_string(&p, rt->flashver);
210 ff_amf_write_field_name(&p, "swfUrl");
211 ff_amf_write_string(&p, rt->swfurl);
214 ff_amf_write_field_name(&p, "tcUrl");
215 ff_amf_write_string(&p, rt->tcurl);
217 ff_amf_write_field_name(&p, "fpad");
218 ff_amf_write_bool(&p, 0);
219 ff_amf_write_field_name(&p, "capabilities");
220 ff_amf_write_number(&p, 15.0);
222 /* Tell the server we support all the audio codecs except
223 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
224 * which are unused in the RTMP protocol implementation. */
225 ff_amf_write_field_name(&p, "audioCodecs");
226 ff_amf_write_number(&p, 4071.0);
227 ff_amf_write_field_name(&p, "videoCodecs");
228 ff_amf_write_number(&p, 252.0);
229 ff_amf_write_field_name(&p, "videoFunction");
230 ff_amf_write_number(&p, 1.0);
232 ff_amf_write_object_end(&p);
235 char *param = rt->conn;
237 // Write arbitrary AMF data to the Connect message.
238 while (param != NULL) {
240 param += strspn(param, " ");
243 sep = strchr(param, ' ');
246 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
247 // Invalid AMF parameter.
248 ff_rtmp_packet_destroy(&pkt);
259 pkt.data_size = p - pkt.data;
261 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
263 ff_rtmp_packet_destroy(&pkt);
269 * Generate 'releaseStream' call and send it to the server. It should make
270 * the server release some channel for media streams.
272 static int gen_release_stream(URLContext *s, RTMPContext *rt)
278 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
279 0, 29 + strlen(rt->playpath))) < 0)
282 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
284 ff_amf_write_string(&p, "releaseStream");
285 ff_amf_write_number(&p, ++rt->nb_invokes);
286 ff_amf_write_null(&p);
287 ff_amf_write_string(&p, rt->playpath);
289 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
291 ff_rtmp_packet_destroy(&pkt);
297 * Generate 'FCPublish' call and send it to the server. It should make
298 * the server preapare for receiving media streams.
300 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
306 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
307 0, 25 + strlen(rt->playpath))) < 0)
310 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
312 ff_amf_write_string(&p, "FCPublish");
313 ff_amf_write_number(&p, ++rt->nb_invokes);
314 ff_amf_write_null(&p);
315 ff_amf_write_string(&p, rt->playpath);
317 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
319 ff_rtmp_packet_destroy(&pkt);
325 * Generate 'FCUnpublish' call and send it to the server. It should make
326 * the server destroy stream.
328 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
334 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
335 0, 27 + strlen(rt->playpath))) < 0)
338 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
340 ff_amf_write_string(&p, "FCUnpublish");
341 ff_amf_write_number(&p, ++rt->nb_invokes);
342 ff_amf_write_null(&p);
343 ff_amf_write_string(&p, rt->playpath);
345 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
347 ff_rtmp_packet_destroy(&pkt);
353 * Generate 'createStream' call and send it to the server. It should make
354 * the server allocate some channel for media streams.
356 static int gen_create_stream(URLContext *s, RTMPContext *rt)
362 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
364 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
369 ff_amf_write_string(&p, "createStream");
370 ff_amf_write_number(&p, ++rt->nb_invokes);
371 ff_amf_write_null(&p);
372 rt->create_stream_invoke = rt->nb_invokes;
374 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
376 ff_rtmp_packet_destroy(&pkt);
383 * Generate 'deleteStream' call and send it to the server. It should make
384 * the server remove some channel for media streams.
386 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
392 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
394 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
399 ff_amf_write_string(&p, "deleteStream");
400 ff_amf_write_number(&p, ++rt->nb_invokes);
401 ff_amf_write_null(&p);
402 ff_amf_write_number(&p, rt->main_channel_id);
404 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
406 ff_rtmp_packet_destroy(&pkt);
412 * Generate client buffer time and send it to the server.
414 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
420 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
425 bytestream_put_be16(&p, 3);
426 bytestream_put_be32(&p, rt->main_channel_id);
427 bytestream_put_be32(&p, rt->client_buffer_time);
429 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
431 ff_rtmp_packet_destroy(&pkt);
437 * Generate 'play' call and send it to the server, then ping the server
438 * to start actual playing.
440 static int gen_play(URLContext *s, RTMPContext *rt)
446 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
448 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
449 0, 29 + strlen(rt->playpath))) < 0)
452 pkt.extra = rt->main_channel_id;
455 ff_amf_write_string(&p, "play");
456 ff_amf_write_number(&p, ++rt->nb_invokes);
457 ff_amf_write_null(&p);
458 ff_amf_write_string(&p, rt->playpath);
459 ff_amf_write_number(&p, rt->live);
461 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
463 ff_rtmp_packet_destroy(&pkt);
469 * Generate 'publish' call and send it to the server.
471 static int gen_publish(URLContext *s, RTMPContext *rt)
477 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
479 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
480 0, 30 + strlen(rt->playpath))) < 0)
483 pkt.extra = rt->main_channel_id;
486 ff_amf_write_string(&p, "publish");
487 ff_amf_write_number(&p, ++rt->nb_invokes);
488 ff_amf_write_null(&p);
489 ff_amf_write_string(&p, rt->playpath);
490 ff_amf_write_string(&p, "live");
492 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
494 ff_rtmp_packet_destroy(&pkt);
500 * Generate ping reply and send it to the server.
502 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
508 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
509 ppkt->timestamp + 1, 6)) < 0)
513 bytestream_put_be16(&p, 7);
514 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
515 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
517 ff_rtmp_packet_destroy(&pkt);
523 * Generate server bandwidth message and send it to the server.
525 static int gen_server_bw(URLContext *s, RTMPContext *rt)
531 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
536 bytestream_put_be32(&p, rt->server_bw);
537 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
539 ff_rtmp_packet_destroy(&pkt);
545 * Generate check bandwidth message and send it to the server.
547 static int gen_check_bw(URLContext *s, RTMPContext *rt)
553 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
558 ff_amf_write_string(&p, "_checkbw");
559 ff_amf_write_number(&p, ++rt->nb_invokes);
560 ff_amf_write_null(&p);
562 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
564 ff_rtmp_packet_destroy(&pkt);
570 * Generate report on bytes read so far and send it to the server.
572 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
578 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
583 bytestream_put_be32(&p, rt->bytes_read);
584 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
586 ff_rtmp_packet_destroy(&pkt);
591 //TODO: Move HMAC code somewhere. Eventually.
592 #define HMAC_IPAD_VAL 0x36
593 #define HMAC_OPAD_VAL 0x5C
596 * Calculate HMAC-SHA2 digest for RTMP handshake packets.
598 * @param src input buffer
599 * @param len input buffer length (should be 1536)
600 * @param gap offset in buffer where 32 bytes should not be taken into account
601 * when calculating digest (since it will be used to store that digest)
602 * @param key digest key
603 * @param keylen digest key length
604 * @param dst buffer where calculated digest will be stored (32 bytes)
606 static int rtmp_calc_digest(const uint8_t *src, int len, int gap,
607 const uint8_t *key, int keylen, uint8_t *dst)
610 uint8_t hmac_buf[64+32] = {0};
613 sha = av_mallocz(av_sha_size);
615 return AVERROR(ENOMEM);
618 memcpy(hmac_buf, key, keylen);
620 av_sha_init(sha, 256);
621 av_sha_update(sha,key, keylen);
622 av_sha_final(sha, hmac_buf);
624 for (i = 0; i < 64; i++)
625 hmac_buf[i] ^= HMAC_IPAD_VAL;
627 av_sha_init(sha, 256);
628 av_sha_update(sha, hmac_buf, 64);
630 av_sha_update(sha, src, len);
631 } else { //skip 32 bytes used for storing digest
632 av_sha_update(sha, src, gap);
633 av_sha_update(sha, src + gap + 32, len - gap - 32);
635 av_sha_final(sha, hmac_buf + 64);
637 for (i = 0; i < 64; i++)
638 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
639 av_sha_init(sha, 256);
640 av_sha_update(sha, hmac_buf, 64+32);
641 av_sha_final(sha, dst);
649 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
650 * will be stored) into that packet.
652 * @param buf handshake data (1536 bytes)
653 * @return offset to the digest inside input data
655 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
657 int i, digest_pos = 0;
660 for (i = 8; i < 12; i++)
661 digest_pos += buf[i];
662 digest_pos = (digest_pos % 728) + 12;
664 ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
665 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
674 * Verify that the received server response has the expected digest value.
676 * @param buf handshake data received from the server (1536 bytes)
677 * @param off position to search digest offset from
678 * @return 0 if digest is valid, digest position otherwise
680 static int rtmp_validate_digest(uint8_t *buf, int off)
682 int i, digest_pos = 0;
686 for (i = 0; i < 4; i++)
687 digest_pos += buf[i + off];
688 digest_pos = (digest_pos % 728) + off + 4;
690 ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
691 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
696 if (!memcmp(digest, buf + digest_pos, 32))
702 * Perform handshake with the server by means of exchanging pseudorandom data
703 * signed with HMAC-SHA2 digest.
705 * @return 0 if handshake succeeds, negative value otherwise
707 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
710 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
711 3, // unencrypted data
712 0, 0, 0, 0, // client uptime
718 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
719 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
721 int server_pos, client_pos;
725 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
727 av_lfg_init(&rnd, 0xDEADC0DE);
728 // generate handshake packet - 1536 bytes of pseudorandom data
729 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
730 tosend[i] = av_lfg_get(&rnd) >> 24;
731 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
735 if ((ret = ffurl_write(rt->stream, tosend,
736 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
737 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
741 if ((ret = ffurl_read_complete(rt->stream, serverdata,
742 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
743 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
747 if ((ret = ffurl_read_complete(rt->stream, clientdata,
748 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
749 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
753 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
754 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
756 if (rt->is_input && serverdata[5] >= 3) {
757 server_pos = rtmp_validate_digest(serverdata + 1, 772);
762 server_pos = rtmp_validate_digest(serverdata + 1, 8);
767 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
772 ret = rtmp_calc_digest(tosend + 1 + client_pos, 32, 0, rtmp_server_key,
773 sizeof(rtmp_server_key), digest);
777 ret = rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
782 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
783 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
787 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
788 tosend[i] = av_lfg_get(&rnd) >> 24;
789 ret = rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
790 rtmp_player_key, sizeof(rtmp_player_key),
795 ret = rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
797 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
801 // write reply back to the server
802 if ((ret = ffurl_write(rt->stream, tosend,
803 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
806 if ((ret = ffurl_write(rt->stream, serverdata + 1,
807 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
815 * Parse received packet and possibly perform some action depending on
816 * the packet contents.
817 * @return 0 for no errors, negative values for serious errors which prevent
818 * further communications, positive values for uncritical errors
820 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
823 const uint8_t *data_end = pkt->data + pkt->data_size;
827 ff_rtmp_packet_dump(s, pkt);
831 case RTMP_PT_CHUNK_SIZE:
832 if (pkt->data_size != 4) {
833 av_log(s, AV_LOG_ERROR,
834 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
838 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size,
839 rt->prev_pkt[1])) < 0)
841 rt->chunk_size = AV_RB32(pkt->data);
842 if (rt->chunk_size <= 0) {
843 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
846 av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
849 t = AV_RB16(pkt->data);
851 if ((ret = gen_pong(s, rt, pkt)) < 0)
854 case RTMP_PT_CLIENT_BW:
855 if (pkt->data_size < 4) {
856 av_log(s, AV_LOG_ERROR,
857 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
861 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
862 rt->client_report_size = AV_RB32(pkt->data) >> 1;
864 case RTMP_PT_SERVER_BW:
865 rt->server_bw = AV_RB32(pkt->data);
866 if (rt->server_bw <= 0) {
867 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n", rt->server_bw);
868 return AVERROR(EINVAL);
870 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
873 //TODO: check for the messages sent for wrong state?
874 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
877 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
878 "description", tmpstr, sizeof(tmpstr)))
879 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
881 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
883 case STATE_HANDSHAKED:
885 if ((ret = gen_release_stream(s, rt)) < 0)
887 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
889 rt->state = STATE_RELEASING;
891 if ((ret = gen_server_bw(s, rt)) < 0)
893 rt->state = STATE_CONNECTING;
895 if ((ret = gen_create_stream(s, rt)) < 0)
898 case STATE_FCPUBLISH:
899 rt->state = STATE_CONNECTING;
901 case STATE_RELEASING:
902 rt->state = STATE_FCPUBLISH;
903 /* hack for Wowza Media Server, it does not send result for
904 * releaseStream and FCPublish calls */
905 if (!pkt->data[10]) {
906 int pkt_id = av_int2double(AV_RB64(pkt->data + 11));
907 if (pkt_id == rt->create_stream_invoke)
908 rt->state = STATE_CONNECTING;
910 if (rt->state != STATE_CONNECTING)
912 case STATE_CONNECTING:
913 //extract a number from the result
914 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
915 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
917 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
920 if ((ret = gen_play(s, rt)) < 0)
922 if ((ret = gen_buffer_time(s, rt)) < 0)
925 if ((ret = gen_publish(s, rt)) < 0)
928 rt->state = STATE_READY;
931 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
932 const uint8_t* ptr = pkt->data + 11;
935 for (i = 0; i < 2; i++) {
936 t = ff_amf_tag_size(ptr, data_end);
941 t = ff_amf_get_field_value(ptr, data_end,
942 "level", tmpstr, sizeof(tmpstr));
943 if (!t && !strcmp(tmpstr, "error")) {
944 if (!ff_amf_get_field_value(ptr, data_end,
945 "description", tmpstr, sizeof(tmpstr)))
946 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
949 t = ff_amf_get_field_value(ptr, data_end,
950 "code", tmpstr, sizeof(tmpstr));
951 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
952 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
953 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
954 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
955 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
956 if ((ret = gen_check_bw(s, rt)) < 0)
961 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
968 * Interact with the server by receiving and sending RTMP packets until
969 * there is some significant data (media data or expected status notification).
971 * @param s reading context
972 * @param for_header non-zero value tells function to work until it
973 * gets notification from the server that playing has been started,
974 * otherwise function will work until some media data is received (or
976 * @return 0 for successful operation, negative value in case of error
978 static int get_packet(URLContext *s, int for_header)
980 RTMPContext *rt = s->priv_data;
985 uint32_t ts, cts, pts=0;
987 if (rt->state == STATE_STOPPED)
991 RTMPPacket rpkt = { 0 };
992 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
993 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
995 return AVERROR(EAGAIN);
1000 rt->bytes_read += ret;
1001 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
1002 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
1003 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
1005 rt->last_bytes_read = rt->bytes_read;
1008 ret = rtmp_parse_result(s, rt, &rpkt);
1009 if (ret < 0) {//serious error in current packet
1010 ff_rtmp_packet_destroy(&rpkt);
1013 if (rt->state == STATE_STOPPED) {
1014 ff_rtmp_packet_destroy(&rpkt);
1017 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
1018 ff_rtmp_packet_destroy(&rpkt);
1021 if (!rpkt.data_size || !rt->is_input) {
1022 ff_rtmp_packet_destroy(&rpkt);
1025 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
1026 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
1027 ts = rpkt.timestamp;
1029 // generate packet header and put data into buffer for FLV demuxer
1031 rt->flv_size = rpkt.data_size + 15;
1032 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
1033 bytestream_put_byte(&p, rpkt.type);
1034 bytestream_put_be24(&p, rpkt.data_size);
1035 bytestream_put_be24(&p, ts);
1036 bytestream_put_byte(&p, ts >> 24);
1037 bytestream_put_be24(&p, 0);
1038 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1039 bytestream_put_be32(&p, 0);
1040 ff_rtmp_packet_destroy(&rpkt);
1042 } else if (rpkt.type == RTMP_PT_METADATA) {
1043 // we got raw FLV data, make it available for FLV demuxer
1045 rt->flv_size = rpkt.data_size;
1046 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1047 /* rewrite timestamps */
1049 ts = rpkt.timestamp;
1050 while (next - rpkt.data < rpkt.data_size - 11) {
1052 data_size = bytestream_get_be24(&next);
1054 cts = bytestream_get_be24(&next);
1055 cts |= bytestream_get_byte(&next) << 24;
1060 bytestream_put_be24(&p, ts);
1061 bytestream_put_byte(&p, ts >> 24);
1062 next += data_size + 3 + 4;
1064 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
1065 ff_rtmp_packet_destroy(&rpkt);
1068 ff_rtmp_packet_destroy(&rpkt);
1072 static int rtmp_close(URLContext *h)
1074 RTMPContext *rt = h->priv_data;
1077 if (!rt->is_input) {
1078 rt->flv_data = NULL;
1079 if (rt->out_pkt.data_size)
1080 ff_rtmp_packet_destroy(&rt->out_pkt);
1081 if (rt->state > STATE_FCPUBLISH)
1082 ret = gen_fcunpublish_stream(h, rt);
1084 if (rt->state > STATE_HANDSHAKED)
1085 ret = gen_delete_stream(h, rt);
1087 av_freep(&rt->flv_data);
1088 ffurl_close(rt->stream);
1093 * Open RTMP connection and verify that the stream can be played.
1095 * URL syntax: rtmp://server[:port][/app][/playpath]
1096 * where 'app' is first one or two directories in the path
1097 * (e.g. /ondemand/, /flash/live/, etc.)
1098 * and 'playpath' is a file name (the rest of the path,
1099 * may be prefixed with "mp4:")
1101 static int rtmp_open(URLContext *s, const char *uri, int flags)
1103 RTMPContext *rt = s->priv_data;
1104 char proto[8], hostname[256], path[1024], *fname;
1110 rt->is_input = !(flags & AVIO_FLAG_WRITE);
1112 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
1113 path, sizeof(path), s->filename);
1116 port = RTMP_DEFAULT_PORT;
1117 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
1119 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
1120 &s->interrupt_callback, NULL)) < 0) {
1121 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
1125 rt->state = STATE_START;
1126 if ((ret = rtmp_handshake(s, rt)) < 0)
1129 rt->chunk_size = 128;
1130 rt->state = STATE_HANDSHAKED;
1132 // Keep the application name when it has been defined by the user.
1135 rt->app = av_malloc(APP_MAX_LENGTH);
1137 ret = AVERROR(ENOMEM);
1141 //extract "app" part from path
1142 if (!strncmp(path, "/ondemand/", 10)) {
1144 memcpy(rt->app, "ondemand", 9);
1146 char *next = *path ? path + 1 : path;
1147 char *p = strchr(next, '/');
1152 // make sure we do not mismatch a playpath for an application instance
1153 char *c = strchr(p + 1, ':');
1154 fname = strchr(p + 1, '/');
1155 if (!fname || (c && c < fname)) {
1157 av_strlcpy(rt->app, path + 1, p - path);
1160 av_strlcpy(rt->app, path + 1, fname - path - 1);
1166 // The name of application has been defined by the user, override it.
1171 if (!rt->playpath) {
1172 int len = strlen(fname);
1174 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
1175 if (!rt->playpath) {
1176 ret = AVERROR(ENOMEM);
1180 if (!strchr(fname, ':') && len >= 4 &&
1181 (!strcmp(fname + len - 4, ".f4v") ||
1182 !strcmp(fname + len - 4, ".mp4"))) {
1183 memcpy(rt->playpath, "mp4:", 5);
1184 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
1185 fname[len - 4] = '\0';
1187 rt->playpath[0] = 0;
1189 strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
1193 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
1195 ret = AVERROR(ENOMEM);
1198 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
1199 port, "/%s", rt->app);
1202 if (!rt->flashver) {
1203 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
1204 if (!rt->flashver) {
1205 ret = AVERROR(ENOMEM);
1209 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
1210 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
1211 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
1213 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
1214 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
1218 rt->client_report_size = 1048576;
1220 rt->last_bytes_read = 0;
1221 rt->server_bw = 2500000;
1223 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
1224 proto, path, rt->app, rt->playpath);
1225 if ((ret = gen_connect(s, rt)) < 0)
1229 ret = get_packet(s, 1);
1230 } while (ret == EAGAIN);
1235 // generate FLV header for demuxer
1237 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1239 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
1242 rt->flv_data = NULL;
1244 rt->skip_bytes = 13;
1247 s->max_packet_size = rt->stream->max_packet_size;
1256 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
1258 RTMPContext *rt = s->priv_data;
1259 int orig_size = size;
1263 int data_left = rt->flv_size - rt->flv_off;
1265 if (data_left >= size) {
1266 memcpy(buf, rt->flv_data + rt->flv_off, size);
1267 rt->flv_off += size;
1270 if (data_left > 0) {
1271 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
1274 rt->flv_off = rt->flv_size;
1277 if ((ret = get_packet(s, 0)) < 0)
1283 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
1285 RTMPContext *rt = s->priv_data;
1286 int size_temp = size;
1287 int pktsize, pkttype;
1289 const uint8_t *buf_temp = buf;
1294 if (rt->skip_bytes) {
1295 int skip = FFMIN(rt->skip_bytes, size_temp);
1298 rt->skip_bytes -= skip;
1302 if (rt->flv_header_bytes < 11) {
1303 const uint8_t *header = rt->flv_header;
1304 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
1305 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
1306 rt->flv_header_bytes += copy;
1308 if (rt->flv_header_bytes < 11)
1311 pkttype = bytestream_get_byte(&header);
1312 pktsize = bytestream_get_be24(&header);
1313 ts = bytestream_get_be24(&header);
1314 ts |= bytestream_get_byte(&header) << 24;
1315 bytestream_get_be24(&header);
1316 rt->flv_size = pktsize;
1318 //force 12bytes header
1319 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1320 pkttype == RTMP_PT_NOTIFY) {
1321 if (pkttype == RTMP_PT_NOTIFY)
1323 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1326 //this can be a big packet, it's better to send it right here
1327 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
1328 pkttype, ts, pktsize)) < 0)
1331 rt->out_pkt.extra = rt->main_channel_id;
1332 rt->flv_data = rt->out_pkt.data;
1334 if (pkttype == RTMP_PT_NOTIFY)
1335 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1338 if (rt->flv_size - rt->flv_off > size_temp) {
1339 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1340 rt->flv_off += size_temp;
1343 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
1344 size_temp -= rt->flv_size - rt->flv_off;
1345 rt->flv_off += rt->flv_size - rt->flv_off;
1348 if (rt->flv_off == rt->flv_size) {
1351 if ((ret = ff_rtmp_packet_write(rt->stream, &rt->out_pkt,
1352 rt->chunk_size, rt->prev_pkt[1])) < 0)
1354 ff_rtmp_packet_destroy(&rt->out_pkt);
1357 rt->flv_header_bytes = 0;
1359 } while (buf_temp - buf < size);
1361 /* set stream into nonblocking mode */
1362 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
1364 /* try to read one byte from the stream */
1365 ret = ffurl_read(rt->stream, &c, 1);
1367 /* switch the stream back into blocking mode */
1368 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
1370 if (ret == AVERROR(EAGAIN)) {
1371 /* no incoming data to handle */
1373 } else if (ret < 0) {
1375 } else if (ret == 1) {
1376 RTMPPacket rpkt = { 0 };
1378 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
1380 rt->prev_pkt[0], c)) <= 0)
1383 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
1386 ff_rtmp_packet_destroy(&rpkt);
1392 #define OFFSET(x) offsetof(RTMPContext, x)
1393 #define DEC AV_OPT_FLAG_DECODING_PARAM
1394 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1396 static const AVOption rtmp_options[] = {
1397 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1398 {"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},
1399 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1400 {"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},
1401 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
1402 {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
1403 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"},
1404 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {0}, 0, 0, DEC, "rtmp_live"},
1405 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1406 {"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},
1407 {"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},
1411 static const AVClass rtmp_class = {
1412 .class_name = "rtmp",
1413 .item_name = av_default_item_name,
1414 .option = rtmp_options,
1415 .version = LIBAVUTIL_VERSION_INT,
1418 URLProtocol ff_rtmp_protocol = {
1420 .url_open = rtmp_open,
1421 .url_read = rtmp_read,
1422 .url_write = rtmp_write,
1423 .url_close = rtmp_close,
1424 .priv_data_size = sizeof(RTMPContext),
1425 .flags = URL_PROTOCOL_FLAG_NETWORK,
1426 .priv_data_class= &rtmp_class,