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 "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 1024
52 #define PLAYPATH_MAX_LENGTH 512
53 #define TCURL_MAX_LENGTH 1024
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 uint64_t bytes_read; ///< number of bytes read from server
98 uint64_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);
159 static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt);
160 static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt);
162 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
166 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
167 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
168 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
169 sizeof(*rt->tracked_methods))) < 0) {
170 rt->nb_tracked_methods = 0;
171 rt->tracked_methods_size = 0;
176 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
177 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
178 return AVERROR(ENOMEM);
179 rt->tracked_methods[rt->nb_tracked_methods].id = id;
180 rt->nb_tracked_methods++;
185 static void del_tracked_method(RTMPContext *rt, int index)
187 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
188 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
189 rt->nb_tracked_methods--;
192 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
193 char **tracked_method)
195 RTMPContext *rt = s->priv_data;
201 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
202 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
205 for (i = 0; i < rt->nb_tracked_methods; i++) {
206 if (rt->tracked_methods[i].id != pkt_id)
209 *tracked_method = rt->tracked_methods[i].name;
210 del_tracked_method(rt, i);
217 static void free_tracked_methods(RTMPContext *rt)
221 for (i = 0; i < rt->nb_tracked_methods; i ++)
222 av_freep(&rt->tracked_methods[i].name);
223 av_freep(&rt->tracked_methods);
224 rt->tracked_methods_size = 0;
225 rt->nb_tracked_methods = 0;
228 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
232 if (pkt->type == RTMP_PT_INVOKE && track) {
238 bytestream2_init(&gbc, pkt->data, pkt->size);
239 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
242 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
245 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
249 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
250 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
252 ff_rtmp_packet_destroy(pkt);
256 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
261 /* The type must be B for Boolean, N for number, S for string, O for
262 * object, or Z for null. For Booleans the data must be either 0 or 1 for
263 * FALSE or TRUE, respectively. Likewise for Objects the data must be
264 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
265 * may be named, by prefixing the type with 'N' and specifying the name
266 * before the value (ie. NB:myFlag:1). This option may be used multiple times
267 * to construct arbitrary AMF sequences. */
268 if (param[0] && param[1] == ':') {
271 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
274 value = strchr(field, ':');
280 ff_amf_write_field_name(p, field);
287 ff_amf_write_bool(p, value[0] != '0');
290 ff_amf_write_string(p, value);
293 ff_amf_write_number(p, strtod(value, NULL));
296 ff_amf_write_null(p);
300 ff_amf_write_object_start(p);
302 ff_amf_write_object_end(p);
312 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
313 return AVERROR(EINVAL);
317 * Generate 'connect' call and send it to the server.
319 static int gen_connect(URLContext *s, RTMPContext *rt)
325 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
326 0, 4096 + APP_MAX_LENGTH)) < 0)
331 ff_amf_write_string(&p, "connect");
332 ff_amf_write_number(&p, ++rt->nb_invokes);
333 ff_amf_write_object_start(&p);
334 ff_amf_write_field_name(&p, "app");
335 ff_amf_write_string2(&p, rt->app, rt->auth_params);
338 ff_amf_write_field_name(&p, "type");
339 ff_amf_write_string(&p, "nonprivate");
341 ff_amf_write_field_name(&p, "flashVer");
342 ff_amf_write_string(&p, rt->flashver);
344 if (rt->swfurl || rt->swfverify) {
345 ff_amf_write_field_name(&p, "swfUrl");
347 ff_amf_write_string(&p, rt->swfurl);
349 ff_amf_write_string(&p, rt->swfverify);
352 ff_amf_write_field_name(&p, "tcUrl");
353 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
355 ff_amf_write_field_name(&p, "fpad");
356 ff_amf_write_bool(&p, 0);
357 ff_amf_write_field_name(&p, "capabilities");
358 ff_amf_write_number(&p, 15.0);
360 /* Tell the server we support all the audio codecs except
361 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
362 * which are unused in the RTMP protocol implementation. */
363 ff_amf_write_field_name(&p, "audioCodecs");
364 ff_amf_write_number(&p, 4071.0);
365 ff_amf_write_field_name(&p, "videoCodecs");
366 ff_amf_write_number(&p, 252.0);
367 ff_amf_write_field_name(&p, "videoFunction");
368 ff_amf_write_number(&p, 1.0);
371 ff_amf_write_field_name(&p, "pageUrl");
372 ff_amf_write_string(&p, rt->pageurl);
375 ff_amf_write_object_end(&p);
378 char *param = rt->conn;
380 // Write arbitrary AMF data to the Connect message.
383 param += strspn(param, " ");
386 sep = strchr(param, ' ');
389 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
390 // Invalid AMF parameter.
391 ff_rtmp_packet_destroy(&pkt);
402 pkt.size = p - pkt.data;
404 return rtmp_send_packet(rt, &pkt, 1);
408 #define RTMP_CTRL_ABORT_MESSAGE (2)
410 static int read_connect(URLContext *s, RTMPContext *rt)
412 RTMPPacket pkt = { 0 };
422 // handle RTMP Protocol Control Messages
424 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
425 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
428 ff_rtmp_packet_dump(s, &pkt);
430 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
431 if ((ret = handle_chunk_size(s, &pkt)) < 0) {
432 ff_rtmp_packet_destroy(&pkt);
435 } else if (pkt.type == RTMP_CTRL_ABORT_MESSAGE) {
436 av_log(s, AV_LOG_ERROR, "received abort message\n");
437 ff_rtmp_packet_destroy(&pkt);
438 return AVERROR_UNKNOWN;
439 } else if (pkt.type == RTMP_PT_BYTES_READ) {
440 av_log(s, AV_LOG_TRACE, "received acknowledgement\n");
441 } else if (pkt.type == RTMP_PT_WINDOW_ACK_SIZE) {
442 if ((ret = handle_window_ack_size(s, &pkt)) < 0) {
443 ff_rtmp_packet_destroy(&pkt);
446 } else if (pkt.type == RTMP_PT_SET_PEER_BW) {
447 if ((ret = handle_set_peer_bw(s, &pkt)) < 0) {
448 ff_rtmp_packet_destroy(&pkt);
451 } else if (pkt.type == RTMP_PT_INVOKE) {
452 // received RTMP Command Message
455 av_log(s, AV_LOG_ERROR, "Unknown control message type (%d)\n", pkt.type);
457 ff_rtmp_packet_destroy(&pkt);
461 bytestream2_init(&gbc, cp, pkt.size);
462 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
463 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
464 ff_rtmp_packet_destroy(&pkt);
465 return AVERROR_INVALIDDATA;
467 if (strcmp(command, "connect")) {
468 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
469 ff_rtmp_packet_destroy(&pkt);
470 return AVERROR_INVALIDDATA;
472 ret = ff_amf_read_number(&gbc, &seqnum);
474 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
475 /* Here one could parse an AMF Object with data as flashVers and others. */
476 ret = ff_amf_get_field_value(gbc.buffer,
477 gbc.buffer + bytestream2_get_bytes_left(&gbc),
478 "app", tmpstr, sizeof(tmpstr));
480 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
481 if (!ret && strcmp(tmpstr, rt->app))
482 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
484 ff_rtmp_packet_destroy(&pkt);
486 // Send Window Acknowledgement Size (as defined in specification)
487 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
488 RTMP_PT_WINDOW_ACK_SIZE, 0, 4)) < 0)
491 // Inform the peer about how often we want acknowledgements about what
492 // we send. (We don't check for the acknowledgements currently.)
493 bytestream_put_be32(&p, rt->max_sent_unacked);
494 pkt.size = p - pkt.data;
495 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
496 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
497 ff_rtmp_packet_destroy(&pkt);
500 // Set Peer Bandwidth
501 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
502 RTMP_PT_SET_PEER_BW, 0, 5)) < 0)
505 // Tell the peer to only send this many bytes unless it gets acknowledgements.
506 // This could be any arbitrary value we want here.
507 bytestream_put_be32(&p, rt->max_sent_unacked);
508 bytestream_put_byte(&p, 2); // dynamic
509 pkt.size = p - pkt.data;
510 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
511 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
512 ff_rtmp_packet_destroy(&pkt);
517 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
518 RTMP_PT_USER_CONTROL, 0, 6)) < 0)
522 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
523 bytestream_put_be32(&p, 0); // Stream 0
524 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
525 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
526 ff_rtmp_packet_destroy(&pkt);
531 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
532 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
536 bytestream_put_be32(&p, rt->out_chunk_size);
537 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
538 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
539 ff_rtmp_packet_destroy(&pkt);
543 // Send _result NetConnection.Connect.Success to connect
544 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
546 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
550 ff_amf_write_string(&p, "_result");
551 ff_amf_write_number(&p, seqnum);
553 ff_amf_write_object_start(&p);
554 ff_amf_write_field_name(&p, "fmsVer");
555 ff_amf_write_string(&p, "FMS/3,0,1,123");
556 ff_amf_write_field_name(&p, "capabilities");
557 ff_amf_write_number(&p, 31);
558 ff_amf_write_object_end(&p);
560 ff_amf_write_object_start(&p);
561 ff_amf_write_field_name(&p, "level");
562 ff_amf_write_string(&p, "status");
563 ff_amf_write_field_name(&p, "code");
564 ff_amf_write_string(&p, "NetConnection.Connect.Success");
565 ff_amf_write_field_name(&p, "description");
566 ff_amf_write_string(&p, "Connection succeeded.");
567 ff_amf_write_field_name(&p, "objectEncoding");
568 ff_amf_write_number(&p, 0);
569 ff_amf_write_object_end(&p);
571 pkt.size = p - pkt.data;
572 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
573 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
574 ff_rtmp_packet_destroy(&pkt);
578 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
579 RTMP_PT_INVOKE, 0, 30)) < 0)
582 ff_amf_write_string(&p, "onBWDone");
583 ff_amf_write_number(&p, 0);
584 ff_amf_write_null(&p);
585 ff_amf_write_number(&p, 8192);
586 pkt.size = p - pkt.data;
587 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
588 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
589 ff_rtmp_packet_destroy(&pkt);
595 * Generate 'releaseStream' call and send it to the server. It should make
596 * the server release some channel for media streams.
598 static int gen_release_stream(URLContext *s, RTMPContext *rt)
604 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
605 0, 29 + strlen(rt->playpath))) < 0)
608 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
610 ff_amf_write_string(&p, "releaseStream");
611 ff_amf_write_number(&p, ++rt->nb_invokes);
612 ff_amf_write_null(&p);
613 ff_amf_write_string(&p, rt->playpath);
615 return rtmp_send_packet(rt, &pkt, 1);
619 * Generate 'FCPublish' call and send it to the server. It should make
620 * the server prepare for receiving media streams.
622 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
628 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
629 0, 25 + strlen(rt->playpath))) < 0)
632 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
634 ff_amf_write_string(&p, "FCPublish");
635 ff_amf_write_number(&p, ++rt->nb_invokes);
636 ff_amf_write_null(&p);
637 ff_amf_write_string(&p, rt->playpath);
639 return rtmp_send_packet(rt, &pkt, 1);
643 * Generate 'FCUnpublish' call and send it to the server. It should make
644 * the server destroy stream.
646 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
652 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
653 0, 27 + strlen(rt->playpath))) < 0)
656 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
658 ff_amf_write_string(&p, "FCUnpublish");
659 ff_amf_write_number(&p, ++rt->nb_invokes);
660 ff_amf_write_null(&p);
661 ff_amf_write_string(&p, rt->playpath);
663 return rtmp_send_packet(rt, &pkt, 0);
667 * Generate 'createStream' call and send it to the server. It should make
668 * the server allocate some channel for media streams.
670 static int gen_create_stream(URLContext *s, RTMPContext *rt)
676 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
678 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
683 ff_amf_write_string(&p, "createStream");
684 ff_amf_write_number(&p, ++rt->nb_invokes);
685 ff_amf_write_null(&p);
687 return rtmp_send_packet(rt, &pkt, 1);
692 * Generate 'deleteStream' call and send it to the server. It should make
693 * the server remove some channel for media streams.
695 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
701 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
703 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
708 ff_amf_write_string(&p, "deleteStream");
709 ff_amf_write_number(&p, ++rt->nb_invokes);
710 ff_amf_write_null(&p);
711 ff_amf_write_number(&p, rt->stream_id);
713 return rtmp_send_packet(rt, &pkt, 0);
717 * Generate 'getStreamLength' call and send it to the server. If the server
718 * knows the duration of the selected stream, it will reply with the duration
721 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
727 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
728 0, 31 + strlen(rt->playpath))) < 0)
732 ff_amf_write_string(&p, "getStreamLength");
733 ff_amf_write_number(&p, ++rt->nb_invokes);
734 ff_amf_write_null(&p);
735 ff_amf_write_string(&p, rt->playpath);
737 return rtmp_send_packet(rt, &pkt, 1);
741 * Generate client buffer time and send it to the server.
743 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
749 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
754 bytestream_put_be16(&p, 3); // SetBuffer Length
755 bytestream_put_be32(&p, rt->stream_id);
756 bytestream_put_be32(&p, rt->client_buffer_time);
758 return rtmp_send_packet(rt, &pkt, 0);
762 * Generate 'play' call and send it to the server, then ping the server
763 * to start actual playing.
765 static int gen_play(URLContext *s, RTMPContext *rt)
771 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
773 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
774 0, 29 + strlen(rt->playpath))) < 0)
777 pkt.extra = rt->stream_id;
780 ff_amf_write_string(&p, "play");
781 ff_amf_write_number(&p, ++rt->nb_invokes);
782 ff_amf_write_null(&p);
783 ff_amf_write_string(&p, rt->playpath);
784 ff_amf_write_number(&p, rt->live * 1000);
786 return rtmp_send_packet(rt, &pkt, 1);
789 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
795 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
798 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
801 pkt.extra = rt->stream_id;
804 ff_amf_write_string(&p, "seek");
805 ff_amf_write_number(&p, 0); //no tracking back responses
806 ff_amf_write_null(&p); //as usual, the first null param
807 ff_amf_write_number(&p, timestamp); //where we want to jump
809 return rtmp_send_packet(rt, &pkt, 1);
813 * Generate a pause packet that either pauses or unpauses the current stream.
815 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
821 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
824 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
827 pkt.extra = rt->stream_id;
830 ff_amf_write_string(&p, "pause");
831 ff_amf_write_number(&p, 0); //no tracking back responses
832 ff_amf_write_null(&p); //as usual, the first null param
833 ff_amf_write_bool(&p, pause); // pause or unpause
834 ff_amf_write_number(&p, timestamp); //where we pause the stream
836 return rtmp_send_packet(rt, &pkt, 1);
840 * Generate 'publish' call and send it to the server.
842 static int gen_publish(URLContext *s, RTMPContext *rt)
848 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
850 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
851 0, 30 + strlen(rt->playpath))) < 0)
854 pkt.extra = rt->stream_id;
857 ff_amf_write_string(&p, "publish");
858 ff_amf_write_number(&p, ++rt->nb_invokes);
859 ff_amf_write_null(&p);
860 ff_amf_write_string(&p, rt->playpath);
861 ff_amf_write_string(&p, "live");
863 return rtmp_send_packet(rt, &pkt, 1);
867 * Generate ping reply and send it to the server.
869 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
875 if (ppkt->size < 6) {
876 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
878 return AVERROR_INVALIDDATA;
881 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,RTMP_PT_USER_CONTROL,
882 ppkt->timestamp + 1, 6)) < 0)
886 bytestream_put_be16(&p, 7); // PingResponse
887 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
889 return rtmp_send_packet(rt, &pkt, 0);
893 * Generate SWF verification message and send it to the server.
895 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
901 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
902 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
907 bytestream_put_be16(&p, 27);
908 memcpy(p, rt->swfverification, 42);
910 return rtmp_send_packet(rt, &pkt, 0);
914 * Generate window acknowledgement size message and send it to the server.
916 static int gen_window_ack_size(URLContext *s, RTMPContext *rt)
922 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_WINDOW_ACK_SIZE,
927 bytestream_put_be32(&p, rt->max_sent_unacked);
929 return rtmp_send_packet(rt, &pkt, 0);
933 * Generate check bandwidth message and send it to the server.
935 static int gen_check_bw(URLContext *s, RTMPContext *rt)
941 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
946 ff_amf_write_string(&p, "_checkbw");
947 ff_amf_write_number(&p, ++rt->nb_invokes);
948 ff_amf_write_null(&p);
950 return rtmp_send_packet(rt, &pkt, 1);
954 * Generate report on bytes read so far and send it to the server.
956 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
962 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
967 bytestream_put_be32(&p, rt->bytes_read);
969 return rtmp_send_packet(rt, &pkt, 0);
972 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
973 const char *subscribe)
979 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
980 0, 27 + strlen(subscribe))) < 0)
984 ff_amf_write_string(&p, "FCSubscribe");
985 ff_amf_write_number(&p, ++rt->nb_invokes);
986 ff_amf_write_null(&p);
987 ff_amf_write_string(&p, subscribe);
989 return rtmp_send_packet(rt, &pkt, 1);
992 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
993 const uint8_t *key, int keylen, uint8_t *dst)
997 hmac = av_hmac_alloc(AV_HMAC_SHA256);
999 return AVERROR(ENOMEM);
1001 av_hmac_init(hmac, key, keylen);
1003 av_hmac_update(hmac, src, len);
1004 } else { //skip 32 bytes used for storing digest
1005 av_hmac_update(hmac, src, gap);
1006 av_hmac_update(hmac, src + gap + 32, len - gap - 32);
1008 av_hmac_final(hmac, dst, 32);
1015 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
1018 int i, digest_pos = 0;
1020 for (i = 0; i < 4; i++)
1021 digest_pos += buf[i + off];
1022 digest_pos = digest_pos % mod_val + add_val;
1028 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
1029 * will be stored) into that packet.
1031 * @param buf handshake data (1536 bytes)
1032 * @param encrypted use an encrypted connection (RTMPE)
1033 * @return offset to the digest inside input data
1035 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1037 int ret, digest_pos;
1040 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1042 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1044 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1045 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1054 * Verify that the received server response has the expected digest value.
1056 * @param buf handshake data received from the server (1536 bytes)
1057 * @param off position to search digest offset from
1058 * @return 0 if digest is valid, digest position otherwise
1060 static int rtmp_validate_digest(uint8_t *buf, int off)
1063 int ret, digest_pos;
1065 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1067 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1068 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1073 if (!memcmp(digest, buf + digest_pos, 32))
1078 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1084 if (rt->swfhash_len != 32) {
1085 av_log(s, AV_LOG_ERROR,
1086 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1087 return AVERROR(EINVAL);
1090 p = &rt->swfverification[0];
1091 bytestream_put_byte(&p, 1);
1092 bytestream_put_byte(&p, 1);
1093 bytestream_put_be32(&p, rt->swfsize);
1094 bytestream_put_be32(&p, rt->swfsize);
1096 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1103 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1104 uint8_t **out_data, int64_t *out_size)
1106 z_stream zs = { 0 };
1111 zs.avail_in = in_size;
1112 zs.next_in = in_data;
1113 ret = inflateInit(&zs);
1115 return AVERROR_UNKNOWN;
1118 uint8_t tmp_buf[16384];
1120 zs.avail_out = sizeof(tmp_buf);
1121 zs.next_out = tmp_buf;
1123 ret = inflate(&zs, Z_NO_FLUSH);
1124 if (ret != Z_OK && ret != Z_STREAM_END) {
1125 ret = AVERROR_UNKNOWN;
1129 size = sizeof(tmp_buf) - zs.avail_out;
1130 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1131 ret = AVERROR(ENOMEM);
1136 memcpy(*out_data + *out_size, tmp_buf, size);
1138 } while (zs.avail_out == 0);
1146 static int rtmp_calc_swfhash(URLContext *s)
1148 RTMPContext *rt = s->priv_data;
1149 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1156 /* Get the SWF player file. */
1157 if ((ret = ffurl_open_whitelist(&stream, rt->swfverify, AVIO_FLAG_READ,
1158 &s->interrupt_callback, NULL,
1159 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
1160 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1164 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1169 if (!(in_data = av_malloc(in_size))) {
1170 ret = AVERROR(ENOMEM);
1174 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1178 ret = AVERROR_INVALIDDATA;
1182 if (!memcmp(in_data, "CWS", 3)) {
1185 /* Decompress the SWF player file using Zlib. */
1186 if (!(out_data = av_malloc(8))) {
1187 ret = AVERROR(ENOMEM);
1190 *in_data = 'F'; // magic stuff
1191 memcpy(out_data, in_data, 8);
1194 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1195 &out_data, &out_size)) < 0)
1200 av_log(s, AV_LOG_ERROR,
1201 "Zlib is required for decompressing the SWF player file.\n");
1202 ret = AVERROR(EINVAL);
1210 /* Compute the SHA256 hash of the SWF player file. */
1211 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1212 "Genuine Adobe Flash Player 001", 30,
1216 /* Set SWFVerification parameters. */
1217 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1218 rt->swfsize = swfsize;
1222 av_freep(&out_data);
1223 ffurl_close(stream);
1228 * Perform handshake with the server by means of exchanging pseudorandom data
1229 * signed with HMAC-SHA2 digest.
1231 * @return 0 if handshake succeeds, negative value otherwise
1233 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1236 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1237 3, // unencrypted data
1238 0, 0, 0, 0, // client uptime
1244 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1245 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1247 int server_pos, client_pos;
1248 uint8_t digest[32], signature[32];
1251 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1253 av_lfg_init(&rnd, 0xDEADC0DE);
1254 // generate handshake packet - 1536 bytes of pseudorandom data
1255 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1256 tosend[i] = av_lfg_get(&rnd) >> 24;
1258 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1259 /* When the client wants to use RTMPE, we have to change the command
1260 * byte to 0x06 which means to use encrypted data and we have to set
1261 * the flash version to at least 9.0.115.0. */
1268 /* Initialize the Diffie-Hellmann context and generate the public key
1269 * to send to the server. */
1270 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1274 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1278 if ((ret = ffurl_write(rt->stream, tosend,
1279 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1280 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1284 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1285 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1286 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1290 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1291 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1292 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1296 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1297 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1298 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1300 if (rt->is_input && serverdata[5] >= 3) {
1301 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1307 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1312 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1313 return AVERROR(EIO);
1317 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1318 * key are the last 32 bytes of the server handshake. */
1320 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1321 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1325 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1326 rtmp_server_key, sizeof(rtmp_server_key),
1331 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1332 0, digest, 32, signature);
1336 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1337 /* Compute the shared secret key sent by the server and initialize
1338 * the RC4 encryption. */
1339 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1340 tosend + 1, type)) < 0)
1343 /* Encrypt the signature received by the server. */
1344 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1347 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1348 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1349 return AVERROR(EIO);
1352 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1353 tosend[i] = av_lfg_get(&rnd) >> 24;
1354 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1355 rtmp_player_key, sizeof(rtmp_player_key),
1360 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1362 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1366 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1367 /* Encrypt the signature to be send to the server. */
1368 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1369 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1373 // write reply back to the server
1374 if ((ret = ffurl_write(rt->stream, tosend,
1375 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1378 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1379 /* Set RC4 keys for encryption and update the keystreams. */
1380 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1384 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1385 /* Compute the shared secret key sent by the server and initialize
1386 * the RC4 encryption. */
1387 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1388 tosend + 1, 1)) < 0)
1391 if (serverdata[0] == 9) {
1392 /* Encrypt the signature received by the server. */
1393 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1398 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1399 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1402 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1403 /* Set RC4 keys for encryption and update the keystreams. */
1404 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1412 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1413 uint32_t *second_int, char *arraydata,
1418 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1419 RTMP_HANDSHAKE_PACKET_SIZE);
1421 return AVERROR(EIO);
1422 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1423 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1424 " not following standard\n", (int)inoutsize);
1425 return AVERROR(EINVAL);
1428 *first_int = AV_RB32(arraydata);
1429 *second_int = AV_RB32(arraydata + 4);
1433 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1434 uint32_t second_int, char *arraydata, int size)
1438 AV_WB32(arraydata, first_int);
1439 AV_WB32(arraydata + 4, second_int);
1440 inoutsize = ffurl_write(rt->stream, arraydata,
1441 RTMP_HANDSHAKE_PACKET_SIZE);
1442 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1443 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1444 return AVERROR(EIO);
1451 * rtmp handshake server side
1453 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1455 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1457 uint32_t hs_my_epoch;
1458 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1459 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1466 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1467 if (inoutsize <= 0) {
1468 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1469 return AVERROR(EIO);
1472 if (buffer[0] != 3) {
1473 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1474 return AVERROR(EIO);
1476 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1477 av_log(s, AV_LOG_ERROR,
1478 "Unable to write answer - RTMP S0\n");
1479 return AVERROR(EIO);
1482 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1483 RTMP_HANDSHAKE_PACKET_SIZE);
1485 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1489 /* By now same epoch will be sent */
1490 hs_my_epoch = hs_epoch;
1491 /* Generate random */
1492 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1494 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1496 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1497 RTMP_HANDSHAKE_PACKET_SIZE);
1499 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1503 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1504 RTMP_HANDSHAKE_PACKET_SIZE);
1506 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1510 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1511 RTMP_HANDSHAKE_PACKET_SIZE);
1513 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1516 if (temp != hs_my_epoch)
1517 av_log(s, AV_LOG_WARNING,
1518 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1519 if (memcmp(buffer + 8, hs_s1 + 8,
1520 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1521 av_log(s, AV_LOG_WARNING,
1522 "Erroneous C2 Message random does not match up\n");
1527 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1529 RTMPContext *rt = s->priv_data;
1532 if (pkt->size < 4) {
1533 av_log(s, AV_LOG_ERROR,
1534 "Too short chunk size change packet (%d)\n",
1536 return AVERROR_INVALIDDATA;
1539 if (!rt->is_input) {
1540 /* Send the same chunk size change packet back to the server,
1541 * setting the outgoing chunk size to the same as the incoming one. */
1542 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1543 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1545 rt->out_chunk_size = AV_RB32(pkt->data);
1548 rt->in_chunk_size = AV_RB32(pkt->data);
1549 if (rt->in_chunk_size <= 0) {
1550 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1552 return AVERROR_INVALIDDATA;
1554 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1560 static int handle_user_control(URLContext *s, RTMPPacket *pkt)
1562 RTMPContext *rt = s->priv_data;
1565 if (pkt->size < 2) {
1566 av_log(s, AV_LOG_ERROR, "Too short user control packet (%d)\n",
1568 return AVERROR_INVALIDDATA;
1571 t = AV_RB16(pkt->data);
1572 if (t == 6) { // PingRequest
1573 if ((ret = gen_pong(s, rt, pkt)) < 0)
1575 } else if (t == 26) {
1577 if ((ret = gen_swf_verification(s, rt)) < 0)
1580 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1587 static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt)
1589 RTMPContext *rt = s->priv_data;
1591 if (pkt->size < 4) {
1592 av_log(s, AV_LOG_ERROR,
1593 "Peer bandwidth packet is less than 4 bytes long (%d)\n",
1595 return AVERROR_INVALIDDATA;
1598 // We currently don't check how much the peer has acknowledged of
1599 // what we have sent. To do that properly, we should call
1600 // gen_window_ack_size here, to tell the peer that we want an
1601 // acknowledgement with (at least) that interval.
1602 rt->max_sent_unacked = AV_RB32(pkt->data);
1603 if (rt->max_sent_unacked <= 0) {
1604 av_log(s, AV_LOG_ERROR, "Incorrect set peer bandwidth %d\n",
1605 rt->max_sent_unacked);
1606 return AVERROR_INVALIDDATA;
1609 av_log(s, AV_LOG_DEBUG, "Max sent, unacked = %d\n", rt->max_sent_unacked);
1614 static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt)
1616 RTMPContext *rt = s->priv_data;
1618 if (pkt->size < 4) {
1619 av_log(s, AV_LOG_ERROR,
1620 "Too short window acknowledgement size packet (%d)\n",
1622 return AVERROR_INVALIDDATA;
1625 rt->receive_report_size = AV_RB32(pkt->data);
1626 if (rt->receive_report_size <= 0) {
1627 av_log(s, AV_LOG_ERROR, "Incorrect window acknowledgement size %d\n",
1628 rt->receive_report_size);
1629 return AVERROR_INVALIDDATA;
1631 av_log(s, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", rt->receive_report_size);
1632 // Send an Acknowledgement packet after receiving half the maximum
1633 // size, to make sure the peer can keep on sending without waiting
1634 // for acknowledgements.
1635 rt->receive_report_size >>= 1;
1640 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1641 const char *opaque, const char *challenge)
1644 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1645 struct AVMD5 *md5 = av_md5_alloc();
1647 return AVERROR(ENOMEM);
1649 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1652 av_md5_update(md5, user, strlen(user));
1653 av_md5_update(md5, salt, strlen(salt));
1654 av_md5_update(md5, rt->password, strlen(rt->password));
1655 av_md5_final(md5, hash);
1656 av_base64_encode(hashstr, sizeof(hashstr), hash,
1659 av_md5_update(md5, hashstr, strlen(hashstr));
1661 av_md5_update(md5, opaque, strlen(opaque));
1663 av_md5_update(md5, challenge, strlen(challenge));
1664 av_md5_update(md5, challenge2, strlen(challenge2));
1665 av_md5_final(md5, hash);
1666 av_base64_encode(hashstr, sizeof(hashstr), hash,
1668 snprintf(rt->auth_params, sizeof(rt->auth_params),
1669 "?authmod=%s&user=%s&challenge=%s&response=%s",
1670 "adobe", user, challenge2, hashstr);
1672 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1673 "&opaque=%s", opaque);
1679 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1682 char hashstr1[33], hashstr2[33];
1683 const char *realm = "live";
1684 const char *method = "publish";
1685 const char *qop = "auth";
1686 const char *nc = "00000001";
1688 struct AVMD5 *md5 = av_md5_alloc();
1690 return AVERROR(ENOMEM);
1692 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1695 av_md5_update(md5, user, strlen(user));
1696 av_md5_update(md5, ":", 1);
1697 av_md5_update(md5, realm, strlen(realm));
1698 av_md5_update(md5, ":", 1);
1699 av_md5_update(md5, rt->password, strlen(rt->password));
1700 av_md5_final(md5, hash);
1701 ff_data_to_hex(hashstr1, hash, 16, 1);
1702 hashstr1[32] = '\0';
1705 av_md5_update(md5, method, strlen(method));
1706 av_md5_update(md5, ":/", 2);
1707 av_md5_update(md5, rt->app, strlen(rt->app));
1708 if (!strchr(rt->app, '/'))
1709 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1710 av_md5_final(md5, hash);
1711 ff_data_to_hex(hashstr2, hash, 16, 1);
1712 hashstr2[32] = '\0';
1715 av_md5_update(md5, hashstr1, strlen(hashstr1));
1716 av_md5_update(md5, ":", 1);
1718 av_md5_update(md5, nonce, strlen(nonce));
1719 av_md5_update(md5, ":", 1);
1720 av_md5_update(md5, nc, strlen(nc));
1721 av_md5_update(md5, ":", 1);
1722 av_md5_update(md5, cnonce, strlen(cnonce));
1723 av_md5_update(md5, ":", 1);
1724 av_md5_update(md5, qop, strlen(qop));
1725 av_md5_update(md5, ":", 1);
1726 av_md5_update(md5, hashstr2, strlen(hashstr2));
1727 av_md5_final(md5, hash);
1728 ff_data_to_hex(hashstr1, hash, 16, 1);
1730 snprintf(rt->auth_params, sizeof(rt->auth_params),
1731 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1732 "llnw", user, nonce, cnonce, nc, hashstr1);
1738 static int handle_connect_error(URLContext *s, const char *desc)
1740 RTMPContext *rt = s->priv_data;
1741 char buf[300], *ptr, authmod[15];
1743 const char *user = "", *salt = "", *opaque = NULL,
1744 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1746 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1747 !(cptr = strstr(desc, "authmod=llnw"))) {
1748 av_log(s, AV_LOG_ERROR,
1749 "Unknown connect error (unsupported authentication method?)\n");
1750 return AVERROR_UNKNOWN;
1752 cptr += strlen("authmod=");
1753 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1754 authmod[i++] = *cptr++;
1757 if (!rt->username[0] || !rt->password[0]) {
1758 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1759 return AVERROR_UNKNOWN;
1762 if (strstr(desc, "?reason=authfailed")) {
1763 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1764 return AVERROR_UNKNOWN;
1765 } else if (strstr(desc, "?reason=nosuchuser")) {
1766 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1767 return AVERROR_UNKNOWN;
1770 if (rt->auth_tried) {
1771 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1772 return AVERROR_UNKNOWN;
1775 rt->auth_params[0] = '\0';
1777 if (strstr(desc, "code=403 need auth")) {
1778 snprintf(rt->auth_params, sizeof(rt->auth_params),
1779 "?authmod=%s&user=%s", authmod, rt->username);
1783 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1784 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1785 return AVERROR_UNKNOWN;
1788 av_strlcpy(buf, cptr + 1, sizeof(buf));
1792 char *next = strchr(ptr, '&');
1793 char *value = strchr(ptr, '=');
1798 if (!strcmp(ptr, "user")) {
1800 } else if (!strcmp(ptr, "salt")) {
1802 } else if (!strcmp(ptr, "opaque")) {
1804 } else if (!strcmp(ptr, "challenge")) {
1806 } else if (!strcmp(ptr, "nonce")) {
1809 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1812 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1817 if (!strcmp(authmod, "adobe")) {
1818 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1821 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1829 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1831 RTMPContext *rt = s->priv_data;
1832 const uint8_t *data_end = pkt->data + pkt->size;
1833 char *tracked_method = NULL;
1834 int level = AV_LOG_ERROR;
1835 uint8_t tmpstr[256];
1838 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1841 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1842 "description", tmpstr, sizeof(tmpstr))) {
1843 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1844 !strcmp(tracked_method, "releaseStream") ||
1845 !strcmp(tracked_method, "FCSubscribe") ||
1846 !strcmp(tracked_method, "FCPublish"))) {
1847 /* Gracefully ignore Adobe-specific historical artifact errors. */
1848 level = AV_LOG_WARNING;
1850 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1851 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1853 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1854 ret = handle_connect_error(s, tmpstr);
1856 rt->do_reconnect = 1;
1857 level = AV_LOG_VERBOSE;
1860 ret = AVERROR_UNKNOWN;
1861 av_log(s, level, "Server error: %s\n", tmpstr);
1864 av_free(tracked_method);
1868 static int write_begin(URLContext *s)
1870 RTMPContext *rt = s->priv_data;
1872 RTMPPacket spkt = { 0 };
1875 // Send Stream Begin 1
1876 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1877 RTMP_PT_USER_CONTROL, 0, 6)) < 0) {
1878 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1882 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1883 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1884 bytestream2_put_be32(&pbc, rt->nb_streamid);
1886 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1887 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1889 ff_rtmp_packet_destroy(&spkt);
1894 static int write_status(URLContext *s, RTMPPacket *pkt,
1895 const char *status, const char *filename)
1897 RTMPContext *rt = s->priv_data;
1898 RTMPPacket spkt = { 0 };
1899 char statusmsg[128];
1903 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1905 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1906 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1911 spkt.extra = pkt->extra;
1912 ff_amf_write_string(&pp, "onStatus");
1913 ff_amf_write_number(&pp, 0);
1914 ff_amf_write_null(&pp);
1916 ff_amf_write_object_start(&pp);
1917 ff_amf_write_field_name(&pp, "level");
1918 ff_amf_write_string(&pp, "status");
1919 ff_amf_write_field_name(&pp, "code");
1920 ff_amf_write_string(&pp, status);
1921 ff_amf_write_field_name(&pp, "description");
1922 snprintf(statusmsg, sizeof(statusmsg),
1923 "%s is now published", filename);
1924 ff_amf_write_string(&pp, statusmsg);
1925 ff_amf_write_field_name(&pp, "details");
1926 ff_amf_write_string(&pp, filename);
1927 ff_amf_write_object_end(&pp);
1929 spkt.size = pp - spkt.data;
1930 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1931 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1932 ff_rtmp_packet_destroy(&spkt);
1937 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1939 RTMPContext *rt = s->priv_data;
1945 const uint8_t *p = pkt->data;
1947 RTMPPacket spkt = { 0 };
1951 bytestream2_init(&gbc, p, pkt->size);
1952 if (ff_amf_read_string(&gbc, command, sizeof(command),
1954 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1955 return AVERROR_INVALIDDATA;
1958 ret = ff_amf_read_number(&gbc, &seqnum);
1961 ret = ff_amf_read_null(&gbc);
1964 if (!strcmp(command, "FCPublish") ||
1965 !strcmp(command, "publish")) {
1966 ret = ff_amf_read_string(&gbc, filename,
1967 sizeof(filename), &stringlen);
1969 if (ret == AVERROR(EINVAL))
1970 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
1972 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
1977 pchar = strrchr(s->filename, '/');
1979 av_log(s, AV_LOG_WARNING,
1980 "Unable to find / in url %s, bad format\n",
1982 pchar = s->filename;
1985 if (strcmp(pchar, filename))
1986 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1987 " %s\n", filename, pchar);
1989 rt->state = STATE_RECEIVING;
1992 if (!strcmp(command, "FCPublish")) {
1993 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1995 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1996 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
2000 ff_amf_write_string(&pp, "onFCPublish");
2001 } else if (!strcmp(command, "publish")) {
2002 ret = write_begin(s);
2006 // Send onStatus(NetStream.Publish.Start)
2007 return write_status(s, pkt, "NetStream.Publish.Start",
2009 } else if (!strcmp(command, "play")) {
2010 ret = write_begin(s);
2013 rt->state = STATE_SENDING;
2014 return write_status(s, pkt, "NetStream.Play.Start",
2017 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
2019 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
2020 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
2024 ff_amf_write_string(&pp, "_result");
2025 ff_amf_write_number(&pp, seqnum);
2026 ff_amf_write_null(&pp);
2027 if (!strcmp(command, "createStream")) {
2029 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
2030 rt->nb_streamid++; /* Values 0 and 2 are reserved */
2031 ff_amf_write_number(&pp, rt->nb_streamid);
2032 /* By now we don't control which streams are removed in
2033 * deleteStream. There is no stream creation control
2034 * if a client creates more than 2^32 - 2 streams. */
2037 spkt.size = pp - spkt.data;
2038 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2039 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2040 ff_rtmp_packet_destroy(&spkt);
2045 * Read the AMF_NUMBER response ("_result") to a function call
2046 * (e.g. createStream()). This response should be made up of the AMF_STRING
2047 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2048 * successful response, we will return set the value to number (otherwise number
2049 * will not be changed).
2051 * @return 0 if reading the value succeeds, negative value otherwise
2053 static int read_number_result(RTMPPacket *pkt, double *number)
2055 // We only need to fit "_result" in this.
2056 uint8_t strbuffer[8];
2061 bytestream2_init(&gbc, pkt->data, pkt->size);
2063 // Value 1/4: "_result" as AMF_STRING
2064 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2065 return AVERROR_INVALIDDATA;
2066 if (strcmp(strbuffer, "_result"))
2067 return AVERROR_INVALIDDATA;
2068 // Value 2/4: The callee reference number
2069 if (ff_amf_read_number(&gbc, &numbuffer))
2070 return AVERROR_INVALIDDATA;
2072 if (ff_amf_read_null(&gbc))
2073 return AVERROR_INVALIDDATA;
2074 // Value 4/4: The response as AMF_NUMBER
2075 if (ff_amf_read_number(&gbc, &numbuffer))
2076 return AVERROR_INVALIDDATA;
2078 *number = numbuffer;
2083 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2085 RTMPContext *rt = s->priv_data;
2086 char *tracked_method = NULL;
2089 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2092 if (!tracked_method) {
2093 /* Ignore this reply when the current method is not tracked. */
2097 if (!strcmp(tracked_method, "connect")) {
2098 if (!rt->is_input) {
2099 if ((ret = gen_release_stream(s, rt)) < 0)
2102 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2105 if ((ret = gen_window_ack_size(s, rt)) < 0)
2109 if ((ret = gen_create_stream(s, rt)) < 0)
2113 /* Send the FCSubscribe command when the name of live
2114 * stream is defined by the user or if it's a live stream. */
2115 if (rt->subscribe) {
2116 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2118 } else if (rt->live == -1) {
2119 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2123 } else if (!strcmp(tracked_method, "createStream")) {
2125 if (read_number_result(pkt, &stream_id)) {
2126 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2128 rt->stream_id = stream_id;
2131 if (!rt->is_input) {
2132 if ((ret = gen_publish(s, rt)) < 0)
2135 if (rt->live != -1) {
2136 if ((ret = gen_get_stream_length(s, rt)) < 0)
2139 if ((ret = gen_play(s, rt)) < 0)
2141 if ((ret = gen_buffer_time(s, rt)) < 0)
2144 } else if (!strcmp(tracked_method, "getStreamLength")) {
2145 if (read_number_result(pkt, &rt->duration)) {
2146 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2151 av_free(tracked_method);
2155 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2157 RTMPContext *rt = s->priv_data;
2158 const uint8_t *data_end = pkt->data + pkt->size;
2159 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2160 uint8_t tmpstr[256];
2163 for (i = 0; i < 2; i++) {
2164 t = ff_amf_tag_size(ptr, data_end);
2170 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2171 if (!t && !strcmp(tmpstr, "error")) {
2172 t = ff_amf_get_field_value(ptr, data_end,
2173 "description", tmpstr, sizeof(tmpstr));
2174 if (t || !tmpstr[0])
2175 t = ff_amf_get_field_value(ptr, data_end, "code",
2176 tmpstr, sizeof(tmpstr));
2178 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2182 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2183 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2184 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2185 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2186 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2187 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2192 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2194 RTMPContext *rt = s->priv_data;
2197 //TODO: check for the messages sent for wrong state?
2198 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2199 if ((ret = handle_invoke_error(s, pkt)) < 0)
2201 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2202 if ((ret = handle_invoke_result(s, pkt)) < 0)
2204 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2205 if ((ret = handle_invoke_status(s, pkt)) < 0)
2207 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2208 if ((ret = gen_check_bw(s, rt)) < 0)
2210 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2211 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2212 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2213 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2214 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2215 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2216 if ((ret = send_invoke_response(s, pkt)) < 0)
2223 static int update_offset(RTMPContext *rt, int size)
2227 // generate packet header and put data into buffer for FLV demuxer
2228 if (rt->flv_off < rt->flv_size) {
2229 // There is old unread data in the buffer, thus append at the end
2230 old_flv_size = rt->flv_size;
2231 rt->flv_size += size;
2233 // All data has been read, write the new data at the start of the buffer
2235 rt->flv_size = size;
2239 return old_flv_size;
2242 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2244 int old_flv_size, ret;
2246 const uint8_t *data = pkt->data + skip;
2247 const int size = pkt->size - skip;
2248 uint32_t ts = pkt->timestamp;
2250 if (pkt->type == RTMP_PT_AUDIO) {
2252 } else if (pkt->type == RTMP_PT_VIDEO) {
2256 old_flv_size = update_offset(rt, size + 15);
2258 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2259 rt->flv_size = rt->flv_off = 0;
2262 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2263 bytestream2_skip_p(&pbc, old_flv_size);
2264 bytestream2_put_byte(&pbc, pkt->type);
2265 bytestream2_put_be24(&pbc, size);
2266 bytestream2_put_be24(&pbc, ts);
2267 bytestream2_put_byte(&pbc, ts >> 24);
2268 bytestream2_put_be24(&pbc, 0);
2269 bytestream2_put_buffer(&pbc, data, size);
2270 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2275 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2277 RTMPContext *rt = s->priv_data;
2278 uint8_t commandbuffer[64];
2279 char statusmsg[128];
2280 int stringlen, ret, skip = 0;
2283 bytestream2_init(&gbc, pkt->data, pkt->size);
2284 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2286 return AVERROR_INVALIDDATA;
2288 if (!strcmp(commandbuffer, "onMetaData")) {
2289 // metadata properties should be stored in a mixed array
2290 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2291 // We have found a metaData Array so flv can determine the streams
2293 rt->received_metadata = 1;
2294 // skip 32-bit max array index
2295 bytestream2_skip(&gbc, 4);
2296 while (bytestream2_get_bytes_left(&gbc) > 3) {
2297 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2299 return AVERROR_INVALIDDATA;
2300 // We do not care about the content of the property (yet).
2301 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2303 return AVERROR_INVALIDDATA;
2304 bytestream2_skip(&gbc, stringlen);
2306 // The presence of the following properties indicates that the
2307 // respective streams are present.
2308 if (!strcmp(statusmsg, "videocodecid")) {
2311 if (!strcmp(statusmsg, "audiocodecid")) {
2315 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2316 return AVERROR_INVALIDDATA;
2320 // Skip the @setDataFrame string and validate it is a notification
2321 if (!strcmp(commandbuffer, "@setDataFrame")) {
2322 skip = gbc.buffer - pkt->data;
2323 ret = ff_amf_read_string(&gbc, statusmsg,
2324 sizeof(statusmsg), &stringlen);
2326 return AVERROR_INVALIDDATA;
2329 return append_flv_data(rt, pkt, skip);
2333 * Parse received packet and possibly perform some action depending on
2334 * the packet contents.
2335 * @return 0 for no errors, negative values for serious errors which prevent
2336 * further communications, positive values for uncritical errors
2338 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2343 ff_rtmp_packet_dump(s, pkt);
2346 switch (pkt->type) {
2347 case RTMP_PT_BYTES_READ:
2348 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2350 case RTMP_PT_CHUNK_SIZE:
2351 if ((ret = handle_chunk_size(s, pkt)) < 0)
2354 case RTMP_PT_USER_CONTROL:
2355 if ((ret = handle_user_control(s, pkt)) < 0)
2358 case RTMP_PT_SET_PEER_BW:
2359 if ((ret = handle_set_peer_bw(s, pkt)) < 0)
2362 case RTMP_PT_WINDOW_ACK_SIZE:
2363 if ((ret = handle_window_ack_size(s, pkt)) < 0)
2366 case RTMP_PT_INVOKE:
2367 if ((ret = handle_invoke(s, pkt)) < 0)
2372 case RTMP_PT_METADATA:
2373 case RTMP_PT_NOTIFY:
2374 /* Audio, Video and Metadata packets are parsed in get_packet() */
2377 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2383 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2385 int ret, old_flv_size, type;
2386 const uint8_t *next;
2389 uint32_t ts, cts, pts = 0;
2391 old_flv_size = update_offset(rt, pkt->size);
2393 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2394 rt->flv_size = rt->flv_off = 0;
2399 p = rt->flv_data + old_flv_size;
2401 /* copy data while rewriting timestamps */
2402 ts = pkt->timestamp;
2404 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2405 type = bytestream_get_byte(&next);
2406 size = bytestream_get_be24(&next);
2407 cts = bytestream_get_be24(&next);
2408 cts |= bytestream_get_byte(&next) << 24;
2413 if (size + 3 + 4 > pkt->data + pkt->size - next)
2415 bytestream_put_byte(&p, type);
2416 bytestream_put_be24(&p, size);
2417 bytestream_put_be24(&p, ts);
2418 bytestream_put_byte(&p, ts >> 24);
2419 memcpy(p, next, size + 3 + 4);
2421 bytestream_put_be32(&p, size + RTMP_HEADER);
2422 next += size + 3 + 4;
2424 if (p != rt->flv_data + rt->flv_size) {
2425 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2426 "RTMP_PT_METADATA packet\n");
2427 rt->flv_size = p - rt->flv_data;
2434 * Interact with the server by receiving and sending RTMP packets until
2435 * there is some significant data (media data or expected status notification).
2437 * @param s reading context
2438 * @param for_header non-zero value tells function to work until it
2439 * gets notification from the server that playing has been started,
2440 * otherwise function will work until some media data is received (or
2442 * @return 0 for successful operation, negative value in case of error
2444 static int get_packet(URLContext *s, int for_header)
2446 RTMPContext *rt = s->priv_data;
2449 if (rt->state == STATE_STOPPED)
2453 RTMPPacket rpkt = { 0 };
2454 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2455 rt->in_chunk_size, &rt->prev_pkt[0],
2456 &rt->nb_prev_pkt[0])) <= 0) {
2458 return AVERROR(EAGAIN);
2460 return AVERROR(EIO);
2464 // Track timestamp for later use
2465 rt->last_timestamp = rpkt.timestamp;
2467 rt->bytes_read += ret;
2468 if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) {
2469 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2470 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2472 rt->last_bytes_read = rt->bytes_read;
2475 ret = rtmp_parse_result(s, rt, &rpkt);
2477 // At this point we must check if we are in the seek state and continue
2478 // with the next packet. handle_invoke will get us out of this state
2479 // when the right message is encountered
2480 if (rt->state == STATE_SEEKING) {
2481 ff_rtmp_packet_destroy(&rpkt);
2482 // We continue, let the natural flow of things happen:
2483 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2487 if (ret < 0) {//serious error in current packet
2488 ff_rtmp_packet_destroy(&rpkt);
2491 if (rt->do_reconnect && for_header) {
2492 ff_rtmp_packet_destroy(&rpkt);
2495 if (rt->state == STATE_STOPPED) {
2496 ff_rtmp_packet_destroy(&rpkt);
2499 if (for_header && (rt->state == STATE_PLAYING ||
2500 rt->state == STATE_PUBLISHING ||
2501 rt->state == STATE_SENDING ||
2502 rt->state == STATE_RECEIVING)) {
2503 ff_rtmp_packet_destroy(&rpkt);
2506 if (!rpkt.size || !rt->is_input) {
2507 ff_rtmp_packet_destroy(&rpkt);
2510 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2511 ret = append_flv_data(rt, &rpkt, 0);
2512 ff_rtmp_packet_destroy(&rpkt);
2514 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2515 ret = handle_notify(s, &rpkt);
2516 ff_rtmp_packet_destroy(&rpkt);
2518 } else if (rpkt.type == RTMP_PT_METADATA) {
2519 ret = handle_metadata(rt, &rpkt);
2520 ff_rtmp_packet_destroy(&rpkt);
2523 ff_rtmp_packet_destroy(&rpkt);
2527 static int rtmp_close(URLContext *h)
2529 RTMPContext *rt = h->priv_data;
2532 if (!rt->is_input) {
2533 rt->flv_data = NULL;
2534 if (rt->out_pkt.size)
2535 ff_rtmp_packet_destroy(&rt->out_pkt);
2536 if (rt->state > STATE_FCPUBLISH)
2537 ret = gen_fcunpublish_stream(h, rt);
2539 if (rt->state > STATE_HANDSHAKED)
2540 ret = gen_delete_stream(h, rt);
2541 for (i = 0; i < 2; i++) {
2542 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2543 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2544 av_freep(&rt->prev_pkt[i]);
2547 free_tracked_methods(rt);
2548 av_freep(&rt->flv_data);
2549 ffurl_close(rt->stream);
2554 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2555 * demuxer about the duration of the stream.
2557 * This should only be done if there was no real onMetadata packet sent by the
2558 * server at the start of the stream and if we were able to retrieve a valid
2559 * duration via a getStreamLength call.
2561 * @return 0 for successful operation, negative value in case of error
2563 static int inject_fake_duration_metadata(RTMPContext *rt)
2565 // We need to insert the metadata packet directly after the FLV
2566 // header, i.e. we need to move all other already read data by the
2567 // size of our fake metadata packet.
2570 // Keep old flv_data pointer
2571 uint8_t* old_flv_data = rt->flv_data;
2572 // Allocate a new flv_data pointer with enough space for the additional package
2573 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2574 rt->flv_data = old_flv_data;
2575 return AVERROR(ENOMEM);
2579 memcpy(rt->flv_data, old_flv_data, 13);
2580 // Copy remaining packets
2581 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2582 // Increase the size by the injected packet
2584 // Delete the old FLV data
2585 av_freep(&old_flv_data);
2587 p = rt->flv_data + 13;
2588 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2589 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2590 bytestream_put_be24(&p, 0); // timestamp
2591 bytestream_put_be32(&p, 0); // reserved
2593 // first event name as a string
2594 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2595 // "onMetaData" as AMF string
2596 bytestream_put_be16(&p, 10);
2597 bytestream_put_buffer(&p, "onMetaData", 10);
2599 // mixed array (hash) with size and string/type/data tuples
2600 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2601 bytestream_put_be32(&p, 1); // metadata_count
2603 // "duration" as AMF string
2604 bytestream_put_be16(&p, 8);
2605 bytestream_put_buffer(&p, "duration", 8);
2606 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2607 bytestream_put_be64(&p, av_double2int(rt->duration));
2610 bytestream_put_be16(&p, 0); // Empty string
2611 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2612 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2618 * Open RTMP connection and verify that the stream can be played.
2620 * URL syntax: rtmp://server[:port][/app][/playpath]
2621 * where 'app' is first one or two directories in the path
2622 * (e.g. /ondemand/, /flash/live/, etc.)
2623 * and 'playpath' is a file name (the rest of the path,
2624 * may be prefixed with "mp4:")
2626 static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
2628 RTMPContext *rt = s->priv_data;
2629 char proto[8], hostname[256], path[1024], auth[100], *fname;
2630 char *old_app, *qmark, *n, fname_buffer[1024];
2635 if (rt->listen_timeout > 0)
2638 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2640 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2641 hostname, sizeof(hostname), &port,
2642 path, sizeof(path), s->filename);
2644 n = strchr(path, ' ');
2646 av_log(s, AV_LOG_WARNING,
2647 "Detected librtmp style URL parameters, these aren't supported "
2648 "by the libavformat internal RTMP handler currently enabled. "
2649 "See the documentation for the correct way to pass parameters.\n");
2650 *n = '\0'; // Trim not supported part
2654 char *ptr = strchr(auth, ':');
2657 av_strlcpy(rt->username, auth, sizeof(rt->username));
2658 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2662 if (rt->listen && strcmp(proto, "rtmp")) {
2663 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2665 return AVERROR(EINVAL);
2667 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2668 if (!strcmp(proto, "rtmpts"))
2669 av_dict_set(opts, "ffrtmphttp_tls", "1", 1);
2671 /* open the http tunneling connection */
2672 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2673 } else if (!strcmp(proto, "rtmps")) {
2674 /* open the tls connection */
2676 port = RTMPS_DEFAULT_PORT;
2677 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2678 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2679 if (!strcmp(proto, "rtmpte"))
2680 av_dict_set(opts, "ffrtmpcrypt_tunneling", "1", 1);
2682 /* open the encrypted connection */
2683 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2686 /* open the tcp connection */
2688 port = RTMP_DEFAULT_PORT;
2690 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2691 "?listen&listen_timeout=%d",
2692 rt->listen_timeout * 1000);
2694 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2698 if ((ret = ffurl_open_whitelist(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2699 &s->interrupt_callback, opts,
2700 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
2701 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2705 if (rt->swfverify) {
2706 if ((ret = rtmp_calc_swfhash(s)) < 0)
2710 rt->state = STATE_START;
2711 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2713 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2716 rt->out_chunk_size = 128;
2717 rt->in_chunk_size = 128; // Probably overwritten later
2718 rt->state = STATE_HANDSHAKED;
2720 // Keep the application name when it has been defined by the user.
2723 rt->app = av_malloc(APP_MAX_LENGTH);
2725 ret = AVERROR(ENOMEM);
2729 //extract "app" part from path
2730 qmark = strchr(path, '?');
2731 if (qmark && strstr(qmark, "slist=")) {
2733 // After slist we have the playpath, the full path is used as app
2734 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2735 fname = strstr(path, "slist=") + 6;
2736 // Strip any further query parameters from fname
2737 amp = strchr(fname, '&');
2739 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2740 sizeof(fname_buffer)));
2741 fname = fname_buffer;
2743 } else if (!strncmp(path, "/ondemand/", 10)) {
2745 memcpy(rt->app, "ondemand", 9);
2747 char *next = *path ? path + 1 : path;
2748 char *p = strchr(next, '/');
2751 // If name of application has been defined by the user, assume that
2752 // playpath is provided in the URL
2756 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2759 // make sure we do not mismatch a playpath for an application instance
2760 char *c = strchr(p + 1, ':');
2761 fname = strchr(p + 1, '/');
2762 if (!fname || (c && c < fname)) {
2764 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2767 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2773 // The name of application has been defined by the user, override it.
2774 if (strlen(old_app) >= APP_MAX_LENGTH) {
2775 ret = AVERROR(EINVAL);
2782 if (!rt->playpath) {
2783 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2784 if (!rt->playpath) {
2785 ret = AVERROR(ENOMEM);
2790 int len = strlen(fname);
2791 if (!strchr(fname, ':') && len >= 4 &&
2792 (!strcmp(fname + len - 4, ".f4v") ||
2793 !strcmp(fname + len - 4, ".mp4"))) {
2794 memcpy(rt->playpath, "mp4:", 5);
2796 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2797 fname[len - 4] = '\0';
2798 rt->playpath[0] = 0;
2800 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2802 rt->playpath[0] = '\0';
2807 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2809 ret = AVERROR(ENOMEM);
2812 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2813 port, "/%s", rt->app);
2816 if (!rt->flashver) {
2817 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2818 if (!rt->flashver) {
2819 ret = AVERROR(ENOMEM);
2823 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2824 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2825 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2827 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2828 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2832 rt->receive_report_size = 1048576;
2836 rt->received_metadata = 0;
2837 rt->last_bytes_read = 0;
2838 rt->max_sent_unacked = 2500000;
2841 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2842 proto, path, rt->app, rt->playpath);
2844 if ((ret = gen_connect(s, rt)) < 0)
2847 if ((ret = read_connect(s, s->priv_data)) < 0)
2852 ret = get_packet(s, 1);
2853 } while (ret == AVERROR(EAGAIN));
2857 if (rt->do_reconnect) {
2859 ffurl_close(rt->stream);
2861 rt->do_reconnect = 0;
2863 for (i = 0; i < 2; i++)
2864 memset(rt->prev_pkt[i], 0,
2865 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2866 free_tracked_methods(rt);
2871 // generate FLV header for demuxer
2873 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2876 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2878 // Read packets until we reach the first A/V packet or read metadata.
2879 // If there was a metadata package in front of the A/V packets, we can
2880 // build the FLV header from this. If we do not receive any metadata,
2881 // the FLV decoder will allocate the needed streams when their first
2882 // audio or video packet arrives.
2883 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2884 if ((ret = get_packet(s, 0)) < 0)
2888 // Either after we have read the metadata or (if there is none) the
2889 // first packet of an A/V stream, we have a better knowledge about the
2890 // streams, so set the FLV header accordingly.
2891 if (rt->has_audio) {
2892 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2894 if (rt->has_video) {
2895 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2898 // If we received the first packet of an A/V stream and no metadata but
2899 // the server returned a valid duration, create a fake metadata packet
2900 // to inform the FLV decoder about the duration.
2901 if (!rt->received_metadata && rt->duration > 0) {
2902 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2907 rt->flv_data = NULL;
2909 rt->skip_bytes = 13;
2912 s->max_packet_size = rt->stream->max_packet_size;
2922 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2924 RTMPContext *rt = s->priv_data;
2925 int orig_size = size;
2929 int data_left = rt->flv_size - rt->flv_off;
2931 if (data_left >= size) {
2932 memcpy(buf, rt->flv_data + rt->flv_off, size);
2933 rt->flv_off += size;
2936 if (data_left > 0) {
2937 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2940 rt->flv_off = rt->flv_size;
2943 if ((ret = get_packet(s, 0)) < 0)
2949 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2952 RTMPContext *rt = s->priv_data;
2954 av_log(s, AV_LOG_DEBUG,
2955 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2956 stream_index, timestamp, flags);
2957 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2958 av_log(s, AV_LOG_ERROR,
2959 "Unable to send seek command on stream index %d at timestamp "
2960 "%"PRId64" with flags %08x\n",
2961 stream_index, timestamp, flags);
2964 rt->flv_off = rt->flv_size;
2965 rt->state = STATE_SEEKING;
2969 static int rtmp_pause(URLContext *s, int pause)
2971 RTMPContext *rt = s->priv_data;
2973 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2974 rt->last_timestamp);
2975 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2976 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2977 rt->last_timestamp);
2983 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2985 RTMPContext *rt = s->priv_data;
2986 int size_temp = size;
2987 int pktsize, pkttype, copy;
2989 const uint8_t *buf_temp = buf;
2994 if (rt->skip_bytes) {
2995 int skip = FFMIN(rt->skip_bytes, size_temp);
2998 rt->skip_bytes -= skip;
3002 if (rt->flv_header_bytes < RTMP_HEADER) {
3003 const uint8_t *header = rt->flv_header;
3004 int channel = RTMP_AUDIO_CHANNEL;
3006 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
3007 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
3008 rt->flv_header_bytes += copy;
3010 if (rt->flv_header_bytes < RTMP_HEADER)
3013 pkttype = bytestream_get_byte(&header);
3014 pktsize = bytestream_get_be24(&header);
3015 ts = bytestream_get_be24(&header);
3016 ts |= bytestream_get_byte(&header) << 24;
3017 bytestream_get_be24(&header);
3018 rt->flv_size = pktsize;
3020 if (pkttype == RTMP_PT_VIDEO)
3021 channel = RTMP_VIDEO_CHANNEL;
3023 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
3024 pkttype == RTMP_PT_NOTIFY) {
3025 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
3026 &rt->nb_prev_pkt[1],
3029 // Force sending a full 12 bytes header by clearing the
3030 // channel id, to make it not match a potential earlier
3031 // packet in the same channel.
3032 rt->prev_pkt[1][channel].channel_id = 0;
3035 //this can be a big packet, it's better to send it right here
3036 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3037 pkttype, ts, pktsize)) < 0)
3040 rt->out_pkt.extra = rt->stream_id;
3041 rt->flv_data = rt->out_pkt.data;
3044 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3045 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3046 rt->flv_off += copy;
3049 if (rt->flv_off == rt->flv_size) {
3052 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3053 // For onMetaData and |RtmpSampleAccess packets, we want
3054 // @setDataFrame prepended to the packet before it gets sent.
3055 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3057 uint8_t commandbuffer[64];
3061 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3062 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3064 if (!strcmp(commandbuffer, "onMetaData") ||
3065 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3067 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3068 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3071 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3072 rt->out_pkt.size += 16;
3073 ptr = rt->out_pkt.data;
3074 ff_amf_write_string(&ptr, "@setDataFrame");
3079 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3083 rt->flv_header_bytes = 0;
3084 rt->flv_nb_packets++;
3086 } while (buf_temp - buf < size);
3088 if (rt->flv_nb_packets < rt->flush_interval)
3090 rt->flv_nb_packets = 0;
3092 /* set stream into nonblocking mode */
3093 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3095 /* try to read one byte from the stream */
3096 ret = ffurl_read(rt->stream, &c, 1);
3098 /* switch the stream back into blocking mode */
3099 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3101 if (ret == AVERROR(EAGAIN)) {
3102 /* no incoming data to handle */
3104 } else if (ret < 0) {
3106 } else if (ret == 1) {
3107 RTMPPacket rpkt = { 0 };
3109 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3112 &rt->nb_prev_pkt[0], c)) <= 0)
3115 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3118 ff_rtmp_packet_destroy(&rpkt);
3124 #define OFFSET(x) offsetof(RTMPContext, x)
3125 #define DEC AV_OPT_FLAG_DECODING_PARAM
3126 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3128 static const AVOption rtmp_options[] = {
3129 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3130 {"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},
3131 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3132 {"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},
3133 {"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},
3134 {"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"},
3135 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3136 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3137 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3138 {"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},
3139 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3140 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3141 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3142 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3143 {"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},
3144 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3145 {"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},
3146 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3147 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3148 {"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" },
3152 #define RTMP_PROTOCOL(flavor) \
3153 static const AVClass flavor##_class = { \
3154 .class_name = #flavor, \
3155 .item_name = av_default_item_name, \
3156 .option = rtmp_options, \
3157 .version = LIBAVUTIL_VERSION_INT, \
3160 const URLProtocol ff_##flavor##_protocol = { \
3162 .url_open2 = rtmp_open, \
3163 .url_read = rtmp_read, \
3164 .url_read_seek = rtmp_seek, \
3165 .url_read_pause = rtmp_pause, \
3166 .url_write = rtmp_write, \
3167 .url_close = rtmp_close, \
3168 .priv_data_size = sizeof(RTMPContext), \
3169 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3170 .priv_data_class= &flavor##_class, \
3175 RTMP_PROTOCOL(rtmpe)
3176 RTMP_PROTOCOL(rtmps)
3177 RTMP_PROTOCOL(rtmpt)
3178 RTMP_PROTOCOL(rtmpte)
3179 RTMP_PROTOCOL(rtmpts)