2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/base64.h"
30 #include "libavutil/hmac.h"
31 #include "libavutil/intfloat.h"
32 #include "libavutil/lfg.h"
33 #include "libavutil/md5.h"
34 #include "libavutil/opt.h"
35 #include "libavutil/random_seed.h"
43 #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
56 #define RTMP_HEADER 11
58 /** RTMP protocol handler state */
60 STATE_START, ///< client has not done anything yet
61 STATE_HANDSHAKED, ///< client has performed handshake
62 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
63 STATE_PLAYING, ///< client has started receiving multimedia data from server
64 STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
65 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
66 STATE_RECEIVING, ///< received a publish command (for input)
67 STATE_SENDING, ///< received a play command (for output)
68 STATE_STOPPED, ///< the broadcast has been stopped
71 typedef struct TrackedMethod {
76 /** protocol handler context */
77 typedef struct RTMPContext {
79 URLContext* stream; ///< TCP stream used in interactions with RTMP server
80 RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
81 int nb_prev_pkt[2]; ///< number of elements in prev_pkt
82 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
83 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
84 int is_input; ///< input/output flag
85 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
86 int live; ///< 0: recorded, -1: live, -2: both
87 char *app; ///< name of application
88 char *conn; ///< append arbitrary AMF data to the Connect message
89 ClientState state; ///< current state
90 int stream_id; ///< ID assigned by the server for the stream
91 uint8_t* flv_data; ///< buffer with data for demuxer
92 int flv_size; ///< current buffer size
93 int flv_off; ///< number of bytes read from current buffer
94 int flv_nb_packets; ///< number of flv packets published
95 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
96 uint32_t receive_report_size; ///< number of bytes after which we should report the number of received bytes to the peer
97 uint32_t bytes_read; ///< number of bytes read from server
98 uint32_t last_bytes_read; ///< number of bytes read last reported to server
99 uint32_t last_timestamp; ///< last timestamp received in a packet
100 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
101 int has_audio; ///< presence of audio data
102 int has_video; ///< presence of video data
103 int received_metadata; ///< Indicates if we have received metadata about the streams
104 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
105 int flv_header_bytes; ///< number of initialized bytes in flv_header
106 int nb_invokes; ///< keeps track of invoke messages
107 char* tcurl; ///< url of the target stream
108 char* flashver; ///< version of the flash plugin
109 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
110 int swfhash_len; ///< length of the SHA256 hash
111 int swfsize; ///< size of the decompressed SWF file
112 char* swfurl; ///< url of the swf player
113 char* swfverify; ///< URL to player swf file, compute hash/size automatically
114 char swfverification[42]; ///< hash of the SWF verification
115 char* pageurl; ///< url of the web page
116 char* subscribe; ///< name of live stream to subscribe
117 int max_sent_unacked; ///< max unacked sent bytes
118 int client_buffer_time; ///< client buffer time in ms
119 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
120 int encrypted; ///< use an encrypted connection (RTMPE only)
121 TrackedMethod*tracked_methods; ///< tracked methods buffer
122 int nb_tracked_methods; ///< number of tracked methods
123 int tracked_methods_size; ///< size of the tracked methods buffer
124 int listen; ///< listen mode flag
125 int listen_timeout; ///< listen timeout to wait for new connections
126 int nb_streamid; ///< The next stream id to return on createStream calls
127 double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
130 char auth_params[500];
135 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
136 /** Client key used for digest signing */
137 static const uint8_t rtmp_player_key[] = {
138 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
139 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
141 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
142 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
143 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
146 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
147 /** Key used for RTMP server digest signing */
148 static const uint8_t rtmp_server_key[] = {
149 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
150 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
151 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
153 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
154 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
155 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
158 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
160 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
164 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
165 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
166 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
167 sizeof(*rt->tracked_methods))) < 0) {
168 rt->nb_tracked_methods = 0;
169 rt->tracked_methods_size = 0;
174 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
175 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
176 return AVERROR(ENOMEM);
177 rt->tracked_methods[rt->nb_tracked_methods].id = id;
178 rt->nb_tracked_methods++;
183 static void del_tracked_method(RTMPContext *rt, int index)
185 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
186 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
187 rt->nb_tracked_methods--;
190 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
191 char **tracked_method)
193 RTMPContext *rt = s->priv_data;
199 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
200 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
203 for (i = 0; i < rt->nb_tracked_methods; i++) {
204 if (rt->tracked_methods[i].id != pkt_id)
207 *tracked_method = rt->tracked_methods[i].name;
208 del_tracked_method(rt, i);
215 static void free_tracked_methods(RTMPContext *rt)
219 for (i = 0; i < rt->nb_tracked_methods; i ++)
220 av_free(rt->tracked_methods[i].name);
221 av_free(rt->tracked_methods);
222 rt->tracked_methods = NULL;
223 rt->tracked_methods_size = 0;
224 rt->nb_tracked_methods = 0;
227 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
231 if (pkt->type == RTMP_PT_INVOKE && track) {
237 bytestream2_init(&gbc, pkt->data, pkt->size);
238 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
241 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
244 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
248 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
249 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
251 ff_rtmp_packet_destroy(pkt);
255 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
260 /* The type must be B for Boolean, N for number, S for string, O for
261 * object, or Z for null. For Booleans the data must be either 0 or 1 for
262 * FALSE or TRUE, respectively. Likewise for Objects the data must be
263 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
264 * may be named, by prefixing the type with 'N' and specifying the name
265 * before the value (ie. NB:myFlag:1). This option may be used multiple times
266 * to construct arbitrary AMF sequences. */
267 if (param[0] && param[1] == ':') {
270 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
273 value = strchr(field, ':');
279 ff_amf_write_field_name(p, field);
286 ff_amf_write_bool(p, value[0] != '0');
289 ff_amf_write_string(p, value);
292 ff_amf_write_number(p, strtod(value, NULL));
295 ff_amf_write_null(p);
299 ff_amf_write_object_start(p);
301 ff_amf_write_object_end(p);
311 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
312 return AVERROR(EINVAL);
316 * Generate 'connect' call and send it to the server.
318 static int gen_connect(URLContext *s, RTMPContext *rt)
324 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
330 ff_amf_write_string(&p, "connect");
331 ff_amf_write_number(&p, ++rt->nb_invokes);
332 ff_amf_write_object_start(&p);
333 ff_amf_write_field_name(&p, "app");
334 ff_amf_write_string2(&p, rt->app, rt->auth_params);
337 ff_amf_write_field_name(&p, "type");
338 ff_amf_write_string(&p, "nonprivate");
340 ff_amf_write_field_name(&p, "flashVer");
341 ff_amf_write_string(&p, rt->flashver);
344 ff_amf_write_field_name(&p, "swfUrl");
345 ff_amf_write_string(&p, rt->swfurl);
348 ff_amf_write_field_name(&p, "tcUrl");
349 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
351 ff_amf_write_field_name(&p, "fpad");
352 ff_amf_write_bool(&p, 0);
353 ff_amf_write_field_name(&p, "capabilities");
354 ff_amf_write_number(&p, 15.0);
356 /* Tell the server we support all the audio codecs except
357 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
358 * which are unused in the RTMP protocol implementation. */
359 ff_amf_write_field_name(&p, "audioCodecs");
360 ff_amf_write_number(&p, 4071.0);
361 ff_amf_write_field_name(&p, "videoCodecs");
362 ff_amf_write_number(&p, 252.0);
363 ff_amf_write_field_name(&p, "videoFunction");
364 ff_amf_write_number(&p, 1.0);
367 ff_amf_write_field_name(&p, "pageUrl");
368 ff_amf_write_string(&p, rt->pageurl);
371 ff_amf_write_object_end(&p);
374 char *param = rt->conn;
376 // Write arbitrary AMF data to the Connect message.
379 param += strspn(param, " ");
382 sep = strchr(param, ' ');
385 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
386 // Invalid AMF parameter.
387 ff_rtmp_packet_destroy(&pkt);
398 pkt.size = p - pkt.data;
400 return rtmp_send_packet(rt, &pkt, 1);
403 static int read_connect(URLContext *s, RTMPContext *rt)
405 RTMPPacket pkt = { 0 };
415 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
416 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
419 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
420 if ((ret = handle_chunk_size(s, &pkt)) < 0)
422 ff_rtmp_packet_destroy(&pkt);
423 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
424 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
429 bytestream2_init(&gbc, cp, pkt.size);
430 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
431 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
432 ff_rtmp_packet_destroy(&pkt);
433 return AVERROR_INVALIDDATA;
435 if (strcmp(command, "connect")) {
436 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
437 ff_rtmp_packet_destroy(&pkt);
438 return AVERROR_INVALIDDATA;
440 ret = ff_amf_read_number(&gbc, &seqnum);
442 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
443 /* Here one could parse an AMF Object with data as flashVers and others. */
444 ret = ff_amf_get_field_value(gbc.buffer,
445 gbc.buffer + bytestream2_get_bytes_left(&gbc),
446 "app", tmpstr, sizeof(tmpstr));
448 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
449 if (!ret && strcmp(tmpstr, rt->app))
450 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
452 ff_rtmp_packet_destroy(&pkt);
454 // Send Window Acknowledgement Size (as defined in specification)
455 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
456 RTMP_PT_WINDOW_ACK_SIZE, 0, 4)) < 0)
459 // Inform the peer about how often we want acknowledgements about what
460 // we send. (We don't check for the acknowledgements currently.)
461 bytestream_put_be32(&p, rt->max_sent_unacked);
462 pkt.size = p - pkt.data;
463 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
464 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
465 ff_rtmp_packet_destroy(&pkt);
468 // Set Peer Bandwidth
469 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
470 RTMP_PT_SET_PEER_BW, 0, 5)) < 0)
473 // Tell the peer to only send this many bytes unless it gets acknowledgements.
474 // This could be any arbitrary value we want here.
475 bytestream_put_be32(&p, rt->max_sent_unacked);
476 bytestream_put_byte(&p, 2); // dynamic
477 pkt.size = p - pkt.data;
478 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
479 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
480 ff_rtmp_packet_destroy(&pkt);
485 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
486 RTMP_PT_USER_CONTROL, 0, 6)) < 0)
490 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
491 bytestream_put_be32(&p, 0); // Stream 0
492 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
493 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
494 ff_rtmp_packet_destroy(&pkt);
499 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
500 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
504 bytestream_put_be32(&p, rt->out_chunk_size);
505 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
506 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
507 ff_rtmp_packet_destroy(&pkt);
511 // Send _result NetConnection.Connect.Success to connect
512 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
514 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
518 ff_amf_write_string(&p, "_result");
519 ff_amf_write_number(&p, seqnum);
521 ff_amf_write_object_start(&p);
522 ff_amf_write_field_name(&p, "fmsVer");
523 ff_amf_write_string(&p, "FMS/3,0,1,123");
524 ff_amf_write_field_name(&p, "capabilities");
525 ff_amf_write_number(&p, 31);
526 ff_amf_write_object_end(&p);
528 ff_amf_write_object_start(&p);
529 ff_amf_write_field_name(&p, "level");
530 ff_amf_write_string(&p, "status");
531 ff_amf_write_field_name(&p, "code");
532 ff_amf_write_string(&p, "NetConnection.Connect.Success");
533 ff_amf_write_field_name(&p, "description");
534 ff_amf_write_string(&p, "Connection succeeded.");
535 ff_amf_write_field_name(&p, "objectEncoding");
536 ff_amf_write_number(&p, 0);
537 ff_amf_write_object_end(&p);
539 pkt.size = p - pkt.data;
540 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
541 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
542 ff_rtmp_packet_destroy(&pkt);
546 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
547 RTMP_PT_INVOKE, 0, 30)) < 0)
550 ff_amf_write_string(&p, "onBWDone");
551 ff_amf_write_number(&p, 0);
552 ff_amf_write_null(&p);
553 ff_amf_write_number(&p, 8192);
554 pkt.size = p - pkt.data;
555 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
556 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
557 ff_rtmp_packet_destroy(&pkt);
563 * Generate 'releaseStream' call and send it to the server. It should make
564 * the server release some channel for media streams.
566 static int gen_release_stream(URLContext *s, RTMPContext *rt)
572 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
573 0, 29 + strlen(rt->playpath))) < 0)
576 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
578 ff_amf_write_string(&p, "releaseStream");
579 ff_amf_write_number(&p, ++rt->nb_invokes);
580 ff_amf_write_null(&p);
581 ff_amf_write_string(&p, rt->playpath);
583 return rtmp_send_packet(rt, &pkt, 1);
587 * Generate 'FCPublish' call and send it to the server. It should make
588 * the server prepare for receiving media streams.
590 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
596 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
597 0, 25 + strlen(rt->playpath))) < 0)
600 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
602 ff_amf_write_string(&p, "FCPublish");
603 ff_amf_write_number(&p, ++rt->nb_invokes);
604 ff_amf_write_null(&p);
605 ff_amf_write_string(&p, rt->playpath);
607 return rtmp_send_packet(rt, &pkt, 1);
611 * Generate 'FCUnpublish' call and send it to the server. It should make
612 * the server destroy stream.
614 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
620 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
621 0, 27 + strlen(rt->playpath))) < 0)
624 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
626 ff_amf_write_string(&p, "FCUnpublish");
627 ff_amf_write_number(&p, ++rt->nb_invokes);
628 ff_amf_write_null(&p);
629 ff_amf_write_string(&p, rt->playpath);
631 return rtmp_send_packet(rt, &pkt, 0);
635 * Generate 'createStream' call and send it to the server. It should make
636 * the server allocate some channel for media streams.
638 static int gen_create_stream(URLContext *s, RTMPContext *rt)
644 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
646 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
651 ff_amf_write_string(&p, "createStream");
652 ff_amf_write_number(&p, ++rt->nb_invokes);
653 ff_amf_write_null(&p);
655 return rtmp_send_packet(rt, &pkt, 1);
660 * Generate 'deleteStream' call and send it to the server. It should make
661 * the server remove some channel for media streams.
663 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
669 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
671 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
676 ff_amf_write_string(&p, "deleteStream");
677 ff_amf_write_number(&p, ++rt->nb_invokes);
678 ff_amf_write_null(&p);
679 ff_amf_write_number(&p, rt->stream_id);
681 return rtmp_send_packet(rt, &pkt, 0);
685 * Generate 'getStreamLength' call and send it to the server. If the server
686 * knows the duration of the selected stream, it will reply with the duration
689 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
695 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
696 0, 31 + strlen(rt->playpath))) < 0)
700 ff_amf_write_string(&p, "getStreamLength");
701 ff_amf_write_number(&p, ++rt->nb_invokes);
702 ff_amf_write_null(&p);
703 ff_amf_write_string(&p, rt->playpath);
705 return rtmp_send_packet(rt, &pkt, 1);
709 * Generate client buffer time and send it to the server.
711 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
717 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
722 bytestream_put_be16(&p, 3); // SetBuffer Length
723 bytestream_put_be32(&p, rt->stream_id);
724 bytestream_put_be32(&p, rt->client_buffer_time);
726 return rtmp_send_packet(rt, &pkt, 0);
730 * Generate 'play' call and send it to the server, then ping the server
731 * to start actual playing.
733 static int gen_play(URLContext *s, RTMPContext *rt)
739 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
741 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
742 0, 29 + strlen(rt->playpath))) < 0)
745 pkt.extra = rt->stream_id;
748 ff_amf_write_string(&p, "play");
749 ff_amf_write_number(&p, ++rt->nb_invokes);
750 ff_amf_write_null(&p);
751 ff_amf_write_string(&p, rt->playpath);
752 ff_amf_write_number(&p, rt->live * 1000);
754 return rtmp_send_packet(rt, &pkt, 1);
757 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
763 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
766 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
769 pkt.extra = rt->stream_id;
772 ff_amf_write_string(&p, "seek");
773 ff_amf_write_number(&p, 0); //no tracking back responses
774 ff_amf_write_null(&p); //as usual, the first null param
775 ff_amf_write_number(&p, timestamp); //where we want to jump
777 return rtmp_send_packet(rt, &pkt, 1);
781 * Generate a pause packet that either pauses or unpauses the current stream.
783 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
789 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
792 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
795 pkt.extra = rt->stream_id;
798 ff_amf_write_string(&p, "pause");
799 ff_amf_write_number(&p, 0); //no tracking back responses
800 ff_amf_write_null(&p); //as usual, the first null param
801 ff_amf_write_bool(&p, pause); // pause or unpause
802 ff_amf_write_number(&p, timestamp); //where we pause the stream
804 return rtmp_send_packet(rt, &pkt, 1);
808 * Generate 'publish' call and send it to the server.
810 static int gen_publish(URLContext *s, RTMPContext *rt)
816 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
818 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
819 0, 30 + strlen(rt->playpath))) < 0)
822 pkt.extra = rt->stream_id;
825 ff_amf_write_string(&p, "publish");
826 ff_amf_write_number(&p, ++rt->nb_invokes);
827 ff_amf_write_null(&p);
828 ff_amf_write_string(&p, rt->playpath);
829 ff_amf_write_string(&p, "live");
831 return rtmp_send_packet(rt, &pkt, 1);
835 * Generate ping reply and send it to the server.
837 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
843 if (ppkt->size < 6) {
844 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
846 return AVERROR_INVALIDDATA;
849 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,RTMP_PT_USER_CONTROL,
850 ppkt->timestamp + 1, 6)) < 0)
854 bytestream_put_be16(&p, 7); // PingResponse
855 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
857 return rtmp_send_packet(rt, &pkt, 0);
861 * Generate SWF verification message and send it to the server.
863 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
869 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
870 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
875 bytestream_put_be16(&p, 27);
876 memcpy(p, rt->swfverification, 42);
878 return rtmp_send_packet(rt, &pkt, 0);
882 * Generate window acknowledgement size message and send it to the server.
884 static int gen_window_ack_size(URLContext *s, RTMPContext *rt)
890 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_WINDOW_ACK_SIZE,
895 bytestream_put_be32(&p, rt->max_sent_unacked);
897 return rtmp_send_packet(rt, &pkt, 0);
901 * Generate check bandwidth message and send it to the server.
903 static int gen_check_bw(URLContext *s, RTMPContext *rt)
909 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
914 ff_amf_write_string(&p, "_checkbw");
915 ff_amf_write_number(&p, ++rt->nb_invokes);
916 ff_amf_write_null(&p);
918 return rtmp_send_packet(rt, &pkt, 1);
922 * Generate report on bytes read so far and send it to the server.
924 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
930 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
935 bytestream_put_be32(&p, rt->bytes_read);
937 return rtmp_send_packet(rt, &pkt, 0);
940 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
941 const char *subscribe)
947 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
948 0, 27 + strlen(subscribe))) < 0)
952 ff_amf_write_string(&p, "FCSubscribe");
953 ff_amf_write_number(&p, ++rt->nb_invokes);
954 ff_amf_write_null(&p);
955 ff_amf_write_string(&p, subscribe);
957 return rtmp_send_packet(rt, &pkt, 1);
960 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
961 const uint8_t *key, int keylen, uint8_t *dst)
965 hmac = av_hmac_alloc(AV_HMAC_SHA256);
967 return AVERROR(ENOMEM);
969 av_hmac_init(hmac, key, keylen);
971 av_hmac_update(hmac, src, len);
972 } else { //skip 32 bytes used for storing digest
973 av_hmac_update(hmac, src, gap);
974 av_hmac_update(hmac, src + gap + 32, len - gap - 32);
976 av_hmac_final(hmac, dst, 32);
983 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
986 int i, digest_pos = 0;
988 for (i = 0; i < 4; i++)
989 digest_pos += buf[i + off];
990 digest_pos = digest_pos % mod_val + add_val;
996 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
997 * will be stored) into that packet.
999 * @param buf handshake data (1536 bytes)
1000 * @param encrypted use an encrypted connection (RTMPE)
1001 * @return offset to the digest inside input data
1003 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1005 int ret, digest_pos;
1008 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1010 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1012 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1013 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1022 * Verify that the received server response has the expected digest value.
1024 * @param buf handshake data received from the server (1536 bytes)
1025 * @param off position to search digest offset from
1026 * @return 0 if digest is valid, digest position otherwise
1028 static int rtmp_validate_digest(uint8_t *buf, int off)
1031 int ret, digest_pos;
1033 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1035 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1036 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1041 if (!memcmp(digest, buf + digest_pos, 32))
1046 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1052 if (rt->swfhash_len != 32) {
1053 av_log(s, AV_LOG_ERROR,
1054 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1055 return AVERROR(EINVAL);
1058 p = &rt->swfverification[0];
1059 bytestream_put_byte(&p, 1);
1060 bytestream_put_byte(&p, 1);
1061 bytestream_put_be32(&p, rt->swfsize);
1062 bytestream_put_be32(&p, rt->swfsize);
1064 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1071 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1072 uint8_t **out_data, int64_t *out_size)
1074 z_stream zs = { 0 };
1079 zs.avail_in = in_size;
1080 zs.next_in = in_data;
1081 ret = inflateInit(&zs);
1083 return AVERROR_UNKNOWN;
1086 uint8_t tmp_buf[16384];
1088 zs.avail_out = sizeof(tmp_buf);
1089 zs.next_out = tmp_buf;
1091 ret = inflate(&zs, Z_NO_FLUSH);
1092 if (ret != Z_OK && ret != Z_STREAM_END) {
1093 ret = AVERROR_UNKNOWN;
1097 size = sizeof(tmp_buf) - zs.avail_out;
1098 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1099 ret = AVERROR(ENOMEM);
1104 memcpy(*out_data + *out_size, tmp_buf, size);
1106 } while (zs.avail_out == 0);
1114 static int rtmp_calc_swfhash(URLContext *s)
1116 RTMPContext *rt = s->priv_data;
1117 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1124 /* Get the SWF player file. */
1125 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1126 &s->interrupt_callback, NULL, s->protocols, s)) < 0) {
1127 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1131 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1136 if (!(in_data = av_malloc(in_size))) {
1137 ret = AVERROR(ENOMEM);
1141 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1145 ret = AVERROR_INVALIDDATA;
1149 if (!memcmp(in_data, "CWS", 3)) {
1152 /* Decompress the SWF player file using Zlib. */
1153 if (!(out_data = av_malloc(8))) {
1154 ret = AVERROR(ENOMEM);
1157 *in_data = 'F'; // magic stuff
1158 memcpy(out_data, in_data, 8);
1161 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1162 &out_data, &out_size)) < 0)
1167 av_log(s, AV_LOG_ERROR,
1168 "Zlib is required for decompressing the SWF player file.\n");
1169 ret = AVERROR(EINVAL);
1177 /* Compute the SHA256 hash of the SWF player file. */
1178 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1179 "Genuine Adobe Flash Player 001", 30,
1183 /* Set SWFVerification parameters. */
1184 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1185 rt->swfsize = swfsize;
1189 av_freep(&out_data);
1190 ffurl_close(stream);
1195 * Perform handshake with the server by means of exchanging pseudorandom data
1196 * signed with HMAC-SHA2 digest.
1198 * @return 0 if handshake succeeds, negative value otherwise
1200 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1203 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1204 3, // unencrypted data
1205 0, 0, 0, 0, // client uptime
1211 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1212 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1214 int server_pos, client_pos;
1215 uint8_t digest[32], signature[32];
1218 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1220 av_lfg_init(&rnd, 0xDEADC0DE);
1221 // generate handshake packet - 1536 bytes of pseudorandom data
1222 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1223 tosend[i] = av_lfg_get(&rnd) >> 24;
1225 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1226 /* When the client wants to use RTMPE, we have to change the command
1227 * byte to 0x06 which means to use encrypted data and we have to set
1228 * the flash version to at least 9.0.115.0. */
1235 /* Initialize the Diffie-Hellmann context and generate the public key
1236 * to send to the server. */
1237 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1241 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1245 if ((ret = ffurl_write(rt->stream, tosend,
1246 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1247 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1251 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1252 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1253 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1257 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1258 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1259 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1263 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1264 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1265 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1267 if (rt->is_input && serverdata[5] >= 3) {
1268 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1274 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1279 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1280 return AVERROR(EIO);
1284 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1285 * key are the last 32 bytes of the server handshake. */
1287 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1288 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1292 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1293 rtmp_server_key, sizeof(rtmp_server_key),
1298 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1299 0, digest, 32, signature);
1303 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1304 /* Compute the shared secret key sent by the server and initialize
1305 * the RC4 encryption. */
1306 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1307 tosend + 1, type)) < 0)
1310 /* Encrypt the signature received by the server. */
1311 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1314 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1315 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1316 return AVERROR(EIO);
1319 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1320 tosend[i] = av_lfg_get(&rnd) >> 24;
1321 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1322 rtmp_player_key, sizeof(rtmp_player_key),
1327 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1329 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1333 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1334 /* Encrypt the signature to be send to the server. */
1335 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1336 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1340 // write reply back to the server
1341 if ((ret = ffurl_write(rt->stream, tosend,
1342 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1345 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1346 /* Set RC4 keys for encryption and update the keystreams. */
1347 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1351 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1352 /* Compute the shared secret key sent by the server and initialize
1353 * the RC4 encryption. */
1354 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1355 tosend + 1, 1)) < 0)
1358 if (serverdata[0] == 9) {
1359 /* Encrypt the signature received by the server. */
1360 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1365 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1366 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1369 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1370 /* Set RC4 keys for encryption and update the keystreams. */
1371 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1379 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1380 uint32_t *second_int, char *arraydata,
1385 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1386 RTMP_HANDSHAKE_PACKET_SIZE);
1388 return AVERROR(EIO);
1389 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1390 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1391 " not following standard\n", (int)inoutsize);
1392 return AVERROR(EINVAL);
1395 *first_int = AV_RB32(arraydata);
1396 *second_int = AV_RB32(arraydata + 4);
1400 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1401 uint32_t second_int, char *arraydata, int size)
1405 AV_WB32(arraydata, first_int);
1406 AV_WB32(arraydata + 4, second_int);
1407 inoutsize = ffurl_write(rt->stream, arraydata,
1408 RTMP_HANDSHAKE_PACKET_SIZE);
1409 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1410 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1411 return AVERROR(EIO);
1418 * rtmp handshake server side
1420 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1422 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1424 uint32_t hs_my_epoch;
1425 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1426 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1433 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1434 if (inoutsize <= 0) {
1435 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1436 return AVERROR(EIO);
1439 if (buffer[0] != 3) {
1440 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1441 return AVERROR(EIO);
1443 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1444 av_log(s, AV_LOG_ERROR,
1445 "Unable to write answer - RTMP S0\n");
1446 return AVERROR(EIO);
1449 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1450 RTMP_HANDSHAKE_PACKET_SIZE);
1452 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1456 /* By now same epoch will be sent */
1457 hs_my_epoch = hs_epoch;
1458 /* Generate random */
1459 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1461 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1463 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1464 RTMP_HANDSHAKE_PACKET_SIZE);
1466 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1470 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1471 RTMP_HANDSHAKE_PACKET_SIZE);
1473 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1477 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1478 RTMP_HANDSHAKE_PACKET_SIZE);
1480 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1483 if (temp != hs_my_epoch)
1484 av_log(s, AV_LOG_WARNING,
1485 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1486 if (memcmp(buffer + 8, hs_s1 + 8,
1487 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1488 av_log(s, AV_LOG_WARNING,
1489 "Erroneous C2 Message random does not match up\n");
1494 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1496 RTMPContext *rt = s->priv_data;
1499 if (pkt->size < 4) {
1500 av_log(s, AV_LOG_ERROR,
1501 "Too short chunk size change packet (%d)\n",
1503 return AVERROR_INVALIDDATA;
1506 if (!rt->is_input) {
1507 /* Send the same chunk size change packet back to the server,
1508 * setting the outgoing chunk size to the same as the incoming one. */
1509 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1510 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1512 rt->out_chunk_size = AV_RB32(pkt->data);
1515 rt->in_chunk_size = AV_RB32(pkt->data);
1516 if (rt->in_chunk_size <= 0) {
1517 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1519 return AVERROR_INVALIDDATA;
1521 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1527 static int handle_user_control(URLContext *s, RTMPPacket *pkt)
1529 RTMPContext *rt = s->priv_data;
1532 if (pkt->size < 2) {
1533 av_log(s, AV_LOG_ERROR, "Too short user control packet (%d)\n",
1535 return AVERROR_INVALIDDATA;
1538 t = AV_RB16(pkt->data);
1539 if (t == 6) { // PingRequest
1540 if ((ret = gen_pong(s, rt, pkt)) < 0)
1542 } else if (t == 26) {
1544 if ((ret = gen_swf_verification(s, rt)) < 0)
1547 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1554 static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt)
1556 RTMPContext *rt = s->priv_data;
1558 if (pkt->size < 4) {
1559 av_log(s, AV_LOG_ERROR,
1560 "Peer bandwidth packet is less than 4 bytes long (%d)\n",
1562 return AVERROR_INVALIDDATA;
1565 // We currently don't check how much the peer has acknowledged of
1566 // what we have sent. To do that properly, we should call
1567 // gen_window_ack_size here, to tell the peer that we want an
1568 // acknowledgement with (at least) that interval.
1569 rt->max_sent_unacked = AV_RB32(pkt->data);
1570 if (rt->max_sent_unacked <= 0) {
1571 av_log(s, AV_LOG_ERROR, "Incorrect set peer bandwidth %d\n",
1572 rt->max_sent_unacked);
1573 return AVERROR_INVALIDDATA;
1576 av_log(s, AV_LOG_DEBUG, "Max sent, unacked = %d\n", rt->max_sent_unacked);
1581 static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt)
1583 RTMPContext *rt = s->priv_data;
1585 if (pkt->size < 4) {
1586 av_log(s, AV_LOG_ERROR,
1587 "Too short window acknowledgement size packet (%d)\n",
1589 return AVERROR_INVALIDDATA;
1592 rt->receive_report_size = AV_RB32(pkt->data);
1593 if (rt->receive_report_size <= 0) {
1594 av_log(s, AV_LOG_ERROR, "Incorrect window acknowledgement size %d\n",
1595 rt->receive_report_size);
1596 return AVERROR_INVALIDDATA;
1598 av_log(s, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", rt->receive_report_size);
1599 // Send an Acknowledgement packet after receiving half the maximum
1600 // size, to make sure the peer can keep on sending without waiting
1601 // for acknowledgements.
1602 rt->receive_report_size >>= 1;
1607 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1608 const char *opaque, const char *challenge)
1611 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1612 struct AVMD5 *md5 = av_md5_alloc();
1614 return AVERROR(ENOMEM);
1616 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1619 av_md5_update(md5, user, strlen(user));
1620 av_md5_update(md5, salt, strlen(salt));
1621 av_md5_update(md5, rt->password, strlen(rt->password));
1622 av_md5_final(md5, hash);
1623 av_base64_encode(hashstr, sizeof(hashstr), hash,
1626 av_md5_update(md5, hashstr, strlen(hashstr));
1628 av_md5_update(md5, opaque, strlen(opaque));
1630 av_md5_update(md5, challenge, strlen(challenge));
1631 av_md5_update(md5, challenge2, strlen(challenge2));
1632 av_md5_final(md5, hash);
1633 av_base64_encode(hashstr, sizeof(hashstr), hash,
1635 snprintf(rt->auth_params, sizeof(rt->auth_params),
1636 "?authmod=%s&user=%s&challenge=%s&response=%s",
1637 "adobe", user, challenge2, hashstr);
1639 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1640 "&opaque=%s", opaque);
1646 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1649 char hashstr1[33], hashstr2[33];
1650 const char *realm = "live";
1651 const char *method = "publish";
1652 const char *qop = "auth";
1653 const char *nc = "00000001";
1655 struct AVMD5 *md5 = av_md5_alloc();
1657 return AVERROR(ENOMEM);
1659 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1662 av_md5_update(md5, user, strlen(user));
1663 av_md5_update(md5, ":", 1);
1664 av_md5_update(md5, realm, strlen(realm));
1665 av_md5_update(md5, ":", 1);
1666 av_md5_update(md5, rt->password, strlen(rt->password));
1667 av_md5_final(md5, hash);
1668 ff_data_to_hex(hashstr1, hash, 16, 1);
1669 hashstr1[32] = '\0';
1672 av_md5_update(md5, method, strlen(method));
1673 av_md5_update(md5, ":/", 2);
1674 av_md5_update(md5, rt->app, strlen(rt->app));
1675 if (!strchr(rt->app, '/'))
1676 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1677 av_md5_final(md5, hash);
1678 ff_data_to_hex(hashstr2, hash, 16, 1);
1679 hashstr2[32] = '\0';
1682 av_md5_update(md5, hashstr1, strlen(hashstr1));
1683 av_md5_update(md5, ":", 1);
1685 av_md5_update(md5, nonce, strlen(nonce));
1686 av_md5_update(md5, ":", 1);
1687 av_md5_update(md5, nc, strlen(nc));
1688 av_md5_update(md5, ":", 1);
1689 av_md5_update(md5, cnonce, strlen(cnonce));
1690 av_md5_update(md5, ":", 1);
1691 av_md5_update(md5, qop, strlen(qop));
1692 av_md5_update(md5, ":", 1);
1693 av_md5_update(md5, hashstr2, strlen(hashstr2));
1694 av_md5_final(md5, hash);
1695 ff_data_to_hex(hashstr1, hash, 16, 1);
1697 snprintf(rt->auth_params, sizeof(rt->auth_params),
1698 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1699 "llnw", user, nonce, cnonce, nc, hashstr1);
1705 static int handle_connect_error(URLContext *s, const char *desc)
1707 RTMPContext *rt = s->priv_data;
1708 char buf[300], *ptr, authmod[15];
1710 const char *user = "", *salt = "", *opaque = NULL,
1711 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1713 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1714 !(cptr = strstr(desc, "authmod=llnw"))) {
1715 av_log(s, AV_LOG_ERROR,
1716 "Unknown connect error (unsupported authentication method?)\n");
1717 return AVERROR_UNKNOWN;
1719 cptr += strlen("authmod=");
1720 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1721 authmod[i++] = *cptr++;
1724 if (!rt->username[0] || !rt->password[0]) {
1725 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1726 return AVERROR_UNKNOWN;
1729 if (strstr(desc, "?reason=authfailed")) {
1730 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1731 return AVERROR_UNKNOWN;
1732 } else if (strstr(desc, "?reason=nosuchuser")) {
1733 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1734 return AVERROR_UNKNOWN;
1737 if (rt->auth_tried) {
1738 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1739 return AVERROR_UNKNOWN;
1742 rt->auth_params[0] = '\0';
1744 if (strstr(desc, "code=403 need auth")) {
1745 snprintf(rt->auth_params, sizeof(rt->auth_params),
1746 "?authmod=%s&user=%s", authmod, rt->username);
1750 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1751 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1752 return AVERROR_UNKNOWN;
1755 av_strlcpy(buf, cptr + 1, sizeof(buf));
1759 char *next = strchr(ptr, '&');
1760 char *value = strchr(ptr, '=');
1765 if (!strcmp(ptr, "user")) {
1767 } else if (!strcmp(ptr, "salt")) {
1769 } else if (!strcmp(ptr, "opaque")) {
1771 } else if (!strcmp(ptr, "challenge")) {
1773 } else if (!strcmp(ptr, "nonce")) {
1779 if (!strcmp(authmod, "adobe")) {
1780 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1783 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1791 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1793 RTMPContext *rt = s->priv_data;
1794 const uint8_t *data_end = pkt->data + pkt->size;
1795 char *tracked_method = NULL;
1796 int level = AV_LOG_ERROR;
1797 uint8_t tmpstr[256];
1800 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1803 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1804 "description", tmpstr, sizeof(tmpstr))) {
1805 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1806 !strcmp(tracked_method, "releaseStream") ||
1807 !strcmp(tracked_method, "FCSubscribe") ||
1808 !strcmp(tracked_method, "FCPublish"))) {
1809 /* Gracefully ignore Adobe-specific historical artifact errors. */
1810 level = AV_LOG_WARNING;
1812 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1813 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1815 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1816 ret = handle_connect_error(s, tmpstr);
1818 rt->do_reconnect = 1;
1819 level = AV_LOG_VERBOSE;
1822 ret = AVERROR_UNKNOWN;
1823 av_log(s, level, "Server error: %s\n", tmpstr);
1826 av_free(tracked_method);
1830 static int write_begin(URLContext *s)
1832 RTMPContext *rt = s->priv_data;
1834 RTMPPacket spkt = { 0 };
1837 // Send Stream Begin 1
1838 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1839 RTMP_PT_USER_CONTROL, 0, 6)) < 0) {
1840 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1844 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1845 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1846 bytestream2_put_be32(&pbc, rt->nb_streamid);
1848 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1849 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1851 ff_rtmp_packet_destroy(&spkt);
1856 static int write_status(URLContext *s, RTMPPacket *pkt,
1857 const char *status, const char *filename)
1859 RTMPContext *rt = s->priv_data;
1860 RTMPPacket spkt = { 0 };
1861 char statusmsg[128];
1865 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1867 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1868 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1873 spkt.extra = pkt->extra;
1874 ff_amf_write_string(&pp, "onStatus");
1875 ff_amf_write_number(&pp, 0);
1876 ff_amf_write_null(&pp);
1878 ff_amf_write_object_start(&pp);
1879 ff_amf_write_field_name(&pp, "level");
1880 ff_amf_write_string(&pp, "status");
1881 ff_amf_write_field_name(&pp, "code");
1882 ff_amf_write_string(&pp, status);
1883 ff_amf_write_field_name(&pp, "description");
1884 snprintf(statusmsg, sizeof(statusmsg),
1885 "%s is now published", filename);
1886 ff_amf_write_string(&pp, statusmsg);
1887 ff_amf_write_field_name(&pp, "details");
1888 ff_amf_write_string(&pp, filename);
1889 ff_amf_write_object_end(&pp);
1891 spkt.size = pp - spkt.data;
1892 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1893 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1894 ff_rtmp_packet_destroy(&spkt);
1899 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1901 RTMPContext *rt = s->priv_data;
1907 const uint8_t *p = pkt->data;
1909 RTMPPacket spkt = { 0 };
1913 bytestream2_init(&gbc, p, pkt->size);
1914 if (ff_amf_read_string(&gbc, command, sizeof(command),
1916 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1917 return AVERROR_INVALIDDATA;
1920 ret = ff_amf_read_number(&gbc, &seqnum);
1923 ret = ff_amf_read_null(&gbc);
1926 if (!strcmp(command, "FCPublish") ||
1927 !strcmp(command, "publish")) {
1928 ret = ff_amf_read_string(&gbc, filename,
1929 sizeof(filename), &stringlen);
1931 if (ret == AVERROR(EINVAL))
1932 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
1934 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
1939 pchar = strrchr(s->filename, '/');
1941 av_log(s, AV_LOG_WARNING,
1942 "Unable to find / in url %s, bad format\n",
1944 pchar = s->filename;
1947 if (strcmp(pchar, filename))
1948 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1949 " %s\n", filename, pchar);
1951 rt->state = STATE_RECEIVING;
1954 if (!strcmp(command, "FCPublish")) {
1955 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1957 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1958 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1962 ff_amf_write_string(&pp, "onFCPublish");
1963 } else if (!strcmp(command, "publish")) {
1964 ret = write_begin(s);
1968 // Send onStatus(NetStream.Publish.Start)
1969 return write_status(s, pkt, "NetStream.Publish.Start",
1971 } else if (!strcmp(command, "play")) {
1972 ret = write_begin(s);
1975 rt->state = STATE_SENDING;
1976 return write_status(s, pkt, "NetStream.Play.Start",
1979 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1981 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1982 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1986 ff_amf_write_string(&pp, "_result");
1987 ff_amf_write_number(&pp, seqnum);
1988 ff_amf_write_null(&pp);
1989 if (!strcmp(command, "createStream")) {
1991 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1992 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1993 ff_amf_write_number(&pp, rt->nb_streamid);
1994 /* By now we don't control which streams are removed in
1995 * deleteStream. There is no stream creation control
1996 * if a client creates more than 2^32 - 2 streams. */
1999 spkt.size = pp - spkt.data;
2000 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2001 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2002 ff_rtmp_packet_destroy(&spkt);
2007 * Read the AMF_NUMBER response ("_result") to a function call
2008 * (e.g. createStream()). This response should be made up of the AMF_STRING
2009 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2010 * successful response, we will return set the value to number (otherwise number
2011 * will not be changed).
2013 * @return 0 if reading the value succeeds, negative value otherwise
2015 static int read_number_result(RTMPPacket *pkt, double *number)
2017 // We only need to fit "_result" in this.
2018 uint8_t strbuffer[8];
2023 bytestream2_init(&gbc, pkt->data, pkt->size);
2025 // Value 1/4: "_result" as AMF_STRING
2026 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2027 return AVERROR_INVALIDDATA;
2028 if (strcmp(strbuffer, "_result"))
2029 return AVERROR_INVALIDDATA;
2030 // Value 2/4: The callee reference number
2031 if (ff_amf_read_number(&gbc, &numbuffer))
2032 return AVERROR_INVALIDDATA;
2034 if (ff_amf_read_null(&gbc))
2035 return AVERROR_INVALIDDATA;
2036 // Value 4/4: The response as AMF_NUMBER
2037 if (ff_amf_read_number(&gbc, &numbuffer))
2038 return AVERROR_INVALIDDATA;
2040 *number = numbuffer;
2045 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2047 RTMPContext *rt = s->priv_data;
2048 char *tracked_method = NULL;
2051 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2054 if (!tracked_method) {
2055 /* Ignore this reply when the current method is not tracked. */
2059 if (!strcmp(tracked_method, "connect")) {
2060 if (!rt->is_input) {
2061 if ((ret = gen_release_stream(s, rt)) < 0)
2064 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2067 if ((ret = gen_window_ack_size(s, rt)) < 0)
2071 if ((ret = gen_create_stream(s, rt)) < 0)
2075 /* Send the FCSubscribe command when the name of live
2076 * stream is defined by the user or if it's a live stream. */
2077 if (rt->subscribe) {
2078 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2080 } else if (rt->live == -1) {
2081 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2085 } else if (!strcmp(tracked_method, "createStream")) {
2087 if (read_number_result(pkt, &stream_id)) {
2088 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2090 rt->stream_id = stream_id;
2093 if (!rt->is_input) {
2094 if ((ret = gen_publish(s, rt)) < 0)
2097 if (rt->live != -1) {
2098 if ((ret = gen_get_stream_length(s, rt)) < 0)
2101 if ((ret = gen_play(s, rt)) < 0)
2103 if ((ret = gen_buffer_time(s, rt)) < 0)
2106 } else if (!strcmp(tracked_method, "getStreamLength")) {
2107 if (read_number_result(pkt, &rt->duration)) {
2108 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2113 av_free(tracked_method);
2117 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2119 RTMPContext *rt = s->priv_data;
2120 const uint8_t *data_end = pkt->data + pkt->size;
2121 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2122 uint8_t tmpstr[256];
2125 for (i = 0; i < 2; i++) {
2126 t = ff_amf_tag_size(ptr, data_end);
2132 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2133 if (!t && !strcmp(tmpstr, "error")) {
2134 t = ff_amf_get_field_value(ptr, data_end,
2135 "description", tmpstr, sizeof(tmpstr));
2136 if (t || !tmpstr[0])
2137 t = ff_amf_get_field_value(ptr, data_end, "code",
2138 tmpstr, sizeof(tmpstr));
2140 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2144 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2145 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2146 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2147 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2148 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2149 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2154 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2156 RTMPContext *rt = s->priv_data;
2159 //TODO: check for the messages sent for wrong state?
2160 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2161 if ((ret = handle_invoke_error(s, pkt)) < 0)
2163 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2164 if ((ret = handle_invoke_result(s, pkt)) < 0)
2166 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2167 if ((ret = handle_invoke_status(s, pkt)) < 0)
2169 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2170 if ((ret = gen_check_bw(s, rt)) < 0)
2172 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2173 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2174 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2175 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2176 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2177 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2178 if ((ret = send_invoke_response(s, pkt)) < 0)
2185 static int update_offset(RTMPContext *rt, int size)
2189 // generate packet header and put data into buffer for FLV demuxer
2190 if (rt->flv_off < rt->flv_size) {
2191 // There is old unread data in the buffer, thus append at the end
2192 old_flv_size = rt->flv_size;
2193 rt->flv_size += size;
2195 // All data has been read, write the new data at the start of the buffer
2197 rt->flv_size = size;
2201 return old_flv_size;
2204 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2206 int old_flv_size, ret;
2208 const uint8_t *data = pkt->data + skip;
2209 const int size = pkt->size - skip;
2210 uint32_t ts = pkt->timestamp;
2212 if (pkt->type == RTMP_PT_AUDIO) {
2214 } else if (pkt->type == RTMP_PT_VIDEO) {
2218 old_flv_size = update_offset(rt, size + 15);
2220 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2221 rt->flv_size = rt->flv_off = 0;
2224 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2225 bytestream2_skip_p(&pbc, old_flv_size);
2226 bytestream2_put_byte(&pbc, pkt->type);
2227 bytestream2_put_be24(&pbc, size);
2228 bytestream2_put_be24(&pbc, ts);
2229 bytestream2_put_byte(&pbc, ts >> 24);
2230 bytestream2_put_be24(&pbc, 0);
2231 bytestream2_put_buffer(&pbc, data, size);
2232 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2237 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2239 RTMPContext *rt = s->priv_data;
2240 uint8_t commandbuffer[64];
2241 char statusmsg[128];
2242 int stringlen, ret, skip = 0;
2245 bytestream2_init(&gbc, pkt->data, pkt->size);
2246 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2248 return AVERROR_INVALIDDATA;
2250 if (!strcmp(commandbuffer, "onMetaData")) {
2251 // metadata properties should be stored in a mixed array
2252 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2253 // We have found a metaData Array so flv can determine the streams
2255 rt->received_metadata = 1;
2256 // skip 32-bit max array index
2257 bytestream2_skip(&gbc, 4);
2258 while (bytestream2_get_bytes_left(&gbc) > 3) {
2259 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2261 return AVERROR_INVALIDDATA;
2262 // We do not care about the content of the property (yet).
2263 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2265 return AVERROR_INVALIDDATA;
2266 bytestream2_skip(&gbc, stringlen);
2268 // The presence of the following properties indicates that the
2269 // respective streams are present.
2270 if (!strcmp(statusmsg, "videocodecid")) {
2273 if (!strcmp(statusmsg, "audiocodecid")) {
2277 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2278 return AVERROR_INVALIDDATA;
2282 // Skip the @setDataFrame string and validate it is a notification
2283 if (!strcmp(commandbuffer, "@setDataFrame")) {
2284 skip = gbc.buffer - pkt->data;
2285 ret = ff_amf_read_string(&gbc, statusmsg,
2286 sizeof(statusmsg), &stringlen);
2288 return AVERROR_INVALIDDATA;
2291 return append_flv_data(rt, pkt, skip);
2295 * Parse received packet and possibly perform some action depending on
2296 * the packet contents.
2297 * @return 0 for no errors, negative values for serious errors which prevent
2298 * further communications, positive values for uncritical errors
2300 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2305 ff_rtmp_packet_dump(s, pkt);
2308 switch (pkt->type) {
2309 case RTMP_PT_BYTES_READ:
2310 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2312 case RTMP_PT_CHUNK_SIZE:
2313 if ((ret = handle_chunk_size(s, pkt)) < 0)
2316 case RTMP_PT_USER_CONTROL:
2317 if ((ret = handle_user_control(s, pkt)) < 0)
2320 case RTMP_PT_SET_PEER_BW:
2321 if ((ret = handle_set_peer_bw(s, pkt)) < 0)
2324 case RTMP_PT_WINDOW_ACK_SIZE:
2325 if ((ret = handle_window_ack_size(s, pkt)) < 0)
2328 case RTMP_PT_INVOKE:
2329 if ((ret = handle_invoke(s, pkt)) < 0)
2334 case RTMP_PT_METADATA:
2335 case RTMP_PT_NOTIFY:
2336 /* Audio, Video and Metadata packets are parsed in get_packet() */
2339 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2345 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2347 int ret, old_flv_size, type;
2348 const uint8_t *next;
2351 uint32_t ts, cts, pts = 0;
2353 old_flv_size = update_offset(rt, pkt->size);
2355 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2356 rt->flv_size = rt->flv_off = 0;
2361 p = rt->flv_data + old_flv_size;
2363 /* copy data while rewriting timestamps */
2364 ts = pkt->timestamp;
2366 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2367 type = bytestream_get_byte(&next);
2368 size = bytestream_get_be24(&next);
2369 cts = bytestream_get_be24(&next);
2370 cts |= bytestream_get_byte(&next) << 24;
2375 if (size + 3 + 4 > pkt->data + pkt->size - next)
2377 bytestream_put_byte(&p, type);
2378 bytestream_put_be24(&p, size);
2379 bytestream_put_be24(&p, ts);
2380 bytestream_put_byte(&p, ts >> 24);
2381 memcpy(p, next, size + 3 + 4);
2383 bytestream_put_be32(&p, size + RTMP_HEADER);
2384 next += size + 3 + 4;
2386 if (p != rt->flv_data + rt->flv_size) {
2387 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2388 "RTMP_PT_METADATA packet\n");
2389 rt->flv_size = p - rt->flv_data;
2396 * Interact with the server by receiving and sending RTMP packets until
2397 * there is some significant data (media data or expected status notification).
2399 * @param s reading context
2400 * @param for_header non-zero value tells function to work until it
2401 * gets notification from the server that playing has been started,
2402 * otherwise function will work until some media data is received (or
2404 * @return 0 for successful operation, negative value in case of error
2406 static int get_packet(URLContext *s, int for_header)
2408 RTMPContext *rt = s->priv_data;
2411 if (rt->state == STATE_STOPPED)
2415 RTMPPacket rpkt = { 0 };
2416 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2417 rt->in_chunk_size, &rt->prev_pkt[0],
2418 &rt->nb_prev_pkt[0])) <= 0) {
2420 return AVERROR(EAGAIN);
2422 return AVERROR(EIO);
2426 // Track timestamp for later use
2427 rt->last_timestamp = rpkt.timestamp;
2429 rt->bytes_read += ret;
2430 if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) {
2431 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2432 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2434 rt->last_bytes_read = rt->bytes_read;
2437 ret = rtmp_parse_result(s, rt, &rpkt);
2439 // At this point we must check if we are in the seek state and continue
2440 // with the next packet. handle_invoke will get us out of this state
2441 // when the right message is encountered
2442 if (rt->state == STATE_SEEKING) {
2443 ff_rtmp_packet_destroy(&rpkt);
2444 // We continue, let the natural flow of things happen:
2445 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2449 if (ret < 0) {//serious error in current packet
2450 ff_rtmp_packet_destroy(&rpkt);
2453 if (rt->do_reconnect && for_header) {
2454 ff_rtmp_packet_destroy(&rpkt);
2457 if (rt->state == STATE_STOPPED) {
2458 ff_rtmp_packet_destroy(&rpkt);
2461 if (for_header && (rt->state == STATE_PLAYING ||
2462 rt->state == STATE_PUBLISHING ||
2463 rt->state == STATE_SENDING ||
2464 rt->state == STATE_RECEIVING)) {
2465 ff_rtmp_packet_destroy(&rpkt);
2468 if (!rpkt.size || !rt->is_input) {
2469 ff_rtmp_packet_destroy(&rpkt);
2472 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2473 ret = append_flv_data(rt, &rpkt, 0);
2474 ff_rtmp_packet_destroy(&rpkt);
2476 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2477 ret = handle_notify(s, &rpkt);
2478 ff_rtmp_packet_destroy(&rpkt);
2480 } else if (rpkt.type == RTMP_PT_METADATA) {
2481 ret = handle_metadata(rt, &rpkt);
2482 ff_rtmp_packet_destroy(&rpkt);
2485 ff_rtmp_packet_destroy(&rpkt);
2489 static int rtmp_close(URLContext *h)
2491 RTMPContext *rt = h->priv_data;
2494 if (!rt->is_input) {
2495 rt->flv_data = NULL;
2496 if (rt->out_pkt.size)
2497 ff_rtmp_packet_destroy(&rt->out_pkt);
2498 if (rt->state > STATE_FCPUBLISH)
2499 ret = gen_fcunpublish_stream(h, rt);
2501 if (rt->state > STATE_HANDSHAKED)
2502 ret = gen_delete_stream(h, rt);
2503 for (i = 0; i < 2; i++) {
2504 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2505 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2506 av_freep(&rt->prev_pkt[i]);
2509 free_tracked_methods(rt);
2510 av_freep(&rt->flv_data);
2511 ffurl_close(rt->stream);
2516 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2517 * demuxer about the duration of the stream.
2519 * This should only be done if there was no real onMetadata packet sent by the
2520 * server at the start of the stream and if we were able to retrieve a valid
2521 * duration via a getStreamLength call.
2523 * @return 0 for successful operation, negative value in case of error
2525 static int inject_fake_duration_metadata(RTMPContext *rt)
2527 // We need to insert the metadata packet directly after the FLV
2528 // header, i.e. we need to move all other already read data by the
2529 // size of our fake metadata packet.
2532 // Keep old flv_data pointer
2533 uint8_t* old_flv_data = rt->flv_data;
2534 // Allocate a new flv_data pointer with enough space for the additional package
2535 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2536 rt->flv_data = old_flv_data;
2537 return AVERROR(ENOMEM);
2541 memcpy(rt->flv_data, old_flv_data, 13);
2542 // Copy remaining packets
2543 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2544 // Increase the size by the injected packet
2546 // Delete the old FLV data
2547 av_free(old_flv_data);
2549 p = rt->flv_data + 13;
2550 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2551 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2552 bytestream_put_be24(&p, 0); // timestamp
2553 bytestream_put_be32(&p, 0); // reserved
2555 // first event name as a string
2556 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2557 // "onMetaData" as AMF string
2558 bytestream_put_be16(&p, 10);
2559 bytestream_put_buffer(&p, "onMetaData", 10);
2561 // mixed array (hash) with size and string/type/data tuples
2562 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2563 bytestream_put_be32(&p, 1); // metadata_count
2565 // "duration" as AMF string
2566 bytestream_put_be16(&p, 8);
2567 bytestream_put_buffer(&p, "duration", 8);
2568 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2569 bytestream_put_be64(&p, av_double2int(rt->duration));
2572 bytestream_put_be16(&p, 0); // Empty string
2573 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2574 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2580 * Open RTMP connection and verify that the stream can be played.
2582 * URL syntax: rtmp://server[:port][/app][/playpath]
2583 * where 'app' is first one or two directories in the path
2584 * (e.g. /ondemand/, /flash/live/, etc.)
2585 * and 'playpath' is a file name (the rest of the path,
2586 * may be prefixed with "mp4:")
2588 static int rtmp_open(URLContext *s, const char *uri, int flags)
2590 RTMPContext *rt = s->priv_data;
2591 char proto[8], hostname[256], path[1024], auth[100], *fname;
2592 char *old_app, *qmark, fname_buffer[1024];
2595 AVDictionary *opts = NULL;
2598 if (rt->listen_timeout > 0)
2601 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2603 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2604 hostname, sizeof(hostname), &port,
2605 path, sizeof(path), s->filename);
2607 if (strchr(path, ' ')) {
2608 av_log(s, AV_LOG_WARNING,
2609 "Detected librtmp style URL parameters, these aren't supported "
2610 "by the libavformat internal RTMP handler currently enabled. "
2611 "See the documentation for the correct way to pass parameters.\n");
2615 char *ptr = strchr(auth, ':');
2618 av_strlcpy(rt->username, auth, sizeof(rt->username));
2619 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2623 if (rt->listen && strcmp(proto, "rtmp")) {
2624 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2626 return AVERROR(EINVAL);
2628 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2629 if (!strcmp(proto, "rtmpts"))
2630 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2632 /* open the http tunneling connection */
2633 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2634 } else if (!strcmp(proto, "rtmps")) {
2635 /* open the tls connection */
2637 port = RTMPS_DEFAULT_PORT;
2638 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2639 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2640 if (!strcmp(proto, "rtmpte"))
2641 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2643 /* open the encrypted connection */
2644 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2647 /* open the tcp connection */
2649 port = RTMP_DEFAULT_PORT;
2651 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2652 "?listen&listen_timeout=%d",
2653 rt->listen_timeout * 1000);
2655 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2659 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2660 &s->interrupt_callback, &opts, s->protocols, s)) < 0) {
2661 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2665 if (rt->swfverify) {
2666 if ((ret = rtmp_calc_swfhash(s)) < 0)
2670 rt->state = STATE_START;
2671 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2673 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2676 rt->out_chunk_size = 128;
2677 rt->in_chunk_size = 128; // Probably overwritten later
2678 rt->state = STATE_HANDSHAKED;
2680 // Keep the application name when it has been defined by the user.
2683 rt->app = av_malloc(APP_MAX_LENGTH);
2685 ret = AVERROR(ENOMEM);
2689 //extract "app" part from path
2690 qmark = strchr(path, '?');
2691 if (qmark && strstr(qmark, "slist=")) {
2693 // After slist we have the playpath, the full path is used as app
2694 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2695 fname = strstr(path, "slist=") + 6;
2696 // Strip any further query parameters from fname
2697 amp = strchr(fname, '&');
2699 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2700 sizeof(fname_buffer)));
2701 fname = fname_buffer;
2703 } else if (!strncmp(path, "/ondemand/", 10)) {
2705 memcpy(rt->app, "ondemand", 9);
2707 char *next = *path ? path + 1 : path;
2708 char *p = strchr(next, '/');
2713 // make sure we do not mismatch a playpath for an application instance
2714 char *c = strchr(p + 1, ':');
2715 fname = strchr(p + 1, '/');
2716 if (!fname || (c && c < fname)) {
2718 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2721 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2727 // The name of application has been defined by the user, override it.
2732 if (!rt->playpath) {
2733 int len = strlen(fname);
2735 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2736 if (!rt->playpath) {
2737 ret = AVERROR(ENOMEM);
2741 if (!strchr(fname, ':') && len >= 4 &&
2742 (!strcmp(fname + len - 4, ".f4v") ||
2743 !strcmp(fname + len - 4, ".mp4"))) {
2744 memcpy(rt->playpath, "mp4:", 5);
2746 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2747 fname[len - 4] = '\0';
2748 rt->playpath[0] = 0;
2750 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2754 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2756 ret = AVERROR(ENOMEM);
2759 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2760 port, "/%s", rt->app);
2763 if (!rt->flashver) {
2764 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2765 if (!rt->flashver) {
2766 ret = AVERROR(ENOMEM);
2770 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2771 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2772 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2774 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2775 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2779 rt->receive_report_size = 1048576;
2783 rt->received_metadata = 0;
2784 rt->last_bytes_read = 0;
2785 rt->max_sent_unacked = 2500000;
2788 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2789 proto, path, rt->app, rt->playpath);
2791 if ((ret = gen_connect(s, rt)) < 0)
2794 if ((ret = read_connect(s, s->priv_data)) < 0)
2799 ret = get_packet(s, 1);
2800 } while (ret == AVERROR(EAGAIN));
2804 if (rt->do_reconnect) {
2806 ffurl_close(rt->stream);
2808 rt->do_reconnect = 0;
2810 for (i = 0; i < 2; i++)
2811 memset(rt->prev_pkt[i], 0,
2812 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2813 free_tracked_methods(rt);
2818 // generate FLV header for demuxer
2820 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2823 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2825 // Read packets until we reach the first A/V packet or read metadata.
2826 // If there was a metadata package in front of the A/V packets, we can
2827 // build the FLV header from this. If we do not receive any metadata,
2828 // the FLV decoder will allocate the needed streams when their first
2829 // audio or video packet arrives.
2830 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2831 if ((ret = get_packet(s, 0)) < 0)
2835 // Either after we have read the metadata or (if there is none) the
2836 // first packet of an A/V stream, we have a better knowledge about the
2837 // streams, so set the FLV header accordingly.
2838 if (rt->has_audio) {
2839 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2841 if (rt->has_video) {
2842 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2845 // If we received the first packet of an A/V stream and no metadata but
2846 // the server returned a valid duration, create a fake metadata packet
2847 // to inform the FLV decoder about the duration.
2848 if (!rt->received_metadata && rt->duration > 0) {
2849 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2854 rt->flv_data = NULL;
2856 rt->skip_bytes = 13;
2859 s->max_packet_size = rt->stream->max_packet_size;
2864 av_dict_free(&opts);
2869 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2871 RTMPContext *rt = s->priv_data;
2872 int orig_size = size;
2876 int data_left = rt->flv_size - rt->flv_off;
2878 if (data_left >= size) {
2879 memcpy(buf, rt->flv_data + rt->flv_off, size);
2880 rt->flv_off += size;
2883 if (data_left > 0) {
2884 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2887 rt->flv_off = rt->flv_size;
2890 if ((ret = get_packet(s, 0)) < 0)
2896 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2899 RTMPContext *rt = s->priv_data;
2901 av_log(s, AV_LOG_DEBUG,
2902 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2903 stream_index, timestamp, flags);
2904 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2905 av_log(s, AV_LOG_ERROR,
2906 "Unable to send seek command on stream index %d at timestamp "
2907 "%"PRId64" with flags %08x\n",
2908 stream_index, timestamp, flags);
2911 rt->flv_off = rt->flv_size;
2912 rt->state = STATE_SEEKING;
2916 static int rtmp_pause(URLContext *s, int pause)
2918 RTMPContext *rt = s->priv_data;
2920 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2921 rt->last_timestamp);
2922 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2923 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2924 rt->last_timestamp);
2930 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2932 RTMPContext *rt = s->priv_data;
2933 int size_temp = size;
2934 int pktsize, pkttype, copy;
2936 const uint8_t *buf_temp = buf;
2941 if (rt->skip_bytes) {
2942 int skip = FFMIN(rt->skip_bytes, size_temp);
2945 rt->skip_bytes -= skip;
2949 if (rt->flv_header_bytes < RTMP_HEADER) {
2950 const uint8_t *header = rt->flv_header;
2951 int channel = RTMP_AUDIO_CHANNEL;
2952 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2953 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2954 rt->flv_header_bytes += copy;
2956 if (rt->flv_header_bytes < RTMP_HEADER)
2959 pkttype = bytestream_get_byte(&header);
2960 pktsize = bytestream_get_be24(&header);
2961 ts = bytestream_get_be24(&header);
2962 ts |= bytestream_get_byte(&header) << 24;
2963 bytestream_get_be24(&header);
2964 rt->flv_size = pktsize;
2966 if (pkttype == RTMP_PT_VIDEO)
2967 channel = RTMP_VIDEO_CHANNEL;
2969 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2970 pkttype == RTMP_PT_NOTIFY) {
2971 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2972 &rt->nb_prev_pkt[1],
2975 // Force sending a full 12 bytes header by clearing the
2976 // channel id, to make it not match a potential earlier
2977 // packet in the same channel.
2978 rt->prev_pkt[1][channel].channel_id = 0;
2981 //this can be a big packet, it's better to send it right here
2982 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
2983 pkttype, ts, pktsize)) < 0)
2986 rt->out_pkt.extra = rt->stream_id;
2987 rt->flv_data = rt->out_pkt.data;
2990 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
2991 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
2992 rt->flv_off += copy;
2995 if (rt->flv_off == rt->flv_size) {
2998 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
2999 // For onMetaData and |RtmpSampleAccess packets, we want
3000 // @setDataFrame prepended to the packet before it gets sent.
3001 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3003 uint8_t commandbuffer[64];
3007 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3008 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3010 if (!strcmp(commandbuffer, "onMetaData") ||
3011 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3013 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3014 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3017 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3018 rt->out_pkt.size += 16;
3019 ptr = rt->out_pkt.data;
3020 ff_amf_write_string(&ptr, "@setDataFrame");
3025 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3029 rt->flv_header_bytes = 0;
3030 rt->flv_nb_packets++;
3032 } while (buf_temp - buf < size);
3034 if (rt->flv_nb_packets < rt->flush_interval)
3036 rt->flv_nb_packets = 0;
3038 /* set stream into nonblocking mode */
3039 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3041 /* try to read one byte from the stream */
3042 ret = ffurl_read(rt->stream, &c, 1);
3044 /* switch the stream back into blocking mode */
3045 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3047 if (ret == AVERROR(EAGAIN)) {
3048 /* no incoming data to handle */
3050 } else if (ret < 0) {
3052 } else if (ret == 1) {
3053 RTMPPacket rpkt = { 0 };
3055 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3058 &rt->nb_prev_pkt[0], c)) <= 0)
3061 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3064 ff_rtmp_packet_destroy(&rpkt);
3070 #define OFFSET(x) offsetof(RTMPContext, x)
3071 #define DEC AV_OPT_FLAG_DECODING_PARAM
3072 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3074 static const AVOption rtmp_options[] = {
3075 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3076 {"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},
3077 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3078 {"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},
3079 {"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},
3080 {"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"},
3081 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3082 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3083 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3084 {"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},
3085 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3086 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3087 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3088 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3089 {"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},
3090 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3091 {"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},
3092 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3093 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3094 {"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" },
3098 #define RTMP_PROTOCOL(flavor) \
3099 static const AVClass flavor##_class = { \
3100 .class_name = #flavor, \
3101 .item_name = av_default_item_name, \
3102 .option = rtmp_options, \
3103 .version = LIBAVUTIL_VERSION_INT, \
3106 const URLProtocol ff_##flavor##_protocol = { \
3108 .url_open = rtmp_open, \
3109 .url_read = rtmp_read, \
3110 .url_read_seek = rtmp_seek, \
3111 .url_read_pause = rtmp_pause, \
3112 .url_write = rtmp_write, \
3113 .url_close = rtmp_close, \
3114 .priv_data_size = sizeof(RTMPContext), \
3115 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3116 .priv_data_class= &flavor##_class, \
3121 RTMP_PROTOCOL(rtmpe)
3122 RTMP_PROTOCOL(rtmps)
3123 RTMP_PROTOCOL(rtmpt)
3124 RTMP_PROTOCOL(rtmpte)
3125 RTMP_PROTOCOL(rtmpts)