2 * RTMP network protocol
3 * Copyright (c) 2009 Kostya Shishkov
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/intfloat.h"
30 #include "libavutil/lfg.h"
31 #include "libavutil/opt.h"
32 #include "libavutil/sha.h"
40 #include "rtmpcrypt.h"
46 #define APP_MAX_LENGTH 128
47 #define PLAYPATH_MAX_LENGTH 256
48 #define TCURL_MAX_LENGTH 512
49 #define FLASHVER_MAX_LENGTH 64
51 /** RTMP protocol handler state */
53 STATE_START, ///< client has not done anything yet
54 STATE_HANDSHAKED, ///< client has performed handshake
55 STATE_RELEASING, ///< client releasing stream before publish it (for output)
56 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
57 STATE_CONNECTING, ///< client connected to server successfully
58 STATE_READY, ///< client has sent all needed commands and waits for server reply
59 STATE_PLAYING, ///< client has started receiving multimedia data from server
60 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
61 STATE_STOPPED, ///< the broadcast has been stopped
64 /** protocol handler context */
65 typedef struct RTMPContext {
67 URLContext* stream; ///< TCP stream used in interactions with RTMP server
68 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
69 int chunk_size; ///< size of the chunks RTMP packets are divided into
70 int is_input; ///< input/output flag
71 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
72 int live; ///< 0: recorded, -1: live, -2: both
73 char *app; ///< name of application
74 char *conn; ///< append arbitrary AMF data to the Connect message
75 ClientState state; ///< current state
76 int main_channel_id; ///< an additional channel ID which is used for some invocations
77 uint8_t* flv_data; ///< buffer with data for demuxer
78 int flv_size; ///< current buffer size
79 int flv_off; ///< number of bytes read from current buffer
80 int flv_nb_packets; ///< number of flv packets published
81 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
82 uint32_t client_report_size; ///< number of bytes after which client should report to server
83 uint32_t bytes_read; ///< number of bytes read from server
84 uint32_t last_bytes_read; ///< number of bytes read last reported to server
85 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
86 uint8_t flv_header[11]; ///< partial incoming flv packet header
87 int flv_header_bytes; ///< number of initialized bytes in flv_header
88 int nb_invokes; ///< keeps track of invoke messages
89 int create_stream_invoke; ///< invoke id for the create stream command
90 char* tcurl; ///< url of the target stream
91 char* flashver; ///< version of the flash plugin
92 char* swfurl; ///< url of the swf player
93 char* pageurl; ///< url of the web page
94 int server_bw; ///< server bandwidth
95 int client_buffer_time; ///< client buffer time in ms
96 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
97 int encrypted; ///< use an encrypted connection (RTMPE only)
100 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
101 /** Client key used for digest signing */
102 static const uint8_t rtmp_player_key[] = {
103 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
104 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
106 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
107 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
108 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
111 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
112 /** Key used for RTMP server digest signing */
113 static const uint8_t rtmp_server_key[] = {
114 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
115 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
116 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
118 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
119 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
120 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
123 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
128 /* The type must be B for Boolean, N for number, S for string, O for
129 * object, or Z for null. For Booleans the data must be either 0 or 1 for
130 * FALSE or TRUE, respectively. Likewise for Objects the data must be
131 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
132 * may be named, by prefixing the type with 'N' and specifying the name
133 * before the value (ie. NB:myFlag:1). This option may be used multiple times
134 * to construct arbitrary AMF sequences. */
135 if (param[0] && param[1] == ':') {
138 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
141 value = strchr(field, ':');
147 if (!field || !value)
150 ff_amf_write_field_name(p, field);
157 ff_amf_write_bool(p, value[0] != '0');
160 ff_amf_write_string(p, value);
163 ff_amf_write_number(p, strtod(value, NULL));
166 ff_amf_write_null(p);
170 ff_amf_write_object_start(p);
172 ff_amf_write_object_end(p);
182 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
183 return AVERROR(EINVAL);
187 * Generate 'connect' call and send it to the server.
189 static int gen_connect(URLContext *s, RTMPContext *rt)
195 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
201 ff_amf_write_string(&p, "connect");
202 ff_amf_write_number(&p, ++rt->nb_invokes);
203 ff_amf_write_object_start(&p);
204 ff_amf_write_field_name(&p, "app");
205 ff_amf_write_string(&p, rt->app);
208 ff_amf_write_field_name(&p, "type");
209 ff_amf_write_string(&p, "nonprivate");
211 ff_amf_write_field_name(&p, "flashVer");
212 ff_amf_write_string(&p, rt->flashver);
215 ff_amf_write_field_name(&p, "swfUrl");
216 ff_amf_write_string(&p, rt->swfurl);
219 ff_amf_write_field_name(&p, "tcUrl");
220 ff_amf_write_string(&p, rt->tcurl);
222 ff_amf_write_field_name(&p, "fpad");
223 ff_amf_write_bool(&p, 0);
224 ff_amf_write_field_name(&p, "capabilities");
225 ff_amf_write_number(&p, 15.0);
227 /* Tell the server we support all the audio codecs except
228 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
229 * which are unused in the RTMP protocol implementation. */
230 ff_amf_write_field_name(&p, "audioCodecs");
231 ff_amf_write_number(&p, 4071.0);
232 ff_amf_write_field_name(&p, "videoCodecs");
233 ff_amf_write_number(&p, 252.0);
234 ff_amf_write_field_name(&p, "videoFunction");
235 ff_amf_write_number(&p, 1.0);
238 ff_amf_write_field_name(&p, "pageUrl");
239 ff_amf_write_string(&p, rt->pageurl);
242 ff_amf_write_object_end(&p);
245 char *param = rt->conn;
247 // Write arbitrary AMF data to the Connect message.
248 while (param != NULL) {
250 param += strspn(param, " ");
253 sep = strchr(param, ' ');
256 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
257 // Invalid AMF parameter.
258 ff_rtmp_packet_destroy(&pkt);
269 pkt.data_size = p - pkt.data;
271 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
273 ff_rtmp_packet_destroy(&pkt);
279 * Generate 'releaseStream' call and send it to the server. It should make
280 * the server release some channel for media streams.
282 static int gen_release_stream(URLContext *s, RTMPContext *rt)
288 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
289 0, 29 + strlen(rt->playpath))) < 0)
292 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
294 ff_amf_write_string(&p, "releaseStream");
295 ff_amf_write_number(&p, ++rt->nb_invokes);
296 ff_amf_write_null(&p);
297 ff_amf_write_string(&p, rt->playpath);
299 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
301 ff_rtmp_packet_destroy(&pkt);
307 * Generate 'FCPublish' call and send it to the server. It should make
308 * the server preapare for receiving media streams.
310 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
316 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
317 0, 25 + strlen(rt->playpath))) < 0)
320 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
322 ff_amf_write_string(&p, "FCPublish");
323 ff_amf_write_number(&p, ++rt->nb_invokes);
324 ff_amf_write_null(&p);
325 ff_amf_write_string(&p, rt->playpath);
327 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
329 ff_rtmp_packet_destroy(&pkt);
335 * Generate 'FCUnpublish' call and send it to the server. It should make
336 * the server destroy stream.
338 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
344 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
345 0, 27 + strlen(rt->playpath))) < 0)
348 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
350 ff_amf_write_string(&p, "FCUnpublish");
351 ff_amf_write_number(&p, ++rt->nb_invokes);
352 ff_amf_write_null(&p);
353 ff_amf_write_string(&p, rt->playpath);
355 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
357 ff_rtmp_packet_destroy(&pkt);
363 * Generate 'createStream' call and send it to the server. It should make
364 * the server allocate some channel for media streams.
366 static int gen_create_stream(URLContext *s, RTMPContext *rt)
372 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
374 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
379 ff_amf_write_string(&p, "createStream");
380 ff_amf_write_number(&p, ++rt->nb_invokes);
381 ff_amf_write_null(&p);
382 rt->create_stream_invoke = rt->nb_invokes;
384 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
386 ff_rtmp_packet_destroy(&pkt);
393 * Generate 'deleteStream' call and send it to the server. It should make
394 * the server remove some channel for media streams.
396 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
402 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
404 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
409 ff_amf_write_string(&p, "deleteStream");
410 ff_amf_write_number(&p, ++rt->nb_invokes);
411 ff_amf_write_null(&p);
412 ff_amf_write_number(&p, rt->main_channel_id);
414 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
416 ff_rtmp_packet_destroy(&pkt);
422 * Generate client buffer time and send it to the server.
424 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
430 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
435 bytestream_put_be16(&p, 3);
436 bytestream_put_be32(&p, rt->main_channel_id);
437 bytestream_put_be32(&p, rt->client_buffer_time);
439 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
441 ff_rtmp_packet_destroy(&pkt);
447 * Generate 'play' call and send it to the server, then ping the server
448 * to start actual playing.
450 static int gen_play(URLContext *s, RTMPContext *rt)
456 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
458 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
459 0, 29 + strlen(rt->playpath))) < 0)
462 pkt.extra = rt->main_channel_id;
465 ff_amf_write_string(&p, "play");
466 ff_amf_write_number(&p, ++rt->nb_invokes);
467 ff_amf_write_null(&p);
468 ff_amf_write_string(&p, rt->playpath);
469 ff_amf_write_number(&p, rt->live);
471 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
473 ff_rtmp_packet_destroy(&pkt);
479 * Generate 'publish' call and send it to the server.
481 static int gen_publish(URLContext *s, RTMPContext *rt)
487 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
489 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
490 0, 30 + strlen(rt->playpath))) < 0)
493 pkt.extra = rt->main_channel_id;
496 ff_amf_write_string(&p, "publish");
497 ff_amf_write_number(&p, ++rt->nb_invokes);
498 ff_amf_write_null(&p);
499 ff_amf_write_string(&p, rt->playpath);
500 ff_amf_write_string(&p, "live");
502 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
504 ff_rtmp_packet_destroy(&pkt);
510 * Generate ping reply and send it to the server.
512 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
518 if (ppkt->data_size < 6) {
519 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
521 return AVERROR_INVALIDDATA;
524 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
525 ppkt->timestamp + 1, 6)) < 0)
529 bytestream_put_be16(&p, 7);
530 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
531 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
533 ff_rtmp_packet_destroy(&pkt);
539 * Generate server bandwidth message and send it to the server.
541 static int gen_server_bw(URLContext *s, RTMPContext *rt)
547 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
552 bytestream_put_be32(&p, rt->server_bw);
553 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
555 ff_rtmp_packet_destroy(&pkt);
561 * Generate check bandwidth message and send it to the server.
563 static int gen_check_bw(URLContext *s, RTMPContext *rt)
569 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
574 ff_amf_write_string(&p, "_checkbw");
575 ff_amf_write_number(&p, ++rt->nb_invokes);
576 ff_amf_write_null(&p);
578 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
580 ff_rtmp_packet_destroy(&pkt);
586 * Generate report on bytes read so far and send it to the server.
588 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
594 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
599 bytestream_put_be32(&p, rt->bytes_read);
600 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
602 ff_rtmp_packet_destroy(&pkt);
607 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
608 const uint8_t *key, int keylen, uint8_t *dst)
611 uint8_t hmac_buf[64+32] = {0};
614 sha = av_mallocz(av_sha_size);
616 return AVERROR(ENOMEM);
619 memcpy(hmac_buf, key, keylen);
621 av_sha_init(sha, 256);
622 av_sha_update(sha,key, keylen);
623 av_sha_final(sha, hmac_buf);
625 for (i = 0; i < 64; i++)
626 hmac_buf[i] ^= HMAC_IPAD_VAL;
628 av_sha_init(sha, 256);
629 av_sha_update(sha, hmac_buf, 64);
631 av_sha_update(sha, src, len);
632 } else { //skip 32 bytes used for storing digest
633 av_sha_update(sha, src, gap);
634 av_sha_update(sha, src + gap + 32, len - gap - 32);
636 av_sha_final(sha, hmac_buf + 64);
638 for (i = 0; i < 64; i++)
639 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
640 av_sha_init(sha, 256);
641 av_sha_update(sha, hmac_buf, 64+32);
642 av_sha_final(sha, dst);
649 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
652 int i, digest_pos = 0;
654 for (i = 0; i < 4; i++)
655 digest_pos += buf[i + off];
656 digest_pos = digest_pos % mod_val + add_val;
662 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
663 * will be stored) into that packet.
665 * @param buf handshake data (1536 bytes)
666 * @param encrypted use an encrypted connection (RTMPE)
667 * @return offset to the digest inside input data
669 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
674 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
676 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
678 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
679 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
688 * Verify that the received server response has the expected digest value.
690 * @param buf handshake data received from the server (1536 bytes)
691 * @param off position to search digest offset from
692 * @return 0 if digest is valid, digest position otherwise
694 static int rtmp_validate_digest(uint8_t *buf, int off)
699 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
701 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
702 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
707 if (!memcmp(digest, buf + digest_pos, 32))
713 * Perform handshake with the server by means of exchanging pseudorandom data
714 * signed with HMAC-SHA2 digest.
716 * @return 0 if handshake succeeds, negative value otherwise
718 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
721 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
722 3, // unencrypted data
723 0, 0, 0, 0, // client uptime
729 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
730 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
732 int server_pos, client_pos;
733 uint8_t digest[32], signature[32];
736 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
738 av_lfg_init(&rnd, 0xDEADC0DE);
739 // generate handshake packet - 1536 bytes of pseudorandom data
740 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
741 tosend[i] = av_lfg_get(&rnd) >> 24;
743 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
744 /* When the client wants to use RTMPE, we have to change the command
745 * byte to 0x06 which means to use encrypted data and we have to set
746 * the flash version to at least 9.0.115.0. */
753 /* Initialize the Diffie-Hellmann context and generate the public key
754 * to send to the server. */
755 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
759 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
763 if ((ret = ffurl_write(rt->stream, tosend,
764 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
765 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
769 if ((ret = ffurl_read_complete(rt->stream, serverdata,
770 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
771 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
775 if ((ret = ffurl_read_complete(rt->stream, clientdata,
776 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
777 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
781 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
782 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
783 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
785 if (rt->is_input && serverdata[5] >= 3) {
786 server_pos = rtmp_validate_digest(serverdata + 1, 772);
792 server_pos = rtmp_validate_digest(serverdata + 1, 8);
797 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
802 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
803 rtmp_server_key, sizeof(rtmp_server_key),
808 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
809 0, digest, 32, signature);
813 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
814 /* Compute the shared secret key sent by the server and initialize
815 * the RC4 encryption. */
816 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
817 tosend + 1, type)) < 0)
820 /* Encrypt the signature received by the server. */
821 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
824 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
825 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
829 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
830 tosend[i] = av_lfg_get(&rnd) >> 24;
831 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
832 rtmp_player_key, sizeof(rtmp_player_key),
837 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
839 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
843 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
844 /* Encrypt the signature to be send to the server. */
845 ff_rtmpe_encrypt_sig(rt->stream, tosend +
846 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
850 // write reply back to the server
851 if ((ret = ffurl_write(rt->stream, tosend,
852 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
855 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
856 /* Set RC4 keys for encryption and update the keystreams. */
857 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
861 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
862 /* Compute the shared secret key sent by the server and initialize
863 * the RC4 encryption. */
864 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
868 if (serverdata[0] == 9) {
869 /* Encrypt the signature received by the server. */
870 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
875 if ((ret = ffurl_write(rt->stream, serverdata + 1,
876 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
879 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
880 /* Set RC4 keys for encryption and update the keystreams. */
881 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
889 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
891 RTMPContext *rt = s->priv_data;
894 if (pkt->data_size < 4) {
895 av_log(s, AV_LOG_ERROR,
896 "Too short chunk size change packet (%d)\n",
898 return AVERROR_INVALIDDATA;
902 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size,
903 rt->prev_pkt[1])) < 0)
907 rt->chunk_size = AV_RB32(pkt->data);
908 if (rt->chunk_size <= 0) {
909 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
910 return AVERROR_INVALIDDATA;
912 av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
917 static int handle_ping(URLContext *s, RTMPPacket *pkt)
919 RTMPContext *rt = s->priv_data;
922 if (pkt->data_size < 2) {
923 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
925 return AVERROR_INVALIDDATA;
928 t = AV_RB16(pkt->data);
930 if ((ret = gen_pong(s, rt, pkt)) < 0)
937 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
939 RTMPContext *rt = s->priv_data;
941 if (pkt->data_size < 4) {
942 av_log(s, AV_LOG_ERROR,
943 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
945 return AVERROR_INVALIDDATA;
948 rt->client_report_size = AV_RB32(pkt->data);
949 if (rt->client_report_size <= 0) {
950 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
951 rt->client_report_size);
952 return AVERROR_INVALIDDATA;
955 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
956 rt->client_report_size >>= 1;
961 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
963 RTMPContext *rt = s->priv_data;
965 if (pkt->data_size < 4) {
966 av_log(s, AV_LOG_ERROR,
967 "Too short server bandwidth report packet (%d)\n",
969 return AVERROR_INVALIDDATA;
972 rt->server_bw = AV_RB32(pkt->data);
973 if (rt->server_bw <= 0) {
974 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
976 return AVERROR_INVALIDDATA;
978 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
983 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
985 RTMPContext *rt = s->priv_data;
987 const uint8_t *data_end = pkt->data + pkt->data_size;
990 //TODO: check for the messages sent for wrong state?
991 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
994 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
995 "description", tmpstr, sizeof(tmpstr)))
996 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
998 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
1000 case STATE_HANDSHAKED:
1001 if (!rt->is_input) {
1002 if ((ret = gen_release_stream(s, rt)) < 0)
1004 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
1006 rt->state = STATE_RELEASING;
1008 if ((ret = gen_server_bw(s, rt)) < 0)
1010 rt->state = STATE_CONNECTING;
1012 if ((ret = gen_create_stream(s, rt)) < 0)
1015 case STATE_FCPUBLISH:
1016 rt->state = STATE_CONNECTING;
1018 case STATE_RELEASING:
1019 rt->state = STATE_FCPUBLISH;
1020 /* hack for Wowza Media Server, it does not send result for
1021 * releaseStream and FCPublish calls */
1022 if (!pkt->data[10]) {
1023 int pkt_id = av_int2double(AV_RB64(pkt->data + 11));
1024 if (pkt_id == rt->create_stream_invoke)
1025 rt->state = STATE_CONNECTING;
1027 if (rt->state != STATE_CONNECTING)
1029 case STATE_CONNECTING:
1030 //extract a number from the result
1031 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
1032 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
1034 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
1037 if ((ret = gen_play(s, rt)) < 0)
1039 if ((ret = gen_buffer_time(s, rt)) < 0)
1042 if ((ret = gen_publish(s, rt)) < 0)
1045 rt->state = STATE_READY;
1048 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
1049 const uint8_t* ptr = pkt->data + 11;
1050 uint8_t tmpstr[256];
1052 for (i = 0; i < 2; i++) {
1053 t = ff_amf_tag_size(ptr, data_end);
1058 t = ff_amf_get_field_value(ptr, data_end,
1059 "level", tmpstr, sizeof(tmpstr));
1060 if (!t && !strcmp(tmpstr, "error")) {
1061 if (!ff_amf_get_field_value(ptr, data_end,
1062 "description", tmpstr, sizeof(tmpstr)))
1063 av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
1066 t = ff_amf_get_field_value(ptr, data_end,
1067 "code", tmpstr, sizeof(tmpstr));
1068 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
1069 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
1070 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
1071 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
1072 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
1073 if ((ret = gen_check_bw(s, rt)) < 0)
1081 * Parse received packet and possibly perform some action depending on
1082 * the packet contents.
1083 * @return 0 for no errors, negative values for serious errors which prevent
1084 * further communications, positive values for uncritical errors
1086 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
1091 ff_rtmp_packet_dump(s, pkt);
1094 switch (pkt->type) {
1095 case RTMP_PT_CHUNK_SIZE:
1096 if ((ret = handle_chunk_size(s, pkt)) < 0)
1100 if ((ret = handle_ping(s, pkt)) < 0)
1103 case RTMP_PT_CLIENT_BW:
1104 if ((ret = handle_client_bw(s, pkt)) < 0)
1107 case RTMP_PT_SERVER_BW:
1108 if ((ret = handle_server_bw(s, pkt)) < 0)
1111 case RTMP_PT_INVOKE:
1112 if ((ret = handle_invoke(s, pkt)) < 0)
1117 case RTMP_PT_METADATA:
1118 /* Audio, Video and Metadata packets are parsed in get_packet() */
1121 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
1128 * Interact with the server by receiving and sending RTMP packets until
1129 * there is some significant data (media data or expected status notification).
1131 * @param s reading context
1132 * @param for_header non-zero value tells function to work until it
1133 * gets notification from the server that playing has been started,
1134 * otherwise function will work until some media data is received (or
1136 * @return 0 for successful operation, negative value in case of error
1138 static int get_packet(URLContext *s, int for_header)
1140 RTMPContext *rt = s->priv_data;
1143 const uint8_t *next;
1145 uint32_t ts, cts, pts=0;
1147 if (rt->state == STATE_STOPPED)
1151 RTMPPacket rpkt = { 0 };
1152 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
1153 rt->chunk_size, rt->prev_pkt[0])) <= 0) {
1155 return AVERROR(EAGAIN);
1157 return AVERROR(EIO);
1160 rt->bytes_read += ret;
1161 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
1162 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
1163 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
1165 rt->last_bytes_read = rt->bytes_read;
1168 ret = rtmp_parse_result(s, rt, &rpkt);
1169 if (ret < 0) {//serious error in current packet
1170 ff_rtmp_packet_destroy(&rpkt);
1173 if (rt->state == STATE_STOPPED) {
1174 ff_rtmp_packet_destroy(&rpkt);
1177 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
1178 ff_rtmp_packet_destroy(&rpkt);
1181 if (!rpkt.data_size || !rt->is_input) {
1182 ff_rtmp_packet_destroy(&rpkt);
1185 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
1186 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
1187 ts = rpkt.timestamp;
1189 // generate packet header and put data into buffer for FLV demuxer
1191 rt->flv_size = rpkt.data_size + 15;
1192 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
1193 bytestream_put_byte(&p, rpkt.type);
1194 bytestream_put_be24(&p, rpkt.data_size);
1195 bytestream_put_be24(&p, ts);
1196 bytestream_put_byte(&p, ts >> 24);
1197 bytestream_put_be24(&p, 0);
1198 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1199 bytestream_put_be32(&p, 0);
1200 ff_rtmp_packet_destroy(&rpkt);
1202 } else if (rpkt.type == RTMP_PT_METADATA) {
1203 // we got raw FLV data, make it available for FLV demuxer
1205 rt->flv_size = rpkt.data_size;
1206 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1207 /* rewrite timestamps */
1209 ts = rpkt.timestamp;
1210 while (next - rpkt.data < rpkt.data_size - 11) {
1212 data_size = bytestream_get_be24(&next);
1214 cts = bytestream_get_be24(&next);
1215 cts |= bytestream_get_byte(&next) << 24;
1220 bytestream_put_be24(&p, ts);
1221 bytestream_put_byte(&p, ts >> 24);
1222 next += data_size + 3 + 4;
1224 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
1225 ff_rtmp_packet_destroy(&rpkt);
1228 ff_rtmp_packet_destroy(&rpkt);
1232 static int rtmp_close(URLContext *h)
1234 RTMPContext *rt = h->priv_data;
1237 if (!rt->is_input) {
1238 rt->flv_data = NULL;
1239 if (rt->out_pkt.data_size)
1240 ff_rtmp_packet_destroy(&rt->out_pkt);
1241 if (rt->state > STATE_FCPUBLISH)
1242 ret = gen_fcunpublish_stream(h, rt);
1244 if (rt->state > STATE_HANDSHAKED)
1245 ret = gen_delete_stream(h, rt);
1247 av_freep(&rt->flv_data);
1248 ffurl_close(rt->stream);
1253 * Open RTMP connection and verify that the stream can be played.
1255 * URL syntax: rtmp://server[:port][/app][/playpath]
1256 * where 'app' is first one or two directories in the path
1257 * (e.g. /ondemand/, /flash/live/, etc.)
1258 * and 'playpath' is a file name (the rest of the path,
1259 * may be prefixed with "mp4:")
1261 static int rtmp_open(URLContext *s, const char *uri, int flags)
1263 RTMPContext *rt = s->priv_data;
1264 char proto[8], hostname[256], path[1024], *fname;
1268 AVDictionary *opts = NULL;
1271 rt->is_input = !(flags & AVIO_FLAG_WRITE);
1273 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
1274 path, sizeof(path), s->filename);
1276 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
1277 if (!strcmp(proto, "rtmpts"))
1278 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
1280 /* open the http tunneling connection */
1281 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
1282 } else if (!strcmp(proto, "rtmps")) {
1283 /* open the tls connection */
1285 port = RTMPS_DEFAULT_PORT;
1286 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
1287 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
1288 if (!strcmp(proto, "rtmpte"))
1289 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
1291 /* open the encrypted connection */
1292 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
1295 /* open the tcp connection */
1297 port = RTMP_DEFAULT_PORT;
1298 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
1301 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
1302 &s->interrupt_callback, &opts)) < 0) {
1303 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
1307 rt->state = STATE_START;
1308 if ((ret = rtmp_handshake(s, rt)) < 0)
1311 rt->chunk_size = 128;
1312 rt->state = STATE_HANDSHAKED;
1314 // Keep the application name when it has been defined by the user.
1317 rt->app = av_malloc(APP_MAX_LENGTH);
1319 ret = AVERROR(ENOMEM);
1323 //extract "app" part from path
1324 if (!strncmp(path, "/ondemand/", 10)) {
1326 memcpy(rt->app, "ondemand", 9);
1328 char *next = *path ? path + 1 : path;
1329 char *p = strchr(next, '/');
1334 // make sure we do not mismatch a playpath for an application instance
1335 char *c = strchr(p + 1, ':');
1336 fname = strchr(p + 1, '/');
1337 if (!fname || (c && c < fname)) {
1339 av_strlcpy(rt->app, path + 1, p - path);
1342 av_strlcpy(rt->app, path + 1, fname - path - 1);
1348 // The name of application has been defined by the user, override it.
1353 if (!rt->playpath) {
1354 int len = strlen(fname);
1356 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
1357 if (!rt->playpath) {
1358 ret = AVERROR(ENOMEM);
1362 if (!strchr(fname, ':') && len >= 4 &&
1363 (!strcmp(fname + len - 4, ".f4v") ||
1364 !strcmp(fname + len - 4, ".mp4"))) {
1365 memcpy(rt->playpath, "mp4:", 5);
1366 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
1367 fname[len - 4] = '\0';
1369 rt->playpath[0] = 0;
1371 strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
1375 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
1377 ret = AVERROR(ENOMEM);
1380 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
1381 port, "/%s", rt->app);
1384 if (!rt->flashver) {
1385 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
1386 if (!rt->flashver) {
1387 ret = AVERROR(ENOMEM);
1391 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
1392 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
1393 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
1395 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
1396 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
1400 rt->client_report_size = 1048576;
1402 rt->last_bytes_read = 0;
1403 rt->server_bw = 2500000;
1405 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
1406 proto, path, rt->app, rt->playpath);
1407 if ((ret = gen_connect(s, rt)) < 0)
1411 ret = get_packet(s, 1);
1412 } while (ret == EAGAIN);
1417 // generate FLV header for demuxer
1419 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1421 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
1424 rt->flv_data = NULL;
1426 rt->skip_bytes = 13;
1429 s->max_packet_size = rt->stream->max_packet_size;
1434 av_dict_free(&opts);
1439 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
1441 RTMPContext *rt = s->priv_data;
1442 int orig_size = size;
1446 int data_left = rt->flv_size - rt->flv_off;
1448 if (data_left >= size) {
1449 memcpy(buf, rt->flv_data + rt->flv_off, size);
1450 rt->flv_off += size;
1453 if (data_left > 0) {
1454 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
1457 rt->flv_off = rt->flv_size;
1460 if ((ret = get_packet(s, 0)) < 0)
1466 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
1468 RTMPContext *rt = s->priv_data;
1469 int size_temp = size;
1470 int pktsize, pkttype;
1472 const uint8_t *buf_temp = buf;
1477 if (rt->skip_bytes) {
1478 int skip = FFMIN(rt->skip_bytes, size_temp);
1481 rt->skip_bytes -= skip;
1485 if (rt->flv_header_bytes < 11) {
1486 const uint8_t *header = rt->flv_header;
1487 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
1488 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
1489 rt->flv_header_bytes += copy;
1491 if (rt->flv_header_bytes < 11)
1494 pkttype = bytestream_get_byte(&header);
1495 pktsize = bytestream_get_be24(&header);
1496 ts = bytestream_get_be24(&header);
1497 ts |= bytestream_get_byte(&header) << 24;
1498 bytestream_get_be24(&header);
1499 rt->flv_size = pktsize;
1501 //force 12bytes header
1502 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1503 pkttype == RTMP_PT_NOTIFY) {
1504 if (pkttype == RTMP_PT_NOTIFY)
1506 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1509 //this can be a big packet, it's better to send it right here
1510 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
1511 pkttype, ts, pktsize)) < 0)
1514 rt->out_pkt.extra = rt->main_channel_id;
1515 rt->flv_data = rt->out_pkt.data;
1517 if (pkttype == RTMP_PT_NOTIFY)
1518 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1521 if (rt->flv_size - rt->flv_off > size_temp) {
1522 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1523 rt->flv_off += size_temp;
1526 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
1527 size_temp -= rt->flv_size - rt->flv_off;
1528 rt->flv_off += rt->flv_size - rt->flv_off;
1531 if (rt->flv_off == rt->flv_size) {
1534 if ((ret = ff_rtmp_packet_write(rt->stream, &rt->out_pkt,
1535 rt->chunk_size, rt->prev_pkt[1])) < 0)
1537 ff_rtmp_packet_destroy(&rt->out_pkt);
1540 rt->flv_header_bytes = 0;
1541 rt->flv_nb_packets++;
1543 } while (buf_temp - buf < size);
1545 if (rt->flv_nb_packets < rt->flush_interval)
1547 rt->flv_nb_packets = 0;
1549 /* set stream into nonblocking mode */
1550 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
1552 /* try to read one byte from the stream */
1553 ret = ffurl_read(rt->stream, &c, 1);
1555 /* switch the stream back into blocking mode */
1556 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
1558 if (ret == AVERROR(EAGAIN)) {
1559 /* no incoming data to handle */
1561 } else if (ret < 0) {
1563 } else if (ret == 1) {
1564 RTMPPacket rpkt = { 0 };
1566 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
1568 rt->prev_pkt[0], c)) <= 0)
1571 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
1574 ff_rtmp_packet_destroy(&rpkt);
1580 #define OFFSET(x) offsetof(RTMPContext, x)
1581 #define DEC AV_OPT_FLAG_DECODING_PARAM
1582 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1584 static const AVOption rtmp_options[] = {
1585 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1586 {"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},
1587 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1588 {"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},
1589 {"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},
1590 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
1591 {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
1592 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"},
1593 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {0}, 0, 0, DEC, "rtmp_live"},
1594 {"rtmp_pageurl", "URL of the web page in which the media was embedded. By default no value will be sent.", OFFSET(pageurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
1595 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1596 {"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},
1597 {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1601 static const AVClass rtmp_class = {
1602 .class_name = "rtmp",
1603 .item_name = av_default_item_name,
1604 .option = rtmp_options,
1605 .version = LIBAVUTIL_VERSION_INT,
1608 URLProtocol ff_rtmp_protocol = {
1610 .url_open = rtmp_open,
1611 .url_read = rtmp_read,
1612 .url_write = rtmp_write,
1613 .url_close = rtmp_close,
1614 .priv_data_size = sizeof(RTMPContext),
1615 .flags = URL_PROTOCOL_FLAG_NETWORK,
1616 .priv_data_class= &rtmp_class,
1619 static const AVClass rtmpe_class = {
1620 .class_name = "rtmpe",
1621 .item_name = av_default_item_name,
1622 .option = rtmp_options,
1623 .version = LIBAVUTIL_VERSION_INT,
1626 URLProtocol ff_rtmpe_protocol = {
1628 .url_open = rtmp_open,
1629 .url_read = rtmp_read,
1630 .url_write = rtmp_write,
1631 .url_close = rtmp_close,
1632 .priv_data_size = sizeof(RTMPContext),
1633 .flags = URL_PROTOCOL_FLAG_NETWORK,
1634 .priv_data_class = &rtmpe_class,
1637 static const AVClass rtmps_class = {
1638 .class_name = "rtmps",
1639 .item_name = av_default_item_name,
1640 .option = rtmp_options,
1641 .version = LIBAVUTIL_VERSION_INT,
1644 URLProtocol ff_rtmps_protocol = {
1646 .url_open = rtmp_open,
1647 .url_read = rtmp_read,
1648 .url_write = rtmp_write,
1649 .url_close = rtmp_close,
1650 .priv_data_size = sizeof(RTMPContext),
1651 .flags = URL_PROTOCOL_FLAG_NETWORK,
1652 .priv_data_class = &rtmps_class,
1655 static const AVClass rtmpt_class = {
1656 .class_name = "rtmpt",
1657 .item_name = av_default_item_name,
1658 .option = rtmp_options,
1659 .version = LIBAVUTIL_VERSION_INT,
1662 URLProtocol ff_rtmpt_protocol = {
1664 .url_open = rtmp_open,
1665 .url_read = rtmp_read,
1666 .url_write = rtmp_write,
1667 .url_close = rtmp_close,
1668 .priv_data_size = sizeof(RTMPContext),
1669 .flags = URL_PROTOCOL_FLAG_NETWORK,
1670 .priv_data_class = &rtmpt_class,
1673 static const AVClass rtmpte_class = {
1674 .class_name = "rtmpte",
1675 .item_name = av_default_item_name,
1676 .option = rtmp_options,
1677 .version = LIBAVUTIL_VERSION_INT,
1680 URLProtocol ff_rtmpte_protocol = {
1682 .url_open = rtmp_open,
1683 .url_read = rtmp_read,
1684 .url_write = rtmp_write,
1685 .url_close = rtmp_close,
1686 .priv_data_size = sizeof(RTMPContext),
1687 .flags = URL_PROTOCOL_FLAG_NETWORK,
1688 .priv_data_class = &rtmpte_class,
1691 static const AVClass rtmpts_class = {
1692 .class_name = "rtmpts",
1693 .item_name = av_default_item_name,
1694 .option = rtmp_options,
1695 .version = LIBAVUTIL_VERSION_INT,
1698 URLProtocol ff_rtmpts_protocol = {
1700 .url_open = rtmp_open,
1701 .url_read = rtmp_read,
1702 .url_write = rtmp_write,
1703 .url_close = rtmp_close,
1704 .priv_data_size = sizeof(RTMPContext),
1705 .flags = URL_PROTOCOL_FLAG_NETWORK,
1706 .priv_data_class = &rtmpts_class,