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/random_seed.h"
33 #include "libavutil/sha.h"
41 #include "rtmpcrypt.h"
51 #define APP_MAX_LENGTH 128
52 #define PLAYPATH_MAX_LENGTH 256
53 #define TCURL_MAX_LENGTH 512
54 #define FLASHVER_MAX_LENGTH 64
55 #define RTMP_PKTDATA_DEFAULT_SIZE 4096
57 /** RTMP protocol handler state */
59 STATE_START, ///< client has not done anything yet
60 STATE_HANDSHAKED, ///< client has performed handshake
61 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
62 STATE_PLAYING, ///< client has started receiving multimedia data from server
63 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
64 STATE_RECEIVING, ///< received a publish command (for input)
65 STATE_STOPPED, ///< the broadcast has been stopped
68 typedef struct TrackedMethod {
73 /** protocol handler context */
74 typedef struct RTMPContext {
76 URLContext* stream; ///< TCP stream used in interactions with RTMP server
77 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
78 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
79 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
80 int is_input; ///< input/output flag
81 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
82 int live; ///< 0: recorded, -1: live, -2: both
83 char *app; ///< name of application
84 char *conn; ///< append arbitrary AMF data to the Connect message
85 ClientState state; ///< current state
86 int main_channel_id; ///< an additional channel ID which is used for some invocations
87 uint8_t* flv_data; ///< buffer with data for demuxer
88 int flv_size; ///< current buffer size
89 int flv_off; ///< number of bytes read from current buffer
90 int flv_nb_packets; ///< number of flv packets published
91 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
92 uint32_t client_report_size; ///< number of bytes after which client should report to server
93 uint32_t bytes_read; ///< number of bytes read from server
94 uint32_t last_bytes_read; ///< number of bytes read last reported to server
95 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
96 uint8_t flv_header[11]; ///< partial incoming flv packet header
97 int flv_header_bytes; ///< number of initialized bytes in flv_header
98 int nb_invokes; ///< keeps track of invoke messages
99 char* tcurl; ///< url of the target stream
100 char* flashver; ///< version of the flash plugin
101 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
102 int swfhash_len; ///< length of the SHA256 hash
103 int swfsize; ///< size of the decompressed SWF file
104 char* swfurl; ///< url of the swf player
105 char* swfverify; ///< URL to player swf file, compute hash/size automatically
106 char swfverification[42]; ///< hash of the SWF verification
107 char* pageurl; ///< url of the web page
108 char* subscribe; ///< name of live stream to subscribe
109 int server_bw; ///< server bandwidth
110 int client_buffer_time; ///< client buffer time in ms
111 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
112 int encrypted; ///< use an encrypted connection (RTMPE only)
113 TrackedMethod*tracked_methods; ///< tracked methods buffer
114 int nb_tracked_methods; ///< number of tracked methods
115 int tracked_methods_size; ///< size of the tracked methods buffer
116 int listen; ///< listen mode flag
117 int listen_timeout; ///< listen timeout to wait for new connections
118 int nb_streamid; ///< The next stream id to return on createStream calls
121 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
122 /** Client key used for digest signing */
123 static const uint8_t rtmp_player_key[] = {
124 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
125 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
127 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
128 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
129 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
132 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
133 /** Key used for RTMP server digest signing */
134 static const uint8_t rtmp_server_key[] = {
135 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
136 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
137 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
139 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
140 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
141 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
144 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
148 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
149 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
150 ptr = av_realloc(rt->tracked_methods,
151 rt->tracked_methods_size * sizeof(*rt->tracked_methods));
153 return AVERROR(ENOMEM);
154 rt->tracked_methods = ptr;
157 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
158 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
159 return AVERROR(ENOMEM);
160 rt->tracked_methods[rt->nb_tracked_methods].id = id;
161 rt->nb_tracked_methods++;
166 static void del_tracked_method(RTMPContext *rt, int index)
168 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
169 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
170 rt->nb_tracked_methods--;
173 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
174 char **tracked_method)
176 RTMPContext *rt = s->priv_data;
182 bytestream2_init(&gbc, pkt->data + offset, pkt->data_size - offset);
183 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
186 for (i = 0; i < rt->nb_tracked_methods; i++) {
187 if (rt->tracked_methods[i].id != pkt_id)
190 *tracked_method = rt->tracked_methods[i].name;
191 del_tracked_method(rt, i);
198 static void free_tracked_methods(RTMPContext *rt)
202 for (i = 0; i < rt->nb_tracked_methods; i ++)
203 av_free(rt->tracked_methods[i].name);
204 av_free(rt->tracked_methods);
207 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
211 if (pkt->type == RTMP_PT_INVOKE && track) {
217 bytestream2_init(&gbc, pkt->data, pkt->data_size);
218 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
221 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
224 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
228 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
231 ff_rtmp_packet_destroy(pkt);
235 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
240 /* The type must be B for Boolean, N for number, S for string, O for
241 * object, or Z for null. For Booleans the data must be either 0 or 1 for
242 * FALSE or TRUE, respectively. Likewise for Objects the data must be
243 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
244 * may be named, by prefixing the type with 'N' and specifying the name
245 * before the value (ie. NB:myFlag:1). This option may be used multiple times
246 * to construct arbitrary AMF sequences. */
247 if (param[0] && param[1] == ':') {
250 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
253 value = strchr(field, ':');
259 ff_amf_write_field_name(p, field);
266 ff_amf_write_bool(p, value[0] != '0');
269 ff_amf_write_string(p, value);
272 ff_amf_write_number(p, strtod(value, NULL));
275 ff_amf_write_null(p);
279 ff_amf_write_object_start(p);
281 ff_amf_write_object_end(p);
291 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
292 return AVERROR(EINVAL);
296 * Generate 'connect' call and send it to the server.
298 static int gen_connect(URLContext *s, RTMPContext *rt)
304 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
310 ff_amf_write_string(&p, "connect");
311 ff_amf_write_number(&p, ++rt->nb_invokes);
312 ff_amf_write_object_start(&p);
313 ff_amf_write_field_name(&p, "app");
314 ff_amf_write_string(&p, rt->app);
317 ff_amf_write_field_name(&p, "type");
318 ff_amf_write_string(&p, "nonprivate");
320 ff_amf_write_field_name(&p, "flashVer");
321 ff_amf_write_string(&p, rt->flashver);
324 ff_amf_write_field_name(&p, "swfUrl");
325 ff_amf_write_string(&p, rt->swfurl);
328 ff_amf_write_field_name(&p, "tcUrl");
329 ff_amf_write_string(&p, rt->tcurl);
331 ff_amf_write_field_name(&p, "fpad");
332 ff_amf_write_bool(&p, 0);
333 ff_amf_write_field_name(&p, "capabilities");
334 ff_amf_write_number(&p, 15.0);
336 /* Tell the server we support all the audio codecs except
337 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
338 * which are unused in the RTMP protocol implementation. */
339 ff_amf_write_field_name(&p, "audioCodecs");
340 ff_amf_write_number(&p, 4071.0);
341 ff_amf_write_field_name(&p, "videoCodecs");
342 ff_amf_write_number(&p, 252.0);
343 ff_amf_write_field_name(&p, "videoFunction");
344 ff_amf_write_number(&p, 1.0);
347 ff_amf_write_field_name(&p, "pageUrl");
348 ff_amf_write_string(&p, rt->pageurl);
351 ff_amf_write_object_end(&p);
354 char *param = rt->conn;
356 // Write arbitrary AMF data to the Connect message.
357 while (param != NULL) {
359 param += strspn(param, " ");
362 sep = strchr(param, ' ');
365 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
366 // Invalid AMF parameter.
367 ff_rtmp_packet_destroy(&pkt);
378 pkt.data_size = p - pkt.data;
380 return rtmp_send_packet(rt, &pkt, 1);
383 static int read_connect(URLContext *s, RTMPContext *rt)
385 RTMPPacket pkt = { 0 };
395 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
396 rt->prev_pkt[1])) < 0)
399 bytestream2_init(&gbc, cp, pkt.data_size);
400 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
401 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
402 ff_rtmp_packet_destroy(&pkt);
403 return AVERROR_INVALIDDATA;
405 if (strcmp(command, "connect")) {
406 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
407 ff_rtmp_packet_destroy(&pkt);
408 return AVERROR_INVALIDDATA;
410 ret = ff_amf_read_number(&gbc, &seqnum);
412 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
413 /* Here one could parse an AMF Object with data as flashVers and others. */
414 ret = ff_amf_get_field_value(gbc.buffer,
415 gbc.buffer + bytestream2_get_bytes_left(&gbc),
416 "app", tmpstr, sizeof(tmpstr));
418 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
419 if (!ret && strcmp(tmpstr, rt->app))
420 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
422 ff_rtmp_packet_destroy(&pkt);
424 // Send Window Acknowledgement Size (as defined in speficication)
425 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
426 RTMP_PT_SERVER_BW, 0, 4)) < 0)
429 bytestream_put_be32(&p, rt->server_bw);
430 pkt.data_size = p - pkt.data;
431 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
433 ff_rtmp_packet_destroy(&pkt);
436 // Send Peer Bandwidth
437 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
438 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
441 bytestream_put_be32(&p, rt->server_bw);
442 bytestream_put_byte(&p, 2); // dynamic
443 pkt.data_size = p - pkt.data;
444 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
446 ff_rtmp_packet_destroy(&pkt);
451 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
452 RTMP_PT_PING, 0, 6)) < 0)
456 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
457 bytestream_put_be32(&p, 0);
458 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
460 ff_rtmp_packet_destroy(&pkt);
465 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
466 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
470 bytestream_put_be32(&p, rt->out_chunk_size);
471 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
473 ff_rtmp_packet_destroy(&pkt);
477 // Send result_ NetConnection.Connect.Success to connect
478 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
480 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
484 ff_amf_write_string(&p, "_result");
485 ff_amf_write_number(&p, seqnum);
487 ff_amf_write_object_start(&p);
488 ff_amf_write_field_name(&p, "fmsVer");
489 ff_amf_write_string(&p, "FMS/3,0,1,123");
490 ff_amf_write_field_name(&p, "capabilities");
491 ff_amf_write_number(&p, 31);
492 ff_amf_write_object_end(&p);
494 ff_amf_write_object_start(&p);
495 ff_amf_write_field_name(&p, "level");
496 ff_amf_write_string(&p, "status");
497 ff_amf_write_field_name(&p, "code");
498 ff_amf_write_string(&p, "NetConnection.Connect.Success");
499 ff_amf_write_field_name(&p, "description");
500 ff_amf_write_string(&p, "Connection succeeded.");
501 ff_amf_write_field_name(&p, "objectEncoding");
502 ff_amf_write_number(&p, 0);
503 ff_amf_write_object_end(&p);
505 pkt.data_size = p - pkt.data;
506 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
508 ff_rtmp_packet_destroy(&pkt);
512 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
513 RTMP_PT_INVOKE, 0, 30)) < 0)
516 ff_amf_write_string(&p, "onBWDone");
517 ff_amf_write_number(&p, 0);
518 ff_amf_write_null(&p);
519 ff_amf_write_number(&p, 8192);
520 pkt.data_size = p - pkt.data;
521 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
523 ff_rtmp_packet_destroy(&pkt);
529 * Generate 'releaseStream' call and send it to the server. It should make
530 * the server release some channel for media streams.
532 static int gen_release_stream(URLContext *s, RTMPContext *rt)
538 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
539 0, 29 + strlen(rt->playpath))) < 0)
542 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
544 ff_amf_write_string(&p, "releaseStream");
545 ff_amf_write_number(&p, ++rt->nb_invokes);
546 ff_amf_write_null(&p);
547 ff_amf_write_string(&p, rt->playpath);
549 return rtmp_send_packet(rt, &pkt, 1);
553 * Generate 'FCPublish' call and send it to the server. It should make
554 * the server preapare for receiving media streams.
556 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
562 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
563 0, 25 + strlen(rt->playpath))) < 0)
566 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
568 ff_amf_write_string(&p, "FCPublish");
569 ff_amf_write_number(&p, ++rt->nb_invokes);
570 ff_amf_write_null(&p);
571 ff_amf_write_string(&p, rt->playpath);
573 return rtmp_send_packet(rt, &pkt, 1);
577 * Generate 'FCUnpublish' call and send it to the server. It should make
578 * the server destroy stream.
580 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
586 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
587 0, 27 + strlen(rt->playpath))) < 0)
590 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
592 ff_amf_write_string(&p, "FCUnpublish");
593 ff_amf_write_number(&p, ++rt->nb_invokes);
594 ff_amf_write_null(&p);
595 ff_amf_write_string(&p, rt->playpath);
597 return rtmp_send_packet(rt, &pkt, 0);
601 * Generate 'createStream' call and send it to the server. It should make
602 * the server allocate some channel for media streams.
604 static int gen_create_stream(URLContext *s, RTMPContext *rt)
610 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
612 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
617 ff_amf_write_string(&p, "createStream");
618 ff_amf_write_number(&p, ++rt->nb_invokes);
619 ff_amf_write_null(&p);
621 return rtmp_send_packet(rt, &pkt, 1);
626 * Generate 'deleteStream' call and send it to the server. It should make
627 * the server remove some channel for media streams.
629 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
635 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
637 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
642 ff_amf_write_string(&p, "deleteStream");
643 ff_amf_write_number(&p, ++rt->nb_invokes);
644 ff_amf_write_null(&p);
645 ff_amf_write_number(&p, rt->main_channel_id);
647 return rtmp_send_packet(rt, &pkt, 0);
651 * Generate client buffer time and send it to the server.
653 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
659 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
664 bytestream_put_be16(&p, 3);
665 bytestream_put_be32(&p, rt->main_channel_id);
666 bytestream_put_be32(&p, rt->client_buffer_time);
668 return rtmp_send_packet(rt, &pkt, 0);
672 * Generate 'play' call and send it to the server, then ping the server
673 * to start actual playing.
675 static int gen_play(URLContext *s, RTMPContext *rt)
681 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
683 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
684 0, 29 + strlen(rt->playpath))) < 0)
687 pkt.extra = rt->main_channel_id;
690 ff_amf_write_string(&p, "play");
691 ff_amf_write_number(&p, ++rt->nb_invokes);
692 ff_amf_write_null(&p);
693 ff_amf_write_string(&p, rt->playpath);
694 ff_amf_write_number(&p, rt->live);
696 return rtmp_send_packet(rt, &pkt, 1);
700 * Generate 'publish' call and send it to the server.
702 static int gen_publish(URLContext *s, RTMPContext *rt)
708 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
710 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
711 0, 30 + strlen(rt->playpath))) < 0)
714 pkt.extra = rt->main_channel_id;
717 ff_amf_write_string(&p, "publish");
718 ff_amf_write_number(&p, ++rt->nb_invokes);
719 ff_amf_write_null(&p);
720 ff_amf_write_string(&p, rt->playpath);
721 ff_amf_write_string(&p, "live");
723 return rtmp_send_packet(rt, &pkt, 1);
727 * Generate ping reply and send it to the server.
729 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
735 if (ppkt->data_size < 6) {
736 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
738 return AVERROR_INVALIDDATA;
741 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
742 ppkt->timestamp + 1, 6)) < 0)
746 bytestream_put_be16(&p, 7);
747 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
749 return rtmp_send_packet(rt, &pkt, 0);
753 * Generate SWF verification message and send it to the server.
755 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
761 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
762 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
767 bytestream_put_be16(&p, 27);
768 memcpy(p, rt->swfverification, 42);
770 return rtmp_send_packet(rt, &pkt, 0);
774 * Generate server bandwidth message and send it to the server.
776 static int gen_server_bw(URLContext *s, RTMPContext *rt)
782 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
787 bytestream_put_be32(&p, rt->server_bw);
789 return rtmp_send_packet(rt, &pkt, 0);
793 * Generate check bandwidth message and send it to the server.
795 static int gen_check_bw(URLContext *s, RTMPContext *rt)
801 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
806 ff_amf_write_string(&p, "_checkbw");
807 ff_amf_write_number(&p, ++rt->nb_invokes);
808 ff_amf_write_null(&p);
810 return rtmp_send_packet(rt, &pkt, 1);
814 * Generate report on bytes read so far and send it to the server.
816 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
822 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
827 bytestream_put_be32(&p, rt->bytes_read);
829 return rtmp_send_packet(rt, &pkt, 0);
832 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
833 const char *subscribe)
839 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
840 0, 27 + strlen(subscribe))) < 0)
844 ff_amf_write_string(&p, "FCSubscribe");
845 ff_amf_write_number(&p, ++rt->nb_invokes);
846 ff_amf_write_null(&p);
847 ff_amf_write_string(&p, subscribe);
849 return rtmp_send_packet(rt, &pkt, 1);
852 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
853 const uint8_t *key, int keylen, uint8_t *dst)
856 uint8_t hmac_buf[64+32] = {0};
859 sha = av_sha_alloc();
861 return AVERROR(ENOMEM);
864 memcpy(hmac_buf, key, keylen);
866 av_sha_init(sha, 256);
867 av_sha_update(sha,key, keylen);
868 av_sha_final(sha, hmac_buf);
870 for (i = 0; i < 64; i++)
871 hmac_buf[i] ^= HMAC_IPAD_VAL;
873 av_sha_init(sha, 256);
874 av_sha_update(sha, hmac_buf, 64);
876 av_sha_update(sha, src, len);
877 } else { //skip 32 bytes used for storing digest
878 av_sha_update(sha, src, gap);
879 av_sha_update(sha, src + gap + 32, len - gap - 32);
881 av_sha_final(sha, hmac_buf + 64);
883 for (i = 0; i < 64; i++)
884 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
885 av_sha_init(sha, 256);
886 av_sha_update(sha, hmac_buf, 64+32);
887 av_sha_final(sha, dst);
894 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
897 int i, digest_pos = 0;
899 for (i = 0; i < 4; i++)
900 digest_pos += buf[i + off];
901 digest_pos = digest_pos % mod_val + add_val;
907 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
908 * will be stored) into that packet.
910 * @param buf handshake data (1536 bytes)
911 * @param encrypted use an encrypted connection (RTMPE)
912 * @return offset to the digest inside input data
914 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
919 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
921 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
923 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
924 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
933 * Verify that the received server response has the expected digest value.
935 * @param buf handshake data received from the server (1536 bytes)
936 * @param off position to search digest offset from
937 * @return 0 if digest is valid, digest position otherwise
939 static int rtmp_validate_digest(uint8_t *buf, int off)
944 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
946 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
947 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
952 if (!memcmp(digest, buf + digest_pos, 32))
957 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
963 if (rt->swfhash_len != 32) {
964 av_log(s, AV_LOG_ERROR,
965 "Hash of the decompressed SWF file is not 32 bytes long.\n");
966 return AVERROR(EINVAL);
969 p = &rt->swfverification[0];
970 bytestream_put_byte(&p, 1);
971 bytestream_put_byte(&p, 1);
972 bytestream_put_be32(&p, rt->swfsize);
973 bytestream_put_be32(&p, rt->swfsize);
975 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
982 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
983 uint8_t **out_data, int64_t *out_size)
990 zs.avail_in = in_size;
991 zs.next_in = in_data;
992 ret = inflateInit(&zs);
994 return AVERROR_UNKNOWN;
997 uint8_t tmp_buf[16384];
999 zs.avail_out = sizeof(tmp_buf);
1000 zs.next_out = tmp_buf;
1002 ret = inflate(&zs, Z_NO_FLUSH);
1003 if (ret != Z_OK && ret != Z_STREAM_END) {
1004 ret = AVERROR_UNKNOWN;
1008 size = sizeof(tmp_buf) - zs.avail_out;
1009 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1010 ret = AVERROR(ENOMEM);
1015 memcpy(*out_data + *out_size, tmp_buf, size);
1017 } while (zs.avail_out == 0);
1025 static int rtmp_calc_swfhash(URLContext *s)
1027 RTMPContext *rt = s->priv_data;
1028 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1029 int64_t in_size, out_size;
1035 /* Get the SWF player file. */
1036 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1037 &s->interrupt_callback, NULL)) < 0) {
1038 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1042 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1047 if (!(in_data = av_malloc(in_size))) {
1048 ret = AVERROR(ENOMEM);
1052 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1056 ret = AVERROR_INVALIDDATA;
1060 if (!memcmp(in_data, "CWS", 3)) {
1061 /* Decompress the SWF player file using Zlib. */
1062 if (!(out_data = av_malloc(8))) {
1063 ret = AVERROR(ENOMEM);
1066 *in_data = 'F'; // magic stuff
1067 memcpy(out_data, in_data, 8);
1071 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1072 &out_data, &out_size)) < 0)
1075 av_log(s, AV_LOG_ERROR,
1076 "Zlib is required for decompressing the SWF player file.\n");
1077 ret = AVERROR(EINVAL);
1087 /* Compute the SHA256 hash of the SWF player file. */
1088 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1089 "Genuine Adobe Flash Player 001", 30,
1093 /* Set SWFVerification parameters. */
1094 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1095 rt->swfsize = swfsize;
1099 av_freep(&out_data);
1100 ffurl_close(stream);
1105 * Perform handshake with the server by means of exchanging pseudorandom data
1106 * signed with HMAC-SHA2 digest.
1108 * @return 0 if handshake succeeds, negative value otherwise
1110 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1113 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1114 3, // unencrypted data
1115 0, 0, 0, 0, // client uptime
1121 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1122 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1124 int server_pos, client_pos;
1125 uint8_t digest[32], signature[32];
1128 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1130 av_lfg_init(&rnd, 0xDEADC0DE);
1131 // generate handshake packet - 1536 bytes of pseudorandom data
1132 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1133 tosend[i] = av_lfg_get(&rnd) >> 24;
1135 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1136 /* When the client wants to use RTMPE, we have to change the command
1137 * byte to 0x06 which means to use encrypted data and we have to set
1138 * the flash version to at least 9.0.115.0. */
1145 /* Initialize the Diffie-Hellmann context and generate the public key
1146 * to send to the server. */
1147 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1151 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1155 if ((ret = ffurl_write(rt->stream, tosend,
1156 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1157 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1161 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1162 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1163 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1167 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1168 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1169 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1173 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1174 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1175 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1177 if (rt->is_input && serverdata[5] >= 3) {
1178 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1184 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1189 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1190 return AVERROR(EIO);
1194 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1195 * key are the last 32 bytes of the server handshake. */
1197 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1198 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1202 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1203 rtmp_server_key, sizeof(rtmp_server_key),
1208 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1209 0, digest, 32, signature);
1213 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1214 /* Compute the shared secret key sent by the server and initialize
1215 * the RC4 encryption. */
1216 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1217 tosend + 1, type)) < 0)
1220 /* Encrypt the signature received by the server. */
1221 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1224 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1225 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1226 return AVERROR(EIO);
1229 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1230 tosend[i] = av_lfg_get(&rnd) >> 24;
1231 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1232 rtmp_player_key, sizeof(rtmp_player_key),
1237 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1239 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1243 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1244 /* Encrypt the signature to be send to the server. */
1245 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1246 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1250 // write reply back to the server
1251 if ((ret = ffurl_write(rt->stream, tosend,
1252 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1255 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1256 /* Set RC4 keys for encryption and update the keystreams. */
1257 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1261 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1262 /* Compute the shared secret key sent by the server and initialize
1263 * the RC4 encryption. */
1264 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1265 tosend + 1, 1)) < 0)
1268 if (serverdata[0] == 9) {
1269 /* Encrypt the signature received by the server. */
1270 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1275 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1276 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1279 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1280 /* Set RC4 keys for encryption and update the keystreams. */
1281 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1289 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1290 uint32_t *second_int, char *arraydata,
1295 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1296 RTMP_HANDSHAKE_PACKET_SIZE);
1298 return AVERROR(EIO);
1299 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1300 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1301 " not following standard\n", (int)inoutsize);
1302 return AVERROR(EINVAL);
1305 *first_int = AV_RB32(arraydata);
1306 *second_int = AV_RB32(arraydata + 4);
1310 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1311 uint32_t second_int, char *arraydata, int size)
1315 AV_WB32(arraydata, first_int);
1316 AV_WB32(arraydata + 4, first_int);
1317 inoutsize = ffurl_write(rt->stream, arraydata,
1318 RTMP_HANDSHAKE_PACKET_SIZE);
1319 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1320 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1321 return AVERROR(EIO);
1328 * rtmp handshake server side
1330 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1332 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1334 uint32_t hs_my_epoch;
1335 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1336 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1343 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1344 if (inoutsize <= 0) {
1345 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1346 return AVERROR(EIO);
1349 if (buffer[0] != 3) {
1350 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1351 return AVERROR(EIO);
1353 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1354 av_log(s, AV_LOG_ERROR,
1355 "Unable to write answer - RTMP S0\n");
1356 return AVERROR(EIO);
1359 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1360 RTMP_HANDSHAKE_PACKET_SIZE);
1362 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1366 av_log(s, AV_LOG_WARNING, "Erroneous C1 Message zero != 0\n");
1368 /* By now same epoch will be sent */
1369 hs_my_epoch = hs_epoch;
1370 /* Generate random */
1371 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1373 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1375 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1376 RTMP_HANDSHAKE_PACKET_SIZE);
1378 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1382 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1383 RTMP_HANDSHAKE_PACKET_SIZE);
1385 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1389 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1390 RTMP_HANDSHAKE_PACKET_SIZE);
1392 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1395 if (temp != hs_my_epoch)
1396 av_log(s, AV_LOG_WARNING,
1397 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1398 if (memcmp(buffer + 8, hs_s1 + 8,
1399 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1400 av_log(s, AV_LOG_WARNING,
1401 "Erroneous C2 Message random does not match up\n");
1406 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1408 RTMPContext *rt = s->priv_data;
1411 if (pkt->data_size < 4) {
1412 av_log(s, AV_LOG_ERROR,
1413 "Too short chunk size change packet (%d)\n",
1415 return AVERROR_INVALIDDATA;
1418 if (!rt->is_input) {
1419 /* Send the same chunk size change packet back to the server,
1420 * setting the outgoing chunk size to the same as the incoming one. */
1421 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1422 rt->prev_pkt[1])) < 0)
1424 rt->out_chunk_size = AV_RB32(pkt->data);
1427 rt->in_chunk_size = AV_RB32(pkt->data);
1428 if (rt->in_chunk_size <= 0) {
1429 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1431 return AVERROR_INVALIDDATA;
1433 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1439 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1441 RTMPContext *rt = s->priv_data;
1444 if (pkt->data_size < 2) {
1445 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1447 return AVERROR_INVALIDDATA;
1450 t = AV_RB16(pkt->data);
1452 if ((ret = gen_pong(s, rt, pkt)) < 0)
1454 } else if (t == 26) {
1456 if ((ret = gen_swf_verification(s, rt)) < 0)
1459 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1466 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1468 RTMPContext *rt = s->priv_data;
1470 if (pkt->data_size < 4) {
1471 av_log(s, AV_LOG_ERROR,
1472 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1474 return AVERROR_INVALIDDATA;
1477 rt->client_report_size = AV_RB32(pkt->data);
1478 if (rt->client_report_size <= 0) {
1479 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1480 rt->client_report_size);
1481 return AVERROR_INVALIDDATA;
1484 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1485 rt->client_report_size >>= 1;
1490 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1492 RTMPContext *rt = s->priv_data;
1494 if (pkt->data_size < 4) {
1495 av_log(s, AV_LOG_ERROR,
1496 "Too short server bandwidth report packet (%d)\n",
1498 return AVERROR_INVALIDDATA;
1501 rt->server_bw = AV_RB32(pkt->data);
1502 if (rt->server_bw <= 0) {
1503 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1505 return AVERROR_INVALIDDATA;
1507 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1512 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1514 const uint8_t *data_end = pkt->data + pkt->data_size;
1515 char *tracked_method = NULL;
1516 int level = AV_LOG_ERROR;
1517 uint8_t tmpstr[256];
1520 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1523 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1524 "description", tmpstr, sizeof(tmpstr))) {
1525 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1526 !strcmp(tracked_method, "releaseStream") ||
1527 !strcmp(tracked_method, "FCSubscribe") ||
1528 !strcmp(tracked_method, "FCPublish"))) {
1529 /* Gracefully ignore Adobe-specific historical artifact errors. */
1530 level = AV_LOG_WARNING;
1534 av_log(s, level, "Server error: %s\n", tmpstr);
1537 av_free(tracked_method);
1541 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1543 RTMPContext *rt = s->priv_data;
1547 char statusmsg[128];
1550 const uint8_t *p = pkt->data;
1552 RTMPPacket spkt = { 0 };
1556 bytestream2_init(&gbc, p, pkt->data_size);
1557 if (ff_amf_read_string(&gbc, command, sizeof(command),
1559 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1560 return AVERROR_INVALIDDATA;
1563 ret = ff_amf_read_number(&gbc, &seqnum);
1566 ret = ff_amf_read_null(&gbc);
1569 if (!strcmp(command, "FCPublish") ||
1570 !strcmp(command, "publish")) {
1571 ret = ff_amf_read_string(&gbc, filename,
1572 sizeof(filename), &stringlen);
1575 pchar = strrchr(s->filename, '/');
1577 av_log(s, AV_LOG_WARNING,
1578 "Unable to find / in url %s, bad format\n",
1580 pchar = s->filename;
1583 if (strcmp(pchar, filename))
1584 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1585 " %s\n", filename, pchar);
1587 rt->state = STATE_RECEIVING;
1590 if (!strcmp(command, "FCPublish")) {
1591 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1593 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1594 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1598 ff_amf_write_string(&pp, "onFCPublish");
1599 } else if (!strcmp(command, "publish")) {
1601 // Send Stream Begin 1
1602 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1603 RTMP_PT_PING, 0, 6)) < 0) {
1604 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1608 bytestream2_init_writer(&pbc, pp, spkt.data_size);
1609 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1610 bytestream2_put_be32(&pbc, rt->nb_streamid);
1611 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1613 ff_rtmp_packet_destroy(&spkt);
1617 // Send onStatus(NetStream.Publish.Start)
1618 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1620 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1621 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1624 spkt.extra = pkt->extra;
1626 ff_amf_write_string(&pp, "onStatus");
1627 ff_amf_write_number(&pp, 0);
1628 ff_amf_write_null(&pp);
1630 ff_amf_write_object_start(&pp);
1631 ff_amf_write_field_name(&pp, "level");
1632 ff_amf_write_string(&pp, "status");
1633 ff_amf_write_field_name(&pp, "code");
1634 ff_amf_write_string(&pp, "NetStream.Publish.Start");
1635 ff_amf_write_field_name(&pp, "description");
1636 snprintf(statusmsg, sizeof(statusmsg),
1637 "%s is now published", filename);
1638 ff_amf_write_string(&pp, statusmsg);
1639 ff_amf_write_field_name(&pp, "details");
1640 ff_amf_write_string(&pp, filename);
1641 ff_amf_write_field_name(&pp, "clientid");
1642 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1643 ff_amf_write_string(&pp, statusmsg);
1644 ff_amf_write_object_end(&pp);
1647 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1649 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1650 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1654 ff_amf_write_string(&pp, "_result");
1655 ff_amf_write_number(&pp, seqnum);
1656 ff_amf_write_null(&pp);
1657 if (!strcmp(command, "createStream")) {
1659 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1660 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1661 ff_amf_write_number(&pp, rt->nb_streamid);
1662 /* By now we don't control which streams are removed in
1663 * deleteStream. There is no stream creation control
1664 * if a client creates more than 2^32 - 2 streams. */
1667 spkt.data_size = pp - spkt.data;
1668 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1670 ff_rtmp_packet_destroy(&spkt);
1674 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
1676 RTMPContext *rt = s->priv_data;
1677 char *tracked_method = NULL;
1680 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
1683 if (!tracked_method) {
1684 /* Ignore this reply when the current method is not tracked. */
1688 if (!memcmp(tracked_method, "connect", 7)) {
1689 if (!rt->is_input) {
1690 if ((ret = gen_release_stream(s, rt)) < 0)
1693 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
1696 if ((ret = gen_server_bw(s, rt)) < 0)
1700 if ((ret = gen_create_stream(s, rt)) < 0)
1704 /* Send the FCSubscribe command when the name of live
1705 * stream is defined by the user or if it's a live stream. */
1706 if (rt->subscribe) {
1707 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
1709 } else if (rt->live == -1) {
1710 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
1714 } else if (!memcmp(tracked_method, "createStream", 12)) {
1715 //extract a number from the result
1716 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
1717 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
1719 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
1722 if (!rt->is_input) {
1723 if ((ret = gen_publish(s, rt)) < 0)
1726 if ((ret = gen_play(s, rt)) < 0)
1728 if ((ret = gen_buffer_time(s, rt)) < 0)
1734 av_free(tracked_method);
1738 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
1740 RTMPContext *rt = s->priv_data;
1741 const uint8_t *data_end = pkt->data + pkt->data_size;
1742 const uint8_t *ptr = pkt->data + 11;
1743 uint8_t tmpstr[256];
1746 for (i = 0; i < 2; i++) {
1747 t = ff_amf_tag_size(ptr, data_end);
1753 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
1754 if (!t && !strcmp(tmpstr, "error")) {
1755 if (!ff_amf_get_field_value(ptr, data_end,
1756 "description", tmpstr, sizeof(tmpstr)))
1757 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
1761 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
1762 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
1763 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
1764 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
1765 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
1770 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
1772 RTMPContext *rt = s->priv_data;
1775 //TODO: check for the messages sent for wrong state?
1776 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
1777 if ((ret = handle_invoke_error(s, pkt)) < 0)
1779 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
1780 if ((ret = handle_invoke_result(s, pkt)) < 0)
1782 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
1783 if ((ret = handle_invoke_status(s, pkt)) < 0)
1785 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
1786 if ((ret = gen_check_bw(s, rt)) < 0)
1788 } else if (!memcmp(pkt->data, "\002\000\015releaseStream", 16) ||
1789 !memcmp(pkt->data, "\002\000\011FCPublish", 12) ||
1790 !memcmp(pkt->data, "\002\000\007publish", 10) ||
1791 !memcmp(pkt->data, "\002\000\010_checkbw", 11) ||
1792 !memcmp(pkt->data, "\002\000\014createStream", 15)) {
1793 if (ret = send_invoke_response(s, pkt) < 0)
1800 static int handle_notify(URLContext *s, RTMPPacket *pkt) {
1801 RTMPContext *rt = s->priv_data;
1802 const uint8_t *p = NULL;
1804 uint8_t commandbuffer[64];
1805 char statusmsg[128];
1811 const uint8_t *datatowrite;
1812 unsigned datatowritelength;
1815 bytestream2_init(&gbc, p, pkt->data_size);
1816 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
1818 return AVERROR_INVALIDDATA;
1819 if (!strcmp(commandbuffer, "@setDataFrame")) {
1820 datatowrite = gbc.buffer;
1821 datatowritelength = bytestream2_get_bytes_left(&gbc);
1822 if (ff_amf_read_string(&gbc, statusmsg,
1823 sizeof(statusmsg), &stringlen))
1824 return AVERROR_INVALIDDATA;
1825 if (strcmp(statusmsg, "onMetaData")) {
1826 av_log(s, AV_LOG_INFO, "Expecting onMetadata but got %s\n",
1831 /* Provide ECMAArray to flv */
1832 ts = pkt->timestamp;
1834 // generate packet header and put data into buffer for FLV demuxer
1835 if (rt->flv_off < rt->flv_size) {
1836 old_flv_size = rt->flv_size;
1837 rt->flv_size += datatowritelength + 15;
1840 rt->flv_size = datatowritelength + 15;
1844 cp = av_realloc(rt->flv_data, rt->flv_size);
1846 return AVERROR(ENOMEM);
1848 bytestream2_init_writer(&pbc, cp, rt->flv_size);
1849 bytestream2_skip_p(&pbc, old_flv_size);
1850 bytestream2_put_byte(&pbc, pkt->type);
1851 bytestream2_put_be24(&pbc, datatowritelength);
1852 bytestream2_put_be24(&pbc, ts);
1853 bytestream2_put_byte(&pbc, ts >> 24);
1854 bytestream2_put_be24(&pbc, 0);
1855 bytestream2_put_buffer(&pbc, datatowrite, datatowritelength);
1856 bytestream2_put_be32(&pbc, 0);
1862 * Parse received packet and possibly perform some action depending on
1863 * the packet contents.
1864 * @return 0 for no errors, negative values for serious errors which prevent
1865 * further communications, positive values for uncritical errors
1867 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
1872 ff_rtmp_packet_dump(s, pkt);
1875 switch (pkt->type) {
1876 case RTMP_PT_BYTES_READ:
1877 av_dlog(s, "received bytes read report\n");
1879 case RTMP_PT_CHUNK_SIZE:
1880 if ((ret = handle_chunk_size(s, pkt)) < 0)
1884 if ((ret = handle_ping(s, pkt)) < 0)
1887 case RTMP_PT_CLIENT_BW:
1888 if ((ret = handle_client_bw(s, pkt)) < 0)
1891 case RTMP_PT_SERVER_BW:
1892 if ((ret = handle_server_bw(s, pkt)) < 0)
1895 case RTMP_PT_INVOKE:
1896 if ((ret = handle_invoke(s, pkt)) < 0)
1901 case RTMP_PT_METADATA:
1902 case RTMP_PT_NOTIFY:
1903 /* Audio, Video and Metadata packets are parsed in get_packet() */
1906 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
1913 * Interact with the server by receiving and sending RTMP packets until
1914 * there is some significant data (media data or expected status notification).
1916 * @param s reading context
1917 * @param for_header non-zero value tells function to work until it
1918 * gets notification from the server that playing has been started,
1919 * otherwise function will work until some media data is received (or
1921 * @return 0 for successful operation, negative value in case of error
1923 static int get_packet(URLContext *s, int for_header)
1925 RTMPContext *rt = s->priv_data;
1928 const uint8_t *next;
1930 uint32_t ts, cts, pts=0;
1932 if (rt->state == STATE_STOPPED)
1936 RTMPPacket rpkt = { 0 };
1937 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
1938 rt->in_chunk_size, rt->prev_pkt[0])) <= 0) {
1940 return AVERROR(EAGAIN);
1942 return AVERROR(EIO);
1945 rt->bytes_read += ret;
1946 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
1947 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
1948 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
1950 rt->last_bytes_read = rt->bytes_read;
1953 ret = rtmp_parse_result(s, rt, &rpkt);
1954 if (ret < 0) {//serious error in current packet
1955 ff_rtmp_packet_destroy(&rpkt);
1958 if (rt->state == STATE_STOPPED) {
1959 ff_rtmp_packet_destroy(&rpkt);
1962 if (for_header && (rt->state == STATE_PLAYING ||
1963 rt->state == STATE_PUBLISHING ||
1964 rt->state == STATE_RECEIVING)) {
1965 ff_rtmp_packet_destroy(&rpkt);
1968 if (!rpkt.data_size || !rt->is_input) {
1969 ff_rtmp_packet_destroy(&rpkt);
1972 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
1973 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
1974 ts = rpkt.timestamp;
1976 // generate packet header and put data into buffer for FLV demuxer
1978 rt->flv_size = rpkt.data_size + 15;
1979 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
1980 bytestream_put_byte(&p, rpkt.type);
1981 bytestream_put_be24(&p, rpkt.data_size);
1982 bytestream_put_be24(&p, ts);
1983 bytestream_put_byte(&p, ts >> 24);
1984 bytestream_put_be24(&p, 0);
1985 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
1986 bytestream_put_be32(&p, 0);
1987 ff_rtmp_packet_destroy(&rpkt);
1989 } else if (rpkt.type == RTMP_PT_NOTIFY) {
1990 ret = handle_notify(s, &rpkt);
1991 ff_rtmp_packet_destroy(&rpkt);
1993 av_log(s, AV_LOG_ERROR, "Handle notify error\n");
1997 } else if (rpkt.type == RTMP_PT_METADATA) {
1998 // we got raw FLV data, make it available for FLV demuxer
2000 rt->flv_size = rpkt.data_size;
2001 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
2002 /* rewrite timestamps */
2004 ts = rpkt.timestamp;
2005 while (next - rpkt.data < rpkt.data_size - 11) {
2007 data_size = bytestream_get_be24(&next);
2009 cts = bytestream_get_be24(&next);
2010 cts |= bytestream_get_byte(&next) << 24;
2015 bytestream_put_be24(&p, ts);
2016 bytestream_put_byte(&p, ts >> 24);
2017 next += data_size + 3 + 4;
2019 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
2020 ff_rtmp_packet_destroy(&rpkt);
2023 ff_rtmp_packet_destroy(&rpkt);
2027 static int rtmp_close(URLContext *h)
2029 RTMPContext *rt = h->priv_data;
2032 if (!rt->is_input) {
2033 rt->flv_data = NULL;
2034 if (rt->out_pkt.data_size)
2035 ff_rtmp_packet_destroy(&rt->out_pkt);
2036 if (rt->state > STATE_FCPUBLISH)
2037 ret = gen_fcunpublish_stream(h, rt);
2039 if (rt->state > STATE_HANDSHAKED)
2040 ret = gen_delete_stream(h, rt);
2042 free_tracked_methods(rt);
2043 av_freep(&rt->flv_data);
2044 ffurl_close(rt->stream);
2049 * Open RTMP connection and verify that the stream can be played.
2051 * URL syntax: rtmp://server[:port][/app][/playpath]
2052 * where 'app' is first one or two directories in the path
2053 * (e.g. /ondemand/, /flash/live/, etc.)
2054 * and 'playpath' is a file name (the rest of the path,
2055 * may be prefixed with "mp4:")
2057 static int rtmp_open(URLContext *s, const char *uri, int flags)
2059 RTMPContext *rt = s->priv_data;
2060 char proto[8], hostname[256], path[1024], *fname;
2064 AVDictionary *opts = NULL;
2067 if (rt->listen_timeout > 0)
2070 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2072 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
2073 path, sizeof(path), s->filename);
2075 if (rt->listen && strcmp(proto, "rtmp")) {
2076 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2078 return AVERROR(EINVAL);
2080 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2081 if (!strcmp(proto, "rtmpts"))
2082 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2084 /* open the http tunneling connection */
2085 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2086 } else if (!strcmp(proto, "rtmps")) {
2087 /* open the tls connection */
2089 port = RTMPS_DEFAULT_PORT;
2090 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2091 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2092 if (!strcmp(proto, "rtmpte"))
2093 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2095 /* open the encrypted connection */
2096 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2099 /* open the tcp connection */
2101 port = RTMP_DEFAULT_PORT;
2103 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2104 "?listen&listen_timeout=%d",
2105 rt->listen_timeout * 1000);
2107 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2110 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2111 &s->interrupt_callback, &opts)) < 0) {
2112 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2116 if (rt->swfverify) {
2117 if ((ret = rtmp_calc_swfhash(s)) < 0)
2121 rt->state = STATE_START;
2122 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2124 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2127 rt->out_chunk_size = 128;
2128 rt->in_chunk_size = 128; // Probably overwritten later
2129 rt->state = STATE_HANDSHAKED;
2131 // Keep the application name when it has been defined by the user.
2134 rt->app = av_malloc(APP_MAX_LENGTH);
2136 ret = AVERROR(ENOMEM);
2140 //extract "app" part from path
2141 if (!strncmp(path, "/ondemand/", 10)) {
2143 memcpy(rt->app, "ondemand", 9);
2145 char *next = *path ? path + 1 : path;
2146 char *p = strchr(next, '/');
2151 // make sure we do not mismatch a playpath for an application instance
2152 char *c = strchr(p + 1, ':');
2153 fname = strchr(p + 1, '/');
2154 if (!fname || (c && c < fname)) {
2156 av_strlcpy(rt->app, path + 1, p - path);
2159 av_strlcpy(rt->app, path + 1, fname - path - 1);
2165 // The name of application has been defined by the user, override it.
2170 if (!rt->playpath) {
2171 int len = strlen(fname);
2173 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2174 if (!rt->playpath) {
2175 ret = AVERROR(ENOMEM);
2179 if (!strchr(fname, ':') && len >= 4 &&
2180 (!strcmp(fname + len - 4, ".f4v") ||
2181 !strcmp(fname + len - 4, ".mp4"))) {
2182 memcpy(rt->playpath, "mp4:", 5);
2183 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
2184 fname[len - 4] = '\0';
2186 rt->playpath[0] = 0;
2188 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2192 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2194 ret = AVERROR(ENOMEM);
2197 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2198 port, "/%s", rt->app);
2201 if (!rt->flashver) {
2202 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2203 if (!rt->flashver) {
2204 ret = AVERROR(ENOMEM);
2208 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2209 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2210 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2212 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2213 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2217 rt->client_report_size = 1048576;
2219 rt->last_bytes_read = 0;
2220 rt->server_bw = 2500000;
2222 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2223 proto, path, rt->app, rt->playpath);
2225 if ((ret = gen_connect(s, rt)) < 0)
2228 if (read_connect(s, s->priv_data) < 0)
2234 ret = get_packet(s, 1);
2235 } while (ret == EAGAIN);
2240 // generate FLV header for demuxer
2242 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
2244 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
2247 rt->flv_data = NULL;
2249 rt->skip_bytes = 13;
2252 s->max_packet_size = rt->stream->max_packet_size;
2257 av_dict_free(&opts);
2262 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2264 RTMPContext *rt = s->priv_data;
2265 int orig_size = size;
2269 int data_left = rt->flv_size - rt->flv_off;
2271 if (data_left >= size) {
2272 memcpy(buf, rt->flv_data + rt->flv_off, size);
2273 rt->flv_off += size;
2276 if (data_left > 0) {
2277 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2280 rt->flv_off = rt->flv_size;
2283 if ((ret = get_packet(s, 0)) < 0)
2289 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2291 RTMPContext *rt = s->priv_data;
2292 int size_temp = size;
2293 int pktsize, pkttype;
2295 const uint8_t *buf_temp = buf;
2300 if (rt->skip_bytes) {
2301 int skip = FFMIN(rt->skip_bytes, size_temp);
2304 rt->skip_bytes -= skip;
2308 if (rt->flv_header_bytes < 11) {
2309 const uint8_t *header = rt->flv_header;
2310 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
2311 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2312 rt->flv_header_bytes += copy;
2314 if (rt->flv_header_bytes < 11)
2317 pkttype = bytestream_get_byte(&header);
2318 pktsize = bytestream_get_be24(&header);
2319 ts = bytestream_get_be24(&header);
2320 ts |= bytestream_get_byte(&header) << 24;
2321 bytestream_get_be24(&header);
2322 rt->flv_size = pktsize;
2324 //force 12bytes header
2325 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2326 pkttype == RTMP_PT_NOTIFY) {
2327 if (pkttype == RTMP_PT_NOTIFY)
2329 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
2332 //this can be a big packet, it's better to send it right here
2333 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
2334 pkttype, ts, pktsize)) < 0)
2337 rt->out_pkt.extra = rt->main_channel_id;
2338 rt->flv_data = rt->out_pkt.data;
2340 if (pkttype == RTMP_PT_NOTIFY)
2341 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
2344 if (rt->flv_size - rt->flv_off > size_temp) {
2345 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
2346 rt->flv_off += size_temp;
2349 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
2350 size_temp -= rt->flv_size - rt->flv_off;
2351 rt->flv_off += rt->flv_size - rt->flv_off;
2354 if (rt->flv_off == rt->flv_size) {
2357 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
2361 rt->flv_header_bytes = 0;
2362 rt->flv_nb_packets++;
2364 } while (buf_temp - buf < size);
2366 if (rt->flv_nb_packets < rt->flush_interval)
2368 rt->flv_nb_packets = 0;
2370 /* set stream into nonblocking mode */
2371 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
2373 /* try to read one byte from the stream */
2374 ret = ffurl_read(rt->stream, &c, 1);
2376 /* switch the stream back into blocking mode */
2377 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
2379 if (ret == AVERROR(EAGAIN)) {
2380 /* no incoming data to handle */
2382 } else if (ret < 0) {
2384 } else if (ret == 1) {
2385 RTMPPacket rpkt = { 0 };
2387 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
2389 rt->prev_pkt[0], c)) <= 0)
2392 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
2395 ff_rtmp_packet_destroy(&rpkt);
2401 #define OFFSET(x) offsetof(RTMPContext, x)
2402 #define DEC AV_OPT_FLAG_DECODING_PARAM
2403 #define ENC AV_OPT_FLAG_ENCODING_PARAM
2405 static const AVOption rtmp_options[] = {
2406 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
2407 {"rtmp_buffer", "Set buffer time in milliseconds. The default is 3000.", OFFSET(client_buffer_time), AV_OPT_TYPE_INT, {.i64 = 3000}, 0, INT_MAX, DEC|ENC},
2408 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
2409 {"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},
2410 {"rtmp_flush_interval", "Number of packets flushed in the same request (RTMPT only).", OFFSET(flush_interval), AV_OPT_TYPE_INT, {.i64 = 10}, 0, INT_MAX, ENC},
2411 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {.i64 = -2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
2412 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
2413 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
2414 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
2415 {"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},
2416 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
2417 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
2418 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
2419 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
2420 {"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},
2421 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
2422 {"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},
2423 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
2424 {"timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
2428 #define RTMP_PROTOCOL(flavor) \
2429 static const AVClass flavor##_class = { \
2430 .class_name = #flavor, \
2431 .item_name = av_default_item_name, \
2432 .option = rtmp_options, \
2433 .version = LIBAVUTIL_VERSION_INT, \
2436 URLProtocol ff_##flavor##_protocol = { \
2438 .url_open = rtmp_open, \
2439 .url_read = rtmp_read, \
2440 .url_write = rtmp_write, \
2441 .url_close = rtmp_close, \
2442 .priv_data_size = sizeof(RTMPContext), \
2443 .flags = URL_PROTOCOL_FLAG_NETWORK, \
2444 .priv_data_class= &flavor##_class, \
2449 RTMP_PROTOCOL(rtmpe)
2450 RTMP_PROTOCOL(rtmps)
2451 RTMP_PROTOCOL(rtmpt)
2452 RTMP_PROTOCOL(rtmpte)
2453 RTMP_PROTOCOL(rtmpts)