2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin 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 "config_components.h"
29 #include "libavcodec/bytestream.h"
30 #include "libavutil/avstring.h"
31 #include "libavutil/base64.h"
32 #include "libavutil/intfloat.h"
33 #include "libavutil/lfg.h"
34 #include "libavutil/md5.h"
35 #include "libavutil/mem.h"
36 #include "libavutil/opt.h"
37 #include "libavutil/random_seed.h"
45 #include "rtmpcrypt.h"
54 #define APP_MAX_LENGTH 1024
55 #define TCURL_MAX_LENGTH 1024
56 #define FLASHVER_MAX_LENGTH 64
57 #define RTMP_PKTDATA_DEFAULT_SIZE 4096
58 #define RTMP_HEADER 11
60 /** RTMP protocol handler state */
62 STATE_START
, ///< client has not done anything yet
63 STATE_HANDSHAKED
, ///< client has performed handshake
64 STATE_FCPUBLISH
, ///< client FCPublishing stream (for output)
65 STATE_PLAYING
, ///< client has started receiving multimedia data from server
66 STATE_SEEKING
, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
67 STATE_PUBLISHING
, ///< client has started sending multimedia data to server (for output)
68 STATE_RECEIVING
, ///< received a publish command (for input)
69 STATE_SENDING
, ///< received a play command (for output)
70 STATE_STOPPED
, ///< the broadcast has been stopped
73 typedef struct TrackedMethod
{
78 /** protocol handler context */
79 typedef struct RTMPContext
{
81 URLContext
* stream
; ///< TCP stream used in interactions with RTMP server
82 RTMPPacket
*prev_pkt
[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
83 int nb_prev_pkt
[2]; ///< number of elements in prev_pkt
84 int in_chunk_size
; ///< size of the chunks incoming RTMP packets are divided into
85 int out_chunk_size
; ///< size of the chunks outgoing RTMP packets are divided into
86 int is_input
; ///< input/output flag
87 char *playpath
; ///< stream identifier to play (with possible "mp4:" prefix)
88 int live
; ///< 0: recorded, -1: live, -2: both
89 char *app
; ///< name of application
90 char *conn
; ///< append arbitrary AMF data to the Connect message
91 ClientState state
; ///< current state
92 int stream_id
; ///< ID assigned by the server for the stream
93 uint8_t* flv_data
; ///< buffer with data for demuxer
94 int flv_size
; ///< current buffer size
95 int flv_off
; ///< number of bytes read from current buffer
96 int flv_nb_packets
; ///< number of flv packets published
97 RTMPPacket out_pkt
; ///< rtmp packet, created from flv a/v or metadata (for output)
98 uint32_t receive_report_size
; ///< number of bytes after which we should report the number of received bytes to the peer
99 uint64_t bytes_read
; ///< number of bytes read from server
100 uint64_t last_bytes_read
; ///< number of bytes read last reported to server
101 uint32_t last_timestamp
; ///< last timestamp received in a packet
102 int skip_bytes
; ///< number of bytes to skip from the input FLV stream in the next write call
103 int has_audio
; ///< presence of audio data
104 int has_video
; ///< presence of video data
105 int received_metadata
; ///< Indicates if we have received metadata about the streams
106 uint8_t flv_header
[RTMP_HEADER
]; ///< partial incoming flv packet header
107 int flv_header_bytes
; ///< number of initialized bytes in flv_header
108 int nb_invokes
; ///< keeps track of invoke messages
109 char* tcurl
; ///< url of the target stream
110 char* flashver
; ///< version of the flash plugin
111 char* swfhash
; ///< SHA256 hash of the decompressed SWF file (32 bytes)
112 int swfhash_len
; ///< length of the SHA256 hash
113 int swfsize
; ///< size of the decompressed SWF file
114 char* swfurl
; ///< url of the swf player
115 char* swfverify
; ///< URL to player swf file, compute hash/size automatically
116 char swfverification
[42]; ///< hash of the SWF verification
117 char* pageurl
; ///< url of the web page
118 char* subscribe
; ///< name of live stream to subscribe
119 int max_sent_unacked
; ///< max unacked sent bytes
120 int client_buffer_time
; ///< client buffer time in ms
121 int flush_interval
; ///< number of packets flushed in the same request (RTMPT only)
122 int encrypted
; ///< use an encrypted connection (RTMPE only)
123 TrackedMethod
*tracked_methods
; ///< tracked methods buffer
124 int nb_tracked_methods
; ///< number of tracked methods
125 int tracked_methods_size
; ///< size of the tracked methods buffer
126 int listen
; ///< listen mode flag
127 int listen_timeout
; ///< listen timeout to wait for new connections
128 int nb_streamid
; ///< The next stream id to return on createStream calls
129 double duration
; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
130 int tcp_nodelay
; ///< Use TCP_NODELAY to disable Nagle's algorithm if set to 1
131 char *enhanced_codecs
; ///< codec list in enhanced rtmp
134 char auth_params
[500];
139 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
140 /** Client key used for digest signing */
141 static const uint8_t rtmp_player_key
[] = {
142 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
143 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
145 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
146 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
147 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
150 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
151 /** Key used for RTMP server digest signing */
152 static const uint8_t rtmp_server_key
[] = {
153 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
154 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
155 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
157 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
158 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
159 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
162 static int handle_chunk_size(URLContext
*s
, RTMPPacket
*pkt
);
163 static int handle_window_ack_size(URLContext
*s
, RTMPPacket
*pkt
);
164 static int handle_set_peer_bw(URLContext
*s
, RTMPPacket
*pkt
);
166 static size_t zstrlen(const char *c
)
173 static int add_tracked_method(RTMPContext
*rt
, const char *name
, int id
)
177 if (rt
->nb_tracked_methods
+ 1 > rt
->tracked_methods_size
) {
178 rt
->tracked_methods_size
= (rt
->nb_tracked_methods
+ 1) * 2;
179 if ((err
= av_reallocp_array(&rt
->tracked_methods
, rt
->tracked_methods_size
,
180 sizeof(*rt
->tracked_methods
))) < 0) {
181 rt
->nb_tracked_methods
= 0;
182 rt
->tracked_methods_size
= 0;
187 rt
->tracked_methods
[rt
->nb_tracked_methods
].name
= av_strdup(name
);
188 if (!rt
->tracked_methods
[rt
->nb_tracked_methods
].name
)
189 return AVERROR(ENOMEM
);
190 rt
->tracked_methods
[rt
->nb_tracked_methods
].id
= id
;
191 rt
->nb_tracked_methods
++;
196 static void del_tracked_method(RTMPContext
*rt
, int index
)
198 memmove(&rt
->tracked_methods
[index
], &rt
->tracked_methods
[index
+ 1],
199 sizeof(*rt
->tracked_methods
) * (rt
->nb_tracked_methods
- index
- 1));
200 rt
->nb_tracked_methods
--;
203 static int find_tracked_method(URLContext
*s
, RTMPPacket
*pkt
, int offset
,
204 char **tracked_method
)
206 RTMPContext
*rt
= s
->priv_data
;
212 bytestream2_init(&gbc
, pkt
->data
+ offset
, pkt
->size
- offset
);
213 if ((ret
= ff_amf_read_number(&gbc
, &pkt_id
)) < 0)
216 for (i
= 0; i
< rt
->nb_tracked_methods
; i
++) {
217 if (rt
->tracked_methods
[i
].id
!= pkt_id
)
220 *tracked_method
= rt
->tracked_methods
[i
].name
;
221 del_tracked_method(rt
, i
);
228 static void free_tracked_methods(RTMPContext
*rt
)
232 for (i
= 0; i
< rt
->nb_tracked_methods
; i
++)
233 av_freep(&rt
->tracked_methods
[i
].name
);
234 av_freep(&rt
->tracked_methods
);
235 rt
->tracked_methods_size
= 0;
236 rt
->nb_tracked_methods
= 0;
239 static int rtmp_send_packet(RTMPContext
*rt
, RTMPPacket
*pkt
, int track
)
243 if (pkt
->type
== RTMP_PT_INVOKE
&& track
) {
249 bytestream2_init(&gbc
, pkt
->data
, pkt
->size
);
250 if ((ret
= ff_amf_read_string(&gbc
, name
, sizeof(name
), &len
)) < 0)
253 if ((ret
= ff_amf_read_number(&gbc
, &pkt_id
)) < 0)
256 if ((ret
= add_tracked_method(rt
, name
, pkt_id
)) < 0)
260 ret
= ff_rtmp_packet_write(rt
->stream
, pkt
, rt
->out_chunk_size
,
261 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
263 ff_rtmp_packet_destroy(pkt
);
267 static int rtmp_write_amf_data(URLContext
*s
, char *param
, uint8_t **p
)
272 /* The type must be B for Boolean, N for number, S for string, O for
273 * object, or Z for null. For Booleans the data must be either 0 or 1 for
274 * FALSE or TRUE, respectively. Likewise for Objects the data must be
275 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
276 * may be named, by prefixing the type with 'N' and specifying the name
277 * before the value (ie. NB:myFlag:1). This option may be used multiple times
278 * to construct arbitrary AMF sequences. */
279 if (param
[0] && param
[1] == ':') {
282 } else if (param
[0] == 'N' && param
[1] && param
[2] == ':') {
285 value
= strchr(field
, ':');
291 ff_amf_write_field_name(p
, field
);
298 ff_amf_write_bool(p
, value
[0] != '0');
301 ff_amf_write_string(p
, value
);
304 ff_amf_write_number(p
, strtod(value
, NULL
));
307 ff_amf_write_null(p
);
311 ff_amf_write_object_start(p
);
313 ff_amf_write_object_end(p
);
323 av_log(s
, AV_LOG_ERROR
, "Invalid AMF parameter: %s\n", param
);
324 return AVERROR(EINVAL
);
328 * Generate 'connect' call and send it to the server.
330 static int gen_connect(URLContext
*s
, RTMPContext
*rt
)
336 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
, RTMP_PT_INVOKE
,
337 0, 4096 + APP_MAX_LENGTH
338 + strlen(rt
->auth_params
) + strlen(rt
->flashver
)
339 + zstrlen(rt
->enhanced_codecs
)/5*7
340 + zstrlen(rt
->swfurl
)
341 + zstrlen(rt
->swfverify
)
343 + zstrlen(rt
->auth_params
)
344 + zstrlen(rt
->pageurl
)
345 + zstrlen(rt
->conn
)*3
351 ff_amf_write_string(&p
, "connect");
352 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
353 ff_amf_write_object_start(&p
);
354 ff_amf_write_field_name(&p
, "app");
355 ff_amf_write_string2(&p
, rt
->app
, rt
->auth_params
);
357 if (rt
->enhanced_codecs
) {
358 uint32_t list_len
= 0;
359 char *fourcc_data
= rt
->enhanced_codecs
;
360 int fourcc_str_len
= strlen(fourcc_data
);
362 // check the string, fourcc + ',' + ... + end fourcc correct length should be (4+1)*n+4
363 if ((fourcc_str_len
+ 1) % 5 != 0) {
364 av_log(s
, AV_LOG_ERROR
, "Malformed rtmp_enhanched_codecs, "
365 "should be of the form hvc1[,av01][,vp09][,...]\n");
366 ff_rtmp_packet_destroy(&pkt
);
367 return AVERROR(EINVAL
);
370 list_len
= (fourcc_str_len
+ 1) / 5;
371 ff_amf_write_field_name(&p
, "fourCcList");
372 ff_amf_write_array_start(&p
, list_len
);
374 while(fourcc_data
- rt
->enhanced_codecs
< fourcc_str_len
) {
375 unsigned char fourcc
[5];
376 if (!strncmp(fourcc_data
, "ac-3", 4) ||
377 !strncmp(fourcc_data
, "av01", 4) ||
378 !strncmp(fourcc_data
, "avc1", 4) ||
379 !strncmp(fourcc_data
, "ec-3", 4) ||
380 !strncmp(fourcc_data
, "fLaC", 4) ||
381 !strncmp(fourcc_data
, "hvc1", 4) ||
382 !strncmp(fourcc_data
, ".mp3", 4) ||
383 !strncmp(fourcc_data
, "mp4a", 4) ||
384 !strncmp(fourcc_data
, "Opus", 4) ||
385 !strncmp(fourcc_data
, "vp09", 4)) {
386 av_strlcpy(fourcc
, fourcc_data
, sizeof(fourcc
));
387 ff_amf_write_string(&p
, fourcc
);
389 av_log(s
, AV_LOG_ERROR
, "Unsupported codec fourcc, %.*s\n", 4, fourcc_data
);
390 ff_rtmp_packet_destroy(&pkt
);
391 return AVERROR_PATCHWELCOME
;
399 ff_amf_write_field_name(&p
, "type");
400 ff_amf_write_string(&p
, "nonprivate");
402 ff_amf_write_field_name(&p
, "flashVer");
403 ff_amf_write_string(&p
, rt
->flashver
);
405 if (rt
->swfurl
|| rt
->swfverify
) {
406 ff_amf_write_field_name(&p
, "swfUrl");
408 ff_amf_write_string(&p
, rt
->swfurl
);
410 ff_amf_write_string(&p
, rt
->swfverify
);
413 ff_amf_write_field_name(&p
, "tcUrl");
414 ff_amf_write_string2(&p
, rt
->tcurl
, rt
->auth_params
);
416 ff_amf_write_field_name(&p
, "fpad");
417 ff_amf_write_bool(&p
, 0);
418 ff_amf_write_field_name(&p
, "capabilities");
419 ff_amf_write_number(&p
, 15.0);
421 /* Tell the server we support all the audio codecs except
422 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
423 * which are unused in the RTMP protocol implementation. */
424 ff_amf_write_field_name(&p
, "audioCodecs");
425 ff_amf_write_number(&p
, 4071.0);
426 ff_amf_write_field_name(&p
, "videoCodecs");
427 ff_amf_write_number(&p
, 252.0);
428 ff_amf_write_field_name(&p
, "videoFunction");
429 ff_amf_write_number(&p
, 1.0);
432 ff_amf_write_field_name(&p
, "pageUrl");
433 ff_amf_write_string(&p
, rt
->pageurl
);
436 ff_amf_write_object_end(&p
);
439 char *param
= rt
->conn
;
441 // Write arbitrary AMF data to the Connect message.
444 param
+= strspn(param
, " ");
447 sep
= strchr(param
, ' ');
450 if ((ret
= rtmp_write_amf_data(s
, param
, &p
)) < 0) {
451 // Invalid AMF parameter.
452 ff_rtmp_packet_destroy(&pkt
);
463 pkt
.size
= p
- pkt
.data
;
465 return rtmp_send_packet(rt
, &pkt
, 1);
469 #define RTMP_CTRL_ABORT_MESSAGE (2)
471 static int read_connect(URLContext
*s
, RTMPContext
*rt
)
473 RTMPPacket pkt
= { 0 };
483 // handle RTMP Protocol Control Messages
485 if ((ret
= ff_rtmp_packet_read(rt
->stream
, &pkt
, rt
->in_chunk_size
,
486 &rt
->prev_pkt
[0], &rt
->nb_prev_pkt
[0])) < 0)
489 ff_rtmp_packet_dump(s
, &pkt
);
491 if (pkt
.type
== RTMP_PT_CHUNK_SIZE
) {
492 if ((ret
= handle_chunk_size(s
, &pkt
)) < 0) {
493 ff_rtmp_packet_destroy(&pkt
);
496 } else if (pkt
.type
== RTMP_CTRL_ABORT_MESSAGE
) {
497 av_log(s
, AV_LOG_ERROR
, "received abort message\n");
498 ff_rtmp_packet_destroy(&pkt
);
499 return AVERROR_UNKNOWN
;
500 } else if (pkt
.type
== RTMP_PT_BYTES_READ
) {
501 av_log(s
, AV_LOG_TRACE
, "received acknowledgement\n");
502 } else if (pkt
.type
== RTMP_PT_WINDOW_ACK_SIZE
) {
503 if ((ret
= handle_window_ack_size(s
, &pkt
)) < 0) {
504 ff_rtmp_packet_destroy(&pkt
);
507 } else if (pkt
.type
== RTMP_PT_SET_PEER_BW
) {
508 if ((ret
= handle_set_peer_bw(s
, &pkt
)) < 0) {
509 ff_rtmp_packet_destroy(&pkt
);
512 } else if (pkt
.type
== RTMP_PT_INVOKE
) {
513 // received RTMP Command Message
516 av_log(s
, AV_LOG_ERROR
, "Unknown control message type (%d)\n", pkt
.type
);
518 ff_rtmp_packet_destroy(&pkt
);
522 bytestream2_init(&gbc
, cp
, pkt
.size
);
523 if (ff_amf_read_string(&gbc
, command
, sizeof(command
), &stringlen
)) {
524 av_log(s
, AV_LOG_ERROR
, "Unable to read command string\n");
525 ff_rtmp_packet_destroy(&pkt
);
526 return AVERROR_INVALIDDATA
;
528 if (strcmp(command
, "connect")) {
529 av_log(s
, AV_LOG_ERROR
, "Expecting connect, got %s\n", command
);
530 ff_rtmp_packet_destroy(&pkt
);
531 return AVERROR_INVALIDDATA
;
533 ret
= ff_amf_read_number(&gbc
, &seqnum
);
535 av_log(s
, AV_LOG_WARNING
, "SeqNum not found\n");
536 /* Here one could parse an AMF Object with data as flashVers and others. */
537 ret
= ff_amf_get_field_value(gbc
.buffer
,
538 gbc
.buffer
+ bytestream2_get_bytes_left(&gbc
),
539 "app", tmpstr
, sizeof(tmpstr
));
541 av_log(s
, AV_LOG_WARNING
, "App field not found in connect\n");
542 if (!ret
&& strcmp(tmpstr
, rt
->app
))
543 av_log(s
, AV_LOG_WARNING
, "App field don't match up: %s <-> %s\n",
545 ff_rtmp_packet_destroy(&pkt
);
547 // Send Window Acknowledgement Size (as defined in specification)
548 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
,
549 RTMP_PT_WINDOW_ACK_SIZE
, 0, 4)) < 0)
552 // Inform the peer about how often we want acknowledgements about what
553 // we send. (We don't check for the acknowledgements currently.)
554 bytestream_put_be32(&p
, rt
->max_sent_unacked
);
555 pkt
.size
= p
- pkt
.data
;
556 ret
= ff_rtmp_packet_write(rt
->stream
, &pkt
, rt
->out_chunk_size
,
557 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
558 ff_rtmp_packet_destroy(&pkt
);
561 // Set Peer Bandwidth
562 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
,
563 RTMP_PT_SET_PEER_BW
, 0, 5)) < 0)
566 // Tell the peer to only send this many bytes unless it gets acknowledgements.
567 // This could be any arbitrary value we want here.
568 bytestream_put_be32(&p
, rt
->max_sent_unacked
);
569 bytestream_put_byte(&p
, 2); // dynamic
570 pkt
.size
= p
- pkt
.data
;
571 ret
= ff_rtmp_packet_write(rt
->stream
, &pkt
, rt
->out_chunk_size
,
572 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
573 ff_rtmp_packet_destroy(&pkt
);
578 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
,
579 RTMP_PT_USER_CONTROL
, 0, 6)) < 0)
583 bytestream_put_be16(&p
, 0); // 0 -> Stream Begin
584 bytestream_put_be32(&p
, 0); // Stream 0
585 ret
= ff_rtmp_packet_write(rt
->stream
, &pkt
, rt
->out_chunk_size
,
586 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
587 ff_rtmp_packet_destroy(&pkt
);
592 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
,
593 RTMP_PT_CHUNK_SIZE
, 0, 4)) < 0)
597 bytestream_put_be32(&p
, rt
->out_chunk_size
);
598 ret
= ff_rtmp_packet_write(rt
->stream
, &pkt
, rt
->out_chunk_size
,
599 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
600 ff_rtmp_packet_destroy(&pkt
);
604 // Send _result NetConnection.Connect.Success to connect
605 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
,
607 RTMP_PKTDATA_DEFAULT_SIZE
)) < 0)
611 ff_amf_write_string(&p
, "_result");
612 ff_amf_write_number(&p
, seqnum
);
614 ff_amf_write_object_start(&p
);
615 ff_amf_write_field_name(&p
, "fmsVer");
616 ff_amf_write_string(&p
, "FMS/3,0,1,123");
617 ff_amf_write_field_name(&p
, "capabilities");
618 ff_amf_write_number(&p
, 31);
619 ff_amf_write_object_end(&p
);
621 ff_amf_write_object_start(&p
);
622 ff_amf_write_field_name(&p
, "level");
623 ff_amf_write_string(&p
, "status");
624 ff_amf_write_field_name(&p
, "code");
625 ff_amf_write_string(&p
, "NetConnection.Connect.Success");
626 ff_amf_write_field_name(&p
, "description");
627 ff_amf_write_string(&p
, "Connection succeeded.");
628 ff_amf_write_field_name(&p
, "objectEncoding");
629 ff_amf_write_number(&p
, 0);
630 ff_amf_write_object_end(&p
);
632 pkt
.size
= p
- pkt
.data
;
633 ret
= ff_rtmp_packet_write(rt
->stream
, &pkt
, rt
->out_chunk_size
,
634 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
635 ff_rtmp_packet_destroy(&pkt
);
639 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
,
640 RTMP_PT_INVOKE
, 0, 30)) < 0)
643 ff_amf_write_string(&p
, "onBWDone");
644 ff_amf_write_number(&p
, 0);
645 ff_amf_write_null(&p
);
646 ff_amf_write_number(&p
, 8192);
647 pkt
.size
= p
- pkt
.data
;
648 ret
= ff_rtmp_packet_write(rt
->stream
, &pkt
, rt
->out_chunk_size
,
649 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
650 ff_rtmp_packet_destroy(&pkt
);
656 * Generate 'releaseStream' call and send it to the server. It should make
657 * the server release some channel for media streams.
659 static int gen_release_stream(URLContext
*s
, RTMPContext
*rt
)
665 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
, RTMP_PT_INVOKE
,
666 0, 29 + strlen(rt
->playpath
))) < 0)
669 av_log(s
, AV_LOG_DEBUG
, "Releasing stream...\n");
671 ff_amf_write_string(&p
, "releaseStream");
672 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
673 ff_amf_write_null(&p
);
674 ff_amf_write_string(&p
, rt
->playpath
);
676 return rtmp_send_packet(rt
, &pkt
, 1);
680 * Generate 'FCPublish' call and send it to the server. It should make
681 * the server prepare for receiving media streams.
683 static int gen_fcpublish_stream(URLContext
*s
, RTMPContext
*rt
)
689 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
, RTMP_PT_INVOKE
,
690 0, 25 + strlen(rt
->playpath
))) < 0)
693 av_log(s
, AV_LOG_DEBUG
, "FCPublish stream...\n");
695 ff_amf_write_string(&p
, "FCPublish");
696 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
697 ff_amf_write_null(&p
);
698 ff_amf_write_string(&p
, rt
->playpath
);
700 return rtmp_send_packet(rt
, &pkt
, 1);
704 * Generate 'FCUnpublish' call and send it to the server. It should make
705 * the server destroy stream.
707 static int gen_fcunpublish_stream(URLContext
*s
, RTMPContext
*rt
)
713 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
, RTMP_PT_INVOKE
,
714 0, 27 + strlen(rt
->playpath
))) < 0)
717 av_log(s
, AV_LOG_DEBUG
, "UnPublishing stream...\n");
719 ff_amf_write_string(&p
, "FCUnpublish");
720 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
721 ff_amf_write_null(&p
);
722 ff_amf_write_string(&p
, rt
->playpath
);
724 return rtmp_send_packet(rt
, &pkt
, 0);
728 * Generate 'createStream' call and send it to the server. It should make
729 * the server allocate some channel for media streams.
731 static int gen_create_stream(URLContext
*s
, RTMPContext
*rt
)
737 av_log(s
, AV_LOG_DEBUG
, "Creating stream...\n");
739 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
, RTMP_PT_INVOKE
,
744 ff_amf_write_string(&p
, "createStream");
745 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
746 ff_amf_write_null(&p
);
748 return rtmp_send_packet(rt
, &pkt
, 1);
753 * Generate 'deleteStream' call and send it to the server. It should make
754 * the server remove some channel for media streams.
756 static int gen_delete_stream(URLContext
*s
, RTMPContext
*rt
)
762 av_log(s
, AV_LOG_DEBUG
, "Deleting stream...\n");
764 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
, RTMP_PT_INVOKE
,
769 ff_amf_write_string(&p
, "deleteStream");
770 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
771 ff_amf_write_null(&p
);
772 ff_amf_write_number(&p
, rt
->stream_id
);
774 return rtmp_send_packet(rt
, &pkt
, 0);
778 * Generate 'getStreamLength' call and send it to the server. If the server
779 * knows the duration of the selected stream, it will reply with the duration
782 static int gen_get_stream_length(URLContext
*s
, RTMPContext
*rt
)
788 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SOURCE_CHANNEL
, RTMP_PT_INVOKE
,
789 0, 31 + strlen(rt
->playpath
))) < 0)
793 ff_amf_write_string(&p
, "getStreamLength");
794 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
795 ff_amf_write_null(&p
);
796 ff_amf_write_string(&p
, rt
->playpath
);
798 return rtmp_send_packet(rt
, &pkt
, 1);
802 * Generate client buffer time and send it to the server.
804 static int gen_buffer_time(URLContext
*s
, RTMPContext
*rt
)
810 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
, RTMP_PT_USER_CONTROL
,
815 bytestream_put_be16(&p
, 3); // SetBuffer Length
816 bytestream_put_be32(&p
, rt
->stream_id
);
817 bytestream_put_be32(&p
, rt
->client_buffer_time
);
819 return rtmp_send_packet(rt
, &pkt
, 0);
823 * Generate 'play' call and send it to the server, then ping the server
824 * to start actual playing.
826 static int gen_play(URLContext
*s
, RTMPContext
*rt
)
832 av_log(s
, AV_LOG_DEBUG
, "Sending play command for '%s'\n", rt
->playpath
);
834 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SOURCE_CHANNEL
, RTMP_PT_INVOKE
,
835 0, 29 + strlen(rt
->playpath
))) < 0)
838 pkt
.extra
= rt
->stream_id
;
841 ff_amf_write_string(&p
, "play");
842 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
843 ff_amf_write_null(&p
);
844 ff_amf_write_string(&p
, rt
->playpath
);
845 ff_amf_write_number(&p
, rt
->live
* 1000);
847 return rtmp_send_packet(rt
, &pkt
, 1);
850 static int gen_seek(URLContext
*s
, RTMPContext
*rt
, int64_t timestamp
)
856 av_log(s
, AV_LOG_DEBUG
, "Sending seek command for timestamp %"PRId64
"\n",
859 if ((ret
= ff_rtmp_packet_create(&pkt
, 3, RTMP_PT_INVOKE
, 0, 26)) < 0)
862 pkt
.extra
= rt
->stream_id
;
865 ff_amf_write_string(&p
, "seek");
866 ff_amf_write_number(&p
, 0); //no tracking back responses
867 ff_amf_write_null(&p
); //as usual, the first null param
868 ff_amf_write_number(&p
, timestamp
); //where we want to jump
870 return rtmp_send_packet(rt
, &pkt
, 1);
874 * Generate a pause packet that either pauses or unpauses the current stream.
876 static int gen_pause(URLContext
*s
, RTMPContext
*rt
, int pause
, uint32_t timestamp
)
882 av_log(s
, AV_LOG_DEBUG
, "Sending pause command for timestamp %d\n",
885 if ((ret
= ff_rtmp_packet_create(&pkt
, 3, RTMP_PT_INVOKE
, 0, 29)) < 0)
888 pkt
.extra
= rt
->stream_id
;
891 ff_amf_write_string(&p
, "pause");
892 ff_amf_write_number(&p
, 0); //no tracking back responses
893 ff_amf_write_null(&p
); //as usual, the first null param
894 ff_amf_write_bool(&p
, pause
); // pause or unpause
895 ff_amf_write_number(&p
, timestamp
); //where we pause the stream
897 return rtmp_send_packet(rt
, &pkt
, 1);
901 * Generate 'publish' call and send it to the server.
903 static int gen_publish(URLContext
*s
, RTMPContext
*rt
)
909 av_log(s
, AV_LOG_DEBUG
, "Sending publish command for '%s'\n", rt
->playpath
);
911 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SOURCE_CHANNEL
, RTMP_PT_INVOKE
,
912 0, 30 + strlen(rt
->playpath
))) < 0)
915 pkt
.extra
= rt
->stream_id
;
918 ff_amf_write_string(&p
, "publish");
919 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
920 ff_amf_write_null(&p
);
921 ff_amf_write_string(&p
, rt
->playpath
);
922 ff_amf_write_string(&p
, "live");
924 return rtmp_send_packet(rt
, &pkt
, 1);
928 * Generate ping reply and send it to the server.
930 static int gen_pong(URLContext
*s
, RTMPContext
*rt
, RTMPPacket
*ppkt
)
936 if (ppkt
->size
< 6) {
937 av_log(s
, AV_LOG_ERROR
, "Too short ping packet (%d)\n",
939 return AVERROR_INVALIDDATA
;
942 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
,RTMP_PT_USER_CONTROL
,
943 ppkt
->timestamp
+ 1, 6)) < 0)
947 bytestream_put_be16(&p
, 7); // PingResponse
948 bytestream_put_be32(&p
, AV_RB32(ppkt
->data
+2));
950 return rtmp_send_packet(rt
, &pkt
, 0);
954 * Generate SWF verification message and send it to the server.
956 static int gen_swf_verification(URLContext
*s
, RTMPContext
*rt
)
962 av_log(s
, AV_LOG_DEBUG
, "Sending SWF verification...\n");
963 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
, RTMP_PT_USER_CONTROL
,
968 bytestream_put_be16(&p
, 27);
969 memcpy(p
, rt
->swfverification
, 42);
971 return rtmp_send_packet(rt
, &pkt
, 0);
975 * Generate window acknowledgement size message and send it to the server.
977 static int gen_window_ack_size(URLContext
*s
, RTMPContext
*rt
)
983 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
, RTMP_PT_WINDOW_ACK_SIZE
,
988 bytestream_put_be32(&p
, rt
->max_sent_unacked
);
990 return rtmp_send_packet(rt
, &pkt
, 0);
994 * Generate check bandwidth message and send it to the server.
996 static int gen_check_bw(URLContext
*s
, RTMPContext
*rt
)
1002 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
, RTMP_PT_INVOKE
,
1007 ff_amf_write_string(&p
, "_checkbw");
1008 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
1009 ff_amf_write_null(&p
);
1011 return rtmp_send_packet(rt
, &pkt
, 1);
1015 * Generate report on bytes read so far and send it to the server.
1017 static int gen_bytes_read(URLContext
*s
, RTMPContext
*rt
, uint32_t ts
)
1023 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_NETWORK_CHANNEL
, RTMP_PT_BYTES_READ
,
1028 bytestream_put_be32(&p
, rt
->bytes_read
);
1030 return rtmp_send_packet(rt
, &pkt
, 0);
1033 static int gen_fcsubscribe_stream(URLContext
*s
, RTMPContext
*rt
,
1034 const char *subscribe
)
1040 if ((ret
= ff_rtmp_packet_create(&pkt
, RTMP_SYSTEM_CHANNEL
, RTMP_PT_INVOKE
,
1041 0, 27 + strlen(subscribe
))) < 0)
1045 ff_amf_write_string(&p
, "FCSubscribe");
1046 ff_amf_write_number(&p
, ++rt
->nb_invokes
);
1047 ff_amf_write_null(&p
);
1048 ff_amf_write_string(&p
, subscribe
);
1050 return rtmp_send_packet(rt
, &pkt
, 1);
1054 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
1055 * will be stored) into that packet.
1057 * @param buf handshake data (1536 bytes)
1058 * @param encrypted use an encrypted connection (RTMPE)
1059 * @return offset to the digest inside input data
1061 static int rtmp_handshake_imprint_with_digest(uint8_t *buf
, int encrypted
)
1063 int ret
, digest_pos
;
1066 digest_pos
= ff_rtmp_calc_digest_pos(buf
, 772, 728, 776);
1068 digest_pos
= ff_rtmp_calc_digest_pos(buf
, 8, 728, 12);
1070 ret
= ff_rtmp_calc_digest(buf
, RTMP_HANDSHAKE_PACKET_SIZE
, digest_pos
,
1071 rtmp_player_key
, PLAYER_KEY_OPEN_PART_LEN
,
1080 * Verify that the received server response has the expected digest value.
1082 * @param buf handshake data received from the server (1536 bytes)
1083 * @param off position to search digest offset from
1084 * @return 0 if digest is valid, digest position otherwise
1086 static int rtmp_validate_digest(uint8_t *buf
, int off
)
1089 int ret
, digest_pos
;
1091 digest_pos
= ff_rtmp_calc_digest_pos(buf
, off
, 728, off
+ 4);
1093 ret
= ff_rtmp_calc_digest(buf
, RTMP_HANDSHAKE_PACKET_SIZE
, digest_pos
,
1094 rtmp_server_key
, SERVER_KEY_OPEN_PART_LEN
,
1099 if (!memcmp(digest
, buf
+ digest_pos
, 32))
1104 static int rtmp_calc_swf_verification(URLContext
*s
, RTMPContext
*rt
,
1110 if (rt
->swfhash_len
!= 32) {
1111 av_log(s
, AV_LOG_ERROR
,
1112 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1113 return AVERROR(EINVAL
);
1116 p
= &rt
->swfverification
[0];
1117 bytestream_put_byte(&p
, 1);
1118 bytestream_put_byte(&p
, 1);
1119 bytestream_put_be32(&p
, rt
->swfsize
);
1120 bytestream_put_be32(&p
, rt
->swfsize
);
1122 if ((ret
= ff_rtmp_calc_digest(rt
->swfhash
, 32, 0, buf
, 32, p
)) < 0)
1129 static int rtmp_uncompress_swfplayer(uint8_t *in_data
, int64_t in_size
,
1130 uint8_t **out_data
, int64_t *out_size
)
1132 z_stream zs
= { 0 };
1137 zs
.avail_in
= in_size
;
1138 zs
.next_in
= in_data
;
1139 ret
= inflateInit(&zs
);
1141 return AVERROR_UNKNOWN
;
1144 uint8_t tmp_buf
[16384];
1146 zs
.avail_out
= sizeof(tmp_buf
);
1147 zs
.next_out
= tmp_buf
;
1149 ret
= inflate(&zs
, Z_NO_FLUSH
);
1150 if (ret
!= Z_OK
&& ret
!= Z_STREAM_END
) {
1151 ret
= AVERROR_UNKNOWN
;
1155 size
= sizeof(tmp_buf
) - zs
.avail_out
;
1156 if (!(ptr
= av_realloc(*out_data
, *out_size
+ size
))) {
1157 ret
= AVERROR(ENOMEM
);
1162 memcpy(*out_data
+ *out_size
, tmp_buf
, size
);
1164 } while (zs
.avail_out
== 0);
1172 static int rtmp_calc_swfhash(URLContext
*s
)
1174 RTMPContext
*rt
= s
->priv_data
;
1175 uint8_t *in_data
= NULL
, *out_data
= NULL
, *swfdata
;
1177 URLContext
*stream
= NULL
;
1182 /* Get the SWF player file. */
1183 if ((ret
= ffurl_open_whitelist(&stream
, rt
->swfverify
, AVIO_FLAG_READ
,
1184 &s
->interrupt_callback
, NULL
,
1185 s
->protocol_whitelist
, s
->protocol_blacklist
, s
)) < 0) {
1186 av_log(s
, AV_LOG_ERROR
, "Cannot open connection %s.\n", rt
->swfverify
);
1190 if ((in_size
= ffurl_seek(stream
, 0, AVSEEK_SIZE
)) < 0) {
1195 if (!(in_data
= av_malloc(in_size
))) {
1196 ret
= AVERROR(ENOMEM
);
1200 if ((ret
= ffurl_read_complete(stream
, in_data
, in_size
)) < 0)
1204 ret
= AVERROR_INVALIDDATA
;
1208 if (!memcmp(in_data
, "CWS", 3)) {
1211 /* Decompress the SWF player file using Zlib. */
1212 if (!(out_data
= av_malloc(8))) {
1213 ret
= AVERROR(ENOMEM
);
1216 *in_data
= 'F'; // magic stuff
1217 memcpy(out_data
, in_data
, 8);
1220 if ((ret
= rtmp_uncompress_swfplayer(in_data
+ 8, in_size
- 8,
1221 &out_data
, &out_size
)) < 0)
1226 av_log(s
, AV_LOG_ERROR
,
1227 "Zlib is required for decompressing the SWF player file.\n");
1228 ret
= AVERROR(EINVAL
);
1236 /* Compute the SHA256 hash of the SWF player file. */
1237 if ((ret
= ff_rtmp_calc_digest(swfdata
, swfsize
, 0,
1238 "Genuine Adobe Flash Player 001", 30,
1242 /* Set SWFVerification parameters. */
1243 av_opt_set_bin(rt
, "rtmp_swfhash", swfhash
, 32, 0);
1244 rt
->swfsize
= swfsize
;
1248 av_freep(&out_data
);
1249 ffurl_close(stream
);
1254 * Perform handshake with the server by means of exchanging pseudorandom data
1255 * signed with HMAC-SHA2 digest.
1257 * @return 0 if handshake succeeds, negative value otherwise
1259 static int rtmp_handshake(URLContext
*s
, RTMPContext
*rt
)
1262 uint8_t tosend
[RTMP_HANDSHAKE_PACKET_SIZE
+1] = {
1263 3, // unencrypted data
1264 0, 0, 0, 0, // client uptime
1270 uint8_t clientdata
[RTMP_HANDSHAKE_PACKET_SIZE
];
1271 uint8_t serverdata
[RTMP_HANDSHAKE_PACKET_SIZE
+1];
1273 int server_pos
, client_pos
;
1274 uint8_t digest
[32], signature
[32];
1276 #if CONFIG_FFRTMPCRYPT_PROTOCOL
1280 av_log(s
, AV_LOG_DEBUG
, "Handshaking...\n");
1282 av_lfg_init(&rnd
, 0xDEADC0DE);
1283 // generate handshake packet - 1536 bytes of pseudorandom data
1284 for (i
= 9; i
<= RTMP_HANDSHAKE_PACKET_SIZE
; i
++)
1285 tosend
[i
] = av_lfg_get(&rnd
) >> 24;
1287 #if CONFIG_FFRTMPCRYPT_PROTOCOL
1288 if (rt
->encrypted
) {
1289 /* When the client wants to use RTMPE, we have to change the command
1290 * byte to 0x06 which means to use encrypted data and we have to set
1291 * the flash version to at least 9.0.115.0. */
1298 /* Initialize the Diffie-Hellmann context and generate the public key
1299 * to send to the server. */
1300 if ((ret
= ff_rtmpe_gen_pub_key(rt
->stream
, tosend
+ 1)) < 0)
1305 client_pos
= rtmp_handshake_imprint_with_digest(tosend
+ 1, rt
->encrypted
);
1309 if ((ret
= ffurl_write(rt
->stream
, tosend
,
1310 RTMP_HANDSHAKE_PACKET_SIZE
+ 1)) < 0) {
1311 av_log(s
, AV_LOG_ERROR
, "Cannot write RTMP handshake request\n");
1315 if ((ret
= ffurl_read_complete(rt
->stream
, serverdata
,
1316 RTMP_HANDSHAKE_PACKET_SIZE
+ 1)) < 0) {
1317 av_log(s
, AV_LOG_ERROR
, "Cannot read RTMP handshake response\n");
1321 if ((ret
= ffurl_read_complete(rt
->stream
, clientdata
,
1322 RTMP_HANDSHAKE_PACKET_SIZE
)) < 0) {
1323 av_log(s
, AV_LOG_ERROR
, "Cannot read RTMP handshake response\n");
1327 av_log(s
, AV_LOG_DEBUG
, "Type answer %d\n", serverdata
[0]);
1328 av_log(s
, AV_LOG_DEBUG
, "Server version %d.%d.%d.%d\n",
1329 serverdata
[5], serverdata
[6], serverdata
[7], serverdata
[8]);
1331 if (rt
->is_input
&& serverdata
[5] >= 3) {
1332 server_pos
= rtmp_validate_digest(serverdata
+ 1, 772);
1337 #if CONFIG_FFRTMPCRYPT_PROTOCOL
1340 server_pos
= rtmp_validate_digest(serverdata
+ 1, 8);
1345 av_log(s
, AV_LOG_ERROR
, "Server response validating failed\n");
1346 return AVERROR(EIO
);
1350 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1351 * key are the last 32 bytes of the server handshake. */
1353 if ((ret
= rtmp_calc_swf_verification(s
, rt
, serverdata
+ 1 +
1354 RTMP_HANDSHAKE_PACKET_SIZE
- 32)) < 0)
1358 ret
= ff_rtmp_calc_digest(tosend
+ 1 + client_pos
, 32, 0,
1359 rtmp_server_key
, sizeof(rtmp_server_key
),
1364 ret
= ff_rtmp_calc_digest(clientdata
, RTMP_HANDSHAKE_PACKET_SIZE
- 32,
1365 0, digest
, 32, signature
);
1369 #if CONFIG_FFRTMPCRYPT_PROTOCOL
1370 if (rt
->encrypted
) {
1371 /* Compute the shared secret key sent by the server and initialize
1372 * the RC4 encryption. */
1373 if ((ret
= ff_rtmpe_compute_secret_key(rt
->stream
, serverdata
+ 1,
1374 tosend
+ 1, type
)) < 0)
1377 /* Encrypt the signature received by the server. */
1378 ff_rtmpe_encrypt_sig(rt
->stream
, signature
, digest
, serverdata
[0]);
1382 if (memcmp(signature
, clientdata
+ RTMP_HANDSHAKE_PACKET_SIZE
- 32, 32)) {
1383 av_log(s
, AV_LOG_ERROR
, "Signature mismatch\n");
1384 return AVERROR(EIO
);
1387 for (i
= 0; i
< RTMP_HANDSHAKE_PACKET_SIZE
; i
++)
1388 tosend
[i
] = av_lfg_get(&rnd
) >> 24;
1389 ret
= ff_rtmp_calc_digest(serverdata
+ 1 + server_pos
, 32, 0,
1390 rtmp_player_key
, sizeof(rtmp_player_key
),
1395 ret
= ff_rtmp_calc_digest(tosend
, RTMP_HANDSHAKE_PACKET_SIZE
- 32, 0,
1397 tosend
+ RTMP_HANDSHAKE_PACKET_SIZE
- 32);
1401 #if CONFIG_FFRTMPCRYPT_PROTOCOL
1402 if (rt
->encrypted
) {
1403 /* Encrypt the signature to be send to the server. */
1404 ff_rtmpe_encrypt_sig(rt
->stream
, tosend
+
1405 RTMP_HANDSHAKE_PACKET_SIZE
- 32, digest
,
1410 // write reply back to the server
1411 if ((ret
= ffurl_write(rt
->stream
, tosend
,
1412 RTMP_HANDSHAKE_PACKET_SIZE
)) < 0)
1415 #if CONFIG_FFRTMPCRYPT_PROTOCOL
1416 if (rt
->encrypted
) {
1417 /* Set RC4 keys for encryption and update the keystreams. */
1418 if ((ret
= ff_rtmpe_update_keystream(rt
->stream
)) < 0)
1423 #if CONFIG_FFRTMPCRYPT_PROTOCOL
1424 if (rt
->encrypted
) {
1425 /* Compute the shared secret key sent by the server and initialize
1426 * the RC4 encryption. */
1427 if ((ret
= ff_rtmpe_compute_secret_key(rt
->stream
, serverdata
+ 1,
1428 tosend
+ 1, 1)) < 0)
1431 if (serverdata
[0] == 9) {
1432 /* Encrypt the signature received by the server. */
1433 ff_rtmpe_encrypt_sig(rt
->stream
, signature
, digest
,
1439 if ((ret
= ffurl_write(rt
->stream
, serverdata
+ 1,
1440 RTMP_HANDSHAKE_PACKET_SIZE
)) < 0)
1443 #if CONFIG_FFRTMPCRYPT_PROTOCOL
1444 if (rt
->encrypted
) {
1445 /* Set RC4 keys for encryption and update the keystreams. */
1446 if ((ret
= ff_rtmpe_update_keystream(rt
->stream
)) < 0)
1455 static int rtmp_receive_hs_packet(RTMPContext
* rt
, uint32_t *first_int
,
1456 uint32_t *second_int
, char *arraydata
,
1461 inoutsize
= ffurl_read_complete(rt
->stream
, arraydata
,
1462 RTMP_HANDSHAKE_PACKET_SIZE
);
1464 return AVERROR(EIO
);
1465 if (inoutsize
!= RTMP_HANDSHAKE_PACKET_SIZE
) {
1466 av_log(rt
, AV_LOG_ERROR
, "Erroneous Message size %d"
1467 " not following standard\n", (int)inoutsize
);
1468 return AVERROR(EINVAL
);
1471 *first_int
= AV_RB32(arraydata
);
1472 *second_int
= AV_RB32(arraydata
+ 4);
1476 static int rtmp_send_hs_packet(RTMPContext
* rt
, uint32_t first_int
,
1477 uint32_t second_int
, char *arraydata
, int size
)
1481 AV_WB32(arraydata
, first_int
);
1482 AV_WB32(arraydata
+ 4, second_int
);
1483 inoutsize
= ffurl_write(rt
->stream
, arraydata
,
1484 RTMP_HANDSHAKE_PACKET_SIZE
);
1485 if (inoutsize
!= RTMP_HANDSHAKE_PACKET_SIZE
) {
1486 av_log(rt
, AV_LOG_ERROR
, "Unable to write answer\n");
1487 return AVERROR(EIO
);
1494 * rtmp handshake server side
1496 static int rtmp_server_handshake(URLContext
*s
, RTMPContext
*rt
)
1498 uint8_t buffer
[RTMP_HANDSHAKE_PACKET_SIZE
];
1500 uint32_t hs_my_epoch
;
1501 uint8_t hs_c1
[RTMP_HANDSHAKE_PACKET_SIZE
];
1502 uint8_t hs_s1
[RTMP_HANDSHAKE_PACKET_SIZE
];
1509 inoutsize
= ffurl_read_complete(rt
->stream
, buffer
, 1); // Receive C0
1510 if (inoutsize
<= 0) {
1511 av_log(s
, AV_LOG_ERROR
, "Unable to read handshake\n");
1512 return AVERROR(EIO
);
1515 if (buffer
[0] != 3) {
1516 av_log(s
, AV_LOG_ERROR
, "RTMP protocol version mismatch\n");
1517 return AVERROR(EIO
);
1519 if (ffurl_write(rt
->stream
, buffer
, 1) <= 0) { // Send S0
1520 av_log(s
, AV_LOG_ERROR
,
1521 "Unable to write answer - RTMP S0\n");
1522 return AVERROR(EIO
);
1525 ret
= rtmp_receive_hs_packet(rt
, &hs_epoch
, &zeroes
, hs_c1
,
1526 RTMP_HANDSHAKE_PACKET_SIZE
);
1528 av_log(s
, AV_LOG_ERROR
, "RTMP Handshake C1 Error\n");
1532 /* By now same epoch will be sent */
1533 hs_my_epoch
= hs_epoch
;
1534 /* Generate random */
1535 for (randomidx
= 8; randomidx
< (RTMP_HANDSHAKE_PACKET_SIZE
);
1537 AV_WB32(hs_s1
+ randomidx
, av_get_random_seed());
1539 ret
= rtmp_send_hs_packet(rt
, hs_my_epoch
, 0, hs_s1
,
1540 RTMP_HANDSHAKE_PACKET_SIZE
);
1542 av_log(s
, AV_LOG_ERROR
, "RTMP Handshake S1 Error\n");
1546 ret
= rtmp_send_hs_packet(rt
, hs_epoch
, 0, hs_c1
,
1547 RTMP_HANDSHAKE_PACKET_SIZE
);
1549 av_log(s
, AV_LOG_ERROR
, "RTMP Handshake S2 Error\n");
1553 ret
= rtmp_receive_hs_packet(rt
, &temp
, &zeroes
, buffer
,
1554 RTMP_HANDSHAKE_PACKET_SIZE
);
1556 av_log(s
, AV_LOG_ERROR
, "RTMP Handshake C2 Error\n");
1559 if (temp
!= hs_my_epoch
)
1560 av_log(s
, AV_LOG_WARNING
,
1561 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1562 if (memcmp(buffer
+ 8, hs_s1
+ 8,
1563 RTMP_HANDSHAKE_PACKET_SIZE
- 8))
1564 av_log(s
, AV_LOG_WARNING
,
1565 "Erroneous C2 Message random does not match up\n");
1570 static int handle_chunk_size(URLContext
*s
, RTMPPacket
*pkt
)
1572 RTMPContext
*rt
= s
->priv_data
;
1575 if (pkt
->size
< 4) {
1576 av_log(s
, AV_LOG_ERROR
,
1577 "Too short chunk size change packet (%d)\n",
1579 return AVERROR_INVALIDDATA
;
1582 if (!rt
->is_input
) {
1583 /* Send the same chunk size change packet back to the server,
1584 * setting the outgoing chunk size to the same as the incoming one. */
1585 if ((ret
= ff_rtmp_packet_write(rt
->stream
, pkt
, rt
->out_chunk_size
,
1586 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1])) < 0)
1588 rt
->out_chunk_size
= AV_RB32(pkt
->data
);
1591 rt
->in_chunk_size
= AV_RB32(pkt
->data
);
1592 if (rt
->in_chunk_size
<= 0) {
1593 av_log(s
, AV_LOG_ERROR
, "Incorrect chunk size %d\n",
1595 return AVERROR_INVALIDDATA
;
1597 av_log(s
, AV_LOG_DEBUG
, "New incoming chunk size = %d\n",
1603 static int handle_user_control(URLContext
*s
, RTMPPacket
*pkt
)
1605 RTMPContext
*rt
= s
->priv_data
;
1608 if (pkt
->size
< 2) {
1609 av_log(s
, AV_LOG_ERROR
, "Too short user control packet (%d)\n",
1611 return AVERROR_INVALIDDATA
;
1614 t
= AV_RB16(pkt
->data
);
1615 if (t
== 6) { // PingRequest
1616 if ((ret
= gen_pong(s
, rt
, pkt
)) < 0)
1618 } else if (t
== 26) {
1620 if ((ret
= gen_swf_verification(s
, rt
)) < 0)
1623 av_log(s
, AV_LOG_WARNING
, "Ignoring SWFVerification request.\n");
1630 static int handle_set_peer_bw(URLContext
*s
, RTMPPacket
*pkt
)
1632 RTMPContext
*rt
= s
->priv_data
;
1634 if (pkt
->size
< 4) {
1635 av_log(s
, AV_LOG_ERROR
,
1636 "Peer bandwidth packet is less than 4 bytes long (%d)\n",
1638 return AVERROR_INVALIDDATA
;
1641 // We currently don't check how much the peer has acknowledged of
1642 // what we have sent. To do that properly, we should call
1643 // gen_window_ack_size here, to tell the peer that we want an
1644 // acknowledgement with (at least) that interval.
1645 rt
->max_sent_unacked
= AV_RB32(pkt
->data
);
1646 if (rt
->max_sent_unacked
<= 0) {
1647 av_log(s
, AV_LOG_ERROR
, "Incorrect set peer bandwidth %d\n",
1648 rt
->max_sent_unacked
);
1649 return AVERROR_INVALIDDATA
;
1652 av_log(s
, AV_LOG_DEBUG
, "Max sent, unacked = %d\n", rt
->max_sent_unacked
);
1657 static int handle_window_ack_size(URLContext
*s
, RTMPPacket
*pkt
)
1659 RTMPContext
*rt
= s
->priv_data
;
1661 if (pkt
->size
< 4) {
1662 av_log(s
, AV_LOG_ERROR
,
1663 "Too short window acknowledgement size packet (%d)\n",
1665 return AVERROR_INVALIDDATA
;
1668 rt
->receive_report_size
= AV_RB32(pkt
->data
);
1669 if (rt
->receive_report_size
<= 0) {
1670 av_log(s
, AV_LOG_ERROR
, "Incorrect window acknowledgement size %d\n",
1671 rt
->receive_report_size
);
1672 return AVERROR_INVALIDDATA
;
1674 av_log(s
, AV_LOG_DEBUG
, "Window acknowledgement size = %d\n", rt
->receive_report_size
);
1675 // Send an Acknowledgement packet after receiving half the maximum
1676 // size, to make sure the peer can keep on sending without waiting
1677 // for acknowledgements.
1678 rt
->receive_report_size
>>= 1;
1683 static int do_adobe_auth(RTMPContext
*rt
, const char *user
, const char *salt
,
1684 const char *opaque
, const char *challenge
)
1687 char hashstr
[AV_BASE64_SIZE(sizeof(hash
))], challenge2
[10];
1688 struct AVMD5
*md5
= av_md5_alloc();
1690 return AVERROR(ENOMEM
);
1692 snprintf(challenge2
, sizeof(challenge2
), "%08x", av_get_random_seed());
1695 av_md5_update(md5
, user
, strlen(user
));
1696 av_md5_update(md5
, salt
, strlen(salt
));
1697 av_md5_update(md5
, rt
->password
, strlen(rt
->password
));
1698 av_md5_final(md5
, hash
);
1699 av_base64_encode(hashstr
, sizeof(hashstr
), hash
,
1702 av_md5_update(md5
, hashstr
, strlen(hashstr
));
1704 av_md5_update(md5
, opaque
, strlen(opaque
));
1706 av_md5_update(md5
, challenge
, strlen(challenge
));
1707 av_md5_update(md5
, challenge2
, strlen(challenge2
));
1708 av_md5_final(md5
, hash
);
1709 av_base64_encode(hashstr
, sizeof(hashstr
), hash
,
1711 snprintf(rt
->auth_params
, sizeof(rt
->auth_params
),
1712 "?authmod=%s&user=%s&challenge=%s&response=%s",
1713 "adobe", user
, challenge2
, hashstr
);
1715 av_strlcatf(rt
->auth_params
, sizeof(rt
->auth_params
),
1716 "&opaque=%s", opaque
);
1722 static int do_llnw_auth(RTMPContext
*rt
, const char *user
, const char *nonce
)
1725 char hashstr1
[33], hashstr2
[33];
1726 const char *realm
= "live";
1727 const char *method
= "publish";
1728 const char *qop
= "auth";
1729 const char *nc
= "00000001";
1731 struct AVMD5
*md5
= av_md5_alloc();
1733 return AVERROR(ENOMEM
);
1735 snprintf(cnonce
, sizeof(cnonce
), "%08x", av_get_random_seed());
1738 av_md5_update(md5
, user
, strlen(user
));
1739 av_md5_update(md5
, ":", 1);
1740 av_md5_update(md5
, realm
, strlen(realm
));
1741 av_md5_update(md5
, ":", 1);
1742 av_md5_update(md5
, rt
->password
, strlen(rt
->password
));
1743 av_md5_final(md5
, hash
);
1744 ff_data_to_hex(hashstr1
, hash
, 16, 1);
1747 av_md5_update(md5
, method
, strlen(method
));
1748 av_md5_update(md5
, ":/", 2);
1749 av_md5_update(md5
, rt
->app
, strlen(rt
->app
));
1750 if (!strchr(rt
->app
, '/'))
1751 av_md5_update(md5
, "/_definst_", strlen("/_definst_"));
1752 av_md5_final(md5
, hash
);
1753 ff_data_to_hex(hashstr2
, hash
, 16, 1);
1756 av_md5_update(md5
, hashstr1
, strlen(hashstr1
));
1757 av_md5_update(md5
, ":", 1);
1759 av_md5_update(md5
, nonce
, strlen(nonce
));
1760 av_md5_update(md5
, ":", 1);
1761 av_md5_update(md5
, nc
, strlen(nc
));
1762 av_md5_update(md5
, ":", 1);
1763 av_md5_update(md5
, cnonce
, strlen(cnonce
));
1764 av_md5_update(md5
, ":", 1);
1765 av_md5_update(md5
, qop
, strlen(qop
));
1766 av_md5_update(md5
, ":", 1);
1767 av_md5_update(md5
, hashstr2
, strlen(hashstr2
));
1768 av_md5_final(md5
, hash
);
1769 ff_data_to_hex(hashstr1
, hash
, 16, 1);
1771 snprintf(rt
->auth_params
, sizeof(rt
->auth_params
),
1772 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1773 "llnw", user
, nonce
, cnonce
, nc
, hashstr1
);
1779 static int handle_connect_error(URLContext
*s
, const char *desc
)
1781 RTMPContext
*rt
= s
->priv_data
;
1782 char buf
[300], *ptr
, authmod
[15];
1784 const char *user
= "", *salt
= "", *opaque
= NULL
,
1785 *challenge
= NULL
, *cptr
= NULL
, *nonce
= NULL
;
1787 if (!(cptr
= strstr(desc
, "authmod=adobe")) &&
1788 !(cptr
= strstr(desc
, "authmod=llnw"))) {
1789 av_log(s
, AV_LOG_ERROR
,
1790 "Unknown connect error (unsupported authentication method?)\n");
1791 return AVERROR_UNKNOWN
;
1793 cptr
+= strlen("authmod=");
1794 while (*cptr
&& *cptr
!= ' ' && i
< sizeof(authmod
) - 1)
1795 authmod
[i
++] = *cptr
++;
1798 if (!rt
->username
[0] || !rt
->password
[0]) {
1799 av_log(s
, AV_LOG_ERROR
, "No credentials set\n");
1800 return AVERROR_UNKNOWN
;
1803 if (strstr(desc
, "?reason=authfailed")) {
1804 av_log(s
, AV_LOG_ERROR
, "Incorrect username/password\n");
1805 return AVERROR_UNKNOWN
;
1806 } else if (strstr(desc
, "?reason=nosuchuser")) {
1807 av_log(s
, AV_LOG_ERROR
, "Incorrect username\n");
1808 return AVERROR_UNKNOWN
;
1811 if (rt
->auth_tried
) {
1812 av_log(s
, AV_LOG_ERROR
, "Authentication failed\n");
1813 return AVERROR_UNKNOWN
;
1816 rt
->auth_params
[0] = '\0';
1818 if (strstr(desc
, "code=403 need auth")) {
1819 snprintf(rt
->auth_params
, sizeof(rt
->auth_params
),
1820 "?authmod=%s&user=%s", authmod
, rt
->username
);
1824 if (!(cptr
= strstr(desc
, "?reason=needauth"))) {
1825 av_log(s
, AV_LOG_ERROR
, "No auth parameters found\n");
1826 return AVERROR_UNKNOWN
;
1829 av_strlcpy(buf
, cptr
+ 1, sizeof(buf
));
1833 char *next
= strchr(ptr
, '&');
1834 char *value
= strchr(ptr
, '=');
1839 if (!strcmp(ptr
, "user")) {
1841 } else if (!strcmp(ptr
, "salt")) {
1843 } else if (!strcmp(ptr
, "opaque")) {
1845 } else if (!strcmp(ptr
, "challenge")) {
1847 } else if (!strcmp(ptr
, "nonce")) {
1850 av_log(s
, AV_LOG_INFO
, "Ignoring unsupported var %s\n", ptr
);
1853 av_log(s
, AV_LOG_WARNING
, "Variable %s has NULL value\n", ptr
);
1858 if (!strcmp(authmod
, "adobe")) {
1859 if ((ret
= do_adobe_auth(rt
, user
, salt
, opaque
, challenge
)) < 0)
1862 if ((ret
= do_llnw_auth(rt
, user
, nonce
)) < 0)
1870 static int handle_invoke_error(URLContext
*s
, RTMPPacket
*pkt
)
1872 RTMPContext
*rt
= s
->priv_data
;
1873 const uint8_t *data_end
= pkt
->data
+ pkt
->size
;
1874 char *tracked_method
= NULL
;
1875 int level
= AV_LOG_ERROR
;
1876 uint8_t tmpstr
[256];
1879 if ((ret
= find_tracked_method(s
, pkt
, 9, &tracked_method
)) < 0)
1882 if (!ff_amf_get_field_value(pkt
->data
+ 9, data_end
,
1883 "description", tmpstr
, sizeof(tmpstr
))) {
1884 if (tracked_method
&& (!strcmp(tracked_method
, "_checkbw") ||
1885 !strcmp(tracked_method
, "releaseStream") ||
1886 !strcmp(tracked_method
, "FCSubscribe") ||
1887 !strcmp(tracked_method
, "FCPublish"))) {
1888 /* Gracefully ignore Adobe-specific historical artifact errors. */
1889 level
= AV_LOG_WARNING
;
1891 } else if (tracked_method
&& !strcmp(tracked_method
, "getStreamLength")) {
1892 level
= rt
->live
? AV_LOG_DEBUG
: AV_LOG_WARNING
;
1894 } else if (tracked_method
&& !strcmp(tracked_method
, "connect")) {
1895 ret
= handle_connect_error(s
, tmpstr
);
1897 rt
->do_reconnect
= 1;
1898 level
= AV_LOG_VERBOSE
;
1901 ret
= AVERROR_UNKNOWN
;
1902 av_log(s
, level
, "Server error: %s\n", tmpstr
);
1905 av_free(tracked_method
);
1909 static int write_begin(URLContext
*s
)
1911 RTMPContext
*rt
= s
->priv_data
;
1913 RTMPPacket spkt
= { 0 };
1916 // Send Stream Begin 1
1917 if ((ret
= ff_rtmp_packet_create(&spkt
, RTMP_NETWORK_CHANNEL
,
1918 RTMP_PT_USER_CONTROL
, 0, 6)) < 0) {
1919 av_log(s
, AV_LOG_ERROR
, "Unable to create response packet\n");
1923 bytestream2_init_writer(&pbc
, spkt
.data
, spkt
.size
);
1924 bytestream2_put_be16(&pbc
, 0); // 0 -> Stream Begin
1925 bytestream2_put_be32(&pbc
, rt
->nb_streamid
);
1927 ret
= ff_rtmp_packet_write(rt
->stream
, &spkt
, rt
->out_chunk_size
,
1928 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
1930 ff_rtmp_packet_destroy(&spkt
);
1935 static int write_status(URLContext
*s
, RTMPPacket
*pkt
,
1936 const char *status
, const char *description
, const char *details
)
1938 RTMPContext
*rt
= s
->priv_data
;
1939 RTMPPacket spkt
= { 0 };
1943 if ((ret
= ff_rtmp_packet_create(&spkt
, RTMP_SYSTEM_CHANNEL
,
1945 RTMP_PKTDATA_DEFAULT_SIZE
1946 + strlen(status
) + strlen(description
)
1947 + zstrlen(details
))) < 0) {
1948 av_log(s
, AV_LOG_ERROR
, "Unable to create response packet\n");
1953 spkt
.extra
= pkt
->extra
;
1954 ff_amf_write_string(&pp
, "onStatus");
1955 ff_amf_write_number(&pp
, 0);
1956 ff_amf_write_null(&pp
);
1958 ff_amf_write_object_start(&pp
);
1959 ff_amf_write_field_name(&pp
, "level");
1960 ff_amf_write_string(&pp
, "status");
1961 ff_amf_write_field_name(&pp
, "code");
1962 ff_amf_write_string(&pp
, status
);
1963 ff_amf_write_field_name(&pp
, "description");
1964 ff_amf_write_string(&pp
, description
);
1966 ff_amf_write_field_name(&pp
, "details");
1967 ff_amf_write_string(&pp
, details
);
1969 ff_amf_write_object_end(&pp
);
1971 spkt
.size
= pp
- spkt
.data
;
1972 ret
= ff_rtmp_packet_write(rt
->stream
, &spkt
, rt
->out_chunk_size
,
1973 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
1974 ff_rtmp_packet_destroy(&spkt
);
1979 static int send_invoke_response(URLContext
*s
, RTMPPacket
*pkt
)
1981 RTMPContext
*rt
= s
->priv_data
;
1987 const uint8_t *p
= pkt
->data
;
1989 RTMPPacket spkt
= { 0 };
1993 bytestream2_init(&gbc
, p
, pkt
->size
);
1994 if (ff_amf_read_string(&gbc
, command
, sizeof(command
),
1996 av_log(s
, AV_LOG_ERROR
, "Error in PT_INVOKE\n");
1997 return AVERROR_INVALIDDATA
;
2000 ret
= ff_amf_read_number(&gbc
, &seqnum
);
2003 ret
= ff_amf_read_null(&gbc
);
2006 if (!strcmp(command
, "FCPublish") ||
2007 !strcmp(command
, "publish")) {
2008 ret
= ff_amf_read_string(&gbc
, filename
,
2009 sizeof(filename
), &stringlen
);
2011 if (ret
== AVERROR(EINVAL
))
2012 av_log(s
, AV_LOG_ERROR
, "Unable to parse stream name - name too long?\n");
2014 av_log(s
, AV_LOG_ERROR
, "Unable to parse stream name\n");
2019 pchar
= strrchr(s
->filename
, '/');
2021 av_log(s
, AV_LOG_WARNING
,
2022 "Unable to find / in url %s, bad format\n",
2024 pchar
= s
->filename
;
2027 if (strcmp(pchar
, filename
))
2028 av_log(s
, AV_LOG_WARNING
, "Unexpected stream %s, expecting"
2029 " %s\n", filename
, pchar
);
2031 rt
->state
= STATE_RECEIVING
;
2034 if (!strcmp(command
, "FCPublish")) {
2035 if ((ret
= ff_rtmp_packet_create(&spkt
, RTMP_SYSTEM_CHANNEL
,
2037 RTMP_PKTDATA_DEFAULT_SIZE
)) < 0) {
2038 av_log(s
, AV_LOG_ERROR
, "Unable to create response packet\n");
2042 ff_amf_write_string(&pp
, "onFCPublish");
2043 } else if (!strcmp(command
, "publish")) {
2044 char statusmsg
[sizeof(filename
) + 32];
2045 snprintf(statusmsg
, sizeof(statusmsg
), "%s is now published", filename
);
2046 ret
= write_begin(s
);
2050 // Send onStatus(NetStream.Publish.Start)
2051 return write_status(s
, pkt
, "NetStream.Publish.Start",
2052 statusmsg
, filename
);
2053 } else if (!strcmp(command
, "play")) {
2054 ret
= write_begin(s
);
2057 rt
->state
= STATE_SENDING
;
2058 return write_status(s
, pkt
, "NetStream.Play.Start",
2059 "playing stream", NULL
);
2061 if ((ret
= ff_rtmp_packet_create(&spkt
, RTMP_SYSTEM_CHANNEL
,
2063 RTMP_PKTDATA_DEFAULT_SIZE
)) < 0) {
2064 av_log(s
, AV_LOG_ERROR
, "Unable to create response packet\n");
2068 ff_amf_write_string(&pp
, "_result");
2069 ff_amf_write_number(&pp
, seqnum
);
2070 ff_amf_write_null(&pp
);
2071 if (!strcmp(command
, "createStream")) {
2073 if (rt
->nb_streamid
== 0 || rt
->nb_streamid
== 2)
2074 rt
->nb_streamid
++; /* Values 0 and 2 are reserved */
2075 ff_amf_write_number(&pp
, rt
->nb_streamid
);
2076 /* By now we don't control which streams are removed in
2077 * deleteStream. There is no stream creation control
2078 * if a client creates more than 2^32 - 2 streams. */
2081 spkt
.size
= pp
- spkt
.data
;
2082 ret
= ff_rtmp_packet_write(rt
->stream
, &spkt
, rt
->out_chunk_size
,
2083 &rt
->prev_pkt
[1], &rt
->nb_prev_pkt
[1]);
2084 ff_rtmp_packet_destroy(&spkt
);
2089 * Read the AMF_NUMBER response ("_result") to a function call
2090 * (e.g. createStream()). This response should be made up of the AMF_STRING
2091 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2092 * successful response, we will return set the value to number (otherwise number
2093 * will not be changed).
2095 * @return 0 if reading the value succeeds, negative value otherwise
2097 static int read_number_result(RTMPPacket
*pkt
, double *number
)
2099 // We only need to fit "_result" in this.
2100 uint8_t strbuffer
[8];
2105 bytestream2_init(&gbc
, pkt
->data
, pkt
->size
);
2107 // Value 1/4: "_result" as AMF_STRING
2108 if (ff_amf_read_string(&gbc
, strbuffer
, sizeof(strbuffer
), &stringlen
))
2109 return AVERROR_INVALIDDATA
;
2110 if (strcmp(strbuffer
, "_result"))
2111 return AVERROR_INVALIDDATA
;
2112 // Value 2/4: The callee reference number
2113 if (ff_amf_read_number(&gbc
, &numbuffer
))
2114 return AVERROR_INVALIDDATA
;
2116 if (ff_amf_read_null(&gbc
))
2117 return AVERROR_INVALIDDATA
;
2118 // Value 4/4: The response as AMF_NUMBER
2119 if (ff_amf_read_number(&gbc
, &numbuffer
))
2120 return AVERROR_INVALIDDATA
;
2122 *number
= numbuffer
;
2127 static int handle_invoke_result(URLContext
*s
, RTMPPacket
*pkt
)
2129 RTMPContext
*rt
= s
->priv_data
;
2130 char *tracked_method
= NULL
;
2133 if ((ret
= find_tracked_method(s
, pkt
, 10, &tracked_method
)) < 0)
2136 if (!tracked_method
) {
2137 /* Ignore this reply when the current method is not tracked. */
2141 if (!strcmp(tracked_method
, "connect")) {
2142 if (!rt
->is_input
) {
2143 if ((ret
= gen_release_stream(s
, rt
)) < 0)
2146 if ((ret
= gen_fcpublish_stream(s
, rt
)) < 0)
2149 if ((ret
= gen_window_ack_size(s
, rt
)) < 0)
2153 if ((ret
= gen_create_stream(s
, rt
)) < 0)
2157 /* Send the FCSubscribe command when the name of live
2158 * stream is defined by the user or if it's a live stream. */
2159 if (rt
->subscribe
) {
2160 if ((ret
= gen_fcsubscribe_stream(s
, rt
, rt
->subscribe
)) < 0)
2162 } else if (rt
->live
== -1) {
2163 if ((ret
= gen_fcsubscribe_stream(s
, rt
, rt
->playpath
)) < 0)
2167 } else if (!strcmp(tracked_method
, "createStream")) {
2169 if (read_number_result(pkt
, &stream_id
)) {
2170 av_log(s
, AV_LOG_WARNING
, "Unexpected reply on connect()\n");
2172 rt
->stream_id
= stream_id
;
2175 if (!rt
->is_input
) {
2176 if ((ret
= gen_publish(s
, rt
)) < 0)
2179 if (rt
->live
!= -1) {
2180 if ((ret
= gen_get_stream_length(s
, rt
)) < 0)
2183 if ((ret
= gen_play(s
, rt
)) < 0)
2185 if ((ret
= gen_buffer_time(s
, rt
)) < 0)
2188 } else if (!strcmp(tracked_method
, "getStreamLength")) {
2189 if (read_number_result(pkt
, &rt
->duration
)) {
2190 av_log(s
, AV_LOG_WARNING
, "Unexpected reply on getStreamLength()\n");
2195 av_free(tracked_method
);
2199 static int handle_invoke_status(URLContext
*s
, RTMPPacket
*pkt
)
2201 RTMPContext
*rt
= s
->priv_data
;
2202 const uint8_t *data_end
= pkt
->data
+ pkt
->size
;
2203 const uint8_t *ptr
= pkt
->data
+ RTMP_HEADER
;
2204 uint8_t tmpstr
[256];
2207 for (i
= 0; i
< 2; i
++) {
2208 t
= ff_amf_tag_size(ptr
, data_end
);
2214 t
= ff_amf_get_field_value(ptr
, data_end
, "level", tmpstr
, sizeof(tmpstr
));
2215 if (!t
&& !strcmp(tmpstr
, "error")) {
2216 t
= ff_amf_get_field_value(ptr
, data_end
,
2217 "description", tmpstr
, sizeof(tmpstr
));
2218 if (t
|| !tmpstr
[0])
2219 t
= ff_amf_get_field_value(ptr
, data_end
, "code",
2220 tmpstr
, sizeof(tmpstr
));
2222 av_log(s
, AV_LOG_ERROR
, "Server error: %s\n", tmpstr
);
2226 t
= ff_amf_get_field_value(ptr
, data_end
, "code", tmpstr
, sizeof(tmpstr
));
2227 if (!t
&& !strcmp(tmpstr
, "NetStream.Play.Start")) rt
->state
= STATE_PLAYING
;
2228 if (!t
&& !strcmp(tmpstr
, "NetStream.Play.Stop")) rt
->state
= STATE_STOPPED
;
2229 if (!t
&& !strcmp(tmpstr
, "NetStream.Play.UnpublishNotify")) rt
->state
= STATE_STOPPED
;
2230 if (!t
&& !strcmp(tmpstr
, "NetStream.Publish.Start")) rt
->state
= STATE_PUBLISHING
;
2231 if (!t
&& !strcmp(tmpstr
, "NetStream.Seek.Notify")) rt
->state
= STATE_PLAYING
;
2236 static int handle_invoke(URLContext
*s
, RTMPPacket
*pkt
)
2238 RTMPContext
*rt
= s
->priv_data
;
2241 //TODO: check for the messages sent for wrong state?
2242 if (ff_amf_match_string(pkt
->data
, pkt
->size
, "_error")) {
2243 if ((ret
= handle_invoke_error(s
, pkt
)) < 0)
2245 } else if (ff_amf_match_string(pkt
->data
, pkt
->size
, "_result")) {
2246 if ((ret
= handle_invoke_result(s
, pkt
)) < 0)
2248 } else if (ff_amf_match_string(pkt
->data
, pkt
->size
, "onStatus")) {
2249 if ((ret
= handle_invoke_status(s
, pkt
)) < 0)
2251 } else if (ff_amf_match_string(pkt
->data
, pkt
->size
, "onBWDone")) {
2252 if ((ret
= gen_check_bw(s
, rt
)) < 0)
2254 } else if (ff_amf_match_string(pkt
->data
, pkt
->size
, "releaseStream") ||
2255 ff_amf_match_string(pkt
->data
, pkt
->size
, "FCPublish") ||
2256 ff_amf_match_string(pkt
->data
, pkt
->size
, "publish") ||
2257 ff_amf_match_string(pkt
->data
, pkt
->size
, "play") ||
2258 ff_amf_match_string(pkt
->data
, pkt
->size
, "_checkbw") ||
2259 ff_amf_match_string(pkt
->data
, pkt
->size
, "createStream")) {
2260 if ((ret
= send_invoke_response(s
, pkt
)) < 0)
2267 static int update_offset(RTMPContext
*rt
, int size
)
2271 // generate packet header and put data into buffer for FLV demuxer
2272 if (rt
->flv_off
< rt
->flv_size
) {
2273 // There is old unread data in the buffer, thus append at the end
2274 old_flv_size
= rt
->flv_size
;
2275 rt
->flv_size
+= size
;
2277 // All data has been read, write the new data at the start of the buffer
2279 rt
->flv_size
= size
;
2283 return old_flv_size
;
2286 static int append_flv_data(RTMPContext
*rt
, RTMPPacket
*pkt
, int skip
)
2288 int old_flv_size
, ret
;
2290 const uint8_t *data
= pkt
->data
+ skip
;
2291 const int size
= pkt
->size
- skip
;
2292 uint32_t ts
= pkt
->timestamp
;
2294 if (pkt
->type
== RTMP_PT_AUDIO
) {
2296 } else if (pkt
->type
== RTMP_PT_VIDEO
) {
2300 old_flv_size
= update_offset(rt
, size
+ 15);
2302 if ((ret
= av_reallocp(&rt
->flv_data
, rt
->flv_size
)) < 0) {
2303 rt
->flv_size
= rt
->flv_off
= 0;
2306 bytestream2_init_writer(&pbc
, rt
->flv_data
, rt
->flv_size
);
2307 bytestream2_skip_p(&pbc
, old_flv_size
);
2308 bytestream2_put_byte(&pbc
, pkt
->type
);
2309 bytestream2_put_be24(&pbc
, size
);
2310 bytestream2_put_be24(&pbc
, ts
);
2311 bytestream2_put_byte(&pbc
, ts
>> 24);
2312 bytestream2_put_be24(&pbc
, 0);
2313 bytestream2_put_buffer(&pbc
, data
, size
);
2314 bytestream2_put_be32(&pbc
, size
+ RTMP_HEADER
);
2319 static int handle_notify(URLContext
*s
, RTMPPacket
*pkt
)
2321 RTMPContext
*rt
= s
->priv_data
;
2322 uint8_t commandbuffer
[64];
2323 char statusmsg
[128];
2324 int stringlen
, ret
, skip
= 0;
2327 bytestream2_init(&gbc
, pkt
->data
, pkt
->size
);
2328 if (ff_amf_read_string(&gbc
, commandbuffer
, sizeof(commandbuffer
),
2330 return AVERROR_INVALIDDATA
;
2332 if (!strcmp(commandbuffer
, "onMetaData")) {
2333 // metadata properties should be stored in a mixed array
2334 if (bytestream2_get_byte(&gbc
) == AMF_DATA_TYPE_MIXEDARRAY
) {
2335 // We have found a metaData Array so flv can determine the streams
2337 rt
->received_metadata
= 1;
2338 // skip 32-bit max array index
2339 bytestream2_skip(&gbc
, 4);
2340 while (bytestream2_get_bytes_left(&gbc
) > 3) {
2341 if (ff_amf_get_string(&gbc
, statusmsg
, sizeof(statusmsg
),
2343 return AVERROR_INVALIDDATA
;
2344 // We do not care about the content of the property (yet).
2345 stringlen
= ff_amf_tag_size(gbc
.buffer
, gbc
.buffer_end
);
2347 return AVERROR_INVALIDDATA
;
2348 bytestream2_skip(&gbc
, stringlen
);
2350 // The presence of the following properties indicates that the
2351 // respective streams are present.
2352 if (!strcmp(statusmsg
, "videocodecid")) {
2355 if (!strcmp(statusmsg
, "audiocodecid")) {
2359 if (bytestream2_get_be24(&gbc
) != AMF_END_OF_OBJECT
)
2360 return AVERROR_INVALIDDATA
;
2364 // Skip the @setDataFrame string and validate it is a notification
2365 if (!strcmp(commandbuffer
, "@setDataFrame")) {
2366 skip
= gbc
.buffer
- pkt
->data
;
2367 ret
= ff_amf_read_string(&gbc
, statusmsg
,
2368 sizeof(statusmsg
), &stringlen
);
2370 return AVERROR_INVALIDDATA
;
2373 return append_flv_data(rt
, pkt
, skip
);
2377 * Parse received packet and possibly perform some action depending on
2378 * the packet contents.
2379 * @return 0 for no errors, negative values for serious errors which prevent
2380 * further communications, positive values for uncritical errors
2382 static int rtmp_parse_result(URLContext
*s
, RTMPContext
*rt
, RTMPPacket
*pkt
)
2387 ff_rtmp_packet_dump(s
, pkt
);
2390 switch (pkt
->type
) {
2391 case RTMP_PT_BYTES_READ
:
2392 av_log(s
, AV_LOG_TRACE
, "received bytes read report\n");
2394 case RTMP_PT_CHUNK_SIZE
:
2395 if ((ret
= handle_chunk_size(s
, pkt
)) < 0)
2398 case RTMP_PT_USER_CONTROL
:
2399 if ((ret
= handle_user_control(s
, pkt
)) < 0)
2402 case RTMP_PT_SET_PEER_BW
:
2403 if ((ret
= handle_set_peer_bw(s
, pkt
)) < 0)
2406 case RTMP_PT_WINDOW_ACK_SIZE
:
2407 if ((ret
= handle_window_ack_size(s
, pkt
)) < 0)
2410 case RTMP_PT_INVOKE
:
2411 if ((ret
= handle_invoke(s
, pkt
)) < 0)
2416 case RTMP_PT_METADATA
:
2417 case RTMP_PT_NOTIFY
:
2418 /* Audio, Video and Metadata packets are parsed in get_packet() */
2421 av_log(s
, AV_LOG_VERBOSE
, "Unknown packet type received 0x%02X\n", pkt
->type
);
2427 static int handle_metadata(RTMPContext
*rt
, RTMPPacket
*pkt
)
2429 int ret
, old_flv_size
, type
;
2430 const uint8_t *next
;
2433 uint32_t ts
, cts
, pts
= 0;
2435 old_flv_size
= update_offset(rt
, pkt
->size
);
2437 if ((ret
= av_reallocp(&rt
->flv_data
, rt
->flv_size
)) < 0) {
2438 rt
->flv_size
= rt
->flv_off
= 0;
2443 p
= rt
->flv_data
+ old_flv_size
;
2445 /* copy data while rewriting timestamps */
2446 ts
= pkt
->timestamp
;
2448 while (next
- pkt
->data
< pkt
->size
- RTMP_HEADER
) {
2449 type
= bytestream_get_byte(&next
);
2450 size
= bytestream_get_be24(&next
);
2451 cts
= bytestream_get_be24(&next
);
2452 cts
|= bytestream_get_byte(&next
) << 24;
2457 if (size
+ 3 + 4 > pkt
->data
+ pkt
->size
- next
)
2459 bytestream_put_byte(&p
, type
);
2460 bytestream_put_be24(&p
, size
);
2461 bytestream_put_be24(&p
, ts
);
2462 bytestream_put_byte(&p
, ts
>> 24);
2463 memcpy(p
, next
, size
+ 3 + 4);
2465 bytestream_put_be32(&p
, size
+ RTMP_HEADER
);
2466 next
+= size
+ 3 + 4;
2468 if (p
!= rt
->flv_data
+ rt
->flv_size
) {
2469 av_log(rt
, AV_LOG_WARNING
, "Incomplete flv packets in "
2470 "RTMP_PT_METADATA packet\n");
2471 rt
->flv_size
= p
- rt
->flv_data
;
2478 * Interact with the server by receiving and sending RTMP packets until
2479 * there is some significant data (media data or expected status notification).
2481 * @param s reading context
2482 * @param for_header non-zero value tells function to work until it
2483 * gets notification from the server that playing has been started,
2484 * otherwise function will work until some media data is received (or
2486 * @return 0 for successful operation, negative value in case of error
2488 static int get_packet(URLContext
*s
, int for_header
)
2490 RTMPContext
*rt
= s
->priv_data
;
2493 if (rt
->state
== STATE_STOPPED
)
2497 RTMPPacket rpkt
= { 0 };
2498 if ((ret
= ff_rtmp_packet_read(rt
->stream
, &rpkt
,
2499 rt
->in_chunk_size
, &rt
->prev_pkt
[0],
2500 &rt
->nb_prev_pkt
[0])) <= 0) {
2502 return AVERROR(EAGAIN
);
2504 return AVERROR(EIO
);
2508 // Track timestamp for later use
2509 rt
->last_timestamp
= rpkt
.timestamp
;
2511 rt
->bytes_read
+= ret
;
2512 if (rt
->bytes_read
- rt
->last_bytes_read
> rt
->receive_report_size
) {
2513 av_log(s
, AV_LOG_DEBUG
, "Sending bytes read report\n");
2514 if ((ret
= gen_bytes_read(s
, rt
, rpkt
.timestamp
+ 1)) < 0) {
2515 ff_rtmp_packet_destroy(&rpkt
);
2518 rt
->last_bytes_read
= rt
->bytes_read
;
2521 ret
= rtmp_parse_result(s
, rt
, &rpkt
);
2523 // At this point we must check if we are in the seek state and continue
2524 // with the next packet. handle_invoke will get us out of this state
2525 // when the right message is encountered
2526 if (rt
->state
== STATE_SEEKING
) {
2527 ff_rtmp_packet_destroy(&rpkt
);
2528 // We continue, let the natural flow of things happen:
2529 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2533 if (ret
< 0) {//serious error in current packet
2534 ff_rtmp_packet_destroy(&rpkt
);
2537 if (rt
->do_reconnect
&& for_header
) {
2538 ff_rtmp_packet_destroy(&rpkt
);
2541 if (rt
->state
== STATE_STOPPED
) {
2542 ff_rtmp_packet_destroy(&rpkt
);
2545 if (for_header
&& (rt
->state
== STATE_PLAYING
||
2546 rt
->state
== STATE_PUBLISHING
||
2547 rt
->state
== STATE_SENDING
||
2548 rt
->state
== STATE_RECEIVING
)) {
2549 ff_rtmp_packet_destroy(&rpkt
);
2552 if (!rpkt
.size
|| !rt
->is_input
) {
2553 ff_rtmp_packet_destroy(&rpkt
);
2556 if (rpkt
.type
== RTMP_PT_VIDEO
|| rpkt
.type
== RTMP_PT_AUDIO
) {
2557 ret
= append_flv_data(rt
, &rpkt
, 0);
2558 ff_rtmp_packet_destroy(&rpkt
);
2560 } else if (rpkt
.type
== RTMP_PT_NOTIFY
) {
2561 ret
= handle_notify(s
, &rpkt
);
2562 ff_rtmp_packet_destroy(&rpkt
);
2564 } else if (rpkt
.type
== RTMP_PT_METADATA
) {
2565 ret
= handle_metadata(rt
, &rpkt
);
2566 ff_rtmp_packet_destroy(&rpkt
);
2569 ff_rtmp_packet_destroy(&rpkt
);
2573 static int rtmp_close(URLContext
*h
)
2575 RTMPContext
*rt
= h
->priv_data
;
2578 if (!rt
->is_input
) {
2579 rt
->flv_data
= NULL
;
2580 if (rt
->out_pkt
.size
)
2581 ff_rtmp_packet_destroy(&rt
->out_pkt
);
2582 if (rt
->state
> STATE_FCPUBLISH
)
2583 ret
= gen_fcunpublish_stream(h
, rt
);
2585 if (rt
->state
> STATE_HANDSHAKED
)
2586 ret
= gen_delete_stream(h
, rt
);
2587 for (i
= 0; i
< 2; i
++) {
2588 for (j
= 0; j
< rt
->nb_prev_pkt
[i
]; j
++)
2589 ff_rtmp_packet_destroy(&rt
->prev_pkt
[i
][j
]);
2590 av_freep(&rt
->prev_pkt
[i
]);
2593 free_tracked_methods(rt
);
2594 av_freep(&rt
->flv_data
);
2595 ffurl_closep(&rt
->stream
);
2600 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2601 * demuxer about the duration of the stream.
2603 * This should only be done if there was no real onMetadata packet sent by the
2604 * server at the start of the stream and if we were able to retrieve a valid
2605 * duration via a getStreamLength call.
2607 * @return 0 for successful operation, negative value in case of error
2609 static int inject_fake_duration_metadata(RTMPContext
*rt
)
2611 // We need to insert the metadata packet directly after the FLV
2612 // header, i.e. we need to move all other already read data by the
2613 // size of our fake metadata packet.
2616 // Keep old flv_data pointer
2617 uint8_t* old_flv_data
= rt
->flv_data
;
2618 // Allocate a new flv_data pointer with enough space for the additional package
2619 if (!(rt
->flv_data
= av_malloc(rt
->flv_size
+ 55))) {
2620 rt
->flv_data
= old_flv_data
;
2621 return AVERROR(ENOMEM
);
2625 memcpy(rt
->flv_data
, old_flv_data
, 13);
2626 // Copy remaining packets
2627 memcpy(rt
->flv_data
+ 13 + 55, old_flv_data
+ 13, rt
->flv_size
- 13);
2628 // Increase the size by the injected packet
2630 // Delete the old FLV data
2631 av_freep(&old_flv_data
);
2633 p
= rt
->flv_data
+ 13;
2634 bytestream_put_byte(&p
, FLV_TAG_TYPE_META
);
2635 bytestream_put_be24(&p
, 40); // size of data part (sum of all parts below)
2636 bytestream_put_be24(&p
, 0); // timestamp
2637 bytestream_put_be32(&p
, 0); // reserved
2639 // first event name as a string
2640 bytestream_put_byte(&p
, AMF_DATA_TYPE_STRING
);
2641 // "onMetaData" as AMF string
2642 bytestream_put_be16(&p
, 10);
2643 bytestream_put_buffer(&p
, "onMetaData", 10);
2645 // mixed array (hash) with size and string/type/data tuples
2646 bytestream_put_byte(&p
, AMF_DATA_TYPE_MIXEDARRAY
);
2647 bytestream_put_be32(&p
, 1); // metadata_count
2649 // "duration" as AMF string
2650 bytestream_put_be16(&p
, 8);
2651 bytestream_put_buffer(&p
, "duration", 8);
2652 bytestream_put_byte(&p
, AMF_DATA_TYPE_NUMBER
);
2653 bytestream_put_be64(&p
, av_double2int(rt
->duration
));
2656 bytestream_put_be16(&p
, 0); // Empty string
2657 bytestream_put_byte(&p
, AMF_END_OF_OBJECT
);
2658 bytestream_put_be32(&p
, 40 + RTMP_HEADER
); // size of data part (sum of all parts above)
2664 * Open RTMP connection and verify that the stream can be played.
2666 * URL syntax: rtmp://server[:port][/app][/playpath]
2667 * where 'app' is first one or two directories in the path
2668 * (e.g. /ondemand/, /flash/live/, etc.)
2669 * and 'playpath' is a file name (the rest of the path,
2670 * may be prefixed with "mp4:")
2672 static int rtmp_open(URLContext
*s
, const char *uri
, int flags
, AVDictionary
**opts
)
2674 RTMPContext
*rt
= s
->priv_data
;
2675 char proto
[8], hostname
[256], path
[1024], auth
[100], *fname
;
2676 char *old_app
, *qmark
, *n
, fname_buffer
[1024];
2681 if (rt
->listen_timeout
> 0)
2684 rt
->is_input
= !(flags
& AVIO_FLAG_WRITE
);
2686 av_url_split(proto
, sizeof(proto
), auth
, sizeof(auth
),
2687 hostname
, sizeof(hostname
), &port
,
2688 path
, sizeof(path
), s
->filename
);
2690 n
= strchr(path
, ' ');
2692 av_log(s
, AV_LOG_WARNING
,
2693 "Detected librtmp style URL parameters, these aren't supported "
2694 "by the libavformat internal RTMP handler currently enabled. "
2695 "See the documentation for the correct way to pass parameters.\n");
2696 *n
= '\0'; // Trim not supported part
2700 char *ptr
= strchr(auth
, ':');
2703 av_strlcpy(rt
->username
, auth
, sizeof(rt
->username
));
2704 av_strlcpy(rt
->password
, ptr
+ 1, sizeof(rt
->password
));
2708 if (rt
->listen
&& strcmp(proto
, "rtmp")) {
2709 av_log(s
, AV_LOG_ERROR
, "rtmp_listen not available for %s\n",
2711 return AVERROR(EINVAL
);
2713 if (!strcmp(proto
, "rtmpt") || !strcmp(proto
, "rtmpts")) {
2714 if (!strcmp(proto
, "rtmpts"))
2715 av_dict_set(opts
, "ffrtmphttp_tls", "1", AV_DICT_MATCH_CASE
);
2717 /* open the http tunneling connection */
2718 ff_url_join(buf
, sizeof(buf
), "ffrtmphttp", NULL
, hostname
, port
, NULL
);
2719 } else if (!strcmp(proto
, "rtmps")) {
2720 /* open the tls connection */
2722 port
= RTMPS_DEFAULT_PORT
;
2723 ff_url_join(buf
, sizeof(buf
), "tls", NULL
, hostname
, port
, NULL
);
2724 } else if (!strcmp(proto
, "rtmpe") || (!strcmp(proto
, "rtmpte"))) {
2725 if (!strcmp(proto
, "rtmpte"))
2726 av_dict_set(opts
, "ffrtmpcrypt_tunneling", "1", 1);
2728 /* open the encrypted connection */
2729 ff_url_join(buf
, sizeof(buf
), "ffrtmpcrypt", NULL
, hostname
, port
, NULL
);
2732 /* open the tcp connection */
2734 port
= RTMP_DEFAULT_PORT
;
2736 ff_url_join(buf
, sizeof(buf
), "tcp", NULL
, hostname
, port
,
2737 "?listen&listen_timeout=%d&tcp_nodelay=%d",
2738 rt
->listen_timeout
* 1000, rt
->tcp_nodelay
);
2740 ff_url_join(buf
, sizeof(buf
), "tcp", NULL
, hostname
, port
, "?tcp_nodelay=%d", rt
->tcp_nodelay
);
2744 if ((ret
= ffurl_open_whitelist(&rt
->stream
, buf
, AVIO_FLAG_READ_WRITE
,
2745 &s
->interrupt_callback
, opts
,
2746 s
->protocol_whitelist
, s
->protocol_blacklist
, s
)) < 0) {
2747 av_log(s
, AV_LOG_ERROR
, "Cannot open connection %s\n", buf
);
2751 if (rt
->swfverify
) {
2752 if ((ret
= rtmp_calc_swfhash(s
)) < 0)
2756 rt
->state
= STATE_START
;
2757 if (!rt
->listen
&& (ret
= rtmp_handshake(s
, rt
)) < 0)
2759 if (rt
->listen
&& (ret
= rtmp_server_handshake(s
, rt
)) < 0)
2762 rt
->out_chunk_size
= 128;
2763 rt
->in_chunk_size
= 128; // Probably overwritten later
2764 rt
->state
= STATE_HANDSHAKED
;
2766 // Keep the application name when it has been defined by the user.
2769 rt
->app
= av_malloc(APP_MAX_LENGTH
);
2771 ret
= AVERROR(ENOMEM
);
2775 //extract "app" part from path
2776 qmark
= strchr(path
, '?');
2777 if (qmark
&& strstr(qmark
, "slist=")) {
2779 // After slist we have the playpath, the full path is used as app
2780 av_strlcpy(rt
->app
, path
+ 1, APP_MAX_LENGTH
);
2781 fname
= strstr(path
, "slist=") + 6;
2782 // Strip any further query parameters from fname
2783 amp
= strchr(fname
, '&');
2785 av_strlcpy(fname_buffer
, fname
, FFMIN(amp
- fname
+ 1,
2786 sizeof(fname_buffer
)));
2787 fname
= fname_buffer
;
2789 } else if (!strncmp(path
, "/ondemand/", 10)) {
2791 memcpy(rt
->app
, "ondemand", 9);
2793 char *next
= *path
? path
+ 1 : path
;
2794 char *p
= strchr(next
, '/');
2797 // If name of application has been defined by the user, assume that
2798 // playpath is provided in the URL
2802 av_strlcpy(rt
->app
, next
, APP_MAX_LENGTH
);
2805 // make sure we do not mismatch a playpath for an application instance
2806 char *c
= strchr(p
+ 1, ':');
2807 fname
= strchr(p
+ 1, '/');
2808 if (!fname
|| (c
&& c
< fname
)) {
2810 av_strlcpy(rt
->app
, path
+ 1, FFMIN(p
- path
, APP_MAX_LENGTH
));
2813 av_strlcpy(rt
->app
, path
+ 1, FFMIN(fname
- path
- 1, APP_MAX_LENGTH
));
2819 // The name of application has been defined by the user, override it.
2820 if (strlen(old_app
) >= APP_MAX_LENGTH
) {
2821 ret
= AVERROR(EINVAL
);
2828 if (!rt
->playpath
) {
2831 max_len
= strlen(fname
) + 5; // add prefix "mp4:"
2832 rt
->playpath
= av_malloc(max_len
);
2833 if (!rt
->playpath
) {
2834 ret
= AVERROR(ENOMEM
);
2839 int len
= strlen(fname
);
2840 if (!strchr(fname
, ':') && len
>= 4 &&
2841 (!strcmp(fname
+ len
- 4, ".f4v") ||
2842 !strcmp(fname
+ len
- 4, ".mp4"))) {
2843 memcpy(rt
->playpath
, "mp4:", 5);
2845 if (len
>= 4 && !strcmp(fname
+ len
- 4, ".flv"))
2846 fname
[len
- 4] = '\0';
2847 rt
->playpath
[0] = 0;
2849 av_strlcat(rt
->playpath
, fname
, max_len
);
2851 rt
->playpath
[0] = '\0';
2856 rt
->tcurl
= av_malloc(TCURL_MAX_LENGTH
);
2858 ret
= AVERROR(ENOMEM
);
2861 ff_url_join(rt
->tcurl
, TCURL_MAX_LENGTH
, proto
, NULL
, hostname
,
2862 port
, "/%s", rt
->app
);
2865 if (!rt
->flashver
) {
2866 rt
->flashver
= av_malloc(FLASHVER_MAX_LENGTH
);
2867 if (!rt
->flashver
) {
2868 ret
= AVERROR(ENOMEM
);
2872 snprintf(rt
->flashver
, FLASHVER_MAX_LENGTH
, "%s %d,%d,%d,%d",
2873 RTMP_CLIENT_PLATFORM
, RTMP_CLIENT_VER1
, RTMP_CLIENT_VER2
,
2874 RTMP_CLIENT_VER3
, RTMP_CLIENT_VER4
);
2876 snprintf(rt
->flashver
, FLASHVER_MAX_LENGTH
,
2877 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT
);
2880 if ( strlen(rt
->flashver
) > FLASHVER_MAX_LENGTH
2881 || strlen(rt
->tcurl
) > TCURL_MAX_LENGTH
2883 ret
= AVERROR(EINVAL
);
2887 rt
->receive_report_size
= 1048576;
2891 rt
->received_metadata
= 0;
2892 rt
->last_bytes_read
= 0;
2893 rt
->max_sent_unacked
= 2500000;
2896 av_log(s
, AV_LOG_DEBUG
, "Proto = %s, path = %s, app = %s, fname = %s\n",
2897 proto
, path
, rt
->app
, rt
->playpath
);
2899 if ((ret
= gen_connect(s
, rt
)) < 0)
2902 if ((ret
= read_connect(s
, s
->priv_data
)) < 0)
2907 ret
= get_packet(s
, 1);
2908 } while (ret
== AVERROR(EAGAIN
));
2912 if (rt
->do_reconnect
) {
2914 ffurl_closep(&rt
->stream
);
2915 rt
->do_reconnect
= 0;
2917 for (i
= 0; i
< 2; i
++)
2918 memset(rt
->prev_pkt
[i
], 0,
2919 sizeof(**rt
->prev_pkt
) * rt
->nb_prev_pkt
[i
]);
2920 free_tracked_methods(rt
);
2925 // generate FLV header for demuxer
2927 if ((ret
= av_reallocp(&rt
->flv_data
, rt
->flv_size
)) < 0)
2930 memcpy(rt
->flv_data
, "FLV\1\0\0\0\0\011\0\0\0\0", rt
->flv_size
);
2932 // Read packets until we reach the first A/V packet or read metadata.
2933 // If there was a metadata package in front of the A/V packets, we can
2934 // build the FLV header from this. If we do not receive any metadata,
2935 // the FLV decoder will allocate the needed streams when their first
2936 // audio or video packet arrives.
2937 while (!rt
->has_audio
&& !rt
->has_video
&& !rt
->received_metadata
) {
2938 if ((ret
= get_packet(s
, 0)) < 0)
2942 // Either after we have read the metadata or (if there is none) the
2943 // first packet of an A/V stream, we have a better knowledge about the
2944 // streams, so set the FLV header accordingly.
2945 if (rt
->has_audio
) {
2946 rt
->flv_data
[4] |= FLV_HEADER_FLAG_HASAUDIO
;
2948 if (rt
->has_video
) {
2949 rt
->flv_data
[4] |= FLV_HEADER_FLAG_HASVIDEO
;
2952 // If we received the first packet of an A/V stream and no metadata but
2953 // the server returned a valid duration, create a fake metadata packet
2954 // to inform the FLV decoder about the duration.
2955 if (!rt
->received_metadata
&& rt
->duration
> 0) {
2956 if ((ret
= inject_fake_duration_metadata(rt
)) < 0)
2961 rt
->flv_data
= NULL
;
2963 rt
->skip_bytes
= 13;
2966 s
->max_packet_size
= rt
->stream
->max_packet_size
;
2975 static int rtmp_read(URLContext
*s
, uint8_t *buf
, int size
)
2977 RTMPContext
*rt
= s
->priv_data
;
2978 int orig_size
= size
;
2982 int data_left
= rt
->flv_size
- rt
->flv_off
;
2984 if (data_left
>= size
) {
2985 memcpy(buf
, rt
->flv_data
+ rt
->flv_off
, size
);
2986 rt
->flv_off
+= size
;
2989 if (data_left
> 0) {
2990 memcpy(buf
, rt
->flv_data
+ rt
->flv_off
, data_left
);
2993 rt
->flv_off
= rt
->flv_size
;
2996 if ((ret
= get_packet(s
, 0)) < 0)
3002 static int64_t rtmp_seek(void *opaque
, int stream_index
, int64_t timestamp
,
3005 URLContext
*s
= opaque
;
3006 RTMPContext
*rt
= s
->priv_data
;
3008 av_log(s
, AV_LOG_DEBUG
,
3009 "Seek on stream index %d at timestamp %"PRId64
" with flags %08x\n",
3010 stream_index
, timestamp
, flags
);
3011 if ((ret
= gen_seek(s
, rt
, timestamp
)) < 0) {
3012 av_log(s
, AV_LOG_ERROR
,
3013 "Unable to send seek command on stream index %d at timestamp "
3014 "%"PRId64
" with flags %08x\n",
3015 stream_index
, timestamp
, flags
);
3018 rt
->flv_off
= rt
->flv_size
;
3019 rt
->state
= STATE_SEEKING
;
3023 static int rtmp_pause(void *opaque
, int pause
)
3025 URLContext
*s
= opaque
;
3026 RTMPContext
*rt
= s
->priv_data
;
3028 av_log(s
, AV_LOG_DEBUG
, "Pause at timestamp %d\n",
3029 rt
->last_timestamp
);
3030 if ((ret
= gen_pause(s
, rt
, pause
, rt
->last_timestamp
)) < 0) {
3031 av_log(s
, AV_LOG_ERROR
, "Unable to send pause command at timestamp %d\n",
3032 rt
->last_timestamp
);
3038 static int rtmp_write(URLContext
*s
, const uint8_t *buf
, int size
)
3040 RTMPContext
*rt
= s
->priv_data
;
3041 int size_temp
= size
;
3042 int pktsize
, pkttype
, copy
;
3044 const uint8_t *buf_temp
= buf
;
3049 if (rt
->skip_bytes
) {
3050 int skip
= FFMIN(rt
->skip_bytes
, size_temp
);
3053 rt
->skip_bytes
-= skip
;
3057 if (rt
->flv_header_bytes
< RTMP_HEADER
) {
3058 const uint8_t *header
= rt
->flv_header
;
3059 int channel
= RTMP_AUDIO_CHANNEL
;
3061 copy
= FFMIN(RTMP_HEADER
- rt
->flv_header_bytes
, size_temp
);
3062 bytestream_get_buffer(&buf_temp
, rt
->flv_header
+ rt
->flv_header_bytes
, copy
);
3063 rt
->flv_header_bytes
+= copy
;
3065 if (rt
->flv_header_bytes
< RTMP_HEADER
)
3068 pkttype
= bytestream_get_byte(&header
);
3069 pktsize
= bytestream_get_be24(&header
);
3070 ts
= bytestream_get_be24(&header
);
3071 ts
|= bytestream_get_byte(&header
) << 24;
3072 bytestream_get_be24(&header
);
3073 rt
->flv_size
= pktsize
;
3075 if (pkttype
== RTMP_PT_VIDEO
)
3076 channel
= RTMP_VIDEO_CHANNEL
;
3078 if (((pkttype
== RTMP_PT_VIDEO
|| pkttype
== RTMP_PT_AUDIO
) && ts
== 0) ||
3079 pkttype
== RTMP_PT_NOTIFY
) {
3080 if ((ret
= ff_rtmp_check_alloc_array(&rt
->prev_pkt
[1],
3081 &rt
->nb_prev_pkt
[1],
3084 // Force sending a full 12 bytes header by clearing the
3085 // channel id, to make it not match a potential earlier
3086 // packet in the same channel.
3087 rt
->prev_pkt
[1][channel
].channel_id
= 0;
3090 //this can be a big packet, it's better to send it right here
3091 if ((ret
= ff_rtmp_packet_create(&rt
->out_pkt
, channel
,
3092 pkttype
, ts
, pktsize
)) < 0)
3095 // If rt->listen, then we're running as a a server and should
3096 // use the ID that we've sent in Stream Begin and in the
3097 // _result to createStream.
3098 // Otherwise, we're running as a client and should use the ID
3099 // that we've received in the createStream from the server.
3100 rt
->out_pkt
.extra
= (rt
->listen
) ? rt
->nb_streamid
: rt
->stream_id
;
3101 rt
->flv_data
= rt
->out_pkt
.data
;
3104 copy
= FFMIN(rt
->flv_size
- rt
->flv_off
, size_temp
);
3105 bytestream_get_buffer(&buf_temp
, rt
->flv_data
+ rt
->flv_off
, copy
);
3106 rt
->flv_off
+= copy
;
3109 if (rt
->flv_off
== rt
->flv_size
) {
3112 if (rt
->out_pkt
.type
== RTMP_PT_NOTIFY
) {
3113 // For onMetaData and |RtmpSampleAccess packets, we want
3114 // @setDataFrame prepended to the packet before it gets sent.
3115 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3117 uint8_t commandbuffer
[64];
3121 bytestream2_init(&gbc
, rt
->flv_data
, rt
->flv_size
);
3122 if (!ff_amf_read_string(&gbc
, commandbuffer
, sizeof(commandbuffer
),
3124 if (!strcmp(commandbuffer
, "onMetaData") ||
3125 !strcmp(commandbuffer
, "|RtmpSampleAccess")) {
3127 if ((ret
= av_reallocp(&rt
->out_pkt
.data
, rt
->out_pkt
.size
+ 16)) < 0) {
3128 rt
->flv_size
= rt
->flv_off
= rt
->flv_header_bytes
= 0;
3131 memmove(rt
->out_pkt
.data
+ 16, rt
->out_pkt
.data
, rt
->out_pkt
.size
);
3132 rt
->out_pkt
.size
+= 16;
3133 ptr
= rt
->out_pkt
.data
;
3134 ff_amf_write_string(&ptr
, "@setDataFrame");
3139 if ((ret
= rtmp_send_packet(rt
, &rt
->out_pkt
, 0)) < 0)
3143 rt
->flv_header_bytes
= 0;
3144 rt
->flv_nb_packets
++;
3146 } while (buf_temp
- buf
< size
);
3148 if (rt
->flv_nb_packets
< rt
->flush_interval
)
3150 rt
->flv_nb_packets
= 0;
3152 /* set stream into nonblocking mode */
3153 rt
->stream
->flags
|= AVIO_FLAG_NONBLOCK
;
3155 /* try to read one byte from the stream */
3156 ret
= ffurl_read(rt
->stream
, &c
, 1);
3158 /* switch the stream back into blocking mode */
3159 rt
->stream
->flags
&= ~AVIO_FLAG_NONBLOCK
;
3161 if (ret
== AVERROR(EAGAIN
)) {
3162 /* no incoming data to handle */
3164 } else if (ret
< 0) {
3166 } else if (ret
== 1) {
3167 RTMPPacket rpkt
= { 0 };
3169 if ((ret
= ff_rtmp_packet_read_internal(rt
->stream
, &rpkt
,
3172 &rt
->nb_prev_pkt
[0], c
)) <= 0)
3175 if ((ret
= rtmp_parse_result(s
, rt
, &rpkt
)) < 0)
3178 ff_rtmp_packet_destroy(&rpkt
);
3184 #define OFFSET(x) offsetof(RTMPContext, x)
3185 #define DEC AV_OPT_FLAG_DECODING_PARAM
3186 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3188 static const AVOption rtmp_options
[] = {
3189 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
|ENC
},
3190 {"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
},
3191 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
|ENC
},
3192 {"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
},
3193 {"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
},
3194 {"rtmp_enhanced_codecs", "Specify the codec(s) to use in an enhanced rtmp live stream", OFFSET(enhanced_codecs
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, ENC
},
3195 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live
), AV_OPT_TYPE_INT
, {.i64
= -2}, INT_MIN
, INT_MAX
, DEC
, .unit
= "rtmp_live"},
3196 {"any", "both", 0, AV_OPT_TYPE_CONST
, {.i64
= -2}, 0, 0, DEC
, .unit
= "rtmp_live"},
3197 {"live", "live stream", 0, AV_OPT_TYPE_CONST
, {.i64
= -1}, 0, 0, DEC
, .unit
= "rtmp_live"},
3198 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST
, {.i64
= 0}, 0, 0, DEC
, .unit
= "rtmp_live"},
3199 {"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
},
3200 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
|ENC
},
3201 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
},
3202 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash
), AV_OPT_TYPE_BINARY
, .flags
= DEC
},
3203 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, DEC
},
3204 {"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
},
3205 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, DEC
},
3206 {"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
},
3207 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen
), AV_OPT_TYPE_INT
, {.i64
= 0}, INT_MIN
, INT_MAX
, DEC
, .unit
= "rtmp_listen" },
3208 {"listen", "Listen for incoming rtmp connections", OFFSET(listen
), AV_OPT_TYPE_INT
, {.i64
= 0}, INT_MIN
, INT_MAX
, DEC
, .unit
= "rtmp_listen" },
3209 {"tcp_nodelay", "Use TCP_NODELAY to disable Nagle's algorithm", OFFSET(tcp_nodelay
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, 1, DEC
|ENC
},
3210 {"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
, .unit
= "rtmp_listen" },
3214 #define RTMP_PROTOCOL_0(flavor)
3215 #define RTMP_PROTOCOL_1(flavor) \
3216 static const AVClass flavor##_class = { \
3217 .class_name = #flavor, \
3218 .item_name = av_default_item_name, \
3219 .option = rtmp_options, \
3220 .version = LIBAVUTIL_VERSION_INT, \
3223 const URLProtocol ff_##flavor##_protocol = { \
3225 .url_open2 = rtmp_open, \
3226 .url_read = rtmp_read, \
3227 .url_read_seek = rtmp_seek, \
3228 .url_read_pause = rtmp_pause, \
3229 .url_write = rtmp_write, \
3230 .url_close = rtmp_close, \
3231 .priv_data_size = sizeof(RTMPContext), \
3232 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3233 .priv_data_class= &flavor##_class, \
3235 #define RTMP_PROTOCOL_2(flavor, enabled) \
3236 RTMP_PROTOCOL_ ## enabled(flavor)
3237 #define RTMP_PROTOCOL_3(flavor, config) \
3238 RTMP_PROTOCOL_2(flavor, config)
3239 #define RTMP_PROTOCOL(flavor, uppercase) \
3240 RTMP_PROTOCOL_3(flavor, CONFIG_ ## uppercase ## _PROTOCOL)
3242 RTMP_PROTOCOL(rtmp
, RTMP
)
3243 RTMP_PROTOCOL(rtmpe
, RTMPE
)
3244 RTMP_PROTOCOL(rtmps
, RTMPS
)
3245 RTMP_PROTOCOL(rtmpt
, RTMPT
)
3246 RTMP_PROTOCOL(rtmpte
, RTMPTE
)
3247 RTMP_PROTOCOL(rtmpts
, RTMPTS
)