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"
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_FCPUBLISH, ///< client FCPublishing stream (for output)
56 STATE_PLAYING, ///< client has started receiving multimedia data from server
57 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
58 STATE_STOPPED, ///< the broadcast has been stopped
61 typedef struct TrackedMethod {
66 /** protocol handler context */
67 typedef struct RTMPContext {
69 URLContext* stream; ///< TCP stream used in interactions with RTMP server
70 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
71 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
72 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
73 int is_input; ///< input/output flag
74 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
75 int live; ///< 0: recorded, -1: live, -2: both
76 char *app; ///< name of application
77 char *conn; ///< append arbitrary AMF data to the Connect message
78 ClientState state; ///< current state
79 int main_channel_id; ///< an additional channel ID which is used for some invocations
80 uint8_t* flv_data; ///< buffer with data for demuxer
81 int flv_size; ///< current buffer size
82 int flv_off; ///< number of bytes read from current buffer
83 int flv_nb_packets; ///< number of flv packets published
84 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
85 uint32_t client_report_size; ///< number of bytes after which client should report to server
86 uint32_t bytes_read; ///< number of bytes read from server
87 uint32_t last_bytes_read; ///< number of bytes read last reported to server
88 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
89 uint8_t flv_header[11]; ///< partial incoming flv packet header
90 int flv_header_bytes; ///< number of initialized bytes in flv_header
91 int nb_invokes; ///< keeps track of invoke messages
92 char* tcurl; ///< url of the target stream
93 char* flashver; ///< version of the flash plugin
94 char* swfurl; ///< url of the swf player
95 char* pageurl; ///< url of the web page
96 char* subscribe; ///< name of live stream to subscribe
97 int server_bw; ///< server bandwidth
98 int client_buffer_time; ///< client buffer time in ms
99 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
100 int encrypted; ///< use an encrypted connection (RTMPE only)
101 TrackedMethod*tracked_methods; ///< tracked methods buffer
102 int nb_tracked_methods; ///< number of tracked methods
103 int tracked_methods_size; ///< size of the tracked methods buffer
106 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
107 /** Client key used for digest signing */
108 static const uint8_t rtmp_player_key[] = {
109 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
110 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
112 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
113 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
114 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
117 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
118 /** Key used for RTMP server digest signing */
119 static const uint8_t rtmp_server_key[] = {
120 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
121 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
122 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
124 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
125 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
126 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
129 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
133 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
134 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
135 ptr = av_realloc(rt->tracked_methods,
136 rt->tracked_methods_size * sizeof(*rt->tracked_methods));
138 return AVERROR(ENOMEM);
139 rt->tracked_methods = ptr;
142 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
143 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
144 return AVERROR(ENOMEM);
145 rt->tracked_methods[rt->nb_tracked_methods].id = id;
146 rt->nb_tracked_methods++;
151 static void del_tracked_method(RTMPContext *rt, int index)
153 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
154 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
155 rt->nb_tracked_methods--;
158 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
159 char **tracked_method)
161 RTMPContext *rt = s->priv_data;
167 bytestream2_init(&gbc, pkt->data + offset, pkt->data_size - offset);
168 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
171 for (i = 0; i < rt->nb_tracked_methods; i++) {
172 if (rt->tracked_methods[i].id != pkt_id)
175 *tracked_method = rt->tracked_methods[i].name;
176 del_tracked_method(rt, i);
183 static void free_tracked_methods(RTMPContext *rt)
187 for (i = 0; i < rt->nb_tracked_methods; i ++)
188 av_free(rt->tracked_methods[i].name);
189 av_free(rt->tracked_methods);
192 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
196 if (pkt->type == RTMP_PT_INVOKE && track) {
202 bytestream2_init(&gbc, pkt->data, pkt->data_size);
203 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
206 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
209 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
213 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
216 ff_rtmp_packet_destroy(pkt);
220 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
225 /* The type must be B for Boolean, N for number, S for string, O for
226 * object, or Z for null. For Booleans the data must be either 0 or 1 for
227 * FALSE or TRUE, respectively. Likewise for Objects the data must be
228 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
229 * may be named, by prefixing the type with 'N' and specifying the name
230 * before the value (ie. NB:myFlag:1). This option may be used multiple times
231 * to construct arbitrary AMF sequences. */
232 if (param[0] && param[1] == ':') {
235 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
238 value = strchr(field, ':');
244 if (!field || !value)
247 ff_amf_write_field_name(p, field);
254 ff_amf_write_bool(p, value[0] != '0');
257 ff_amf_write_string(p, value);
260 ff_amf_write_number(p, strtod(value, NULL));
263 ff_amf_write_null(p);
267 ff_amf_write_object_start(p);
269 ff_amf_write_object_end(p);
279 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
280 return AVERROR(EINVAL);
284 * Generate 'connect' call and send it to the server.
286 static int gen_connect(URLContext *s, RTMPContext *rt)
292 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
298 ff_amf_write_string(&p, "connect");
299 ff_amf_write_number(&p, ++rt->nb_invokes);
300 ff_amf_write_object_start(&p);
301 ff_amf_write_field_name(&p, "app");
302 ff_amf_write_string(&p, rt->app);
305 ff_amf_write_field_name(&p, "type");
306 ff_amf_write_string(&p, "nonprivate");
308 ff_amf_write_field_name(&p, "flashVer");
309 ff_amf_write_string(&p, rt->flashver);
312 ff_amf_write_field_name(&p, "swfUrl");
313 ff_amf_write_string(&p, rt->swfurl);
316 ff_amf_write_field_name(&p, "tcUrl");
317 ff_amf_write_string(&p, rt->tcurl);
319 ff_amf_write_field_name(&p, "fpad");
320 ff_amf_write_bool(&p, 0);
321 ff_amf_write_field_name(&p, "capabilities");
322 ff_amf_write_number(&p, 15.0);
324 /* Tell the server we support all the audio codecs except
325 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
326 * which are unused in the RTMP protocol implementation. */
327 ff_amf_write_field_name(&p, "audioCodecs");
328 ff_amf_write_number(&p, 4071.0);
329 ff_amf_write_field_name(&p, "videoCodecs");
330 ff_amf_write_number(&p, 252.0);
331 ff_amf_write_field_name(&p, "videoFunction");
332 ff_amf_write_number(&p, 1.0);
335 ff_amf_write_field_name(&p, "pageUrl");
336 ff_amf_write_string(&p, rt->pageurl);
339 ff_amf_write_object_end(&p);
342 char *param = rt->conn;
344 // Write arbitrary AMF data to the Connect message.
345 while (param != NULL) {
347 param += strspn(param, " ");
350 sep = strchr(param, ' ');
353 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
354 // Invalid AMF parameter.
355 ff_rtmp_packet_destroy(&pkt);
366 pkt.data_size = p - pkt.data;
368 return rtmp_send_packet(rt, &pkt, 1);
372 * Generate 'releaseStream' call and send it to the server. It should make
373 * the server release some channel for media streams.
375 static int gen_release_stream(URLContext *s, RTMPContext *rt)
381 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
382 0, 29 + strlen(rt->playpath))) < 0)
385 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
387 ff_amf_write_string(&p, "releaseStream");
388 ff_amf_write_number(&p, ++rt->nb_invokes);
389 ff_amf_write_null(&p);
390 ff_amf_write_string(&p, rt->playpath);
392 return rtmp_send_packet(rt, &pkt, 0);
396 * Generate 'FCPublish' call and send it to the server. It should make
397 * the server preapare for receiving media streams.
399 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
405 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
406 0, 25 + strlen(rt->playpath))) < 0)
409 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
411 ff_amf_write_string(&p, "FCPublish");
412 ff_amf_write_number(&p, ++rt->nb_invokes);
413 ff_amf_write_null(&p);
414 ff_amf_write_string(&p, rt->playpath);
416 return rtmp_send_packet(rt, &pkt, 0);
420 * Generate 'FCUnpublish' call and send it to the server. It should make
421 * the server destroy stream.
423 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
429 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
430 0, 27 + strlen(rt->playpath))) < 0)
433 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
435 ff_amf_write_string(&p, "FCUnpublish");
436 ff_amf_write_number(&p, ++rt->nb_invokes);
437 ff_amf_write_null(&p);
438 ff_amf_write_string(&p, rt->playpath);
440 return rtmp_send_packet(rt, &pkt, 0);
444 * Generate 'createStream' call and send it to the server. It should make
445 * the server allocate some channel for media streams.
447 static int gen_create_stream(URLContext *s, RTMPContext *rt)
453 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
455 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
460 ff_amf_write_string(&p, "createStream");
461 ff_amf_write_number(&p, ++rt->nb_invokes);
462 ff_amf_write_null(&p);
464 return rtmp_send_packet(rt, &pkt, 1);
469 * Generate 'deleteStream' call and send it to the server. It should make
470 * the server remove some channel for media streams.
472 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
478 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
480 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
485 ff_amf_write_string(&p, "deleteStream");
486 ff_amf_write_number(&p, ++rt->nb_invokes);
487 ff_amf_write_null(&p);
488 ff_amf_write_number(&p, rt->main_channel_id);
490 return rtmp_send_packet(rt, &pkt, 0);
494 * Generate client buffer time and send it to the server.
496 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
502 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
507 bytestream_put_be16(&p, 3);
508 bytestream_put_be32(&p, rt->main_channel_id);
509 bytestream_put_be32(&p, rt->client_buffer_time);
511 return rtmp_send_packet(rt, &pkt, 0);
515 * Generate 'play' call and send it to the server, then ping the server
516 * to start actual playing.
518 static int gen_play(URLContext *s, RTMPContext *rt)
524 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
526 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
527 0, 29 + strlen(rt->playpath))) < 0)
530 pkt.extra = rt->main_channel_id;
533 ff_amf_write_string(&p, "play");
534 ff_amf_write_number(&p, ++rt->nb_invokes);
535 ff_amf_write_null(&p);
536 ff_amf_write_string(&p, rt->playpath);
537 ff_amf_write_number(&p, rt->live);
539 return rtmp_send_packet(rt, &pkt, 1);
543 * Generate 'publish' call and send it to the server.
545 static int gen_publish(URLContext *s, RTMPContext *rt)
551 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
553 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
554 0, 30 + strlen(rt->playpath))) < 0)
557 pkt.extra = rt->main_channel_id;
560 ff_amf_write_string(&p, "publish");
561 ff_amf_write_number(&p, ++rt->nb_invokes);
562 ff_amf_write_null(&p);
563 ff_amf_write_string(&p, rt->playpath);
564 ff_amf_write_string(&p, "live");
566 return rtmp_send_packet(rt, &pkt, 1);
570 * Generate ping reply and send it to the server.
572 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
578 if (ppkt->data_size < 6) {
579 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
581 return AVERROR_INVALIDDATA;
584 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
585 ppkt->timestamp + 1, 6)) < 0)
589 bytestream_put_be16(&p, 7);
590 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
592 return rtmp_send_packet(rt, &pkt, 0);
596 * Generate server bandwidth message and send it to the server.
598 static int gen_server_bw(URLContext *s, RTMPContext *rt)
604 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
609 bytestream_put_be32(&p, rt->server_bw);
611 return rtmp_send_packet(rt, &pkt, 0);
615 * Generate check bandwidth message and send it to the server.
617 static int gen_check_bw(URLContext *s, RTMPContext *rt)
623 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
628 ff_amf_write_string(&p, "_checkbw");
629 ff_amf_write_number(&p, RTMP_NOTIFICATION);
630 ff_amf_write_null(&p);
632 return rtmp_send_packet(rt, &pkt, 0);
636 * Generate report on bytes read so far and send it to the server.
638 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
644 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
649 bytestream_put_be32(&p, rt->bytes_read);
651 return rtmp_send_packet(rt, &pkt, 0);
654 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
655 const char *subscribe)
661 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
662 0, 27 + strlen(subscribe))) < 0)
666 ff_amf_write_string(&p, "FCSubscribe");
667 ff_amf_write_number(&p, ++rt->nb_invokes);
668 ff_amf_write_null(&p);
669 ff_amf_write_string(&p, subscribe);
671 return rtmp_send_packet(rt, &pkt, 1);
674 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
675 const uint8_t *key, int keylen, uint8_t *dst)
678 uint8_t hmac_buf[64+32] = {0};
681 sha = av_mallocz(av_sha_size);
683 return AVERROR(ENOMEM);
686 memcpy(hmac_buf, key, keylen);
688 av_sha_init(sha, 256);
689 av_sha_update(sha,key, keylen);
690 av_sha_final(sha, hmac_buf);
692 for (i = 0; i < 64; i++)
693 hmac_buf[i] ^= HMAC_IPAD_VAL;
695 av_sha_init(sha, 256);
696 av_sha_update(sha, hmac_buf, 64);
698 av_sha_update(sha, src, len);
699 } else { //skip 32 bytes used for storing digest
700 av_sha_update(sha, src, gap);
701 av_sha_update(sha, src + gap + 32, len - gap - 32);
703 av_sha_final(sha, hmac_buf + 64);
705 for (i = 0; i < 64; i++)
706 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
707 av_sha_init(sha, 256);
708 av_sha_update(sha, hmac_buf, 64+32);
709 av_sha_final(sha, dst);
716 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
719 int i, digest_pos = 0;
721 for (i = 0; i < 4; i++)
722 digest_pos += buf[i + off];
723 digest_pos = digest_pos % mod_val + add_val;
729 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
730 * will be stored) into that packet.
732 * @param buf handshake data (1536 bytes)
733 * @param encrypted use an encrypted connection (RTMPE)
734 * @return offset to the digest inside input data
736 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
741 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
743 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
745 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
746 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
755 * Verify that the received server response has the expected digest value.
757 * @param buf handshake data received from the server (1536 bytes)
758 * @param off position to search digest offset from
759 * @return 0 if digest is valid, digest position otherwise
761 static int rtmp_validate_digest(uint8_t *buf, int off)
766 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
768 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
769 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
774 if (!memcmp(digest, buf + digest_pos, 32))
780 * Perform handshake with the server by means of exchanging pseudorandom data
781 * signed with HMAC-SHA2 digest.
783 * @return 0 if handshake succeeds, negative value otherwise
785 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
788 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
789 3, // unencrypted data
790 0, 0, 0, 0, // client uptime
796 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
797 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
799 int server_pos, client_pos;
800 uint8_t digest[32], signature[32];
803 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
805 av_lfg_init(&rnd, 0xDEADC0DE);
806 // generate handshake packet - 1536 bytes of pseudorandom data
807 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
808 tosend[i] = av_lfg_get(&rnd) >> 24;
810 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
811 /* When the client wants to use RTMPE, we have to change the command
812 * byte to 0x06 which means to use encrypted data and we have to set
813 * the flash version to at least 9.0.115.0. */
820 /* Initialize the Diffie-Hellmann context and generate the public key
821 * to send to the server. */
822 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
826 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
830 if ((ret = ffurl_write(rt->stream, tosend,
831 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
832 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
836 if ((ret = ffurl_read_complete(rt->stream, serverdata,
837 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
838 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
842 if ((ret = ffurl_read_complete(rt->stream, clientdata,
843 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
844 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
848 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
849 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
850 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
852 if (rt->is_input && serverdata[5] >= 3) {
853 server_pos = rtmp_validate_digest(serverdata + 1, 772);
859 server_pos = rtmp_validate_digest(serverdata + 1, 8);
864 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
869 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
870 rtmp_server_key, sizeof(rtmp_server_key),
875 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
876 0, digest, 32, signature);
880 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
881 /* Compute the shared secret key sent by the server and initialize
882 * the RC4 encryption. */
883 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
884 tosend + 1, type)) < 0)
887 /* Encrypt the signature received by the server. */
888 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
891 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
892 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
896 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
897 tosend[i] = av_lfg_get(&rnd) >> 24;
898 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
899 rtmp_player_key, sizeof(rtmp_player_key),
904 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
906 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
910 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
911 /* Encrypt the signature to be send to the server. */
912 ff_rtmpe_encrypt_sig(rt->stream, tosend +
913 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
917 // write reply back to the server
918 if ((ret = ffurl_write(rt->stream, tosend,
919 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
922 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
923 /* Set RC4 keys for encryption and update the keystreams. */
924 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
928 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
929 /* Compute the shared secret key sent by the server and initialize
930 * the RC4 encryption. */
931 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
935 if (serverdata[0] == 9) {
936 /* Encrypt the signature received by the server. */
937 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
942 if ((ret = ffurl_write(rt->stream, serverdata + 1,
943 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
946 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
947 /* Set RC4 keys for encryption and update the keystreams. */
948 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
956 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
958 RTMPContext *rt = s->priv_data;
961 if (pkt->data_size < 4) {
962 av_log(s, AV_LOG_ERROR,
963 "Too short chunk size change packet (%d)\n",
965 return AVERROR_INVALIDDATA;
969 /* Send the same chunk size change packet back to the server,
970 * setting the outgoing chunk size to the same as the incoming one. */
971 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
972 rt->prev_pkt[1])) < 0)
974 rt->out_chunk_size = AV_RB32(pkt->data);
977 rt->in_chunk_size = AV_RB32(pkt->data);
978 if (rt->in_chunk_size <= 0) {
979 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
981 return AVERROR_INVALIDDATA;
983 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
989 static int handle_ping(URLContext *s, RTMPPacket *pkt)
991 RTMPContext *rt = s->priv_data;
994 if (pkt->data_size < 2) {
995 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
997 return AVERROR_INVALIDDATA;
1000 t = AV_RB16(pkt->data);
1002 if ((ret = gen_pong(s, rt, pkt)) < 0)
1009 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1011 RTMPContext *rt = s->priv_data;
1013 if (pkt->data_size < 4) {
1014 av_log(s, AV_LOG_ERROR,
1015 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1017 return AVERROR_INVALIDDATA;
1020 rt->client_report_size = AV_RB32(pkt->data);
1021 if (rt->client_report_size <= 0) {
1022 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1023 rt->client_report_size);
1024 return AVERROR_INVALIDDATA;
1027 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1028 rt->client_report_size >>= 1;
1033 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1035 RTMPContext *rt = s->priv_data;
1037 if (pkt->data_size < 4) {
1038 av_log(s, AV_LOG_ERROR,
1039 "Too short server bandwidth report packet (%d)\n",
1041 return AVERROR_INVALIDDATA;
1044 rt->server_bw = AV_RB32(pkt->data);
1045 if (rt->server_bw <= 0) {
1046 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1048 return AVERROR_INVALIDDATA;
1050 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1055 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1057 const uint8_t *data_end = pkt->data + pkt->data_size;
1058 uint8_t tmpstr[256];
1060 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1061 "description", tmpstr, sizeof(tmpstr))) {
1062 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
1069 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
1071 RTMPContext *rt = s->priv_data;
1072 char *tracked_method = NULL;
1075 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
1078 if (!tracked_method) {
1079 /* Ignore this reply when the current method is not tracked. */
1083 if (!memcmp(tracked_method, "connect", 7)) {
1084 if (!rt->is_input) {
1085 if ((ret = gen_release_stream(s, rt)) < 0)
1088 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
1091 if ((ret = gen_server_bw(s, rt)) < 0)
1095 if ((ret = gen_create_stream(s, rt)) < 0)
1099 /* Send the FCSubscribe command when the name of live
1100 * stream is defined by the user or if it's a live stream. */
1101 if (rt->subscribe) {
1102 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
1104 } else if (rt->live == -1) {
1105 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
1109 } else if (!memcmp(tracked_method, "createStream", 12)) {
1110 //extract a number from the result
1111 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
1112 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
1114 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
1117 if (!rt->is_input) {
1118 if ((ret = gen_publish(s, rt)) < 0)
1121 if ((ret = gen_play(s, rt)) < 0)
1123 if ((ret = gen_buffer_time(s, rt)) < 0)
1129 av_free(tracked_method);
1133 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
1135 RTMPContext *rt = s->priv_data;
1136 const uint8_t *data_end = pkt->data + pkt->data_size;
1137 const uint8_t *ptr = pkt->data + 11;
1138 uint8_t tmpstr[256];
1141 for (i = 0; i < 2; i++) {
1142 t = ff_amf_tag_size(ptr, data_end);
1148 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
1149 if (!t && !strcmp(tmpstr, "error")) {
1150 if (!ff_amf_get_field_value(ptr, data_end,
1151 "description", tmpstr, sizeof(tmpstr)))
1152 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
1156 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
1157 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
1158 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
1159 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
1160 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
1165 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
1167 RTMPContext *rt = s->priv_data;
1170 //TODO: check for the messages sent for wrong state?
1171 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
1172 if ((ret = handle_invoke_error(s, pkt)) < 0)
1174 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
1175 if ((ret = handle_invoke_result(s, pkt)) < 0)
1177 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
1178 if ((ret = handle_invoke_status(s, pkt)) < 0)
1180 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
1181 if ((ret = gen_check_bw(s, rt)) < 0)
1189 * Parse received packet and possibly perform some action depending on
1190 * the packet contents.
1191 * @return 0 for no errors, negative values for serious errors which prevent
1192 * further communications, positive values for uncritical errors
1194 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
1199 ff_rtmp_packet_dump(s, pkt);
1202 switch (pkt->type) {
1203 case RTMP_PT_BYTES_READ:
1204 av_dlog(s, "received bytes read report\n");
1206 case RTMP_PT_CHUNK_SIZE:
1207 if ((ret = handle_chunk_size(s, pkt)) < 0)
1211 if ((ret = handle_ping(s, pkt)) < 0)
1214 case RTMP_PT_CLIENT_BW:
1215 if ((ret = handle_client_bw(s, pkt)) < 0)
1218 case RTMP_PT_SERVER_BW:
1219 if ((ret = handle_server_bw(s, pkt)) < 0)
1222 case RTMP_PT_INVOKE:
1223 if ((ret = handle_invoke(s, pkt)) < 0)
1228 case RTMP_PT_METADATA:
1229 /* Audio, Video and Metadata packets are parsed in get_packet() */
1232 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
1239 * Interact with the server by receiving and sending RTMP packets until
1240 * there is some significant data (media data or expected status notification).
1242 * @param s reading context
1243 * @param for_header non-zero value tells function to work until it
1244 * gets notification from the server that playing has been started,
1245 * otherwise function will work until some media data is received (or
1247 * @return 0 for successful operation, negative value in case of error
1249 static int get_packet(URLContext *s, int for_header)
1251 RTMPContext *rt = s->priv_data;
1254 const uint8_t *next;
1256 uint32_t ts, cts, pts=0;
1258 if (rt->state == STATE_STOPPED)
1262 RTMPPacket rpkt = { 0 };
1263 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
1264 rt->in_chunk_size, rt->prev_pkt[0])) <= 0) {
1266 return AVERROR(EAGAIN);
1268 return AVERROR(EIO);
1271 rt->bytes_read += ret;
1272 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
1273 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
1274 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
1276 rt->last_bytes_read = rt->bytes_read;
1279 ret = rtmp_parse_result(s, rt, &rpkt);
1280 if (ret < 0) {//serious error in current packet
1281 ff_rtmp_packet_destroy(&rpkt);
1284 if (rt->state == STATE_STOPPED) {
1285 ff_rtmp_packet_destroy(&rpkt);
1288 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) {
1289 ff_rtmp_packet_destroy(&rpkt);
1292 if (!rpkt.data_size || !rt->is_input) {
1293 ff_rtmp_packet_destroy(&rpkt);
1296 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
1297 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
1298 ts = rpkt.timestamp;
1300 // generate packet header and put data into buffer for FLV demuxer
1302 rt->flv_size = rpkt.data_size + 15;
1303 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
1304 bytestream_put_byte(&p, rpkt.type);
1305 bytestream_put_be24(&p, rpkt.data_size);
1306 bytestream_put_be24(&p, ts);
1307 bytestream_put_byte(&p, ts >> 24);
1308 bytestream_put_be24(&p, 0);
1309 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1310 bytestream_put_be32(&p, 0);
1311 ff_rtmp_packet_destroy(&rpkt);
1313 } else if (rpkt.type == RTMP_PT_METADATA) {
1314 // we got raw FLV data, make it available for FLV demuxer
1316 rt->flv_size = rpkt.data_size;
1317 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1318 /* rewrite timestamps */
1320 ts = rpkt.timestamp;
1321 while (next - rpkt.data < rpkt.data_size - 11) {
1323 data_size = bytestream_get_be24(&next);
1325 cts = bytestream_get_be24(&next);
1326 cts |= bytestream_get_byte(&next) << 24;
1331 bytestream_put_be24(&p, ts);
1332 bytestream_put_byte(&p, ts >> 24);
1333 next += data_size + 3 + 4;
1335 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
1336 ff_rtmp_packet_destroy(&rpkt);
1339 ff_rtmp_packet_destroy(&rpkt);
1343 static int rtmp_close(URLContext *h)
1345 RTMPContext *rt = h->priv_data;
1348 if (!rt->is_input) {
1349 rt->flv_data = NULL;
1350 if (rt->out_pkt.data_size)
1351 ff_rtmp_packet_destroy(&rt->out_pkt);
1352 if (rt->state > STATE_FCPUBLISH)
1353 ret = gen_fcunpublish_stream(h, rt);
1355 if (rt->state > STATE_HANDSHAKED)
1356 ret = gen_delete_stream(h, rt);
1358 free_tracked_methods(rt);
1359 av_freep(&rt->flv_data);
1360 ffurl_close(rt->stream);
1365 * Open RTMP connection and verify that the stream can be played.
1367 * URL syntax: rtmp://server[:port][/app][/playpath]
1368 * where 'app' is first one or two directories in the path
1369 * (e.g. /ondemand/, /flash/live/, etc.)
1370 * and 'playpath' is a file name (the rest of the path,
1371 * may be prefixed with "mp4:")
1373 static int rtmp_open(URLContext *s, const char *uri, int flags)
1375 RTMPContext *rt = s->priv_data;
1376 char proto[8], hostname[256], path[1024], *fname;
1380 AVDictionary *opts = NULL;
1383 rt->is_input = !(flags & AVIO_FLAG_WRITE);
1385 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
1386 path, sizeof(path), s->filename);
1388 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
1389 if (!strcmp(proto, "rtmpts"))
1390 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
1392 /* open the http tunneling connection */
1393 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
1394 } else if (!strcmp(proto, "rtmps")) {
1395 /* open the tls connection */
1397 port = RTMPS_DEFAULT_PORT;
1398 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
1399 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
1400 if (!strcmp(proto, "rtmpte"))
1401 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
1403 /* open the encrypted connection */
1404 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
1407 /* open the tcp connection */
1409 port = RTMP_DEFAULT_PORT;
1410 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
1413 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
1414 &s->interrupt_callback, &opts)) < 0) {
1415 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
1419 rt->state = STATE_START;
1420 if ((ret = rtmp_handshake(s, rt)) < 0)
1423 rt->out_chunk_size = 128;
1424 rt->in_chunk_size = 128; // Probably overwritten later
1425 rt->state = STATE_HANDSHAKED;
1427 // Keep the application name when it has been defined by the user.
1430 rt->app = av_malloc(APP_MAX_LENGTH);
1432 ret = AVERROR(ENOMEM);
1436 //extract "app" part from path
1437 if (!strncmp(path, "/ondemand/", 10)) {
1439 memcpy(rt->app, "ondemand", 9);
1441 char *next = *path ? path + 1 : path;
1442 char *p = strchr(next, '/');
1447 // make sure we do not mismatch a playpath for an application instance
1448 char *c = strchr(p + 1, ':');
1449 fname = strchr(p + 1, '/');
1450 if (!fname || (c && c < fname)) {
1452 av_strlcpy(rt->app, path + 1, p - path);
1455 av_strlcpy(rt->app, path + 1, fname - path - 1);
1461 // The name of application has been defined by the user, override it.
1466 if (!rt->playpath) {
1467 int len = strlen(fname);
1469 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
1470 if (!rt->playpath) {
1471 ret = AVERROR(ENOMEM);
1475 if (!strchr(fname, ':') && len >= 4 &&
1476 (!strcmp(fname + len - 4, ".f4v") ||
1477 !strcmp(fname + len - 4, ".mp4"))) {
1478 memcpy(rt->playpath, "mp4:", 5);
1479 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
1480 fname[len - 4] = '\0';
1482 rt->playpath[0] = 0;
1484 strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5);
1488 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
1490 ret = AVERROR(ENOMEM);
1493 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
1494 port, "/%s", rt->app);
1497 if (!rt->flashver) {
1498 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
1499 if (!rt->flashver) {
1500 ret = AVERROR(ENOMEM);
1504 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
1505 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
1506 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
1508 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
1509 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
1513 rt->client_report_size = 1048576;
1515 rt->last_bytes_read = 0;
1516 rt->server_bw = 2500000;
1518 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
1519 proto, path, rt->app, rt->playpath);
1520 if ((ret = gen_connect(s, rt)) < 0)
1524 ret = get_packet(s, 1);
1525 } while (ret == EAGAIN);
1530 // generate FLV header for demuxer
1532 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
1534 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
1537 rt->flv_data = NULL;
1539 rt->skip_bytes = 13;
1542 s->max_packet_size = rt->stream->max_packet_size;
1547 av_dict_free(&opts);
1552 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
1554 RTMPContext *rt = s->priv_data;
1555 int orig_size = size;
1559 int data_left = rt->flv_size - rt->flv_off;
1561 if (data_left >= size) {
1562 memcpy(buf, rt->flv_data + rt->flv_off, size);
1563 rt->flv_off += size;
1566 if (data_left > 0) {
1567 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
1570 rt->flv_off = rt->flv_size;
1573 if ((ret = get_packet(s, 0)) < 0)
1579 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
1581 RTMPContext *rt = s->priv_data;
1582 int size_temp = size;
1583 int pktsize, pkttype;
1585 const uint8_t *buf_temp = buf;
1590 if (rt->skip_bytes) {
1591 int skip = FFMIN(rt->skip_bytes, size_temp);
1594 rt->skip_bytes -= skip;
1598 if (rt->flv_header_bytes < 11) {
1599 const uint8_t *header = rt->flv_header;
1600 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
1601 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
1602 rt->flv_header_bytes += copy;
1604 if (rt->flv_header_bytes < 11)
1607 pkttype = bytestream_get_byte(&header);
1608 pktsize = bytestream_get_be24(&header);
1609 ts = bytestream_get_be24(&header);
1610 ts |= bytestream_get_byte(&header) << 24;
1611 bytestream_get_be24(&header);
1612 rt->flv_size = pktsize;
1614 //force 12bytes header
1615 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
1616 pkttype == RTMP_PT_NOTIFY) {
1617 if (pkttype == RTMP_PT_NOTIFY)
1619 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
1622 //this can be a big packet, it's better to send it right here
1623 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
1624 pkttype, ts, pktsize)) < 0)
1627 rt->out_pkt.extra = rt->main_channel_id;
1628 rt->flv_data = rt->out_pkt.data;
1630 if (pkttype == RTMP_PT_NOTIFY)
1631 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
1634 if (rt->flv_size - rt->flv_off > size_temp) {
1635 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
1636 rt->flv_off += size_temp;
1639 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
1640 size_temp -= rt->flv_size - rt->flv_off;
1641 rt->flv_off += rt->flv_size - rt->flv_off;
1644 if (rt->flv_off == rt->flv_size) {
1647 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
1651 rt->flv_header_bytes = 0;
1652 rt->flv_nb_packets++;
1654 } while (buf_temp - buf < size);
1656 if (rt->flv_nb_packets < rt->flush_interval)
1658 rt->flv_nb_packets = 0;
1660 /* set stream into nonblocking mode */
1661 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
1663 /* try to read one byte from the stream */
1664 ret = ffurl_read(rt->stream, &c, 1);
1666 /* switch the stream back into blocking mode */
1667 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
1669 if (ret == AVERROR(EAGAIN)) {
1670 /* no incoming data to handle */
1672 } else if (ret < 0) {
1674 } else if (ret == 1) {
1675 RTMPPacket rpkt = { 0 };
1677 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
1679 rt->prev_pkt[0], c)) <= 0)
1682 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
1685 ff_rtmp_packet_destroy(&rpkt);
1691 #define OFFSET(x) offsetof(RTMPContext, x)
1692 #define DEC AV_OPT_FLAG_DECODING_PARAM
1693 #define ENC AV_OPT_FLAG_ENCODING_PARAM
1695 static const AVOption rtmp_options[] = {
1696 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1697 {"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},
1698 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1699 {"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},
1700 {"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},
1701 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {-2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
1702 {"any", "both", 0, AV_OPT_TYPE_CONST, {-2}, 0, 0, DEC, "rtmp_live"},
1703 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {-1}, 0, 0, DEC, "rtmp_live"},
1704 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {0}, 0, 0, DEC, "rtmp_live"},
1705 {"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},
1706 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1707 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
1708 {"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},
1709 {"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},
1713 #define RTMP_PROTOCOL(flavor) \
1714 static const AVClass flavor##_class = { \
1715 .class_name = #flavor, \
1716 .item_name = av_default_item_name, \
1717 .option = rtmp_options, \
1718 .version = LIBAVUTIL_VERSION_INT, \
1721 URLProtocol ff_##flavor##_protocol = { \
1723 .url_open = rtmp_open, \
1724 .url_read = rtmp_read, \
1725 .url_write = rtmp_write, \
1726 .url_close = rtmp_close, \
1727 .priv_data_size = sizeof(RTMPContext), \
1728 .flags = URL_PROTOCOL_FLAG_NETWORK, \
1729 .priv_data_class= &flavor##_class, \
1734 RTMP_PROTOCOL(rtmpe)
1735 RTMP_PROTOCOL(rtmps)
1736 RTMP_PROTOCOL(rtmpt)
1737 RTMP_PROTOCOL(rtmpte)
1738 RTMP_PROTOCOL(rtmpts)