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
93 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
94 /** Client key used for digest signing */
95 static const uint8_t rtmp_player_key[] = {
96 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
97 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
99 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
100 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
101 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
104 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
105 /** Key used for RTMP server digest signing */
106 static const uint8_t rtmp_server_key[] = {
107 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
108 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
109 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
111 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
112 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
113 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
116 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
118 char *field, *value, *saveptr;
121 /* The type must be B for Boolean, N for number, S for string, O for
122 * object, or Z for null. For Booleans the data must be either 0 or 1 for
123 * FALSE or TRUE, respectively. Likewise for Objects the data must be
124 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
125 * may be named, by prefixing the type with 'N' and specifying the name
126 * before the value (ie. NB:myFlag:1). This option may be used multiple times
127 * to construct arbitrary AMF sequences. */
128 if (param[0] && param[1] == ':') {
131 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
133 field = av_strtok(param + 3, ":", &saveptr);
134 value = av_strtok(NULL, ":", &saveptr);
136 if (!field || !value)
139 ff_amf_write_field_name(p, field);
146 ff_amf_write_bool(p, value[0] != '0');
149 ff_amf_write_string(p, value);
152 ff_amf_write_number(p, strtod(value, NULL));
155 ff_amf_write_null(p);
159 ff_amf_write_object_start(p);
161 ff_amf_write_object_end(p);
171 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
172 return AVERROR(EINVAL);
176 * Generate 'connect' call and send it to the server.
178 static int gen_connect(URLContext *s, RTMPContext *rt)
184 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
190 ff_amf_write_string(&p, "connect");
191 ff_amf_write_number(&p, ++rt->nb_invokes);
192 ff_amf_write_object_start(&p);
193 ff_amf_write_field_name(&p, "app");
194 ff_amf_write_string(&p, rt->app);
197 ff_amf_write_field_name(&p, "type");
198 ff_amf_write_string(&p, "nonprivate");
200 ff_amf_write_field_name(&p, "flashVer");
201 ff_amf_write_string(&p, rt->flashver);
204 ff_amf_write_field_name(&p, "swfUrl");
205 ff_amf_write_string(&p, rt->swfurl);
208 ff_amf_write_field_name(&p, "tcUrl");
209 ff_amf_write_string(&p, rt->tcurl);
211 ff_amf_write_field_name(&p, "fpad");
212 ff_amf_write_bool(&p, 0);
213 ff_amf_write_field_name(&p, "capabilities");
214 ff_amf_write_number(&p, 15.0);
216 /* Tell the server we support all the audio codecs except
217 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
218 * which are unused in the RTMP protocol implementation. */
219 ff_amf_write_field_name(&p, "audioCodecs");
220 ff_amf_write_number(&p, 4071.0);
221 ff_amf_write_field_name(&p, "videoCodecs");
222 ff_amf_write_number(&p, 252.0);
223 ff_amf_write_field_name(&p, "videoFunction");
224 ff_amf_write_number(&p, 1.0);
226 ff_amf_write_object_end(&p);
229 char *param, *saveptr;
231 // Write arbitrary AMF data to the Connect message.
232 param = av_strtok(rt->conn, " ", &saveptr);
233 while (param != NULL) {
234 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
235 // Invalid AMF parameter.
236 ff_rtmp_packet_destroy(&pkt);
240 param = av_strtok(NULL, " ", &saveptr);
244 pkt.data_size = p - pkt.data;
246 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
248 ff_rtmp_packet_destroy(&pkt);
254 * Generate 'releaseStream' call and send it to the server. It should make
255 * the server release some channel for media streams.
257 static int gen_release_stream(URLContext *s, RTMPContext *rt)
263 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
264 0, 29 + strlen(rt->playpath))) < 0)
267 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
269 ff_amf_write_string(&p, "releaseStream");
270 ff_amf_write_number(&p, ++rt->nb_invokes);
271 ff_amf_write_null(&p);
272 ff_amf_write_string(&p, rt->playpath);
274 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
276 ff_rtmp_packet_destroy(&pkt);
282 * Generate 'FCPublish' call and send it to the server. It should make
283 * the server preapare for receiving media streams.
285 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
291 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
292 0, 25 + strlen(rt->playpath))) < 0)
295 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
297 ff_amf_write_string(&p, "FCPublish");
298 ff_amf_write_number(&p, ++rt->nb_invokes);
299 ff_amf_write_null(&p);
300 ff_amf_write_string(&p, rt->playpath);
302 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
304 ff_rtmp_packet_destroy(&pkt);
310 * Generate 'FCUnpublish' call and send it to the server. It should make
311 * the server destroy stream.
313 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
319 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
320 0, 27 + strlen(rt->playpath))) < 0)
323 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
325 ff_amf_write_string(&p, "FCUnpublish");
326 ff_amf_write_number(&p, ++rt->nb_invokes);
327 ff_amf_write_null(&p);
328 ff_amf_write_string(&p, rt->playpath);
330 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
332 ff_rtmp_packet_destroy(&pkt);
338 * Generate 'createStream' call and send it to the server. It should make
339 * the server allocate some channel for media streams.
341 static int gen_create_stream(URLContext *s, RTMPContext *rt)
347 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
349 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
354 ff_amf_write_string(&p, "createStream");
355 ff_amf_write_number(&p, ++rt->nb_invokes);
356 ff_amf_write_null(&p);
357 rt->create_stream_invoke = rt->nb_invokes;
359 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
361 ff_rtmp_packet_destroy(&pkt);
368 * Generate 'deleteStream' call and send it to the server. It should make
369 * the server remove some channel for media streams.
371 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
377 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
379 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
384 ff_amf_write_string(&p, "deleteStream");
385 ff_amf_write_number(&p, ++rt->nb_invokes);
386 ff_amf_write_null(&p);
387 ff_amf_write_number(&p, rt->main_channel_id);
389 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
391 ff_rtmp_packet_destroy(&pkt);
397 * Generate 'play' call and send it to the server, then ping the server
398 * to start actual playing.
400 static int gen_play(URLContext *s, RTMPContext *rt)
406 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
408 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
409 0, 29 + strlen(rt->playpath))) < 0)
412 pkt.extra = rt->main_channel_id;
415 ff_amf_write_string(&p, "play");
416 ff_amf_write_number(&p, ++rt->nb_invokes);
417 ff_amf_write_null(&p);
418 ff_amf_write_string(&p, rt->playpath);
419 ff_amf_write_number(&p, rt->live);
421 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
423 ff_rtmp_packet_destroy(&pkt);
428 // set client buffer time disguised in ping packet
429 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
434 bytestream_put_be16(&p, 3);
435 bytestream_put_be32(&p, 1);
436 bytestream_put_be32(&p, 256); //TODO: what is a good value here?
438 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
440 ff_rtmp_packet_destroy(&pkt);
446 * Generate 'publish' call and send it to the server.
448 static int gen_publish(URLContext *s, RTMPContext *rt)
454 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
456 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
457 0, 30 + strlen(rt->playpath))) < 0)
460 pkt.extra = rt->main_channel_id;
463 ff_amf_write_string(&p, "publish");
464 ff_amf_write_number(&p, ++rt->nb_invokes);
465 ff_amf_write_null(&p);
466 ff_amf_write_string(&p, rt->playpath);
467 ff_amf_write_string(&p, "live");
469 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
471 ff_rtmp_packet_destroy(&pkt);
477 * Generate ping reply and send it to the server.
479 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
485 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
486 ppkt->timestamp + 1, 6)) < 0)
490 bytestream_put_be16(&p, 7);
491 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
492 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
494 ff_rtmp_packet_destroy(&pkt);
500 * Generate server bandwidth message and send it to the server.
502 static int gen_server_bw(URLContext *s, RTMPContext *rt)
508 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
513 bytestream_put_be32(&p, 2500000);
514 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
516 ff_rtmp_packet_destroy(&pkt);
522 * Generate check bandwidth message and send it to the server.
524 static int gen_check_bw(URLContext *s, RTMPContext *rt)
530 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
535 ff_amf_write_string(&p, "_checkbw");
536 ff_amf_write_number(&p, ++rt->nb_invokes);
537 ff_amf_write_null(&p);
539 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
541 ff_rtmp_packet_destroy(&pkt);
547 * Generate report on bytes read so far and send it to the server.
549 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
555 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
560 bytestream_put_be32(&p, rt->bytes_read);
561 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
563 ff_rtmp_packet_destroy(&pkt);
568 //TODO: Move HMAC code somewhere. Eventually.
569 #define HMAC_IPAD_VAL 0x36
570 #define HMAC_OPAD_VAL 0x5C
573 * Calculate HMAC-SHA2 digest for RTMP handshake packets.
575 * @param src input buffer
576 * @param len input buffer length (should be 1536)
577 * @param gap offset in buffer where 32 bytes should not be taken into account
578 * when calculating digest (since it will be used to store that digest)
579 * @param key digest key
580 * @param keylen digest key length
581 * @param dst buffer where calculated digest will be stored (32 bytes)
583 static int rtmp_calc_digest(const uint8_t *src, int len, int gap,
584 const uint8_t *key, int keylen, uint8_t *dst)
587 uint8_t hmac_buf[64+32] = {0};
590 sha = av_mallocz(av_sha_size);
592 return AVERROR(ENOMEM);
595 memcpy(hmac_buf, key, keylen);
597 av_sha_init(sha, 256);
598 av_sha_update(sha,key, keylen);
599 av_sha_final(sha, hmac_buf);
601 for (i = 0; i < 64; i++)
602 hmac_buf[i] ^= HMAC_IPAD_VAL;
604 av_sha_init(sha, 256);
605 av_sha_update(sha, hmac_buf, 64);
607 av_sha_update(sha, src, len);
608 } else { //skip 32 bytes used for storing digest
609 av_sha_update(sha, src, gap);
610 av_sha_update(sha, src + gap + 32, len - gap - 32);
612 av_sha_final(sha, hmac_buf + 64);
614 for (i = 0; i < 64; i++)
615 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
616 av_sha_init(sha, 256);
617 av_sha_update(sha, hmac_buf, 64+32);
618 av_sha_final(sha, dst);
626 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
627 * will be stored) into that packet.
629 * @param buf handshake data (1536 bytes)
630 * @return offset to the digest inside input data
632 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
634 int i, digest_pos = 0;
637 for (i = 8; i < 12; i++)
638 digest_pos += buf[i];
639 digest_pos = (digest_pos % 728) + 12;
641 ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
642 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
651 * Verify that the received server response has the expected digest value.
653 * @param buf handshake data received from the server (1536 bytes)
654 * @param off position to search digest offset from
655 * @return 0 if digest is valid, digest position otherwise
657 static int rtmp_validate_digest(uint8_t *buf, int off)
659 int i, digest_pos = 0;
663 for (i = 0; i < 4; i++)
664 digest_pos += buf[i + off];
665 digest_pos = (digest_pos % 728) + off + 4;
667 ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
668 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
673 if (!memcmp(digest, buf + digest_pos, 32))
679 * Perform handshake with the server by means of exchanging pseudorandom data
680 * signed with HMAC-SHA2 digest.
682 * @return 0 if handshake succeeds, negative value otherwise
684 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
687 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
688 3, // unencrypted data
689 0, 0, 0, 0, // client uptime
695 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
696 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
698 int server_pos, client_pos;
702 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
704 av_lfg_init(&rnd, 0xDEADC0DE);
705 // generate handshake packet - 1536 bytes of pseudorandom data
706 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
707 tosend[i] = av_lfg_get(&rnd) >> 24;
708 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
712 if ((ret = ffurl_write(rt->stream, tosend,
713 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
714 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
718 if ((ret = ffurl_read_complete(rt->stream, serverdata,
719 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
720 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
724 if ((ret = ffurl_read_complete(rt->stream, clientdata,
725 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
726 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
730 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
731 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
733 if (rt->is_input && serverdata[5] >= 3) {
734 server_pos = rtmp_validate_digest(serverdata + 1, 772);
739 server_pos = rtmp_validate_digest(serverdata + 1, 8);
744 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
749 ret = rtmp_calc_digest(tosend + 1 + client_pos, 32, 0, rtmp_server_key,
750 sizeof(rtmp_server_key), digest);
754 ret = rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
759 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
760 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
764 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
765 tosend[i] = av_lfg_get(&rnd) >> 24;
766 ret = rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
767 rtmp_player_key, sizeof(rtmp_player_key),
772 ret = rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
774 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
778 // write reply back to the server
779 if ((ret = ffurl_write(rt->stream, tosend,
780 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
783 if ((ret = ffurl_write(rt->stream, serverdata + 1,
784 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
792 * Parse received packet and possibly perform some action depending on
793 * the packet contents.
794 * @return 0 for no errors, negative values for serious errors which prevent
795 * further communications, positive values for uncritical errors
797 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
800 const uint8_t *data_end = pkt->data + pkt->data_size;
804 ff_rtmp_packet_dump(s, pkt);
808 case RTMP_PT_CHUNK_SIZE:
809 if (pkt->data_size != 4) {
810 av_log(s, AV_LOG_ERROR,
811 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
815 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size,
816 rt->prev_pkt[1])) < 0)
818 rt->chunk_size = AV_RB32(pkt->data);
819 if (rt->chunk_size <= 0) {
820 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
823 av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
826 t = AV_RB16(pkt->data);
828 if ((ret = gen_pong(s, rt, pkt)) < 0)
831 case RTMP_PT_CLIENT_BW:
832 if (pkt->data_size < 4) {
833 av_log(s, AV_LOG_ERROR,
834 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
838 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
839 rt->client_report_size = AV_RB32(pkt->data) >> 1;
842 //TODO: check for the messages sent for wrong state?
843 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
846 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
847 "description", tmpstr, sizeof(tmpstr)))
848 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
850 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
852 case STATE_HANDSHAKED:
854 if ((ret = gen_release_stream(s, rt)) < 0)
856 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
858 rt->state = STATE_RELEASING;
860 if ((ret = gen_server_bw(s, rt)) < 0)
862 rt->state = STATE_CONNECTING;
864 if ((ret = gen_create_stream(s, rt)) < 0)
867 case STATE_FCPUBLISH:
868 rt->state = STATE_CONNECTING;
870 case STATE_RELEASING:
871 rt->state = STATE_FCPUBLISH;
872 /* hack for Wowza Media Server, it does not send result for
873 * releaseStream and FCPublish calls */
874 if (!pkt->data[10]) {
875 int pkt_id = av_int2double(AV_RB64(pkt->data + 11));
876 if (pkt_id == rt->create_stream_invoke)
877 rt->state = STATE_CONNECTING;
879 if (rt->state != STATE_CONNECTING)
881 case STATE_CONNECTING:
882 //extract a number from the result
883 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
884 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
886 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
889 if ((ret = gen_play(s, rt)) < 0)
892 if ((ret = gen_publish(s, rt)) < 0)
895 rt->state = STATE_READY;
898 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
899 const uint8_t* ptr = pkt->data + 11;
902 for (i = 0; i < 2; i++) {
903 t = ff_amf_tag_size(ptr, data_end);
908 t = ff_amf_get_field_value(ptr, data_end,
909 "level", tmpstr, sizeof(tmpstr));
910 if (!t && !strcmp(tmpstr, "error")) {
911 if (!ff_amf_get_field_value(ptr, data_end,
912 "description", tmpstr, sizeof(tmpstr)))
913 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
916 t = ff_amf_get_field_value(ptr, data_end,
917 "code", tmpstr, sizeof(tmpstr));
918 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
919 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
920 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
921 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
922 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
923 if ((ret = gen_check_bw(s, rt)) < 0)
932 * Interact with the server by receiving and sending RTMP packets until
933 * there is some significant data (media data or expected status notification).
935 * @param s reading context
936 * @param for_header non-zero value tells function to work until it
937 * gets notification from the server that playing has been started,
938 * otherwise function will work until some media data is received (or
940 * @return 0 for successful operation, negative value in case of error
942 static int get_packet(URLContext *s, int for_header)
944 RTMPContext *rt = s->priv_data;
949 uint32_t ts, cts, pts=0;
951 if (rt->state == STATE_STOPPED)
955 RTMPPacket rpkt = { 0 };
956 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
957 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
959 return AVERROR(EAGAIN);
964 rt->bytes_read += ret;
965 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
966 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
967 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
969 rt->last_bytes_read = rt->bytes_read;
972 ret = rtmp_parse_result(s, rt, &rpkt);
973 if (ret < 0) {//serious error in current packet
974 ff_rtmp_packet_destroy(&rpkt);
977 if (rt->state == STATE_STOPPED) {
978 ff_rtmp_packet_destroy(&rpkt);
981 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
982 ff_rtmp_packet_destroy(&rpkt);
985 if (!rpkt.data_size || !rt->is_input) {
986 ff_rtmp_packet_destroy(&rpkt);
989 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
990 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
993 // generate packet header and put data into buffer for FLV demuxer
995 rt->flv_size = rpkt.data_size + 15;
996 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
997 bytestream_put_byte(&p, rpkt.type);
998 bytestream_put_be24(&p, rpkt.data_size);
999 bytestream_put_be24(&p, ts);
1000 bytestream_put_byte(&p, ts >> 24);
1001 bytestream_put_be24(&p, 0);
1002 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1003 bytestream_put_be32(&p, 0);
1004 ff_rtmp_packet_destroy(&rpkt);
1006 } else if (rpkt.type == RTMP_PT_METADATA) {
1007 // we got raw FLV data, make it available for FLV demuxer
1009 rt->flv_size = rpkt.data_size;
1010 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1011 /* rewrite timestamps */
1013 ts = rpkt.timestamp;
1014 while (next - rpkt.data < rpkt.data_size - 11) {
1016 data_size = bytestream_get_be24(&next);
1018 cts = bytestream_get_be24(&next);
1019 cts |= bytestream_get_byte(&next) << 24;
1024 bytestream_put_be24(&p, ts);
1025 bytestream_put_byte(&p, ts >> 24);
1026 next += data_size + 3 + 4;
1028 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
1029 ff_rtmp_packet_destroy(&rpkt);
1032 ff_rtmp_packet_destroy(&rpkt);
1036 static int rtmp_close(URLContext *h)
1038 RTMPContext *rt = h->priv_data;
1041 if (!rt->is_input) {
1042 rt->flv_data = NULL;
1043 if (rt->out_pkt.data_size)
1044 ff_rtmp_packet_destroy(&rt->out_pkt);
1045 if (rt->state > STATE_FCPUBLISH)
1046 ret = gen_fcunpublish_stream(h, rt);
1048 if (rt->state > STATE_HANDSHAKED)
1049 ret = gen_delete_stream(h, rt);
1051 av_freep(&rt->flv_data);
1052 ffurl_close(rt->stream);
1057 * Open RTMP connection and verify that the stream can be played.
1059 * URL syntax: rtmp://server[:port][/app][/playpath]
1060 * where 'app' is first one or two directories in the path
1061 * (e.g. /ondemand/, /flash/live/, etc.)
1062 * and 'playpath' is a file name (the rest of the path,
1063 * may be prefixed with "mp4:")
1065 static int rtmp_open(URLContext *s, const char *uri, int flags)
1067 RTMPContext *rt = s->priv_data;
1068 char proto[8], hostname[256], path[1024], *fname;
1074 rt->is_input = !(flags & AVIO_FLAG_WRITE);
1076 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
1077 path, sizeof(path), s->filename);
1080 port = RTMP_DEFAULT_PORT;
1081 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
1083 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
1084 &s->interrupt_callback, NULL)) < 0) {
1085 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
1089 rt->state = STATE_START;
1090 if ((ret = rtmp_handshake(s, rt)) < 0)
1093 rt->chunk_size = 128;
1094 rt->state = STATE_HANDSHAKED;
1096 // Keep the application name when it has been defined by the user.
1099 rt->app = av_malloc(APP_MAX_LENGTH);
1101 ret = AVERROR(ENOMEM);
1105 //extract "app" part from path
1106 if (!strncmp(path, "/ondemand/", 10)) {
1108 memcpy(rt->app, "ondemand", 9);
1110 char *next = *path ? path + 1 : path;
1111 char *p = strchr(next, '/');
1116 // make sure we do not mismatch a playpath for an application instance
1117 char *c = strchr(p + 1, ':');
1118 fname = strchr(p + 1, '/');
1119 if (!fname || (c && c < fname)) {
1121 av_strlcpy(rt->app, path + 1, p - path);
1124 av_strlcpy(rt->app, path + 1, fname - path - 1);
1130 // The name of application has been defined by the user, override it.
1135 if (!rt->playpath) {
1136 int len = strlen(fname);
1138 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
1139 if (!rt->playpath) {
1140 ret = AVERROR(ENOMEM);
1144 if (!strchr(fname, ':') && len >= 4 &&
1145 (!strcmp(fname + len - 4, ".f4v") ||
1146 !strcmp(fname + len - 4, ".mp4"))) {
1147 memcpy(rt->playpath, "mp4:", 5);
1148 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
1149 fname[len - 4] = '\0';
1151 rt->playpath[0] = 0;
1153 strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
1157 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
1159 ret = AVERROR(ENOMEM);
1162 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
1163 port, "/%s", rt->app);
1166 if (!rt->flashver) {
1167 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
1168 if (!rt->flashver) {
1169 ret = AVERROR(ENOMEM);
1173 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
1174 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
1175 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
1177 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
1178 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
1182 rt->client_report_size = 1048576;
1184 rt->last_bytes_read = 0;
1186 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
1187 proto, path, rt->app, rt->playpath);
1188 if ((ret = gen_connect(s, rt)) < 0)
1192 ret = get_packet(s, 1);
1193 } while (ret == EAGAIN);
1198 // generate FLV header for demuxer
1200 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1202 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
1205 rt->flv_data = NULL;
1207 rt->skip_bytes = 13;
1210 s->max_packet_size = rt->stream->max_packet_size;
1219 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
1221 RTMPContext *rt = s->priv_data;
1222 int orig_size = size;
1226 int data_left = rt->flv_size - rt->flv_off;
1228 if (data_left >= size) {
1229 memcpy(buf, rt->flv_data + rt->flv_off, size);
1230 rt->flv_off += size;
1233 if (data_left > 0) {
1234 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
1237 rt->flv_off = rt->flv_size;
1240 if ((ret = get_packet(s, 0)) < 0)
1246 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
1248 RTMPContext *rt = s->priv_data;
1249 int size_temp = size;
1250 int pktsize, pkttype;
1252 const uint8_t *buf_temp = buf;
1256 if (rt->skip_bytes) {
1257 int skip = FFMIN(rt->skip_bytes, size_temp);
1260 rt->skip_bytes -= skip;
1264 if (rt->flv_header_bytes < 11) {
1265 const uint8_t *header = rt->flv_header;
1266 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
1267 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
1268 rt->flv_header_bytes += copy;
1270 if (rt->flv_header_bytes < 11)
1273 pkttype = bytestream_get_byte(&header);
1274 pktsize = bytestream_get_be24(&header);
1275 ts = bytestream_get_be24(&header);
1276 ts |= bytestream_get_byte(&header) << 24;
1277 bytestream_get_be24(&header);
1278 rt->flv_size = pktsize;
1280 //force 12bytes header
1281 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1282 pkttype == RTMP_PT_NOTIFY) {
1283 if (pkttype == RTMP_PT_NOTIFY)
1285 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1288 //this can be a big packet, it's better to send it right here
1289 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
1290 pkttype, ts, pktsize)) < 0)
1293 rt->out_pkt.extra = rt->main_channel_id;
1294 rt->flv_data = rt->out_pkt.data;
1296 if (pkttype == RTMP_PT_NOTIFY)
1297 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1300 if (rt->flv_size - rt->flv_off > size_temp) {
1301 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1302 rt->flv_off += size_temp;
1305 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
1306 size_temp -= rt->flv_size - rt->flv_off;
1307 rt->flv_off += rt->flv_size - rt->flv_off;
1310 if (rt->flv_off == rt->flv_size) {
1313 if ((ret = ff_rtmp_packet_write(rt->stream, &rt->out_pkt,
1314 rt->chunk_size, rt->prev_pkt[1])) < 0)
1316 ff_rtmp_packet_destroy(&rt->out_pkt);
1319 rt->flv_header_bytes = 0;
1321 } while (buf_temp - buf < size);
1325 #define OFFSET(x) offsetof(RTMPContext, x)
1326 #define DEC AV_OPT_FLAG_DECODING_PARAM
1327 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1329 static const AVOption rtmp_options[] = {
1330 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1331 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1332 {"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},
1333 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
1334 {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
1335 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"},
1336 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {0}, 0, 0, DEC, "rtmp_live"},
1337 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1338 {"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},
1339 {"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},
1343 static const AVClass rtmp_class = {
1344 .class_name = "rtmp",
1345 .item_name = av_default_item_name,
1346 .option = rtmp_options,
1347 .version = LIBAVUTIL_VERSION_INT,
1350 URLProtocol ff_rtmp_protocol = {
1352 .url_open = rtmp_open,
1353 .url_read = rtmp_read,
1354 .url_write = rtmp_write,
1355 .url_close = rtmp_close,
1356 .priv_data_size = sizeof(RTMPContext),
1357 .flags = URL_PROTOCOL_FLAG_NETWORK,
1358 .priv_data_class= &rtmp_class,